aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dictionaries/ro_wordlist.combined.gzbin0 -> 3874544 bytes
-rw-r--r--dictionaries/ru_wordlist.combined.gzbin1384967 -> 1395338 bytes
-rw-r--r--java-overridable/src/com/android/inputmethod/compat/AppWorkaroundsHelper.java (renamed from java/src/com/android/inputmethod/compat/AppWorkaroundsHelper.java)0
-rw-r--r--java-overridable/src/com/android/inputmethod/dictionarypack/DictionaryPackConstants.java (renamed from java/src/com/android/inputmethod/dictionarypack/DictionaryPackConstants.java)0
-rw-r--r--java-overridable/src/com/android/inputmethod/dictionarypack/MetadataUriGetter.java (renamed from java/src/com/android/inputmethod/dictionarypack/MetadataUriGetter.java)0
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/SpecialKeyDetector.java43
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/about/AboutPreferences.java (renamed from java/src/com/android/inputmethod/latin/about/AboutPreferences.java)0
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/define/DebugFlags.java (renamed from java/src/com/android/inputmethod/latin/define/DebugFlags.java)0
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/define/JniLibName.java (renamed from java/src/com/android/inputmethod/latin/define/JniLibName.java)0
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java (renamed from java/src/com/android/inputmethod/latin/define/ProductionFlags.java)19
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/personalization/ContextualDictionaryUpdater.java (renamed from java/src/com/android/inputmethod/latin/personalization/ContextualDictionaryUpdater.java)0
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdater.java (renamed from java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdater.java)0
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java (renamed from java/src/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java)0
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/utils/FeedbackUtils.java (renamed from java/src/com/android/inputmethod/latin/utils/FeedbackUtils.java)4
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/utils/FileTransforms.java (renamed from java/src/com/android/inputmethod/latin/utils/FileTransforms.java)0
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/utils/MetadataFileUriGetter.java (renamed from java/src/com/android/inputmethod/latin/utils/MetadataFileUriGetter.java)0
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/utils/StatsUtils.java (renamed from java/src/com/android/inputmethod/latin/utils/StatsUtils.java)0
-rw-r--r--java/Android.mk4
-rw-r--r--java/AndroidManifest.xml2
-rw-r--r--java/res/anim/key_preview_dismiss_holo.xml32
-rw-r--r--java/res/anim/key_preview_dismiss_lxx.xml32
-rw-r--r--java/res/anim/key_preview_show_up_holo.xml32
-rw-r--r--java/res/anim/key_preview_show_up_lxx.xml32
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_active_lxx_dark.9.pngbin1710 -> 1200 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_active_lxx_light.9.pngbin1470 -> 1199 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_active_pressed_lxx_dark.9.pngbin1756 -> 1195 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_key_active_pressed_lxx_light.9.pngbin1237 -> 1200 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_spacebar_normal_lxx_dark.9.png (renamed from java/res/drawable-hdpi/sym_keyboard_spacebar_lxx_dark.9.png)bin306 -> 306 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_spacebar_normal_lxx_light.9.png (renamed from java/res/drawable-hdpi/sym_keyboard_spacebar_lxx_light.9.png)bin333 -> 333 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.pngbin0 -> 321 bytes
-rw-r--r--java/res/drawable-hdpi/btn_keyboard_spacebar_pressed_lxx_light.9.pngbin0 -> 346 bytes
-rw-r--r--java/res/drawable-hdpi/ic_add_circle_wht_24dp.pngbin0 -> 436 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_people_activated_lxx_dark.pngbin1374 -> 1508 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_people_activated_lxx_light.pngbin1485 -> 1619 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_people_normal_lxx_dark.pngbin1221 -> 1282 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_people_normal_lxx_light.pngbin1274 -> 1346 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_places_activated_lxx_dark.pngbin1178 -> 1116 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_places_activated_lxx_light.pngbin1147 -> 1099 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_places_normal_lxx_dark.pngbin1021 -> 964 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_places_normal_lxx_light.pngbin1053 -> 978 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_recents_activated_lxx_dark.pngbin1317 -> 1411 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_recents_activated_lxx_light.pngbin1377 -> 1500 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_recents_normal_lxx_dark.pngbin1165 -> 1233 bytes
-rw-r--r--java/res/drawable-hdpi/ic_emoji_recents_normal_lxx_light.pngbin1256 -> 1277 bytes
-rw-r--r--java/res/drawable-hdpi/ic_launcher_keyboard.pngbin8523 -> 3967 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_background_lxx_dark.9.pngbin0 -> 170 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_background_lxx_light.9.pngbin0 -> 165 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_key_feedback_background_lxx_dark.9.pngbin774 -> 937 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_key_feedback_background_lxx_light.9.pngbin714 -> 901 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_key_feedback_more_background_lxx_dark.9.pngbin1020 -> 1199 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_key_feedback_more_background_lxx_light.9.pngbin974 -> 1123 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_suggest_strip_lxx_dark.9.pngbin0 -> 170 bytes
-rw-r--r--java/res/drawable-hdpi/keyboard_suggest_strip_lxx_light.9.pngbin0 -> 168 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_smiley_lxx_light.pngbin1134 -> 1619 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_space_lxx_dark.pngbin0 -> 402 bytes
-rw-r--r--java/res/drawable-hdpi/sym_keyboard_space_lxx_light.pngbin0 -> 407 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_active_lxx_dark.9.pngbin1094 -> 782 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_active_lxx_light.9.pngbin974 -> 781 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_active_pressed_lxx_dark.9.pngbin1159 -> 778 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_key_active_pressed_lxx_light.9.pngbin868 -> 782 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_spacebar_normal_lxx_dark.9.png (renamed from java/res/drawable-mdpi/sym_keyboard_spacebar_lxx_dark.9.png)bin234 -> 234 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_spacebar_normal_lxx_light.9.png (renamed from java/res/drawable-mdpi/sym_keyboard_spacebar_lxx_light.9.png)bin260 -> 260 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.pngbin0 -> 244 bytes
-rw-r--r--java/res/drawable-mdpi/btn_keyboard_spacebar_pressed_lxx_light.9.pngbin0 -> 265 bytes
-rw-r--r--java/res/drawable-mdpi/ic_add_circle_wht_24dp.pngbin0 -> 305 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_people_activated_lxx_dark.pngbin912 -> 929 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_people_activated_lxx_light.pngbin963 -> 996 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_people_normal_lxx_dark.pngbin835 -> 866 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_people_normal_lxx_light.pngbin864 -> 911 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_places_activated_lxx_dark.pngbin868 -> 811 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_places_activated_lxx_light.pngbin859 -> 819 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_places_normal_lxx_dark.pngbin759 -> 708 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_places_normal_lxx_light.pngbin778 -> 711 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_recents_activated_lxx_dark.pngbin877 -> 869 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_recents_activated_lxx_light.pngbin925 -> 946 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_recents_normal_lxx_dark.pngbin804 -> 828 bytes
-rw-r--r--java/res/drawable-mdpi/ic_emoji_recents_normal_lxx_light.pngbin864 -> 846 bytes
-rw-r--r--java/res/drawable-mdpi/ic_launcher_keyboard.pngbin4772 -> 2586 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_background_lxx_dark.9.pngbin0 -> 159 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_background_lxx_light.9.pngbin0 -> 158 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_key_feedback_background_lxx_dark.9.pngbin517 -> 580 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_key_feedback_background_lxx_light.9.pngbin494 -> 553 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_key_feedback_more_background_lxx_dark.9.pngbin658 -> 716 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_key_feedback_more_background_lxx_light.9.pngbin643 -> 709 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_suggest_strip_lxx_dark.9.pngbin0 -> 159 bytes
-rw-r--r--java/res/drawable-mdpi/keyboard_suggest_strip_lxx_light.9.pngbin0 -> 159 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_smiley_lxx_light.pngbin777 -> 996 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_space_lxx_dark.pngbin0 -> 379 bytes
-rw-r--r--java/res/drawable-mdpi/sym_keyboard_space_lxx_light.pngbin0 -> 395 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_active_lxx_dark.9.pngbin2258 -> 1534 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_active_lxx_light.9.pngbin1978 -> 1538 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_active_pressed_lxx_dark.9.pngbin2380 -> 1536 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_key_active_pressed_lxx_light.9.pngbin1648 -> 1534 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_spacebar_normal_lxx_dark.9.png (renamed from java/res/drawable-xhdpi/sym_keyboard_spacebar_lxx_dark.9.png)bin386 -> 386 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_spacebar_normal_lxx_light.9.png (renamed from java/res/drawable-xhdpi/sym_keyboard_spacebar_lxx_light.9.png)bin415 -> 415 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.pngbin0 -> 398 bytes
-rw-r--r--java/res/drawable-xhdpi/btn_keyboard_spacebar_pressed_lxx_light.9.pngbin0 -> 450 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_add_circle_wht_24dp.pngbin0 -> 466 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_people_activated_lxx_dark.pngbin1948 -> 2093 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_people_activated_lxx_light.pngbin2027 -> 2089 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_people_normal_lxx_dark.pngbin1678 -> 1714 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_people_normal_lxx_light.pngbin1713 -> 1748 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_places_activated_lxx_dark.pngbin1504 -> 1303 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_places_activated_lxx_light.pngbin1483 -> 1240 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_places_normal_lxx_dark.pngbin1265 -> 1042 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_places_normal_lxx_light.pngbin1280 -> 1055 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_recents_activated_lxx_dark.pngbin1878 -> 2017 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_recents_activated_lxx_light.pngbin1907 -> 1967 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_recents_normal_lxx_dark.pngbin1597 -> 1670 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_emoji_recents_normal_lxx_light.pngbin1612 -> 1674 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_launcher_keyboard.pngbin13098 -> 5387 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_background_lxx_dark.9.pngbin0 -> 190 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_background_lxx_light.9.pngbin0 -> 186 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_key_feedback_background_lxx_dark.9.pngbin1073 -> 1312 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_key_feedback_background_lxx_light.9.pngbin943 -> 1166 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_key_feedback_more_background_lxx_dark.9.pngbin1304 -> 1564 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_key_feedback_more_background_lxx_light.9.pngbin1218 -> 1443 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_suggest_strip_lxx_dark.9.pngbin0 -> 190 bytes
-rw-r--r--java/res/drawable-xhdpi/keyboard_suggest_strip_lxx_light.9.pngbin0 -> 188 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_smiley_lxx_light.pngbin1344 -> 2089 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_space_lxx_dark.pngbin0 -> 416 bytes
-rw-r--r--java/res/drawable-xhdpi/sym_keyboard_space_lxx_light.pngbin0 -> 421 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_key_active_lxx_dark.9.pngbin3615 -> 2588 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_key_active_lxx_light.9.pngbin3280 -> 2584 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_key_active_pressed_lxx_dark.9.pngbin3712 -> 2585 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_key_active_pressed_lxx_light.9.pngbin2662 -> 2588 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_spacebar_normal_lxx_dark.9.png (renamed from java/res/drawable-xxhdpi/sym_keyboard_spacebar_lxx_dark.9.png)bin585 -> 585 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_spacebar_normal_lxx_light.9.png (renamed from java/res/drawable-xxhdpi/sym_keyboard_spacebar_lxx_light.9.png)bin658 -> 658 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.pngbin0 -> 608 bytes
-rw-r--r--java/res/drawable-xxhdpi/btn_keyboard_spacebar_pressed_lxx_light.9.pngbin0 -> 673 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_add_circle_wht_24dp.pngbin0 -> 684 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_people_activated_lxx_dark.pngbin3232 -> 3277 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_people_activated_lxx_light.pngbin3261 -> 3338 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_people_normal_lxx_dark.pngbin2671 -> 2674 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_people_normal_lxx_light.pngbin2808 -> 3035 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_places_activated_lxx_dark.pngbin2121 -> 1716 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_places_activated_lxx_light.pngbin2032 -> 1655 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_places_normal_lxx_dark.pngbin1759 -> 1503 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_places_normal_lxx_light.pngbin1802 -> 1516 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_recents_activated_lxx_dark.pngbin3069 -> 3096 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_recents_activated_lxx_light.pngbin3062 -> 3139 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_recents_normal_lxx_dark.pngbin2591 -> 2541 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_emoji_recents_normal_lxx_light.pngbin2753 -> 2873 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_launcher_keyboard.pngbin25067 -> 8365 bytes
-rw-r--r--java/res/drawable-xxhdpi/keyboard_background_lxx_dark.9.pngbin0 -> 225 bytes
-rw-r--r--java/res/drawable-xxhdpi/keyboard_background_lxx_light.9.pngbin0 -> 219 bytes
-rw-r--r--java/res/drawable-xxhdpi/keyboard_key_feedback_background_lxx_dark.9.pngbin1751 -> 2162 bytes
-rw-r--r--java/res/drawable-xxhdpi/keyboard_key_feedback_background_lxx_light.9.pngbin1573 -> 1975 bytes
-rw-r--r--java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_lxx_dark.9.pngbin2164 -> 2584 bytes
-rw-r--r--java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_lxx_light.9.pngbin2000 -> 2381 bytes
-rw-r--r--java/res/drawable-xxhdpi/keyboard_suggest_strip_lxx_dark.9.pngbin0 -> 223 bytes
-rw-r--r--java/res/drawable-xxhdpi/keyboard_suggest_strip_lxx_light.9.pngbin0 -> 222 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_smiley_lxx_light.pngbin1967 -> 3338 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_space_lxx_dark.pngbin0 -> 440 bytes
-rw-r--r--java/res/drawable-xxhdpi/sym_keyboard_space_lxx_light.pngbin0 -> 451 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_key_active_lxx_dark.9.pngbin0 -> 3343 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_key_active_lxx_light.9.pngbin0 -> 3342 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_key_active_pressed_lxx_dark.9.pngbin0 -> 3341 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_key_active_pressed_lxx_light.9.pngbin0 -> 3340 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_key_normal_off_lxx_dark.9.pngbin0 -> 1162 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_key_normal_off_lxx_light.9.pngbin0 -> 1152 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_key_normal_on_lxx_dark.9.pngbin0 -> 1167 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_key_normal_on_lxx_light.9.pngbin0 -> 1164 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_key_popup_selected_lxx_dark.9.pngbin0 -> 1232 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_key_popup_selected_lxx_light.9.pngbin0 -> 1284 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_key_pressed_off_lxx_dark.9.pngbin0 -> 1147 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_key_pressed_off_lxx_light.9.pngbin0 -> 1156 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_key_pressed_on_lxx_dark.9.pngbin0 -> 1167 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_key_pressed_on_lxx_light.9.pngbin0 -> 1172 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_spacebar_normal_lxx_dark.9.pngbin0 -> 1554 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_spacebar_normal_lxx_light.9.pngbin0 -> 1611 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.pngbin0 -> 1606 bytes
-rw-r--r--java/res/drawable-xxxhdpi/btn_keyboard_spacebar_pressed_lxx_light.9.pngbin0 -> 1655 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_add_circle_white_24dp.pngbin0 -> 889 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_emoticons_activated_lxx_dark.pngbin0 -> 3558 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_emoticons_activated_lxx_light.pngbin0 -> 4392 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_emoticons_normal_lxx_dark.pngbin0 -> 3150 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_emoticons_normal_lxx_light.pngbin0 -> 3974 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_nature_activated_lxx_dark.pngbin0 -> 3158 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_nature_activated_lxx_light.pngbin0 -> 3266 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_nature_normal_lxx_dark.pngbin0 -> 2918 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_nature_normal_lxx_light.pngbin0 -> 2992 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_objects_activated_lxx_dark.pngbin0 -> 2811 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_objects_activated_lxx_light.pngbin0 -> 2899 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_objects_normal_lxx_dark.pngbin0 -> 2613 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_objects_normal_lxx_light.pngbin0 -> 2648 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_people_activated_lxx_dark.pngbin0 -> 3111 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_people_activated_lxx_light.pngbin0 -> 3402 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_people_normal_lxx_dark.pngbin0 -> 2844 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_people_normal_lxx_light.pngbin0 -> 3113 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_places_activated_lxx_dark.pngbin0 -> 1810 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_places_activated_lxx_light.pngbin0 -> 1834 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_places_normal_lxx_dark.pngbin0 -> 1747 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_places_normal_lxx_light.pngbin0 -> 1766 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_recents_activated_lxx_dark.pngbin0 -> 2978 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_recents_activated_lxx_light.pngbin0 -> 3220 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_recents_normal_lxx_dark.pngbin0 -> 2720 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_recents_normal_lxx_light.pngbin0 -> 2958 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_symbols_activated_lxx_dark.pngbin0 -> 1916 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_symbols_activated_lxx_light.pngbin0 -> 1872 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_symbols_normal_lxx_dark.pngbin0 -> 1760 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_emoji_symbols_normal_lxx_light.pngbin0 -> 1783 bytes
-rw-r--r--java/res/drawable-xxxhdpi/ic_launcher_keyboard.pngbin0 -> 11435 bytes
-rw-r--r--java/res/drawable-xxxhdpi/keyboard_background_lxx_dark.9.pngbin0 -> 1139 bytes
-rw-r--r--java/res/drawable-xxxhdpi/keyboard_background_lxx_light.9.pngbin0 -> 1133 bytes
-rw-r--r--java/res/drawable-xxxhdpi/keyboard_key_feedback_background_lxx_dark.9.pngbin0 -> 3475 bytes
-rw-r--r--java/res/drawable-xxxhdpi/keyboard_key_feedback_background_lxx_light.9.pngbin0 -> 3259 bytes
-rw-r--r--java/res/drawable-xxxhdpi/keyboard_key_feedback_more_background_lxx_dark.9.pngbin0 -> 3883 bytes
-rw-r--r--java/res/drawable-xxxhdpi/keyboard_key_feedback_more_background_lxx_light.9.pngbin0 -> 3682 bytes
-rw-r--r--java/res/drawable-xxxhdpi/keyboard_popup_panel_background_lxx_dark.9.pngbin0 -> 2780 bytes
-rw-r--r--java/res/drawable-xxxhdpi/keyboard_popup_panel_background_lxx_light.9.pngbin0 -> 2624 bytes
-rw-r--r--java/res/drawable-xxxhdpi/keyboard_suggest_strip_lxx_dark.9.pngbin0 -> 1138 bytes
-rw-r--r--java/res/drawable-xxxhdpi/keyboard_suggest_strip_lxx_light.9.pngbin0 -> 1124 bytes
-rw-r--r--java/res/drawable-xxxhdpi/suggestions_strip_divider_lxx_dark.pngbin0 -> 1017 bytes
-rw-r--r--java/res/drawable-xxxhdpi/suggestions_strip_divider_lxx_light.pngbin0 -> 1017 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_delete_lxx_dark.pngbin0 -> 1974 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_delete_lxx_light.pngbin0 -> 2051 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_done_lxx_dark.pngbin0 -> 2091 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_done_lxx_light.pngbin0 -> 2162 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_go_lxx_dark.pngbin0 -> 1474 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_go_lxx_light.pngbin0 -> 1474 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_language_switch_lxx_dark.pngbin0 -> 3263 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_language_switch_lxx_light.pngbin0 -> 3405 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_next_lxx_dark.pngbin0 -> 1826 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_next_lxx_light.pngbin0 -> 1826 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_previous_lxx_dark.pngbin0 -> 1827 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_previous_lxx_light.pngbin0 -> 1701 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_return_lxx_dark.pngbin0 -> 1385 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_return_lxx_light.pngbin0 -> 1385 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_search_lxx_dark.pngbin0 -> 2443 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_search_lxx_light.pngbin0 -> 2434 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_send_lxx_dark.pngbin0 -> 1886 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_send_lxx_light.pngbin0 -> 1845 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_settings_lxx_dark.pngbin0 -> 2565 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_settings_lxx_light.pngbin0 -> 2694 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_shift_locked_lxx_dark.pngbin0 -> 1865 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_shift_locked_lxx_light.pngbin0 -> 1865 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_shift_lxx_dark.pngbin0 -> 1913 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_shift_lxx_light.pngbin0 -> 1801 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_smiley_lxx_dark.pngbin0 -> 2587 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_smiley_lxx_light.pngbin0 -> 2612 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_space_lxx_dark.pngbin0 -> 1196 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_space_lxx_light.pngbin0 -> 1208 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_tab_lxx_dark.pngbin0 -> 1424 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_tab_lxx_light.pngbin0 -> 1450 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_voice_lxx_dark.pngbin0 -> 2135 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_voice_lxx_light.pngbin0 -> 2189 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_voice_off_lxx_dark.pngbin0 -> 2138 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_voice_off_lxx_light.pngbin0 -> 2209 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_zwj_lxx_dark.pngbin0 -> 1393 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_zwj_lxx_light.pngbin0 -> 1423 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_zwnj_lxx_dark.pngbin0 -> 1370 bytes
-rw-r--r--java/res/drawable-xxxhdpi/sym_keyboard_zwnj_lxx_light.pngbin0 -> 1397 bytes
-rw-r--r--java/res/drawable/btn_keyboard_key_popup_action_lxx_dark.xml21
-rw-r--r--java/res/drawable/btn_keyboard_key_popup_action_lxx_light.xml21
-rw-r--r--java/res/drawable/btn_keyboard_key_popup_lxx_light.xml21
-rw-r--r--java/res/drawable/btn_keyboard_spacebar_lxx_dark.xml4
-rw-r--r--java/res/drawable/btn_keyboard_spacebar_lxx_light.xml4
-rw-r--r--java/res/layout/additional_subtype_dialog.xml89
-rw-r--r--java/res/layout/emoji_palettes_view.xml4
-rw-r--r--java/res/layout/input_view.xml35
-rw-r--r--java/res/layout/main_keyboard_frame.xml45
-rw-r--r--java/res/layout/more_keys_keyboard.xml3
-rw-r--r--java/res/layout/more_keys_keyboard_for_action_lxx.xml (renamed from java/res/xml-sw600dp/key_question_exclamation.xml)31
-rw-r--r--java/res/layout/radio_button_preference_widget.xml23
-rw-r--r--java/res/layout/suggestion_divider.xml1
-rw-r--r--java/res/layout/suggestions_strip.xml3
-rw-r--r--java/res/layout/user_dictionary_item.xml4
-rw-r--r--java/res/menu/add_style.xml (renamed from java/res/anim/more_keys_keyboard_fadein.xml)19
-rw-r--r--java/res/raw/main_ru.dictbin2229479 -> 2239473 bytes
-rw-r--r--java/res/values-az-rAZ/bools.xml (renamed from java/res/anim/more_keys_keyboard_fadeout.xml)17
-rw-r--r--java/res/values-bn-rIN/bools.xml (renamed from java/res/xml-sw600dp/key_f1.xml)24
-rw-r--r--java/res/values-eu-rES/bools.xml24
-rw-r--r--java/res/values-gl-rES/bools.xml24
-rw-r--r--java/res/values-hy-rAM/bools.xml24
-rw-r--r--java/res/values-is-rIS/bools.xml24
-rw-r--r--java/res/values-kk-rKZ/bools.xml24
-rw-r--r--java/res/values-km-rKH/bools.xml24
-rw-r--r--java/res/values-kn-rIN/bools.xml24
-rw-r--r--java/res/values-ky-rKG/bools.xml24
-rw-r--r--java/res/values-land/config.xml22
-rw-r--r--java/res/values-land/keyboard-heights.xml2
-rw-r--r--java/res/values-lo-rLA/bools.xml24
-rw-r--r--java/res/values-mk-rMK/bools.xml24
-rw-r--r--java/res/values-ml-rIN/bools.xml24
-rw-r--r--java/res/values-mn-rMN/bools.xml24
-rw-r--r--java/res/values-mr-rIN/bools.xml24
-rw-r--r--java/res/values-ne-rNP/bools.xml24
-rw-r--r--java/res/values-sw600dp-land/config.xml20
-rw-r--r--java/res/values-sw600dp/config.xml21
-rw-r--r--java/res/values-sw768dp-land/config.xml22
-rw-r--r--java/res/values-sw768dp/config.xml21
-rw-r--r--java/res/values-ta-rIN/bools.xml24
-rw-r--r--java/res/values-te-rIN/bools.xml24
-rw-r--r--java/res/values/attrs.xml83
-rw-r--r--java/res/values/colors.xml6
-rw-r--r--java/res/values/config-common.xml6
-rw-r--r--java/res/values/config.xml24
-rw-r--r--java/res/values/donottranslate-debug-settings.xml59
-rw-r--r--java/res/values/donottranslate-text-decorator.xml76
-rw-r--r--java/res/values/donottranslate.xml5
-rw-r--r--java/res/values/keyboard-icons-holo.xml3
-rw-r--r--java/res/values/keyboard-icons-lxx-dark.xml8
-rw-r--r--java/res/values/keyboard-icons-lxx-light.xml10
-rw-r--r--java/res/values/strings.xml54
-rw-r--r--java/res/values/themes-common.xml29
-rw-r--r--java/res/values/themes-holo.xml39
-rw-r--r--java/res/values/themes-ics.xml20
-rw-r--r--java/res/values/themes-klp.xml20
-rw-r--r--java/res/values/themes-lxx-dark.xml36
-rw-r--r--java/res/values/themes-lxx-light.xml39
-rw-r--r--java/res/values/themes-lxx.xml41
-rw-r--r--java/res/xml-sw600dp/key_comma.xml39
-rw-r--r--java/res/xml-sw600dp/key_period.xml7
-rw-r--r--java/res/xml-sw600dp/key_space_7kw.xml (renamed from java/res/xml-sw600dp/key_space_5kw.xml)8
-rw-r--r--java/res/xml-sw600dp/key_styles_common.xml6
-rw-r--r--java/res/xml-sw600dp/key_styles_enter.xml138
-rw-r--r--java/res/xml-sw600dp/row_dvorak4.xml49
-rw-r--r--java/res/xml-sw600dp/row_pcqwerty5.xml2
-rw-r--r--java/res/xml-sw600dp/row_qwerty4.xml10
-rw-r--r--java/res/xml-sw600dp/rows_dvorak.xml4
-rw-r--r--java/res/xml-sw600dp/rows_number_normal.xml5
-rw-r--r--java/res/xml-sw600dp/rows_phone.xml5
-rw-r--r--java/res/xml-sw600dp/rows_symbols.xml2
-rw-r--r--java/res/xml-sw600dp/rows_symbols_shift.xml2
-rw-r--r--java/res/xml/key_comma.xml (renamed from java/res/xml/key_f1.xml)9
-rw-r--r--java/res/xml/key_emoji.xml (renamed from java/res/xml/key_f2.xml)0
-rw-r--r--java/res/xml/key_period.xml8
-rw-r--r--java/res/xml/key_space_symbols.xml1
-rw-r--r--java/res/xml/key_styles_actions.xml133
-rw-r--r--java/res/xml/key_styles_common.xml26
-rw-r--r--java/res/xml/key_styles_currency.xml42
-rw-r--r--java/res/xml/key_styles_currency_generic.xml42
-rw-r--r--java/res/xml/key_styles_enter.xml195
-rw-r--r--java/res/xml/key_styles_navigate_more_keys.xml86
-rw-r--r--java/res/xml/key_styles_number.xml31
-rw-r--r--java/res/xml/key_styles_settings.xml8
-rw-r--r--java/res/xml/keyboard_layout_set_bengali.xml2
-rw-r--r--java/res/xml/keyboard_layout_set_hindi.xml2
-rw-r--r--java/res/xml/keyboard_layout_set_hindi_compact.xml2
-rw-r--r--java/res/xml/keyboard_layout_set_kannada.xml2
-rw-r--r--java/res/xml/keyboard_layout_set_khmer.xml2
-rw-r--r--java/res/xml/keyboard_layout_set_lao.xml2
-rw-r--r--java/res/xml/keyboard_layout_set_malayalam.xml2
-rw-r--r--java/res/xml/keyboard_layout_set_marathi.xml2
-rw-r--r--java/res/xml/keyboard_layout_set_myanmar.xml2
-rw-r--r--java/res/xml/keyboard_layout_set_nepali_romanized.xml2
-rw-r--r--java/res/xml/keyboard_layout_set_nepali_traditional.xml2
-rw-r--r--java/res/xml/keyboard_layout_set_sinhala.xml2
-rw-r--r--java/res/xml/keyboard_layout_set_tamil.xml2
-rw-r--r--java/res/xml/keyboard_layout_set_telugu.xml2
-rw-r--r--java/res/xml/keyboard_layout_set_thai.xml2
-rw-r--r--java/res/xml/method.xml55
-rw-r--r--java/res/xml/prefs.xml142
-rw-r--r--java/res/xml/prefs_screen_advanced.xml52
-rw-r--r--java/res/xml/prefs_screen_appearance.xml29
-rw-r--r--java/res/xml/prefs_screen_correction.xml76
-rw-r--r--java/res/xml/prefs_screen_debug.xml37
-rw-r--r--java/res/xml/prefs_screen_gesture.xml47
-rw-r--r--java/res/xml/prefs_screen_multilingual.xml (renamed from java/res/xml/prefs_screen_multi_lingual.xml)8
-rw-r--r--java/res/xml/prefs_screen_preferences.xml (renamed from java/res/xml/prefs_screen_input.xml)2
-rw-r--r--java/res/xml/prefs_screen_theme.xml23
-rw-r--r--java/res/xml/row_dvorak4.xml45
-rw-r--r--java/res/xml/row_qwerty4.xml2
-rw-r--r--java/res/xml/rowkeys_kannada3.xml9
-rw-r--r--java/res/xml/rowkeys_tamil1.xml20
-rw-r--r--java/res/xml/rowkeys_tamil2.xml24
-rw-r--r--java/res/xml/rowkeys_tamil3.xml14
-rw-r--r--java/res/xml/rows_dvorak.xml4
-rw-r--r--java/src/com/android/inputmethod/compat/BuildCompatUtils.java43
-rw-r--r--java/src/com/android/inputmethod/compat/CompatUtils.java141
-rw-r--r--java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java161
-rw-r--r--java/src/com/android/inputmethod/compat/DownloadManagerCompatUtils.java2
-rw-r--r--java/src/com/android/inputmethod/compat/InputConnectionCompatUtils.java110
-rw-r--r--java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java2
-rw-r--r--java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java4
-rw-r--r--java/src/com/android/inputmethod/compat/NotificationCompatUtils.java83
-rw-r--r--java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java6
-rw-r--r--java/src/com/android/inputmethod/compat/UserDictionaryCompatUtils.java2
-rw-r--r--java/src/com/android/inputmethod/compat/ViewCompatUtils.java25
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java18
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java13
-rw-r--r--java/src/com/android/inputmethod/event/Combiner.java3
-rw-r--r--java/src/com/android/inputmethod/event/CombinerChain.java35
-rw-r--r--java/src/com/android/inputmethod/event/DeadKeyCombiner.java10
-rw-r--r--java/src/com/android/inputmethod/event/Event.java21
-rw-r--r--java/src/com/android/inputmethod/event/InputTransaction.java16
-rw-r--r--java/src/com/android/inputmethod/event/MyanmarReordering.java23
-rw-r--r--java/src/com/android/inputmethod/keyboard/Key.java187
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java12
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java41
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardTheme.java38
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java93
-rw-r--r--java/src/com/android/inputmethod/keyboard/MainKeyboardView.java52
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java70
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java42
-rw-r--r--java/src/com/android/inputmethod/keyboard/TextDecorator.java368
-rw-r--r--java/src/com/android/inputmethod/keyboard/TextDecoratorUi.java262
-rw-r--r--java/src/com/android/inputmethod/keyboard/TextDecoratorUiOperator.java51
-rw-r--r--java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java5
-rw-r--r--java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java3
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java31
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java93
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java86
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java51
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java12
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java18
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java6
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java371
-rw-r--r--java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java2
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFacilitator.java9
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java58
-rw-r--r--java/src/com/android/inputmethod/latin/InputAttributes.java13
-rw-r--r--java/src/com/android/inputmethod/latin/InputView.java4
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java438
-rw-r--r--java/src/com/android/inputmethod/latin/PunctuationSuggestions.java2
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java159
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java47
-rw-r--r--java/src/com/android/inputmethod/latin/SuggestedWords.java63
-rw-r--r--java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java29
-rw-r--r--java/src/com/android/inputmethod/latin/UserBinaryDictionary.java4
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java34
-rw-r--r--java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java2
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java688
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java9
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java1
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java4
-rw-r--r--java/src/com/android/inputmethod/latin/settings/AdvancedSettingsFragment.java248
-rw-r--r--java/src/com/android/inputmethod/latin/settings/AppearanceSettingsFragment.java41
-rw-r--r--java/src/com/android/inputmethod/latin/settings/CorrectionSettingsFragment.java123
-rw-r--r--java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java52
-rw-r--r--java/src/com/android/inputmethod/latin/settings/DebugSettings.java286
-rw-r--r--java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java294
-rw-r--r--java/src/com/android/inputmethod/latin/settings/GestureSettingsFragment.java39
-rw-r--r--java/src/com/android/inputmethod/latin/settings/MultiLingualSettingsFragment.java48
-rw-r--r--java/src/com/android/inputmethod/latin/settings/PreferencesSettingsFragment.java (renamed from java/src/com/android/inputmethod/latin/settings/InputSettingsFragment.java)6
-rw-r--r--java/src/com/android/inputmethod/latin/settings/RadioButtonPreference.java93
-rw-r--r--java/src/com/android/inputmethod/latin/settings/Settings.java26
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SettingsActivity.java27
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SettingsFragment.java386
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SettingsValues.java75
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java17
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SubScreenFragment.java5
-rw-r--r--java/src/com/android/inputmethod/latin/settings/ThemeSettingsFragment.java114
-rw-r--r--java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java9
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java6
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java214
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java65
-rw-r--r--java/src/com/android/inputmethod/latin/utils/CursorAnchorInfoUtils.java236
-rw-r--r--java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java3
-rw-r--r--java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatches.java129
-rw-r--r--java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java286
-rw-r--r--java/src/com/android/inputmethod/latin/utils/FragmentUtils.java18
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java41
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ScriptUtils.java123
-rw-r--r--java/src/com/android/inputmethod/latin/utils/StringUtils.java63
-rw-r--r--java/src/com/android/inputmethod/latin/utils/SuggestionResults.java13
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ViewLayoutUtils.java39
-rw-r--r--native/jni/NativeFileList.mk11
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node.h11
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node_utils.cpp11
-rw-r--r--native/jni/src/suggest/core/dictionary/dictionary.cpp83
-rw-r--r--native/jni/src/suggest/core/dictionary/dictionary.h16
-rw-r--r--native/jni/src/suggest/core/dictionary/multi_bigram_map.cpp64
-rw-r--r--native/jni/src/suggest/core/dictionary/multi_bigram_map.h25
-rw-r--r--native/jni/src/suggest/core/dictionary/ngram_listener.h (renamed from native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/dict_content.h)21
-rw-r--r--native/jni/src/suggest/core/layout/proximity_info_state.h4
-rw-r--r--native/jni/src/suggest/core/layout/proximity_info_state_utils.cpp10
-rw-r--r--native/jni/src/suggest/core/layout/proximity_info_state_utils.h10
-rw-r--r--native/jni/src/suggest/core/policy/dictionary_bigrams_structure_policy.h2
-rw-r--r--native/jni/src/suggest/core/policy/dictionary_header_structure_policy.h2
-rw-r--r--native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h11
-rw-r--r--native/jni/src/suggest/core/policy/scoring.h1
-rw-r--r--native/jni/src/suggest/core/result/suggestions_output_utils.cpp10
-rw-r--r--native/jni/src/suggest/core/session/prev_words_info.h47
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/bigram/ver4_bigram_list_policy.h3
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/single_dict_content.h6
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/sparse_table_dict_content.h14
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.cpp11
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp29
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.h14
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp42
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h7
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp8
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.cpp21
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h7
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h1
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp46
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h11
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h9
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v2/bigram/bigram_list_policy.h17
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp53
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h19
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/bigram/ver4_bigram_list_policy.h3
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp95
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h83
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.cpp159
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h66
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h52
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h6
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.h19
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp50
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h14
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp11
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h3
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.cpp5
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h10
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp27
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h8
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp49
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h9
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp10
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp24
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h22
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h2
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h16
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.cpp387
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.h384
-rw-r--r--native/jni/src/suggest/policyimpl/typing/typing_scoring.h4
-rw-r--r--native/jni/src/utils/byte_array_view.h87
-rw-r--r--native/jni/src/utils/int_array_view.h105
-rw-r--r--native/jni/tests/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content_test.cpp59
-rw-r--r--native/jni/tests/suggest/policyimpl/dictionary/structure/v4/content/probability_entry_test.cpp60
-rw-r--r--native/jni/tests/suggest/policyimpl/dictionary/utils/trie_map_test.cpp224
-rw-r--r--native/jni/tests/utils/int_array_view_test.cpp61
-rw-r--r--tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelBase.java156
-rw-r--r--tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelKlpTests.java199
-rw-r--r--tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelLxxTests.java24
-rw-r--r--tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysBase.java337
-rw-r--r--tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysKlpTests.java28
-rw-r--r--tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysLxxTests.java40
-rw-r--r--tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetSubtypesCountTests.java2
-rw-r--r--tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java17
-rw-r--r--tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java4
-rw-r--r--tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderAutoOrderTests.java2464
-rw-r--r--tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderFixedOrderTests.java3
-rw-r--r--tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderMaxOrderTests.java (renamed from tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderTests.java)5
-rw-r--r--tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecSplitTests.java2
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/Arabic.java5
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/ArmenianPhonetic.java30
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/Dvorak.java61
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/Farsi.java5
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/HindiCompact.java2
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/Kannada.java7
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/Khmer.java26
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/Lao.java26
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java95
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/Myanmar.java30
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/PcQwerty.java7
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/Sinhala.java12
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/Symbols.java12
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/SymbolsShifted.java12
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/Tamil.java46
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/Thai.java26
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java31
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKey.java12
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java34
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyVisual.java25
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakEmail.java91
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakUrl.java91
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishDvorak.java2
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMalayalamIN.java2
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMyanmarMM.java4
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyEmail.java73
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyUrl.java73
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSinhalaLK.java4
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTamilIN.java21
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTamilLK.java56
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTamilSG.java37
-rw-r--r--tests/src/com/android/inputmethod/latin/DistracterFilterTest.java66
-rw-r--r--tests/src/com/android/inputmethod/latin/InputLogicTestsReorderingMyanmar.java3
-rw-r--r--tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java40
-rw-r--r--tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java111
-rw-r--r--tests/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java13
-rw-r--r--tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java2
-rw-r--r--tests/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelperTests.java221
-rw-r--r--tests/src/com/android/inputmethod/latin/utils/ImportantNoticeUtilsTests.java222
-rw-r--r--tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java192
-rw-r--r--tools/dicttool/Android.mk45
-rw-r--r--tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java8
-rw-r--r--tools/make-keyboard-text/res/values-bn-rIN/donottranslate-more-keys.xml4
-rw-r--r--tools/make-keyboard-text/res/values-si-rLK/donottranslate-more-keys.xml2
-rw-r--r--tools/make-keyboard-text/res/values-ta-rLK/donottranslate-more-keys.xml28
-rw-r--r--tools/make-keyboard-text/res/values-ta-rSG/donottranslate-more-keys.xml26
-rw-r--r--tools/make-keyboard-text/res/values/donottranslate-more-keys.xml4
585 files changed, 14215 insertions, 4179 deletions
diff --git a/dictionaries/ro_wordlist.combined.gz b/dictionaries/ro_wordlist.combined.gz
new file mode 100644
index 000000000..829abd9b8
--- /dev/null
+++ b/dictionaries/ro_wordlist.combined.gz
Binary files differ
diff --git a/dictionaries/ru_wordlist.combined.gz b/dictionaries/ru_wordlist.combined.gz
index acde9bc73..7794f7bed 100644
--- a/dictionaries/ru_wordlist.combined.gz
+++ b/dictionaries/ru_wordlist.combined.gz
Binary files differ
diff --git a/java/src/com/android/inputmethod/compat/AppWorkaroundsHelper.java b/java-overridable/src/com/android/inputmethod/compat/AppWorkaroundsHelper.java
index 21535e421..21535e421 100644
--- a/java/src/com/android/inputmethod/compat/AppWorkaroundsHelper.java
+++ b/java-overridable/src/com/android/inputmethod/compat/AppWorkaroundsHelper.java
diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionaryPackConstants.java b/java-overridable/src/com/android/inputmethod/dictionarypack/DictionaryPackConstants.java
index df0e3f0e1..df0e3f0e1 100644
--- a/java/src/com/android/inputmethod/dictionarypack/DictionaryPackConstants.java
+++ b/java-overridable/src/com/android/inputmethod/dictionarypack/DictionaryPackConstants.java
diff --git a/java/src/com/android/inputmethod/dictionarypack/MetadataUriGetter.java b/java-overridable/src/com/android/inputmethod/dictionarypack/MetadataUriGetter.java
index ed817658e..ed817658e 100644
--- a/java/src/com/android/inputmethod/dictionarypack/MetadataUriGetter.java
+++ b/java-overridable/src/com/android/inputmethod/dictionarypack/MetadataUriGetter.java
diff --git a/java-overridable/src/com/android/inputmethod/latin/SpecialKeyDetector.java b/java-overridable/src/com/android/inputmethod/latin/SpecialKeyDetector.java
new file mode 100644
index 000000000..27b2f5012
--- /dev/null
+++ b/java-overridable/src/com/android/inputmethod/latin/SpecialKeyDetector.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.content.Context;
+import android.view.KeyEvent;
+
+final class SpecialKeyDetector {
+ /**
+ * Special physical key detector
+ * @param context a context of this detector.
+ */
+ public SpecialKeyDetector(final Context context) {
+ }
+
+ /**
+ * Record a down key event.
+ * @param keyEvent a down key event.
+ */
+ public void onKeyDown(final KeyEvent keyEvent) {
+ }
+
+ /**
+ * Record an up key event.
+ * @param keyEvent an up key event.
+ */
+ public void onKeyUp(final KeyEvent keyEvent) {
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/about/AboutPreferences.java b/java-overridable/src/com/android/inputmethod/latin/about/AboutPreferences.java
index f60b189f1..f60b189f1 100644
--- a/java/src/com/android/inputmethod/latin/about/AboutPreferences.java
+++ b/java-overridable/src/com/android/inputmethod/latin/about/AboutPreferences.java
diff --git a/java/src/com/android/inputmethod/latin/define/DebugFlags.java b/java-overridable/src/com/android/inputmethod/latin/define/DebugFlags.java
index c509e8322..c509e8322 100644
--- a/java/src/com/android/inputmethod/latin/define/DebugFlags.java
+++ b/java-overridable/src/com/android/inputmethod/latin/define/DebugFlags.java
diff --git a/java/src/com/android/inputmethod/latin/define/JniLibName.java b/java-overridable/src/com/android/inputmethod/latin/define/JniLibName.java
index abfc36d39..abfc36d39 100644
--- a/java/src/com/android/inputmethod/latin/define/JniLibName.java
+++ b/java-overridable/src/com/android/inputmethod/latin/define/JniLibName.java
diff --git a/java/src/com/android/inputmethod/latin/define/ProductionFlags.java b/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java
index d385cf840..5ab126486 100644
--- a/java/src/com/android/inputmethod/latin/define/ProductionFlags.java
+++ b/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java
@@ -24,21 +24,12 @@ public final class ProductionFlags {
public static final boolean IS_HARDWARE_KEYBOARD_SUPPORTED = false;
/**
- * When true, enable {@link InputMethodService#onUpdateCursorAnchorInfo} callback via
- * {@link InputConnection#requestCursorAnchorInfo}. This flag has no effect in API Level 20
- * and prior. In general, this callback provides more detailed positional information,
- * even though an explicit support is required by the editor.
+ * When true, enable {@link InputMethodService#onUpdateCursorAnchorInfo} callback via
+ * {@link InputConnection#requestUpdateCursorAnchorInfo}. This flag has no effect in API
+ * Level 20 and prior. In general, this callback provides detailed positional information,
+ * even though an explicit support is required by the editor.
*/
- public static final boolean ENABLE_CURSOR_ANCHOR_INFO_CALLBACK = false;
-
- /**
- * When true, enable {@link InputMethodService#onUpdateCursor} callback via
- * {@link InputConnection#requestCursorAnchorInfo}. Although this callback has been available
- * since API Level 3, the callback has never been used until API Level 20. Thus it may or may
- * not work well as expected. Should rely on {@link InputMethodService#onUpdateCursorAnchorInfo}
- * whenever possible since it is supposed to be more reliable and accurate.
- */
- public static final boolean ENABLE_CURSOR_RECT_CALLBACK = false;
+ public static final boolean ENABLE_CURSOR_ANCHOR_INFO_CALLBACK = true;
/**
* Include all suggestions from all dictionaries in {@link SuggestedWords#mRawSuggestions}.
diff --git a/java/src/com/android/inputmethod/latin/personalization/ContextualDictionaryUpdater.java b/java-overridable/src/com/android/inputmethod/latin/personalization/ContextualDictionaryUpdater.java
index 7dc120e06..7dc120e06 100644
--- a/java/src/com/android/inputmethod/latin/personalization/ContextualDictionaryUpdater.java
+++ b/java-overridable/src/com/android/inputmethod/latin/personalization/ContextualDictionaryUpdater.java
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdater.java b/java-overridable/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdater.java
index c97a0d232..c97a0d232 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdater.java
+++ b/java-overridable/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdater.java
diff --git a/java/src/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java b/java-overridable/src/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java
index 6543003e8..6543003e8 100644
--- a/java/src/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java
+++ b/java-overridable/src/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java
diff --git a/java/src/com/android/inputmethod/latin/utils/FeedbackUtils.java b/java-overridable/src/com/android/inputmethod/latin/utils/FeedbackUtils.java
index ec7eaf4a0..0aed41ee4 100644
--- a/java/src/com/android/inputmethod/latin/utils/FeedbackUtils.java
+++ b/java-overridable/src/com/android/inputmethod/latin/utils/FeedbackUtils.java
@@ -20,11 +20,11 @@ import android.content.Context;
import android.content.Intent;
public class FeedbackUtils {
- public static boolean isFeedbackFormSupported() {
+ public static boolean isHelpAndFeedbackFormSupported() {
return false;
}
- public static void showFeedbackForm(Context context) {
+ public static void showHelpAndFeedbackForm(Context context) {
}
public static int getAboutKeyboardTitleResId() {
diff --git a/java/src/com/android/inputmethod/latin/utils/FileTransforms.java b/java-overridable/src/com/android/inputmethod/latin/utils/FileTransforms.java
index 9f4584ec9..9f4584ec9 100644
--- a/java/src/com/android/inputmethod/latin/utils/FileTransforms.java
+++ b/java-overridable/src/com/android/inputmethod/latin/utils/FileTransforms.java
diff --git a/java/src/com/android/inputmethod/latin/utils/MetadataFileUriGetter.java b/java-overridable/src/com/android/inputmethod/latin/utils/MetadataFileUriGetter.java
index 9ad319da6..9ad319da6 100644
--- a/java/src/com/android/inputmethod/latin/utils/MetadataFileUriGetter.java
+++ b/java-overridable/src/com/android/inputmethod/latin/utils/MetadataFileUriGetter.java
diff --git a/java/src/com/android/inputmethod/latin/utils/StatsUtils.java b/java-overridable/src/com/android/inputmethod/latin/utils/StatsUtils.java
index 79c19d077..79c19d077 100644
--- a/java/src/com/android/inputmethod/latin/utils/StatsUtils.java
+++ b/java-overridable/src/com/android/inputmethod/latin/utils/StatsUtils.java
diff --git a/java/Android.mk b/java/Android.mk
index b580624d7..0d12c45fe 100644
--- a/java/Android.mk
+++ b/java/Android.mk
@@ -17,7 +17,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src ../java-overridable/src)
LOCAL_PACKAGE_NAME := LatinIME
@@ -25,7 +25,7 @@ LOCAL_CERTIFICATE := shared
LOCAL_JNI_SHARED_LIBRARIES := libjni_latinime
-LOCAL_STATIC_JAVA_LIBRARIES := android-common inputmethod-common android-support-v4
+LOCAL_STATIC_JAVA_LIBRARIES := android-common inputmethod-common android-support-v4 jsr305
# Do not compress dictionary files to mmap dict data runtime
LOCAL_AAPT_FLAGS := -0 .dict
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
index f37f6cc4b..1797dc92c 100644
--- a/java/AndroidManifest.xml
+++ b/java/AndroidManifest.xml
@@ -33,7 +33,6 @@
<application android:label="@string/english_ime_name"
android:icon="@drawable/ic_launcher_keyboard"
- android:killAfterRestore="false"
android:supportsRtl="true"
android:allowBackup="true">
@@ -82,6 +81,7 @@
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_INITIALIZE" />
+ <action android:name="android.intent.action.LOCALE_CHANGED" />
</intent-filter>
</receiver>
diff --git a/java/res/anim/key_preview_dismiss_holo.xml b/java/res/anim/key_preview_dismiss_holo.xml
new file mode 100644
index 000000000..0bf725435
--- /dev/null
+++ b/java/res/anim/key_preview_dismiss_holo.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="53"
+ android:valueFrom="1.00"
+ android:valueTo="0.94" />
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="53"
+ android:valueFrom="1.00"
+ android:valueTo="0.94" />
+</set>
diff --git a/java/res/anim/key_preview_dismiss_lxx.xml b/java/res/anim/key_preview_dismiss_lxx.xml
new file mode 100644
index 000000000..326e534ec
--- /dev/null
+++ b/java/res/anim/key_preview_dismiss_lxx.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="53"
+ android:valueFrom="1.00"
+ android:valueTo="1.00" />
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="53"
+ android:valueFrom="1.00"
+ android:valueTo="0.94" />
+</set>
diff --git a/java/res/anim/key_preview_show_up_holo.xml b/java/res/anim/key_preview_show_up_holo.xml
new file mode 100644
index 000000000..ad2e413a1
--- /dev/null
+++ b/java/res/anim/key_preview_show_up_holo.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="17"
+ android:valueFrom="0.98"
+ android:valueTo="1.00" />
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="17"
+ android:valueFrom="0.98"
+ android:valueTo="1.00" />
+</set>
diff --git a/java/res/anim/key_preview_show_up_lxx.xml b/java/res/anim/key_preview_show_up_lxx.xml
new file mode 100644
index 000000000..f5003499c
--- /dev/null
+++ b/java/res/anim/key_preview_show_up_lxx.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+ <objectAnimator
+ android:propertyName="scaleX"
+ android:duration="17"
+ android:valueFrom="1.00"
+ android:valueTo="1.00" />
+ <objectAnimator
+ android:propertyName="scaleY"
+ android:duration="17"
+ android:valueFrom="0.98"
+ android:valueTo="1.00" />
+</set>
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_active_lxx_dark.9.png b/java/res/drawable-hdpi/btn_keyboard_key_active_lxx_dark.9.png
index bbdc41116..55ef3e7f5 100644
--- a/java/res/drawable-hdpi/btn_keyboard_key_active_lxx_dark.9.png
+++ b/java/res/drawable-hdpi/btn_keyboard_key_active_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_active_lxx_light.9.png b/java/res/drawable-hdpi/btn_keyboard_key_active_lxx_light.9.png
index 854c849cb..9f307dc7f 100644
--- a/java/res/drawable-hdpi/btn_keyboard_key_active_lxx_light.9.png
+++ b/java/res/drawable-hdpi/btn_keyboard_key_active_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png b/java/res/drawable-hdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png
index 33f7d8077..17a77cccb 100644
--- a/java/res/drawable-hdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png
+++ b/java/res/drawable-hdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_active_pressed_lxx_light.9.png b/java/res/drawable-hdpi/btn_keyboard_key_active_pressed_lxx_light.9.png
index 7a7e98297..55ef3e7f5 100644
--- a/java/res/drawable-hdpi/btn_keyboard_key_active_pressed_lxx_light.9.png
+++ b/java/res/drawable-hdpi/btn_keyboard_key_active_pressed_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_spacebar_lxx_dark.9.png b/java/res/drawable-hdpi/btn_keyboard_spacebar_normal_lxx_dark.9.png
index 32311666f..32311666f 100644
--- a/java/res/drawable-hdpi/sym_keyboard_spacebar_lxx_dark.9.png
+++ b/java/res/drawable-hdpi/btn_keyboard_spacebar_normal_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_spacebar_lxx_light.9.png b/java/res/drawable-hdpi/btn_keyboard_spacebar_normal_lxx_light.9.png
index 1256b8b21..1256b8b21 100644
--- a/java/res/drawable-hdpi/sym_keyboard_spacebar_lxx_light.9.png
+++ b/java/res/drawable-hdpi/btn_keyboard_spacebar_normal_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.png b/java/res/drawable-hdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.png
new file mode 100644
index 000000000..cd0d884c6
--- /dev/null
+++ b/java/res/drawable-hdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_spacebar_pressed_lxx_light.9.png b/java/res/drawable-hdpi/btn_keyboard_spacebar_pressed_lxx_light.9.png
new file mode 100644
index 000000000..c05605fbf
--- /dev/null
+++ b/java/res/drawable-hdpi/btn_keyboard_spacebar_pressed_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_add_circle_wht_24dp.png b/java/res/drawable-hdpi/ic_add_circle_wht_24dp.png
new file mode 100644
index 000000000..314c52137
--- /dev/null
+++ b/java/res/drawable-hdpi/ic_add_circle_wht_24dp.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_people_activated_lxx_dark.png b/java/res/drawable-hdpi/ic_emoji_people_activated_lxx_dark.png
index 47e673afe..e1c713a01 100644
--- a/java/res/drawable-hdpi/ic_emoji_people_activated_lxx_dark.png
+++ b/java/res/drawable-hdpi/ic_emoji_people_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_people_activated_lxx_light.png b/java/res/drawable-hdpi/ic_emoji_people_activated_lxx_light.png
index ad933ca01..b1fe2c0b1 100644
--- a/java/res/drawable-hdpi/ic_emoji_people_activated_lxx_light.png
+++ b/java/res/drawable-hdpi/ic_emoji_people_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_people_normal_lxx_dark.png b/java/res/drawable-hdpi/ic_emoji_people_normal_lxx_dark.png
index a894c60b0..6369ac9a9 100644
--- a/java/res/drawable-hdpi/ic_emoji_people_normal_lxx_dark.png
+++ b/java/res/drawable-hdpi/ic_emoji_people_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_people_normal_lxx_light.png b/java/res/drawable-hdpi/ic_emoji_people_normal_lxx_light.png
index 2d8bdf884..dbb111ffc 100644
--- a/java/res/drawable-hdpi/ic_emoji_people_normal_lxx_light.png
+++ b/java/res/drawable-hdpi/ic_emoji_people_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_places_activated_lxx_dark.png b/java/res/drawable-hdpi/ic_emoji_places_activated_lxx_dark.png
index c9b81e1de..c4d2115e2 100644
--- a/java/res/drawable-hdpi/ic_emoji_places_activated_lxx_dark.png
+++ b/java/res/drawable-hdpi/ic_emoji_places_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_places_activated_lxx_light.png b/java/res/drawable-hdpi/ic_emoji_places_activated_lxx_light.png
index 1c031c0bc..b2b068763 100644
--- a/java/res/drawable-hdpi/ic_emoji_places_activated_lxx_light.png
+++ b/java/res/drawable-hdpi/ic_emoji_places_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_places_normal_lxx_dark.png b/java/res/drawable-hdpi/ic_emoji_places_normal_lxx_dark.png
index 36fbf9150..53f13d949 100644
--- a/java/res/drawable-hdpi/ic_emoji_places_normal_lxx_dark.png
+++ b/java/res/drawable-hdpi/ic_emoji_places_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_places_normal_lxx_light.png b/java/res/drawable-hdpi/ic_emoji_places_normal_lxx_light.png
index 3bd317c19..90cc77d88 100644
--- a/java/res/drawable-hdpi/ic_emoji_places_normal_lxx_light.png
+++ b/java/res/drawable-hdpi/ic_emoji_places_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_recents_activated_lxx_dark.png b/java/res/drawable-hdpi/ic_emoji_recents_activated_lxx_dark.png
index 43d3f304c..5f23ec230 100644
--- a/java/res/drawable-hdpi/ic_emoji_recents_activated_lxx_dark.png
+++ b/java/res/drawable-hdpi/ic_emoji_recents_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_recents_activated_lxx_light.png b/java/res/drawable-hdpi/ic_emoji_recents_activated_lxx_light.png
index 3a6b3acff..6566ba89b 100644
--- a/java/res/drawable-hdpi/ic_emoji_recents_activated_lxx_light.png
+++ b/java/res/drawable-hdpi/ic_emoji_recents_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_recents_normal_lxx_dark.png b/java/res/drawable-hdpi/ic_emoji_recents_normal_lxx_dark.png
index a07f6069c..6da194c10 100644
--- a/java/res/drawable-hdpi/ic_emoji_recents_normal_lxx_dark.png
+++ b/java/res/drawable-hdpi/ic_emoji_recents_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_emoji_recents_normal_lxx_light.png b/java/res/drawable-hdpi/ic_emoji_recents_normal_lxx_light.png
index d86c1b98a..b50eba746 100644
--- a/java/res/drawable-hdpi/ic_emoji_recents_normal_lxx_light.png
+++ b/java/res/drawable-hdpi/ic_emoji_recents_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_launcher_keyboard.png b/java/res/drawable-hdpi/ic_launcher_keyboard.png
index 7ae00ed3f..3a01e61b9 100644
--- a/java/res/drawable-hdpi/ic_launcher_keyboard.png
+++ b/java/res/drawable-hdpi/ic_launcher_keyboard.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_background_lxx_dark.9.png b/java/res/drawable-hdpi/keyboard_background_lxx_dark.9.png
new file mode 100644
index 000000000..e34c5666b
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_background_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_background_lxx_light.9.png b/java/res/drawable-hdpi/keyboard_background_lxx_light.9.png
new file mode 100644
index 000000000..bf5450cc7
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_background_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_background_lxx_dark.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_background_lxx_dark.9.png
index 306e4554c..93f300a13 100644
--- a/java/res/drawable-hdpi/keyboard_key_feedback_background_lxx_dark.9.png
+++ b/java/res/drawable-hdpi/keyboard_key_feedback_background_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_background_lxx_light.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_background_lxx_light.9.png
index 867f5516d..e7c516a0e 100644
--- a/java/res/drawable-hdpi/keyboard_key_feedback_background_lxx_light.9.png
+++ b/java/res/drawable-hdpi/keyboard_key_feedback_background_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_more_background_lxx_dark.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_more_background_lxx_dark.9.png
index b3e6ee784..b56fcf910 100644
--- a/java/res/drawable-hdpi/keyboard_key_feedback_more_background_lxx_dark.9.png
+++ b/java/res/drawable-hdpi/keyboard_key_feedback_more_background_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_more_background_lxx_light.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_more_background_lxx_light.9.png
index 827f80f13..32005c37b 100644
--- a/java/res/drawable-hdpi/keyboard_key_feedback_more_background_lxx_light.9.png
+++ b/java/res/drawable-hdpi/keyboard_key_feedback_more_background_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_suggest_strip_lxx_dark.9.png b/java/res/drawable-hdpi/keyboard_suggest_strip_lxx_dark.9.png
new file mode 100644
index 000000000..3f6a943b2
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_suggest_strip_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_suggest_strip_lxx_light.9.png b/java/res/drawable-hdpi/keyboard_suggest_strip_lxx_light.9.png
new file mode 100644
index 000000000..107cfc77d
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_suggest_strip_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_smiley_lxx_light.png b/java/res/drawable-hdpi/sym_keyboard_smiley_lxx_light.png
index 2cfe1d406..b1fe2c0b1 100644
--- a/java/res/drawable-hdpi/sym_keyboard_smiley_lxx_light.png
+++ b/java/res/drawable-hdpi/sym_keyboard_smiley_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_space_lxx_dark.png b/java/res/drawable-hdpi/sym_keyboard_space_lxx_dark.png
new file mode 100644
index 000000000..9ff640224
--- /dev/null
+++ b/java/res/drawable-hdpi/sym_keyboard_space_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_space_lxx_light.png b/java/res/drawable-hdpi/sym_keyboard_space_lxx_light.png
new file mode 100644
index 000000000..d43e4dd60
--- /dev/null
+++ b/java/res/drawable-hdpi/sym_keyboard_space_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_active_lxx_dark.9.png b/java/res/drawable-mdpi/btn_keyboard_key_active_lxx_dark.9.png
index 787ce45ce..765191881 100644
--- a/java/res/drawable-mdpi/btn_keyboard_key_active_lxx_dark.9.png
+++ b/java/res/drawable-mdpi/btn_keyboard_key_active_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_active_lxx_light.9.png b/java/res/drawable-mdpi/btn_keyboard_key_active_lxx_light.9.png
index e7a585b70..8131549e5 100644
--- a/java/res/drawable-mdpi/btn_keyboard_key_active_lxx_light.9.png
+++ b/java/res/drawable-mdpi/btn_keyboard_key_active_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png b/java/res/drawable-mdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png
index 7e34c6cf1..dcf814ada 100644
--- a/java/res/drawable-mdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png
+++ b/java/res/drawable-mdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_active_pressed_lxx_light.9.png b/java/res/drawable-mdpi/btn_keyboard_key_active_pressed_lxx_light.9.png
index 5a6513392..765191881 100644
--- a/java/res/drawable-mdpi/btn_keyboard_key_active_pressed_lxx_light.9.png
+++ b/java/res/drawable-mdpi/btn_keyboard_key_active_pressed_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_spacebar_lxx_dark.9.png b/java/res/drawable-mdpi/btn_keyboard_spacebar_normal_lxx_dark.9.png
index b8e56dab4..b8e56dab4 100644
--- a/java/res/drawable-mdpi/sym_keyboard_spacebar_lxx_dark.9.png
+++ b/java/res/drawable-mdpi/btn_keyboard_spacebar_normal_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_spacebar_lxx_light.9.png b/java/res/drawable-mdpi/btn_keyboard_spacebar_normal_lxx_light.9.png
index 281f83062..281f83062 100644
--- a/java/res/drawable-mdpi/sym_keyboard_spacebar_lxx_light.9.png
+++ b/java/res/drawable-mdpi/btn_keyboard_spacebar_normal_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.png b/java/res/drawable-mdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.png
new file mode 100644
index 000000000..cb2ca06d3
--- /dev/null
+++ b/java/res/drawable-mdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_spacebar_pressed_lxx_light.9.png b/java/res/drawable-mdpi/btn_keyboard_spacebar_pressed_lxx_light.9.png
new file mode 100644
index 000000000..653da974c
--- /dev/null
+++ b/java/res/drawable-mdpi/btn_keyboard_spacebar_pressed_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_add_circle_wht_24dp.png b/java/res/drawable-mdpi/ic_add_circle_wht_24dp.png
new file mode 100644
index 000000000..11363b173
--- /dev/null
+++ b/java/res/drawable-mdpi/ic_add_circle_wht_24dp.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_people_activated_lxx_dark.png b/java/res/drawable-mdpi/ic_emoji_people_activated_lxx_dark.png
index 952b570f8..bb37a63b1 100644
--- a/java/res/drawable-mdpi/ic_emoji_people_activated_lxx_dark.png
+++ b/java/res/drawable-mdpi/ic_emoji_people_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_people_activated_lxx_light.png b/java/res/drawable-mdpi/ic_emoji_people_activated_lxx_light.png
index d0d72dbdb..e639416cd 100644
--- a/java/res/drawable-mdpi/ic_emoji_people_activated_lxx_light.png
+++ b/java/res/drawable-mdpi/ic_emoji_people_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_people_normal_lxx_dark.png b/java/res/drawable-mdpi/ic_emoji_people_normal_lxx_dark.png
index 1f46b9b7e..a7f816064 100644
--- a/java/res/drawable-mdpi/ic_emoji_people_normal_lxx_dark.png
+++ b/java/res/drawable-mdpi/ic_emoji_people_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_people_normal_lxx_light.png b/java/res/drawable-mdpi/ic_emoji_people_normal_lxx_light.png
index 8b7c1a385..d4b114c3e 100644
--- a/java/res/drawable-mdpi/ic_emoji_people_normal_lxx_light.png
+++ b/java/res/drawable-mdpi/ic_emoji_people_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_places_activated_lxx_dark.png b/java/res/drawable-mdpi/ic_emoji_places_activated_lxx_dark.png
index fadb7511f..630836b8a 100644
--- a/java/res/drawable-mdpi/ic_emoji_places_activated_lxx_dark.png
+++ b/java/res/drawable-mdpi/ic_emoji_places_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_places_activated_lxx_light.png b/java/res/drawable-mdpi/ic_emoji_places_activated_lxx_light.png
index 5c0e40d57..2ba430120 100644
--- a/java/res/drawable-mdpi/ic_emoji_places_activated_lxx_light.png
+++ b/java/res/drawable-mdpi/ic_emoji_places_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_places_normal_lxx_dark.png b/java/res/drawable-mdpi/ic_emoji_places_normal_lxx_dark.png
index 5eed3d9c8..8bc3503ca 100644
--- a/java/res/drawable-mdpi/ic_emoji_places_normal_lxx_dark.png
+++ b/java/res/drawable-mdpi/ic_emoji_places_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_places_normal_lxx_light.png b/java/res/drawable-mdpi/ic_emoji_places_normal_lxx_light.png
index fff799823..b033c83de 100644
--- a/java/res/drawable-mdpi/ic_emoji_places_normal_lxx_light.png
+++ b/java/res/drawable-mdpi/ic_emoji_places_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_recents_activated_lxx_dark.png b/java/res/drawable-mdpi/ic_emoji_recents_activated_lxx_dark.png
index e6c8dc0f2..b0b683bc5 100644
--- a/java/res/drawable-mdpi/ic_emoji_recents_activated_lxx_dark.png
+++ b/java/res/drawable-mdpi/ic_emoji_recents_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_recents_activated_lxx_light.png b/java/res/drawable-mdpi/ic_emoji_recents_activated_lxx_light.png
index 25ac3f5d9..39c22c41f 100644
--- a/java/res/drawable-mdpi/ic_emoji_recents_activated_lxx_light.png
+++ b/java/res/drawable-mdpi/ic_emoji_recents_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_recents_normal_lxx_dark.png b/java/res/drawable-mdpi/ic_emoji_recents_normal_lxx_dark.png
index e660891fc..b0138f5c2 100644
--- a/java/res/drawable-mdpi/ic_emoji_recents_normal_lxx_dark.png
+++ b/java/res/drawable-mdpi/ic_emoji_recents_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_emoji_recents_normal_lxx_light.png b/java/res/drawable-mdpi/ic_emoji_recents_normal_lxx_light.png
index 614d081ce..99e788463 100644
--- a/java/res/drawable-mdpi/ic_emoji_recents_normal_lxx_light.png
+++ b/java/res/drawable-mdpi/ic_emoji_recents_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_launcher_keyboard.png b/java/res/drawable-mdpi/ic_launcher_keyboard.png
index cc73f3be1..574da25f5 100644
--- a/java/res/drawable-mdpi/ic_launcher_keyboard.png
+++ b/java/res/drawable-mdpi/ic_launcher_keyboard.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_background_lxx_dark.9.png b/java/res/drawable-mdpi/keyboard_background_lxx_dark.9.png
new file mode 100644
index 000000000..012d91455
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_background_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_background_lxx_light.9.png b/java/res/drawable-mdpi/keyboard_background_lxx_light.9.png
new file mode 100644
index 000000000..91adfac47
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_background_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_background_lxx_dark.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_background_lxx_dark.9.png
index 4f6731f60..1a7dd34ed 100644
--- a/java/res/drawable-mdpi/keyboard_key_feedback_background_lxx_dark.9.png
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_background_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_background_lxx_light.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_background_lxx_light.9.png
index 14da5f919..268863e68 100644
--- a/java/res/drawable-mdpi/keyboard_key_feedback_background_lxx_light.9.png
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_background_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_more_background_lxx_dark.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_more_background_lxx_dark.9.png
index 9bca991b2..08d67ef6a 100644
--- a/java/res/drawable-mdpi/keyboard_key_feedback_more_background_lxx_dark.9.png
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_more_background_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_more_background_lxx_light.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_more_background_lxx_light.9.png
index 14f4b5f24..d0e46b14e 100644
--- a/java/res/drawable-mdpi/keyboard_key_feedback_more_background_lxx_light.9.png
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_more_background_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_suggest_strip_lxx_dark.9.png b/java/res/drawable-mdpi/keyboard_suggest_strip_lxx_dark.9.png
new file mode 100644
index 000000000..d85ca712a
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_suggest_strip_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_suggest_strip_lxx_light.9.png b/java/res/drawable-mdpi/keyboard_suggest_strip_lxx_light.9.png
new file mode 100644
index 000000000..983a6956c
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_suggest_strip_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_smiley_lxx_light.png b/java/res/drawable-mdpi/sym_keyboard_smiley_lxx_light.png
index ff49d58e1..e639416cd 100644
--- a/java/res/drawable-mdpi/sym_keyboard_smiley_lxx_light.png
+++ b/java/res/drawable-mdpi/sym_keyboard_smiley_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_space_lxx_dark.png b/java/res/drawable-mdpi/sym_keyboard_space_lxx_dark.png
new file mode 100644
index 000000000..9119a9d91
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_space_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_space_lxx_light.png b/java/res/drawable-mdpi/sym_keyboard_space_lxx_light.png
new file mode 100644
index 000000000..6c495beed
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_space_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_active_lxx_dark.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_active_lxx_dark.9.png
index 47264065a..0f3d3196b 100644
--- a/java/res/drawable-xhdpi/btn_keyboard_key_active_lxx_dark.9.png
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_active_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_active_lxx_light.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_active_lxx_light.9.png
index dca7a3274..cef6d00c0 100644
--- a/java/res/drawable-xhdpi/btn_keyboard_key_active_lxx_light.9.png
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_active_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png
index 8063fcd82..b5768e629 100644
--- a/java/res/drawable-xhdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_active_pressed_lxx_light.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_active_pressed_lxx_light.9.png
index fa32a2c6e..0f3d3196b 100644
--- a/java/res/drawable-xhdpi/btn_keyboard_key_active_pressed_lxx_light.9.png
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_active_pressed_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_spacebar_lxx_dark.9.png b/java/res/drawable-xhdpi/btn_keyboard_spacebar_normal_lxx_dark.9.png
index ab032dc17..ab032dc17 100644
--- a/java/res/drawable-xhdpi/sym_keyboard_spacebar_lxx_dark.9.png
+++ b/java/res/drawable-xhdpi/btn_keyboard_spacebar_normal_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_spacebar_lxx_light.9.png b/java/res/drawable-xhdpi/btn_keyboard_spacebar_normal_lxx_light.9.png
index c1ed863f8..c1ed863f8 100644
--- a/java/res/drawable-xhdpi/sym_keyboard_spacebar_lxx_light.9.png
+++ b/java/res/drawable-xhdpi/btn_keyboard_spacebar_normal_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.png b/java/res/drawable-xhdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.png
new file mode 100644
index 000000000..c3428bede
--- /dev/null
+++ b/java/res/drawable-xhdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_spacebar_pressed_lxx_light.9.png b/java/res/drawable-xhdpi/btn_keyboard_spacebar_pressed_lxx_light.9.png
new file mode 100644
index 000000000..f795ee9af
--- /dev/null
+++ b/java/res/drawable-xhdpi/btn_keyboard_spacebar_pressed_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_add_circle_wht_24dp.png b/java/res/drawable-xhdpi/ic_add_circle_wht_24dp.png
new file mode 100644
index 000000000..32a5b05ba
--- /dev/null
+++ b/java/res/drawable-xhdpi/ic_add_circle_wht_24dp.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_people_activated_lxx_dark.png b/java/res/drawable-xhdpi/ic_emoji_people_activated_lxx_dark.png
index cf2aeb591..538796ed1 100644
--- a/java/res/drawable-xhdpi/ic_emoji_people_activated_lxx_dark.png
+++ b/java/res/drawable-xhdpi/ic_emoji_people_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_people_activated_lxx_light.png b/java/res/drawable-xhdpi/ic_emoji_people_activated_lxx_light.png
index 3ecf9d010..0d8c33bcd 100644
--- a/java/res/drawable-xhdpi/ic_emoji_people_activated_lxx_light.png
+++ b/java/res/drawable-xhdpi/ic_emoji_people_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_people_normal_lxx_dark.png b/java/res/drawable-xhdpi/ic_emoji_people_normal_lxx_dark.png
index b0a448ae0..dbde6b0d7 100644
--- a/java/res/drawable-xhdpi/ic_emoji_people_normal_lxx_dark.png
+++ b/java/res/drawable-xhdpi/ic_emoji_people_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_people_normal_lxx_light.png b/java/res/drawable-xhdpi/ic_emoji_people_normal_lxx_light.png
index d71bc1cbb..aeecdee3e 100644
--- a/java/res/drawable-xhdpi/ic_emoji_people_normal_lxx_light.png
+++ b/java/res/drawable-xhdpi/ic_emoji_people_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_places_activated_lxx_dark.png b/java/res/drawable-xhdpi/ic_emoji_places_activated_lxx_dark.png
index 33f4e0a1f..607ad8408 100644
--- a/java/res/drawable-xhdpi/ic_emoji_places_activated_lxx_dark.png
+++ b/java/res/drawable-xhdpi/ic_emoji_places_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_places_activated_lxx_light.png b/java/res/drawable-xhdpi/ic_emoji_places_activated_lxx_light.png
index 194f49332..fe3f0eec5 100644
--- a/java/res/drawable-xhdpi/ic_emoji_places_activated_lxx_light.png
+++ b/java/res/drawable-xhdpi/ic_emoji_places_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_places_normal_lxx_dark.png b/java/res/drawable-xhdpi/ic_emoji_places_normal_lxx_dark.png
index 82d4ce613..bbec72f34 100644
--- a/java/res/drawable-xhdpi/ic_emoji_places_normal_lxx_dark.png
+++ b/java/res/drawable-xhdpi/ic_emoji_places_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_places_normal_lxx_light.png b/java/res/drawable-xhdpi/ic_emoji_places_normal_lxx_light.png
index e1b90a919..e3f201d10 100644
--- a/java/res/drawable-xhdpi/ic_emoji_places_normal_lxx_light.png
+++ b/java/res/drawable-xhdpi/ic_emoji_places_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_recents_activated_lxx_dark.png b/java/res/drawable-xhdpi/ic_emoji_recents_activated_lxx_dark.png
index 330573753..66d9c8e9f 100644
--- a/java/res/drawable-xhdpi/ic_emoji_recents_activated_lxx_dark.png
+++ b/java/res/drawable-xhdpi/ic_emoji_recents_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_recents_activated_lxx_light.png b/java/res/drawable-xhdpi/ic_emoji_recents_activated_lxx_light.png
index 8c74847a2..2a97d59bd 100644
--- a/java/res/drawable-xhdpi/ic_emoji_recents_activated_lxx_light.png
+++ b/java/res/drawable-xhdpi/ic_emoji_recents_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_recents_normal_lxx_dark.png b/java/res/drawable-xhdpi/ic_emoji_recents_normal_lxx_dark.png
index b9c1a659b..f60bba4c1 100644
--- a/java/res/drawable-xhdpi/ic_emoji_recents_normal_lxx_dark.png
+++ b/java/res/drawable-xhdpi/ic_emoji_recents_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_emoji_recents_normal_lxx_light.png b/java/res/drawable-xhdpi/ic_emoji_recents_normal_lxx_light.png
index 64e1c4df5..a13db7443 100644
--- a/java/res/drawable-xhdpi/ic_emoji_recents_normal_lxx_light.png
+++ b/java/res/drawable-xhdpi/ic_emoji_recents_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_launcher_keyboard.png b/java/res/drawable-xhdpi/ic_launcher_keyboard.png
index f2ac50dfe..17695015a 100644
--- a/java/res/drawable-xhdpi/ic_launcher_keyboard.png
+++ b/java/res/drawable-xhdpi/ic_launcher_keyboard.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_background_lxx_dark.9.png b/java/res/drawable-xhdpi/keyboard_background_lxx_dark.9.png
new file mode 100644
index 000000000..1c3a38e10
--- /dev/null
+++ b/java/res/drawable-xhdpi/keyboard_background_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_background_lxx_light.9.png b/java/res/drawable-xhdpi/keyboard_background_lxx_light.9.png
new file mode 100644
index 000000000..a7f18b5c8
--- /dev/null
+++ b/java/res/drawable-xhdpi/keyboard_background_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_background_lxx_dark.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_background_lxx_dark.9.png
index 654ccd10c..f934e33bd 100644
--- a/java/res/drawable-xhdpi/keyboard_key_feedback_background_lxx_dark.9.png
+++ b/java/res/drawable-xhdpi/keyboard_key_feedback_background_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_background_lxx_light.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_background_lxx_light.9.png
index c566e3d7c..f70599e99 100644
--- a/java/res/drawable-xhdpi/keyboard_key_feedback_background_lxx_light.9.png
+++ b/java/res/drawable-xhdpi/keyboard_key_feedback_background_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_lxx_dark.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_lxx_dark.9.png
index f5f613caa..fa5ddf2b6 100644
--- a/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_lxx_dark.9.png
+++ b/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_lxx_light.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_lxx_light.9.png
index 35aaa7d7c..0da8919b2 100644
--- a/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_lxx_light.9.png
+++ b/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_suggest_strip_lxx_dark.9.png b/java/res/drawable-xhdpi/keyboard_suggest_strip_lxx_dark.9.png
new file mode 100644
index 000000000..ac20faf80
--- /dev/null
+++ b/java/res/drawable-xhdpi/keyboard_suggest_strip_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_suggest_strip_lxx_light.9.png b/java/res/drawable-xhdpi/keyboard_suggest_strip_lxx_light.9.png
new file mode 100644
index 000000000..7ccd1ea9d
--- /dev/null
+++ b/java/res/drawable-xhdpi/keyboard_suggest_strip_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_smiley_lxx_light.png b/java/res/drawable-xhdpi/sym_keyboard_smiley_lxx_light.png
index df3eba750..0d8c33bcd 100644
--- a/java/res/drawable-xhdpi/sym_keyboard_smiley_lxx_light.png
+++ b/java/res/drawable-xhdpi/sym_keyboard_smiley_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_space_lxx_dark.png b/java/res/drawable-xhdpi/sym_keyboard_space_lxx_dark.png
new file mode 100644
index 000000000..2cab2d2fd
--- /dev/null
+++ b/java/res/drawable-xhdpi/sym_keyboard_space_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_space_lxx_light.png b/java/res/drawable-xhdpi/sym_keyboard_space_lxx_light.png
new file mode 100644
index 000000000..621eec69a
--- /dev/null
+++ b/java/res/drawable-xhdpi/sym_keyboard_space_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_active_lxx_dark.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_active_lxx_dark.9.png
index f49239794..927d87b58 100644
--- a/java/res/drawable-xxhdpi/btn_keyboard_key_active_lxx_dark.9.png
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_active_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_active_lxx_light.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_active_lxx_light.9.png
index 1f5f922dc..ce84bde4c 100644
--- a/java/res/drawable-xxhdpi/btn_keyboard_key_active_lxx_light.9.png
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_active_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png
index 65e455c7b..5b0854e46 100644
--- a/java/res/drawable-xxhdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_active_pressed_lxx_light.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_active_pressed_lxx_light.9.png
index 031014360..927d87b58 100644
--- a/java/res/drawable-xxhdpi/btn_keyboard_key_active_pressed_lxx_light.9.png
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_active_pressed_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_spacebar_lxx_dark.9.png b/java/res/drawable-xxhdpi/btn_keyboard_spacebar_normal_lxx_dark.9.png
index 0339de37d..0339de37d 100644
--- a/java/res/drawable-xxhdpi/sym_keyboard_spacebar_lxx_dark.9.png
+++ b/java/res/drawable-xxhdpi/btn_keyboard_spacebar_normal_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_spacebar_lxx_light.9.png b/java/res/drawable-xxhdpi/btn_keyboard_spacebar_normal_lxx_light.9.png
index b57cfb3d2..b57cfb3d2 100644
--- a/java/res/drawable-xxhdpi/sym_keyboard_spacebar_lxx_light.9.png
+++ b/java/res/drawable-xxhdpi/btn_keyboard_spacebar_normal_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.png b/java/res/drawable-xxhdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.png
new file mode 100644
index 000000000..8e74c6723
--- /dev/null
+++ b/java/res/drawable-xxhdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_spacebar_pressed_lxx_light.9.png b/java/res/drawable-xxhdpi/btn_keyboard_spacebar_pressed_lxx_light.9.png
new file mode 100644
index 000000000..1ca1ae3e9
--- /dev/null
+++ b/java/res/drawable-xxhdpi/btn_keyboard_spacebar_pressed_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_add_circle_wht_24dp.png b/java/res/drawable-xxhdpi/ic_add_circle_wht_24dp.png
new file mode 100644
index 000000000..a22c463f9
--- /dev/null
+++ b/java/res/drawable-xxhdpi/ic_add_circle_wht_24dp.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_people_activated_lxx_dark.png b/java/res/drawable-xxhdpi/ic_emoji_people_activated_lxx_dark.png
index 9ca031a5a..47f655470 100644
--- a/java/res/drawable-xxhdpi/ic_emoji_people_activated_lxx_dark.png
+++ b/java/res/drawable-xxhdpi/ic_emoji_people_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_people_activated_lxx_light.png b/java/res/drawable-xxhdpi/ic_emoji_people_activated_lxx_light.png
index 6faad5c80..ef5bf5a6f 100644
--- a/java/res/drawable-xxhdpi/ic_emoji_people_activated_lxx_light.png
+++ b/java/res/drawable-xxhdpi/ic_emoji_people_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_people_normal_lxx_dark.png b/java/res/drawable-xxhdpi/ic_emoji_people_normal_lxx_dark.png
index ed71326a9..8ebecb27a 100644
--- a/java/res/drawable-xxhdpi/ic_emoji_people_normal_lxx_dark.png
+++ b/java/res/drawable-xxhdpi/ic_emoji_people_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_people_normal_lxx_light.png b/java/res/drawable-xxhdpi/ic_emoji_people_normal_lxx_light.png
index a5516fa3a..d6369d9cc 100644
--- a/java/res/drawable-xxhdpi/ic_emoji_people_normal_lxx_light.png
+++ b/java/res/drawable-xxhdpi/ic_emoji_people_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_places_activated_lxx_dark.png b/java/res/drawable-xxhdpi/ic_emoji_places_activated_lxx_dark.png
index 513198227..6ba4c3a0c 100644
--- a/java/res/drawable-xxhdpi/ic_emoji_places_activated_lxx_dark.png
+++ b/java/res/drawable-xxhdpi/ic_emoji_places_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_places_activated_lxx_light.png b/java/res/drawable-xxhdpi/ic_emoji_places_activated_lxx_light.png
index 8a4614d73..b7531321a 100644
--- a/java/res/drawable-xxhdpi/ic_emoji_places_activated_lxx_light.png
+++ b/java/res/drawable-xxhdpi/ic_emoji_places_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_places_normal_lxx_dark.png b/java/res/drawable-xxhdpi/ic_emoji_places_normal_lxx_dark.png
index 0dfbadd66..d64581411 100644
--- a/java/res/drawable-xxhdpi/ic_emoji_places_normal_lxx_dark.png
+++ b/java/res/drawable-xxhdpi/ic_emoji_places_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_places_normal_lxx_light.png b/java/res/drawable-xxhdpi/ic_emoji_places_normal_lxx_light.png
index 2f22dfbb5..95b111d5a 100644
--- a/java/res/drawable-xxhdpi/ic_emoji_places_normal_lxx_light.png
+++ b/java/res/drawable-xxhdpi/ic_emoji_places_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_recents_activated_lxx_dark.png b/java/res/drawable-xxhdpi/ic_emoji_recents_activated_lxx_dark.png
index 28402b8c8..1501a07ac 100644
--- a/java/res/drawable-xxhdpi/ic_emoji_recents_activated_lxx_dark.png
+++ b/java/res/drawable-xxhdpi/ic_emoji_recents_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_recents_activated_lxx_light.png b/java/res/drawable-xxhdpi/ic_emoji_recents_activated_lxx_light.png
index 92da7f2bb..dcf876a57 100644
--- a/java/res/drawable-xxhdpi/ic_emoji_recents_activated_lxx_light.png
+++ b/java/res/drawable-xxhdpi/ic_emoji_recents_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_recents_normal_lxx_dark.png b/java/res/drawable-xxhdpi/ic_emoji_recents_normal_lxx_dark.png
index 24561f9fc..5aeb79a03 100644
--- a/java/res/drawable-xxhdpi/ic_emoji_recents_normal_lxx_dark.png
+++ b/java/res/drawable-xxhdpi/ic_emoji_recents_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_emoji_recents_normal_lxx_light.png b/java/res/drawable-xxhdpi/ic_emoji_recents_normal_lxx_light.png
index 96ff801b2..7b8b003df 100644
--- a/java/res/drawable-xxhdpi/ic_emoji_recents_normal_lxx_light.png
+++ b/java/res/drawable-xxhdpi/ic_emoji_recents_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_launcher_keyboard.png b/java/res/drawable-xxhdpi/ic_launcher_keyboard.png
index df386e827..624c82efd 100644
--- a/java/res/drawable-xxhdpi/ic_launcher_keyboard.png
+++ b/java/res/drawable-xxhdpi/ic_launcher_keyboard.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_background_lxx_dark.9.png b/java/res/drawable-xxhdpi/keyboard_background_lxx_dark.9.png
new file mode 100644
index 000000000..8b8917012
--- /dev/null
+++ b/java/res/drawable-xxhdpi/keyboard_background_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_background_lxx_light.9.png b/java/res/drawable-xxhdpi/keyboard_background_lxx_light.9.png
new file mode 100644
index 000000000..847df8a6e
--- /dev/null
+++ b/java/res/drawable-xxhdpi/keyboard_background_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_background_lxx_dark.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_background_lxx_dark.9.png
index f5215bc56..1b92455e9 100644
--- a/java/res/drawable-xxhdpi/keyboard_key_feedback_background_lxx_dark.9.png
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_background_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_background_lxx_light.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_background_lxx_light.9.png
index b565ff07c..3effde383 100644
--- a/java/res/drawable-xxhdpi/keyboard_key_feedback_background_lxx_light.9.png
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_background_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_lxx_dark.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_lxx_dark.9.png
index 6d931ed42..55d633098 100644
--- a/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_lxx_dark.9.png
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_lxx_light.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_lxx_light.9.png
index 2c5ced966..4523be965 100644
--- a/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_lxx_light.9.png
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_suggest_strip_lxx_dark.9.png b/java/res/drawable-xxhdpi/keyboard_suggest_strip_lxx_dark.9.png
new file mode 100644
index 000000000..2de0c9c42
--- /dev/null
+++ b/java/res/drawable-xxhdpi/keyboard_suggest_strip_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_suggest_strip_lxx_light.9.png b/java/res/drawable-xxhdpi/keyboard_suggest_strip_lxx_light.9.png
new file mode 100644
index 000000000..8b495f39b
--- /dev/null
+++ b/java/res/drawable-xxhdpi/keyboard_suggest_strip_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_smiley_lxx_light.png b/java/res/drawable-xxhdpi/sym_keyboard_smiley_lxx_light.png
index 08d4f8adc..ef5bf5a6f 100644
--- a/java/res/drawable-xxhdpi/sym_keyboard_smiley_lxx_light.png
+++ b/java/res/drawable-xxhdpi/sym_keyboard_smiley_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_space_lxx_dark.png b/java/res/drawable-xxhdpi/sym_keyboard_space_lxx_dark.png
new file mode 100644
index 000000000..f05d7d238
--- /dev/null
+++ b/java/res/drawable-xxhdpi/sym_keyboard_space_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/sym_keyboard_space_lxx_light.png b/java/res/drawable-xxhdpi/sym_keyboard_space_lxx_light.png
new file mode 100644
index 000000000..94be9067c
--- /dev/null
+++ b/java/res/drawable-xxhdpi/sym_keyboard_space_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_key_active_lxx_dark.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_key_active_lxx_dark.9.png
new file mode 100644
index 000000000..eac447583
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_key_active_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_key_active_lxx_light.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_key_active_lxx_light.9.png
new file mode 100644
index 000000000..16d1f687f
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_key_active_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png
new file mode 100644
index 000000000..78923a887
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_key_active_pressed_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_key_active_pressed_lxx_light.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_key_active_pressed_lxx_light.9.png
new file mode 100644
index 000000000..e57e80d05
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_key_active_pressed_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_key_normal_off_lxx_dark.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_key_normal_off_lxx_dark.9.png
new file mode 100644
index 000000000..0b3d796e4
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_key_normal_off_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_key_normal_off_lxx_light.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_key_normal_off_lxx_light.9.png
new file mode 100644
index 000000000..6edd4e3d5
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_key_normal_off_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_key_normal_on_lxx_dark.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_key_normal_on_lxx_dark.9.png
new file mode 100644
index 000000000..61a5efc2f
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_key_normal_on_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_key_normal_on_lxx_light.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_key_normal_on_lxx_light.9.png
new file mode 100644
index 000000000..c60a23547
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_key_normal_on_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_key_popup_selected_lxx_dark.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_key_popup_selected_lxx_dark.9.png
new file mode 100644
index 000000000..842c6858d
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_key_popup_selected_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_key_popup_selected_lxx_light.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_key_popup_selected_lxx_light.9.png
new file mode 100644
index 000000000..6b033067f
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_key_popup_selected_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_key_pressed_off_lxx_dark.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_key_pressed_off_lxx_dark.9.png
new file mode 100644
index 000000000..276065e3b
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_key_pressed_off_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_key_pressed_off_lxx_light.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_key_pressed_off_lxx_light.9.png
new file mode 100644
index 000000000..e64147f4f
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_key_pressed_off_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_key_pressed_on_lxx_dark.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_key_pressed_on_lxx_dark.9.png
new file mode 100644
index 000000000..c1300140c
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_key_pressed_on_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_key_pressed_on_lxx_light.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_key_pressed_on_lxx_light.9.png
new file mode 100644
index 000000000..e433f5669
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_key_pressed_on_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_spacebar_normal_lxx_dark.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_spacebar_normal_lxx_dark.9.png
new file mode 100644
index 000000000..ee4d16b64
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_spacebar_normal_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_spacebar_normal_lxx_light.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_spacebar_normal_lxx_light.9.png
new file mode 100644
index 000000000..14cba3c24
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_spacebar_normal_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.png
new file mode 100644
index 000000000..671c31f08
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_spacebar_pressed_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/btn_keyboard_spacebar_pressed_lxx_light.9.png b/java/res/drawable-xxxhdpi/btn_keyboard_spacebar_pressed_lxx_light.9.png
new file mode 100644
index 000000000..8a6f32afe
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/btn_keyboard_spacebar_pressed_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_add_circle_white_24dp.png b/java/res/drawable-xxxhdpi/ic_add_circle_white_24dp.png
new file mode 100644
index 000000000..a0116fafe
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_add_circle_white_24dp.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_emoticons_activated_lxx_dark.png b/java/res/drawable-xxxhdpi/ic_emoji_emoticons_activated_lxx_dark.png
new file mode 100644
index 000000000..0198bce94
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_emoticons_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_emoticons_activated_lxx_light.png b/java/res/drawable-xxxhdpi/ic_emoji_emoticons_activated_lxx_light.png
new file mode 100644
index 000000000..f530ba139
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_emoticons_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_emoticons_normal_lxx_dark.png b/java/res/drawable-xxxhdpi/ic_emoji_emoticons_normal_lxx_dark.png
new file mode 100644
index 000000000..d9022bbe3
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_emoticons_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_emoticons_normal_lxx_light.png b/java/res/drawable-xxxhdpi/ic_emoji_emoticons_normal_lxx_light.png
new file mode 100644
index 000000000..89dc4cd92
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_emoticons_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_nature_activated_lxx_dark.png b/java/res/drawable-xxxhdpi/ic_emoji_nature_activated_lxx_dark.png
new file mode 100644
index 000000000..efbf51c11
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_nature_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_nature_activated_lxx_light.png b/java/res/drawable-xxxhdpi/ic_emoji_nature_activated_lxx_light.png
new file mode 100644
index 000000000..95355c635
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_nature_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_nature_normal_lxx_dark.png b/java/res/drawable-xxxhdpi/ic_emoji_nature_normal_lxx_dark.png
new file mode 100644
index 000000000..f5531ea11
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_nature_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_nature_normal_lxx_light.png b/java/res/drawable-xxxhdpi/ic_emoji_nature_normal_lxx_light.png
new file mode 100644
index 000000000..b5085cb6a
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_nature_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_objects_activated_lxx_dark.png b/java/res/drawable-xxxhdpi/ic_emoji_objects_activated_lxx_dark.png
new file mode 100644
index 000000000..730f75d94
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_objects_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_objects_activated_lxx_light.png b/java/res/drawable-xxxhdpi/ic_emoji_objects_activated_lxx_light.png
new file mode 100644
index 000000000..f4a250ddd
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_objects_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_objects_normal_lxx_dark.png b/java/res/drawable-xxxhdpi/ic_emoji_objects_normal_lxx_dark.png
new file mode 100644
index 000000000..4658ceac0
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_objects_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_objects_normal_lxx_light.png b/java/res/drawable-xxxhdpi/ic_emoji_objects_normal_lxx_light.png
new file mode 100644
index 000000000..7b27829e7
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_objects_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_people_activated_lxx_dark.png b/java/res/drawable-xxxhdpi/ic_emoji_people_activated_lxx_dark.png
new file mode 100644
index 000000000..b70f07ac5
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_people_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_people_activated_lxx_light.png b/java/res/drawable-xxxhdpi/ic_emoji_people_activated_lxx_light.png
new file mode 100644
index 000000000..7e052080b
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_people_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_people_normal_lxx_dark.png b/java/res/drawable-xxxhdpi/ic_emoji_people_normal_lxx_dark.png
new file mode 100644
index 000000000..c960d15e4
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_people_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_people_normal_lxx_light.png b/java/res/drawable-xxxhdpi/ic_emoji_people_normal_lxx_light.png
new file mode 100644
index 000000000..44325cf35
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_people_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_places_activated_lxx_dark.png b/java/res/drawable-xxxhdpi/ic_emoji_places_activated_lxx_dark.png
new file mode 100644
index 000000000..bca6bbaa7
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_places_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_places_activated_lxx_light.png b/java/res/drawable-xxxhdpi/ic_emoji_places_activated_lxx_light.png
new file mode 100644
index 000000000..8f340d2df
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_places_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_places_normal_lxx_dark.png b/java/res/drawable-xxxhdpi/ic_emoji_places_normal_lxx_dark.png
new file mode 100644
index 000000000..a06e1d858
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_places_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_places_normal_lxx_light.png b/java/res/drawable-xxxhdpi/ic_emoji_places_normal_lxx_light.png
new file mode 100644
index 000000000..b247768f7
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_places_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_recents_activated_lxx_dark.png b/java/res/drawable-xxxhdpi/ic_emoji_recents_activated_lxx_dark.png
new file mode 100644
index 000000000..3508374ba
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_recents_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_recents_activated_lxx_light.png b/java/res/drawable-xxxhdpi/ic_emoji_recents_activated_lxx_light.png
new file mode 100644
index 000000000..82a029ee7
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_recents_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_recents_normal_lxx_dark.png b/java/res/drawable-xxxhdpi/ic_emoji_recents_normal_lxx_dark.png
new file mode 100644
index 000000000..6797d7b31
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_recents_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_recents_normal_lxx_light.png b/java/res/drawable-xxxhdpi/ic_emoji_recents_normal_lxx_light.png
new file mode 100644
index 000000000..6b622ac6d
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_recents_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_symbols_activated_lxx_dark.png b/java/res/drawable-xxxhdpi/ic_emoji_symbols_activated_lxx_dark.png
new file mode 100644
index 000000000..51336e93a
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_symbols_activated_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_symbols_activated_lxx_light.png b/java/res/drawable-xxxhdpi/ic_emoji_symbols_activated_lxx_light.png
new file mode 100644
index 000000000..2ab8fa6a7
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_symbols_activated_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_symbols_normal_lxx_dark.png b/java/res/drawable-xxxhdpi/ic_emoji_symbols_normal_lxx_dark.png
new file mode 100644
index 000000000..e02ad6175
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_symbols_normal_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_emoji_symbols_normal_lxx_light.png b/java/res/drawable-xxxhdpi/ic_emoji_symbols_normal_lxx_light.png
new file mode 100644
index 000000000..b17f06674
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_emoji_symbols_normal_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/ic_launcher_keyboard.png b/java/res/drawable-xxxhdpi/ic_launcher_keyboard.png
new file mode 100644
index 000000000..39636a1b7
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/ic_launcher_keyboard.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/keyboard_background_lxx_dark.9.png b/java/res/drawable-xxxhdpi/keyboard_background_lxx_dark.9.png
new file mode 100644
index 000000000..a7dd5378b
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/keyboard_background_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/keyboard_background_lxx_light.9.png b/java/res/drawable-xxxhdpi/keyboard_background_lxx_light.9.png
new file mode 100644
index 000000000..ef7ab2097
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/keyboard_background_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/keyboard_key_feedback_background_lxx_dark.9.png b/java/res/drawable-xxxhdpi/keyboard_key_feedback_background_lxx_dark.9.png
new file mode 100644
index 000000000..0e08b6b95
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/keyboard_key_feedback_background_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/keyboard_key_feedback_background_lxx_light.9.png b/java/res/drawable-xxxhdpi/keyboard_key_feedback_background_lxx_light.9.png
new file mode 100644
index 000000000..fb10523d2
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/keyboard_key_feedback_background_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/keyboard_key_feedback_more_background_lxx_dark.9.png b/java/res/drawable-xxxhdpi/keyboard_key_feedback_more_background_lxx_dark.9.png
new file mode 100644
index 000000000..fd88668bb
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/keyboard_key_feedback_more_background_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/keyboard_key_feedback_more_background_lxx_light.9.png b/java/res/drawable-xxxhdpi/keyboard_key_feedback_more_background_lxx_light.9.png
new file mode 100644
index 000000000..ab1bfad7d
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/keyboard_key_feedback_more_background_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/keyboard_popup_panel_background_lxx_dark.9.png b/java/res/drawable-xxxhdpi/keyboard_popup_panel_background_lxx_dark.9.png
new file mode 100644
index 000000000..3489a9c4c
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/keyboard_popup_panel_background_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/keyboard_popup_panel_background_lxx_light.9.png b/java/res/drawable-xxxhdpi/keyboard_popup_panel_background_lxx_light.9.png
new file mode 100644
index 000000000..2e3797263
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/keyboard_popup_panel_background_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/keyboard_suggest_strip_lxx_dark.9.png b/java/res/drawable-xxxhdpi/keyboard_suggest_strip_lxx_dark.9.png
new file mode 100644
index 000000000..098fa0652
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/keyboard_suggest_strip_lxx_dark.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/keyboard_suggest_strip_lxx_light.9.png b/java/res/drawable-xxxhdpi/keyboard_suggest_strip_lxx_light.9.png
new file mode 100644
index 000000000..c1c48c973
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/keyboard_suggest_strip_lxx_light.9.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/suggestions_strip_divider_lxx_dark.png b/java/res/drawable-xxxhdpi/suggestions_strip_divider_lxx_dark.png
new file mode 100644
index 000000000..0dc783d7c
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/suggestions_strip_divider_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/suggestions_strip_divider_lxx_light.png b/java/res/drawable-xxxhdpi/suggestions_strip_divider_lxx_light.png
new file mode 100644
index 000000000..f3162e422
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/suggestions_strip_divider_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_delete_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_delete_lxx_dark.png
new file mode 100644
index 000000000..c8a064d87
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_delete_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_delete_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_delete_lxx_light.png
new file mode 100644
index 000000000..2d2e6e158
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_delete_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_done_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_done_lxx_dark.png
new file mode 100644
index 000000000..27426da97
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_done_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_done_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_done_lxx_light.png
new file mode 100644
index 000000000..4b1a69f5b
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_done_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_go_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_go_lxx_dark.png
new file mode 100644
index 000000000..79d3eef5d
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_go_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_go_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_go_lxx_light.png
new file mode 100644
index 000000000..a87e24028
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_go_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_language_switch_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_language_switch_lxx_dark.png
new file mode 100644
index 000000000..26f361540
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_language_switch_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_language_switch_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_language_switch_lxx_light.png
new file mode 100644
index 000000000..93efb378f
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_language_switch_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_next_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_next_lxx_dark.png
new file mode 100644
index 000000000..27bf68941
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_next_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_next_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_next_lxx_light.png
new file mode 100644
index 000000000..c62410429
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_next_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_previous_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_previous_lxx_dark.png
new file mode 100644
index 000000000..50e0a31d2
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_previous_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_previous_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_previous_lxx_light.png
new file mode 100644
index 000000000..3f4424927
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_previous_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_return_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_return_lxx_dark.png
new file mode 100644
index 000000000..c10107125
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_return_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_return_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_return_lxx_light.png
new file mode 100644
index 000000000..54e7fb05b
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_return_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_search_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_search_lxx_dark.png
new file mode 100644
index 000000000..8f7dfcefc
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_search_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_search_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_search_lxx_light.png
new file mode 100644
index 000000000..07d555149
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_search_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_send_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_send_lxx_dark.png
new file mode 100644
index 000000000..9c12ec29f
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_send_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_send_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_send_lxx_light.png
new file mode 100644
index 000000000..fc6882833
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_send_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_settings_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_settings_lxx_dark.png
new file mode 100644
index 000000000..d728b8308
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_settings_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_settings_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_settings_lxx_light.png
new file mode 100644
index 000000000..1351710ad
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_settings_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_shift_locked_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_shift_locked_lxx_dark.png
new file mode 100644
index 000000000..e75d556b4
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_shift_locked_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_shift_locked_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_shift_locked_lxx_light.png
new file mode 100644
index 000000000..00521bf09
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_shift_locked_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_shift_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_shift_lxx_dark.png
new file mode 100644
index 000000000..f47bf66e2
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_shift_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_shift_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_shift_lxx_light.png
new file mode 100644
index 000000000..fdb6cd77a
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_shift_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_smiley_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_smiley_lxx_dark.png
new file mode 100644
index 000000000..26fd4e7ef
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_smiley_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_smiley_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_smiley_lxx_light.png
new file mode 100644
index 000000000..7b0467aa2
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_smiley_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_space_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_space_lxx_dark.png
new file mode 100644
index 000000000..1f6c92da0
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_space_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_space_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_space_lxx_light.png
new file mode 100644
index 000000000..656cf99ca
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_space_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_tab_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_tab_lxx_dark.png
new file mode 100644
index 000000000..89884698c
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_tab_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_tab_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_tab_lxx_light.png
new file mode 100644
index 000000000..aeedba6da
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_tab_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_voice_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_voice_lxx_dark.png
new file mode 100644
index 000000000..9d5b73307
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_voice_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_voice_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_voice_lxx_light.png
new file mode 100644
index 000000000..9db910daa
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_voice_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_voice_off_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_voice_off_lxx_dark.png
new file mode 100644
index 000000000..e233d0993
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_voice_off_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_voice_off_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_voice_off_lxx_light.png
new file mode 100644
index 000000000..7e0a964dc
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_voice_off_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_zwj_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_zwj_lxx_dark.png
new file mode 100644
index 000000000..94de9165b
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_zwj_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_zwj_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_zwj_lxx_light.png
new file mode 100644
index 000000000..2b13ba737
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_zwj_lxx_light.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_zwnj_lxx_dark.png b/java/res/drawable-xxxhdpi/sym_keyboard_zwnj_lxx_dark.png
new file mode 100644
index 000000000..134bca67c
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_zwnj_lxx_dark.png
Binary files differ
diff --git a/java/res/drawable-xxxhdpi/sym_keyboard_zwnj_lxx_light.png b/java/res/drawable-xxxhdpi/sym_keyboard_zwnj_lxx_light.png
new file mode 100644
index 000000000..31cf75bb3
--- /dev/null
+++ b/java/res/drawable-xxxhdpi/sym_keyboard_zwnj_lxx_light.png
Binary files differ
diff --git a/java/res/drawable/btn_keyboard_key_popup_action_lxx_dark.xml b/java/res/drawable/btn_keyboard_key_popup_action_lxx_dark.xml
new file mode 100644
index 000000000..8b637f204
--- /dev/null
+++ b/java/res/drawable/btn_keyboard_key_popup_action_lxx_dark.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true"
+ android:drawable="@drawable/btn_keyboard_key_active_pressed_lxx_dark" />
+ <item android:drawable="@drawable/btn_keyboard_key_active_lxx_dark" />
+</selector>
diff --git a/java/res/drawable/btn_keyboard_key_popup_action_lxx_light.xml b/java/res/drawable/btn_keyboard_key_popup_action_lxx_light.xml
new file mode 100644
index 000000000..67fc52144
--- /dev/null
+++ b/java/res/drawable/btn_keyboard_key_popup_action_lxx_light.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true"
+ android:drawable="@drawable/btn_keyboard_key_active_pressed_lxx_light" />
+ <item android:drawable="@drawable/btn_keyboard_key_active_lxx_light" />
+</selector>
diff --git a/java/res/drawable/btn_keyboard_key_popup_lxx_light.xml b/java/res/drawable/btn_keyboard_key_popup_lxx_light.xml
new file mode 100644
index 000000000..d6cd2b831
--- /dev/null
+++ b/java/res/drawable/btn_keyboard_key_popup_lxx_light.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true"
+ android:drawable="@drawable/btn_keyboard_key_popup_selected_lxx_light" />
+ <item android:drawable="@android:color/transparent" />
+</selector>
diff --git a/java/res/drawable/btn_keyboard_spacebar_lxx_dark.xml b/java/res/drawable/btn_keyboard_spacebar_lxx_dark.xml
index 5c595d9ed..e930e40e4 100644
--- a/java/res/drawable/btn_keyboard_spacebar_lxx_dark.xml
+++ b/java/res/drawable/btn_keyboard_spacebar_lxx_dark.xml
@@ -16,6 +16,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
- android:drawable="@color/key_background_pressed_lxx_dark" />
- <item android:drawable="@color/key_background_lxx_dark" />
+ android:drawable="@drawable/btn_keyboard_spacebar_pressed_lxx_dark" />
+ <item android:drawable="@drawable/btn_keyboard_spacebar_normal_lxx_dark" />
</selector>
diff --git a/java/res/drawable/btn_keyboard_spacebar_lxx_light.xml b/java/res/drawable/btn_keyboard_spacebar_lxx_light.xml
index acd19fda4..2b059938d 100644
--- a/java/res/drawable/btn_keyboard_spacebar_lxx_light.xml
+++ b/java/res/drawable/btn_keyboard_spacebar_lxx_light.xml
@@ -16,6 +16,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
- android:drawable="@color/key_background_pressed_lxx_light" />
- <item android:drawable="@color/key_background_lxx_light" />
+ android:drawable="@drawable/btn_keyboard_spacebar_pressed_lxx_light" />
+ <item android:drawable="@drawable/btn_keyboard_spacebar_normal_lxx_light" />
</selector>
diff --git a/java/res/layout/additional_subtype_dialog.xml b/java/res/layout/additional_subtype_dialog.xml
index f97c006d6..b7804f5df 100644
--- a/java/res/layout/additional_subtype_dialog.xml
+++ b/java/res/layout/additional_subtype_dialog.xml
@@ -18,39 +18,60 @@
*/
-->
-<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:columnCount="2"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginLeft="8dip"
- android:layout_marginRight="8dip"
- android:padding="8dip">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="left|center_vertical"
- style="?android:attr/textAppearanceSmall"
- android:text="@string/subtype_locale" />
- <Spinner
- android:id="@+id/subtype_locale_spinner"
- android:layout_width="wrap_content"
- android:layout_marginLeft="8dip"
- android:layout_marginBottom="8dip"
- android:layout_marginTop="8dip"
- android:layout_gravity="fill_horizontal|center_vertical"
- android:prompt="@string/subtype_locale" />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="left|center_vertical"
- style="?android:attr/textAppearanceSmall"
- android:text="@string/keyboard_layout_set" />
- <Spinner
- android:id="@+id/keyboard_layout_set_spinner"
- android:layout_width="wrap_content"
- android:layout_marginLeft="8dip"
- android:layout_marginBottom="8dip"
- android:layout_marginTop="8dip"
- android:layout_gravity="fill_horizontal|center_vertical"
- android:prompt="@string/keyboard_layout_set" />
-</GridLayout>
+ android:padding="16dip">
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:layout_width="0dp"
+ android:layout_weight="30"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start|center_vertical"
+ android:gravity="start|left"
+ android:textAlignment="viewStart"
+ style="?android:attr/textAppearanceSmall"
+ android:text="@string/subtype_locale" />
+ <Spinner
+ android:id="@+id/subtype_locale_spinner"
+ android:spinnerMode="dialog"
+ android:layout_width="0dp"
+ android:layout_weight="70"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dip"
+ android:layout_marginBottom="8dip"
+ android:layout_marginTop="8dip"
+ android:layout_gravity="fill_horizontal|center_vertical"
+ android:gravity="start|left"
+ android:prompt="@string/subtype_locale" />
+ </LinearLayout>
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:layout_width="0dp"
+ android:layout_weight="30"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start|center_vertical"
+ android:textAlignment="viewStart"
+ style="?android:attr/textAppearanceSmall"
+ android:text="@string/keyboard_layout_set" />
+ <Spinner
+ android:id="@+id/keyboard_layout_set_spinner"
+ android:spinnerMode="dialog"
+ android:layout_width="0dp"
+ android:layout_weight="70"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dip"
+ android:layout_marginBottom="8dip"
+ android:layout_marginTop="8dip"
+ android:layout_gravity="fill_horizontal|center_vertical"
+ android:gravity="start|left"
+ android:prompt="@string/keyboard_layout_set" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/java/res/layout/emoji_palettes_view.xml b/java/res/layout/emoji_palettes_view.xml
index a6ea38ba4..26cc042ab 100644
--- a/java/res/layout/emoji_palettes_view.xml
+++ b/java/res/layout/emoji_palettes_view.xml
@@ -20,10 +20,10 @@
<com.android.inputmethod.keyboard.emoji.EmojiPalettesView
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"
+ android:layout_gravity="bottom"
+ android:orientation="vertical"
style="?attr/emojiPalettesViewStyle"
>
<LinearLayout
diff --git a/java/res/layout/input_view.xml b/java/res/layout/input_view.xml
index ff0b403d1..46551f63f 100644
--- a/java/res/layout/input_view.xml
+++ b/java/res/layout/input_view.xml
@@ -21,38 +21,11 @@
<com.android.inputmethod.latin.InputView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="bottom|center_horizontal"
- 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="0dp" />
- <LinearLayout
+ android:layout_height="wrap_content">
+ <include
android:id="@+id/main_keyboard_frame"
- android:layout_width="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/config_suggestions_strip_height"
- android:gravity="center_vertical"
- 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>
+ layout="@layout/main_keyboard_frame" />
<include
+ android:id="@+id/emoji_palettes_view"
layout="@layout/emoji_palettes_view" />
</com.android.inputmethod.latin.InputView>
diff --git a/java/res/layout/main_keyboard_frame.xml b/java/res/layout/main_keyboard_frame.xml
new file mode 100644
index 000000000..ebf746679
--- /dev/null
+++ b/java/res/layout/main_keyboard_frame.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ 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/config_suggestions_strip_height"
+ android:gravity="center_vertical"
+ 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>
diff --git a/java/res/layout/more_keys_keyboard.xml b/java/res/layout/more_keys_keyboard.xml
index f3795afdc..449c00f92 100644
--- a/java/res/layout/more_keys_keyboard.xml
+++ b/java/res/layout/more_keys_keyboard.xml
@@ -27,5 +27,6 @@
<com.android.inputmethod.keyboard.MoreKeysKeyboardView
android:id="@+id/more_keys_keyboard_view"
android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ style="?attr/moreKeysKeyboardViewStyle" />
</LinearLayout>
diff --git a/java/res/xml-sw600dp/key_question_exclamation.xml b/java/res/layout/more_keys_keyboard_for_action_lxx.xml
index edee5c5dd..d23faa4f0 100644
--- a/java/res/xml-sw600dp/key_question_exclamation.xml
+++ b/java/res/layout/more_keys_keyboard_for_action_lxx.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2012, The Android Open Source Project
+** Copyright 2014, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -18,22 +18,15 @@
*/
-->
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
>
- <switch>
- <case
- latin:mode="email|url"
- >
- <Key
- latin:keySpec="-" />
- </case>
- <default>
- <Key
- latin:keySpec="\?"
- latin:keyHintLabel="!"
- latin:moreKeys="!"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- </default>
- </switch>
-</merge>
+ <com.android.inputmethod.keyboard.MoreKeysKeyboardView
+ android:id="@+id/more_keys_keyboard_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="?attr/moreKeysKeyboardViewForActionStyle" />
+</LinearLayout>
diff --git a/java/res/layout/radio_button_preference_widget.xml b/java/res/layout/radio_button_preference_widget.xml
new file mode 100644
index 000000000..ee9cda1cc
--- /dev/null
+++ b/java/res/layout/radio_button_preference_widget.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<RadioButton
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/radio_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clickable="false"
+ android:focusable="false" />
diff --git a/java/res/layout/suggestion_divider.xml b/java/res/layout/suggestion_divider.xml
index dfea017e6..a5bb6c562 100644
--- a/java/res/layout/suggestion_divider.xml
+++ b/java/res/layout/suggestion_divider.xml
@@ -31,4 +31,5 @@
android:longClickable="false"
android:hapticFeedbackEnabled="false"
android:soundEffectsEnabled="false"
+ android:background="@null"
style="?attr/suggestionStripViewStyle" />
diff --git a/java/res/layout/suggestions_strip.xml b/java/res/layout/suggestions_strip.xml
index 489477990..aefdb8cad 100644
--- a/java/res/layout/suggestions_strip.xml
+++ b/java/res/layout/suggestions_strip.xml
@@ -48,12 +48,13 @@
android:layout_height="match_parent"
style="?attr/suggestionWordStyle" />
<include
+ android:id="@+id/word_to_save_divider"
layout="@layout/suggestion_divider" />
<TextView
android:id="@+id/hint_add_to_dictionary"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:textAlignment="viewStart"
+ android:gravity="center_vertical|start"
style="?attr/suggestionWordStyle" />
</LinearLayout>
<!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
diff --git a/java/res/layout/user_dictionary_item.xml b/java/res/layout/user_dictionary_item.xml
index b8d48b56d..fe7d47ec2 100644
--- a/java/res/layout/user_dictionary_item.xml
+++ b/java/res/layout/user_dictionary_item.xml
@@ -29,7 +29,7 @@
android:layout_weight="1" >
<TextView
- android:id="@+android:id/text1"
+ android:id="@android:id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
@@ -38,7 +38,7 @@
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
- android:id="@+android:id/text2"
+ android:id="@android:id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="@android:id/text1"
diff --git a/java/res/anim/more_keys_keyboard_fadein.xml b/java/res/menu/add_style.xml
index c781f36ad..d1cab4bb5 100644
--- a/java/res/anim/more_keys_keyboard_fadein.xml
+++ b/java/res/menu/add_style.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2010, The Android Open Source Project
+** Copyright 2014, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -17,13 +17,10 @@
** limitations under the License.
*/
-->
-
-<set
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:anim/decelerate_interpolator"
->
- <alpha
- android:fromAlpha="0.5"
- android:toAlpha="1.0"
- android:duration="@integer/config_more_keys_keyboard_fadein_anim_time" />
-</set>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/action_add_style"
+ android:icon="@drawable/ic_add_circle_wht_24dp"
+ android:title="@string/add_style"
+ android:showAsAction="always" />
+</menu> \ No newline at end of file
diff --git a/java/res/raw/main_ru.dict b/java/res/raw/main_ru.dict
index 0f08f1735..9fdaf3148 100644
--- a/java/res/raw/main_ru.dict
+++ b/java/res/raw/main_ru.dict
Binary files differ
diff --git a/java/res/anim/more_keys_keyboard_fadeout.xml b/java/res/values-az-rAZ/bools.xml
index 32fae6bd8..130e52eab 100644
--- a/java/res/anim/more_keys_keyboard_fadeout.xml
+++ b/java/res/values-az-rAZ/bools.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2010, The Android Open Source Project
+** Copyright 2014, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -17,13 +17,8 @@
** limitations under the License.
*/
-->
-
-<set
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:anim/accelerate_interpolator"
->
- <alpha
- android:fromAlpha="1.0"
- android:toAlpha="0.0"
- android:duration="@integer/config_more_keys_keyboard_fadeout_anim_time" />
-</set>
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/xml-sw600dp/key_f1.xml b/java/res/values-bn-rIN/bools.xml
index ba78a6430..130e52eab 100644
--- a/java/res/xml-sw600dp/key_f1.xml
+++ b/java/res/values-bn-rIN/bools.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2012, The Android Open Source Project
+** Copyright 2014, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -17,20 +17,8 @@
** limitations under the License.
*/
-->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <switch>
- <case
- latin:mode="email"
- >
- <Key
- latin:keySpec="\@" />
- </case>
- <default>
- <Key
- latin:keySpec="/" />
- </default>
- </switch>
-</merge>
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/values-eu-rES/bools.xml b/java/res/values-eu-rES/bools.xml
new file mode 100644
index 000000000..130e52eab
--- /dev/null
+++ b/java/res/values-eu-rES/bools.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/values-gl-rES/bools.xml b/java/res/values-gl-rES/bools.xml
new file mode 100644
index 000000000..130e52eab
--- /dev/null
+++ b/java/res/values-gl-rES/bools.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/values-hy-rAM/bools.xml b/java/res/values-hy-rAM/bools.xml
new file mode 100644
index 000000000..130e52eab
--- /dev/null
+++ b/java/res/values-hy-rAM/bools.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/values-is-rIS/bools.xml b/java/res/values-is-rIS/bools.xml
new file mode 100644
index 000000000..130e52eab
--- /dev/null
+++ b/java/res/values-is-rIS/bools.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/values-kk-rKZ/bools.xml b/java/res/values-kk-rKZ/bools.xml
new file mode 100644
index 000000000..130e52eab
--- /dev/null
+++ b/java/res/values-kk-rKZ/bools.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/values-km-rKH/bools.xml b/java/res/values-km-rKH/bools.xml
new file mode 100644
index 000000000..130e52eab
--- /dev/null
+++ b/java/res/values-km-rKH/bools.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/values-kn-rIN/bools.xml b/java/res/values-kn-rIN/bools.xml
new file mode 100644
index 000000000..130e52eab
--- /dev/null
+++ b/java/res/values-kn-rIN/bools.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/values-ky-rKG/bools.xml b/java/res/values-ky-rKG/bools.xml
new file mode 100644
index 000000000..130e52eab
--- /dev/null
+++ b/java/res/values-ky-rKG/bools.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/values-land/config.xml b/java/res/values-land/config.xml
index 5eea4c1c6..d36f6a0fc 100644
--- a/java/res/values-land/config.xml
+++ b/java/res/values-land/config.xml
@@ -40,14 +40,22 @@
<!-- config_more_keys_keyboard_key_height x -0.5 -->
<dimen name="config_more_keys_keyboard_vertical_correction_holo">-22.4dp</dimen>
<dimen name="config_key_preview_offset_holo">1.6dp</dimen>
-
+ <dimen name="config_key_preview_height_holo">80dp</dimen>
+ <dimen name="config_key_preview_offset_lxx">43.6dp</dimen>
+ <dimen name="config_key_preview_height_lxx">122dp</dimen>
<fraction name="config_key_preview_text_ratio">90%</fraction>
- <fraction name="config_key_letter_ratio">65%</fraction>
- <fraction name="config_key_large_letter_ratio">74%</fraction>
- <fraction name="config_key_label_ratio">40%</fraction>
- <fraction name="config_key_hint_letter_ratio">30%</fraction>
- <fraction name="config_key_hint_label_ratio">52%</fraction>
- <fraction name="config_key_shifted_letter_hint_ratio">40%</fraction>
+ <fraction name="config_key_letter_ratio_holo">65%</fraction>
+ <fraction name="config_key_letter_ratio_lxx">65%</fraction>
+ <fraction name="config_key_large_letter_ratio_holo">74%</fraction>
+ <fraction name="config_key_large_letter_ratio_lxx">90%</fraction>
+ <fraction name="config_key_label_ratio_holo">40%</fraction>
+ <fraction name="config_key_label_ratio_lxx">40%</fraction>
+ <fraction name="config_key_hint_letter_ratio_holo">30%</fraction>
+ <fraction name="config_key_hint_letter_ratio_lxx">30%</fraction>
+ <fraction name="config_key_hint_label_ratio_holo">52%</fraction>
+ <fraction name="config_key_hint_label_ratio_lxx">30%</fraction>
+ <fraction name="config_key_shifted_letter_hint_ratio_holo">40%</fraction>
+ <fraction name="config_key_shifted_letter_hint_ratio_lxx">40%</fraction>
<fraction name="config_language_on_spacebar_text_ratio">40.000%</fraction>
<!-- For 5-row keyboard -->
diff --git a/java/res/values-land/keyboard-heights.xml b/java/res/values-land/keyboard-heights.xml
index d57f96be3..02d8b14c8 100644
--- a/java/res/values-land/keyboard-heights.xml
+++ b/java/res/values-land/keyboard-heights.xml
@@ -33,5 +33,7 @@
<!-- Preferable keyboard height in absolute scale: 45.0mm -->
<!-- Xoom -->
<item>HARDWARE=stingray,265.4378</item>
+ <!-- Volantis -->
+ <item>HARDWARE=flounder,272.0</item>
</string-array>
</resources>
diff --git a/java/res/values-lo-rLA/bools.xml b/java/res/values-lo-rLA/bools.xml
new file mode 100644
index 000000000..130e52eab
--- /dev/null
+++ b/java/res/values-lo-rLA/bools.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/values-mk-rMK/bools.xml b/java/res/values-mk-rMK/bools.xml
new file mode 100644
index 000000000..130e52eab
--- /dev/null
+++ b/java/res/values-mk-rMK/bools.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/values-ml-rIN/bools.xml b/java/res/values-ml-rIN/bools.xml
new file mode 100644
index 000000000..130e52eab
--- /dev/null
+++ b/java/res/values-ml-rIN/bools.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/values-mn-rMN/bools.xml b/java/res/values-mn-rMN/bools.xml
new file mode 100644
index 000000000..130e52eab
--- /dev/null
+++ b/java/res/values-mn-rMN/bools.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/values-mr-rIN/bools.xml b/java/res/values-mr-rIN/bools.xml
new file mode 100644
index 000000000..130e52eab
--- /dev/null
+++ b/java/res/values-mr-rIN/bools.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/values-ne-rNP/bools.xml b/java/res/values-ne-rNP/bools.xml
new file mode 100644
index 000000000..130e52eab
--- /dev/null
+++ b/java/res/values-ne-rNP/bools.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/values-sw600dp-land/config.xml b/java/res/values-sw600dp-land/config.xml
index 6368eef41..d33af2e37 100644
--- a/java/res/values-sw600dp-land/config.xml
+++ b/java/res/values-sw600dp-land/config.xml
@@ -23,7 +23,7 @@
<!-- Preferable keyboard height in absolute scale: 45.0mm -->
<!-- This config_default_keyboard_height value should match with keyboard-heights.xml -->
<dimen name="config_default_keyboard_height">283.5dp</dimen>
- <fraction name="config_min_keyboard_height">45%p</fraction>
+ <fraction name="config_min_keyboard_height">40%p</fraction>
<dimen name="config_more_keys_keyboard_key_height">81.9dp</dimen>
@@ -32,12 +32,18 @@
<fraction name="config_key_vertical_gap_holo">4.5%p</fraction>
<fraction name="config_key_horizontal_gap_holo">0.9%p</fraction>
- <fraction name="config_key_letter_ratio">50%</fraction>
- <fraction name="config_key_large_letter_ratio">48%</fraction>
- <fraction name="config_key_label_ratio">32%</fraction>
- <fraction name="config_key_hint_letter_ratio">23%</fraction>
- <fraction name="config_key_hint_label_ratio">34%</fraction>
- <fraction name="config_key_shifted_letter_hint_ratio">29%</fraction>
+ <fraction name="config_key_letter_ratio_holo">50%</fraction>
+ <fraction name="config_key_letter_ratio_lxx">50%</fraction>
+ <fraction name="config_key_large_letter_ratio_holo">48%</fraction>
+ <fraction name="config_key_large_letter_ratio_lxx">60%</fraction>
+ <fraction name="config_key_label_ratio_holo">32%</fraction>
+ <fraction name="config_key_label_ratio_lxx">32%</fraction>
+ <fraction name="config_key_hint_letter_ratio_holo">23%</fraction>
+ <fraction name="config_key_hint_letter_ratio_lxx">23%</fraction>
+ <fraction name="config_key_hint_label_ratio_holo">34%</fraction>
+ <fraction name="config_key_hint_label_ratio_lxx">20%</fraction>
+ <fraction name="config_key_shifted_letter_hint_ratio_holo">29%</fraction>
+ <fraction name="config_key_shifted_letter_hint_ratio_lxx">29%</fraction>
<fraction name="config_language_on_spacebar_text_ratio">30.0%</fraction>
<dimen name="config_key_shifted_letter_hint_padding">4dp</dimen>
diff --git a/java/res/values-sw600dp/config.xml b/java/res/values-sw600dp/config.xml
index 9d16e2cb9..44e0d0632 100644
--- a/java/res/values-sw600dp/config.xml
+++ b/java/res/values-sw600dp/config.xml
@@ -40,17 +40,20 @@
<fraction name="config_key_horizontal_gap_holo">1.565%p</fraction>
<!-- config_more_keys_keyboard_key_height x -0.5 -->
<dimen name="config_more_keys_keyboard_vertical_correction_holo">-31.5dp</dimen>
- <dimen name="config_key_preview_offset_holo">8.0dp</dimen>
- <dimen name="config_key_preview_height">94.5dp</dimen>
<fraction name="config_key_preview_text_ratio">50%</fraction>
- <fraction name="config_key_letter_ratio">42%</fraction>
- <fraction name="config_key_large_letter_ratio">45%</fraction>
- <fraction name="config_key_label_ratio">25%</fraction>
- <fraction name="config_key_large_label_ratio">32%</fraction>
- <fraction name="config_key_hint_letter_ratio">23%</fraction>
- <fraction name="config_key_hint_label_ratio">28%</fraction>
- <fraction name="config_key_shifted_letter_hint_ratio">22%</fraction>
+ <fraction name="config_key_letter_ratio_holo">42%</fraction>
+ <fraction name="config_key_letter_ratio_lxx">50%</fraction>
+ <fraction name="config_key_large_letter_ratio_holo">45%</fraction>
+ <fraction name="config_key_large_letter_ratio_lxx">60%</fraction>
+ <fraction name="config_key_label_ratio_holo">25%</fraction>
+ <fraction name="config_key_label_ratio_lxx">32%</fraction>
+ <fraction name="config_key_hint_letter_ratio_holo">23%</fraction>
+ <fraction name="config_key_hint_letter_ratio_lxx">23%</fraction>
+ <fraction name="config_key_hint_label_ratio_holo">28%</fraction>
+ <fraction name="config_key_hint_label_ratio_lxx">20%</fraction>
+ <fraction name="config_key_shifted_letter_hint_ratio_holo">22%</fraction>
+ <fraction name="config_key_shifted_letter_hint_ratio_lxx">22%</fraction>
<fraction name="config_language_on_spacebar_text_ratio">28.0%</fraction>
<dimen name="config_key_hint_letter_padding">3dp</dimen>
<dimen name="config_key_shifted_letter_hint_padding">3dp</dimen>
diff --git a/java/res/values-sw768dp-land/config.xml b/java/res/values-sw768dp-land/config.xml
index a1659b45a..fdb95c6cc 100644
--- a/java/res/values-sw768dp-land/config.xml
+++ b/java/res/values-sw768dp-land/config.xml
@@ -23,23 +23,27 @@
<!-- Preferable keyboard height in absolute scale: 58.0mm -->
<!-- This config_default_keyboard_height value should match with keyboard-heights.xml -->
<dimen name="config_default_keyboard_height">365.4dp</dimen>
- <fraction name="config_min_keyboard_height">45%p</fraction>
+ <fraction name="config_min_keyboard_height">35%p</fraction>
<fraction name="config_keyboard_top_padding_holo">1.896%p</fraction>
<fraction name="config_keyboard_bottom_padding_holo">0.0%p</fraction>
<fraction name="config_key_vertical_gap_holo">3.690%p</fraction>
<fraction name="config_key_horizontal_gap_holo">1.030%p</fraction>
- <dimen name="config_key_preview_offset_holo">8.0dp</dimen>
<dimen name="config_more_keys_keyboard_key_height">81.9dp</dimen>
- <dimen name="config_key_preview_height">107.1dp</dimen>
- <fraction name="config_key_letter_ratio">43%</fraction>
- <fraction name="config_key_large_letter_ratio">42%</fraction>
- <fraction name="config_key_label_ratio">28%</fraction>
- <fraction name="config_key_hint_letter_ratio">23%</fraction>
- <fraction name="config_key_hint_label_ratio">28%</fraction>
- <fraction name="config_key_shifted_letter_hint_ratio">24%</fraction>
+ <fraction name="config_key_letter_ratio_holo">43%</fraction>
+ <fraction name="config_key_letter_ratio_lxx">50%</fraction>
+ <fraction name="config_key_large_letter_ratio_holo">42%</fraction>
+ <fraction name="config_key_large_letter_ratio_lxx">60%</fraction>
+ <fraction name="config_key_label_ratio_holo">28%</fraction>
+ <fraction name="config_key_label_ratio_lxx">32%</fraction>
+ <fraction name="config_key_hint_letter_ratio_holo">23%</fraction>
+ <fraction name="config_key_hint_letter_ratio_lxx">23%</fraction>
+ <fraction name="config_key_hint_label_ratio_holo">28%</fraction>
+ <fraction name="config_key_hint_label_ratio_lxx">20%</fraction>
+ <fraction name="config_key_shifted_letter_hint_ratio_holo">24%</fraction>
+ <fraction name="config_key_shifted_letter_hint_ratio_lxx">24%</fraction>
<fraction name="config_language_on_spacebar_text_ratio">24.00%</fraction>
<!-- For 5-row keyboard -->
diff --git a/java/res/values-sw768dp/config.xml b/java/res/values-sw768dp/config.xml
index 635061d24..13be6bedf 100644
--- a/java/res/values-sw768dp/config.xml
+++ b/java/res/values-sw768dp/config.xml
@@ -32,7 +32,6 @@
<fraction name="config_key_horizontal_gap_holo">1.066%p</fraction>
<!-- config_more_keys_keyboard_key_height x -0.5 -->
<dimen name="config_more_keys_keyboard_vertical_correction_holo">-31.5dp</dimen>
- <dimen name="config_key_preview_offset_holo">8.0dp</dimen>
<dimen name="config_more_keys_keyboard_key_height">63.0dp</dimen>
<dimen name="config_more_keys_keyboard_key_horizontal_padding">12dp</dimen>
@@ -40,15 +39,19 @@
<!-- config_more_keys_keyboard_key_height x 1.2 -->
<dimen name="config_more_keys_keyboard_slide_allowance">98.3dp</dimen>
- <dimen name="config_key_preview_height">94.5dp</dimen>
<fraction name="config_key_preview_text_ratio">50%</fraction>
- <fraction name="config_key_letter_ratio">40%</fraction>
- <fraction name="config_key_large_letter_ratio">42%</fraction>
- <fraction name="config_key_label_ratio">28%</fraction>
- <fraction name="config_key_large_label_ratio">28%</fraction>
- <fraction name="config_key_hint_letter_ratio">23%</fraction>
- <fraction name="config_key_hint_label_ratio">28%</fraction>
- <fraction name="config_key_shifted_letter_hint_ratio">26%</fraction>
+ <fraction name="config_key_letter_ratio_holo">40%</fraction>
+ <fraction name="config_key_letter_ratio_lxx">50%</fraction>
+ <fraction name="config_key_large_letter_ratio_holo">42%</fraction>
+ <fraction name="config_key_large_letter_ratio_lxx">60%</fraction>
+ <fraction name="config_key_label_ratio_holo">28%</fraction>
+ <fraction name="config_key_label_ratio_lxx">32%</fraction>
+ <fraction name="config_key_hint_letter_ratio_holo">23%</fraction>
+ <fraction name="config_key_hint_letter_ratio_lxx">23%</fraction>
+ <fraction name="config_key_hint_label_ratio_holo">28%</fraction>
+ <fraction name="config_key_hint_label_ratio_lxx">20%</fraction>
+ <fraction name="config_key_shifted_letter_hint_ratio_holo">26%</fraction>
+ <fraction name="config_key_shifted_letter_hint_ratio_lxx">26%</fraction>
<fraction name="config_language_on_spacebar_text_ratio">29.03%</fraction>
<dimen name="config_key_hint_letter_padding">3dp</dimen>
<dimen name="config_key_shifted_letter_hint_padding">3dp</dimen>
diff --git a/java/res/values-ta-rIN/bools.xml b/java/res/values-ta-rIN/bools.xml
new file mode 100644
index 000000000..130e52eab
--- /dev/null
+++ b/java/res/values-ta-rIN/bools.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/values-te-rIN/bools.xml b/java/res/values-te-rIN/bools.xml
new file mode 100644
index 000000000..130e52eab
--- /dev/null
+++ b/java/res/values-te-rIN/bools.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <!-- Whether this input method should be used as the default for a locale. Override it
+ for supported languages. -->
+ <bool name="im_is_default">true</bool>
+</resources>
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 5434106c5..f1253b40c 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -32,6 +32,8 @@
<attr name="moreKeysKeyboardStyle" format="reference" />
<!-- MoreKeysKeyboardView style -->
<attr name="moreKeysKeyboardViewStyle" format="reference" />
+ <!-- MoreKeysKeyboardView style for action key -->
+ <attr name="moreKeysKeyboardViewForActionStyle" format="reference" />
<!-- Suggestions strip style -->
<attr name="suggestionStripViewStyle" format="reference" />
<!-- Suggestion word style -->
@@ -52,7 +54,9 @@
<attr name="spacebarIconWidthRatio" format="float" />
<!-- Right padding of hint letter to the edge of the key.-->
<attr name="keyHintLetterPadding" format="dimension" />
- <!-- Bottom padding of popup hint letter "..." to the edge of the key.-->
+ <!-- Popup hint letter string-->
+ <attr name="keyPopupHintLetter" format="string" />
+ <!-- Bottom padding of popup hint letter to the edge of the key.-->
<attr name="keyPopupHintLetterPadding" format="dimension" />
<!-- Right padding of shifted letter hint to the edge of the key.-->
<attr name="keyShiftedLetterHintPadding" format="dimension" />
@@ -111,8 +115,14 @@
<!-- TODO: consolidate key preview linger timeout with the key preview animation parameters. -->
<!-- Delay after key releasing and key press feedback dismissing in millisecond -->
<attr name="keyPreviewLingerTimeout" format="integer" />
+ <!-- Key preview show up animator -->
+ <attr name="keyPreviewShowUpAnimator" format="reference" />
+ <!-- Key preview dismiss animator -->
+ <attr name="keyPreviewDismissAnimator" format="reference" />
<!-- Layout resource for more keys keyboard -->
<attr name="moreKeysKeyboardLayout" format="reference" />
+ <!-- Layout resource for more keys keyboard of action key -->
+ <attr name="moreKeysKeyboardForActionLayout" format="reference" />
<attr name="backgroundDimAlpha" format="integer" />
<!-- More keys keyboard will shown at touched point. -->
<attr name="showMoreKeysKeyboardAtTouchedPoint" format="boolean" />
@@ -167,6 +177,10 @@
<attr name="suppressKeyPreviewAfterBatchInputDuration" format="integer" />
</declare-styleable>
+ <declare-styleable name="MoreKeysKeyboardView">
+ <attr name="divider" format="reference" />
+ </declare-styleable>
+
<declare-styleable name="EmojiPalettesView">
<attr name="categoryIndicatorEnabled" format="boolean" />
<attr name="categoryIndicatorDrawable" format="reference" />
@@ -201,7 +215,13 @@
</declare-styleable>
<declare-styleable name="Keyboard">
- <attr name="themeId" format="integer" />
+ <attr name="themeId" format="enum">
+ <!-- This should be aligned with KeyboardTheme.THEME_ID_*. -->
+ <enum name="ICS" value="0" />
+ <enum name="KLP" value="2" />
+ <enum name="LXXLight" value="3" />
+ <enum name="LXXDark" value="4" />
+ </attr>
<!-- Touch position correction -->
<attr name="touchPositionCorrectionData" format="reference" />
<!-- Keyboard top, bottom, left, right edges paddings, in propotion of keyboard height. -->
@@ -240,7 +260,8 @@
<attr name="iconZwnjKey" format="reference" />
<attr name="iconZwjKey" format="reference" />
<attr name="iconImeKey" format="reference" />
- <attr name="iconEmojiKey" format="reference" />
+ <attr name="iconEmojiActionKey" format="reference" />
+ <attr name="iconEmojiNormalKey" format="reference" />
</declare-styleable>
<declare-styleable name="Keyboard_GridRows">
@@ -268,9 +289,10 @@
<enum name="empty" value="0" />
<enum name="normal" value="1" />
<enum name="functional" value="2" />
- <enum name="action" value="3" />
- <enum name="stickyOff" value="4" />
- <enum name="stickyOn" value="5" />
+ <enum name="stickyOff" value="3" />
+ <enum name="stickyOn" value="4" />
+ <enum name="action" value="5" />
+ <enum name="spacebar" value="6" />
</attr>
<!-- The key action flags. -->
<attr name="keyActionFlags" format="integer">
@@ -289,14 +311,15 @@
<!-- The key label flags. -->
<attr name="keyLabelFlags" format="integer">
<!-- This should be aligned with Key.LABEL_FLAGS__* -->
- <flag name="alignLeftOfCenter" value="0x08" />
+ <flag name="alignHintLabelToBottom" value="0x02" />
+ <flag name="alignIconToBottom" value="0x04" />
+ <flag name="alignLabelOffCenter" value="0x08" />
<flag name="fontNormal" value="0x10" />
<flag name="fontMonoSpace" value="0x20" />
<flag name="fontDefault" value="0x30" />
<flag name="followKeyLargeLetterRatio" value="0x40" />
<flag name="followKeyLetterRatio" value="0x80" />
<flag name="followKeyLabelRatio" value="0xC0" />
- <flag name="followKeyLargeLabelRatio" value="0x100" />
<flag name="followKeyHintLabelRatio" value="0x140" />
<flag name="hasPopupHint" value="0x200" />
<flag name="hasShiftedLetterHint" value="0x400" />
@@ -315,6 +338,8 @@
<!-- If true, use functionalTextColor instead of ketTextColor to drawing the label on
the key -->
<flag name="followFunctionalTextColor" value="0x80000" />
+ <!-- Keep aspect ratio of key background. -->
+ <flag name="keepBackgroundAspectRatio" value="0x100000" />
<!-- If true, disable keyHintLabel. -->
<flag name="disableKeyHintLabel" value="0x40000000" />
<!-- If true, disable additionalMoreKeys. -->
@@ -355,8 +380,6 @@
<attr name="keyLabelSize" format="dimension|fraction" />
<!-- Large size of the text for one letter keys, in the proportion of key height. -->
<attr name="keyLargeLetterRatio" format="fraction" />
- <!-- Large size of the text for keys with multiple letters, in the proportion of key height. -->
- <attr name="keyLargeLabelRatio" format="fraction" />
<!-- Size of the text for hint letter (= one character hint label), in the proportion of
key height. -->
<attr name="keyHintLetterRatio" format="fraction" />
@@ -364,6 +387,14 @@
<attr name="keyHintLabelRatio" format="fraction" />
<!-- Size of the text for shifted letter hint, in the proportion of key height. -->
<attr name="keyShiftedLetterHintRatio" format="fraction" />
+ <!-- The label's horizontal offset to the center of the key. Negative is to left and
+ positive is to right. The value is in proportion of the width of
+ TypefaceUtils.KEY_LABEL_REFERENCE_CHAR. -->
+ <attr name="keyLabelOffCenterRatio" format="fraction" />
+ <!-- The hint label's horizontal offset to the center of the key. Negative is to left and
+ positive is to right. The value is in proportion of the width of
+ TypefaceUtils.KEY_LABEL_REFERENCE_CHAR. -->
+ <attr name="keyHintLabelOffCenterRatio" format="fraction" />
<!-- Color to use for the label in a key. -->
<attr name="keyTextColor" format="color" />
<attr name="keyTextShadowColor" format="color" />
@@ -412,6 +443,13 @@
<enum name="emojiCategory5" value="15" />
<enum name="emojiCategory6" value="16" />
</attr>
+ <!-- This should be aligned with Keyboard.themeId and KeyboardTheme.THEME_ID_* -->
+ <attr name="keyboardTheme" format="enum|string">
+ <enum name="ICS" value="0" />
+ <enum name="KLP" value="2" />
+ <enum name="LXXLight" value="3" />
+ <enum name="LXXDark" value="4" />
+ </attr>
<!-- This should be aligned with KeyboardId.MODE_* -->
<attr name="mode" format="enum|string">
<enum name="text" value="0" />
@@ -481,13 +519,24 @@
<declare-styleable name="KeyboardLayoutSet_Feature">
<!-- This should be aligned with ScriptUtils.SCRIPT_* -->
<attr name="supportedScript" format="enum">
- <enum name="latin" value="0" />
- <enum name="cyrillic" value="1" />
- <enum name="greek" value="2" />
- <enum name="arabic" value="3" />
- <enum name="hebrew" value="4" />
- <enum name="armenian" value="5" />
- <enum name="georgian" value="6" />
+ <enum name="arabic" value="0" />
+ <enum name="armenian" value="1" />
+ <enum name="bengali" value="2" />
+ <enum name="cyrillic" value="3" />
+ <enum name="devanagari" value="4" />
+ <enum name="georgian" value="5" />
+ <enum name="greek" value="6" />
+ <enum name="hebrew" value="7" />
+ <enum name="kannada" value="8" />
+ <enum name="khmer" value="9" />
+ <enum name="lao" value="10" />
+ <enum name="latin" value="11" />
+ <enum name="malayalam" value="12" />
+ <enum name="myanmar" value="13" />
+ <enum name="sinhala" value="14" />
+ <enum name="tamil" value="15" />
+ <enum name="telugu" value="16" />
+ <enum name="thai" value="17" />
</attr>
</declare-styleable>
diff --git a/java/res/values/colors.xml b/java/res/values/colors.xml
index 783105dc0..5453d51c1 100644
--- a/java/res/values/colors.xml
+++ b/java/res/values/colors.xml
@@ -53,10 +53,8 @@
<color name="suggested_word_color_lxx_light">#B337474F</color>
<color name="gesture_trail_color_lxx_light">#4DB6AC</color>
<color name="sliding_key_input_preview_color_lxx_light">#B34DB6AC</color>
- <color name="keyboard_background_lxx_light">#ECEFF1</color>
<color name="key_background_lxx_light">#ECEFF1</color>
<color name="key_background_pressed_lxx_light">#2637474F</color>
- <color name="suggestions_strip_background_lxx_light">#E4E7E9</color>
<color name="suggested_word_background_selected_lxx_light">#2637474F</color>
<color name="gesture_floating_preview_color_lxx_light">#E6ECEFF1</color>
<color name="emoji_tab_page_indicator_background_lxx_light">#E4E7E9</color>
@@ -73,10 +71,8 @@
<color name="suggested_word_color_lxx_dark">#B3FFFFFF</color>
<color name="gesture_trail_color_lxx_dark">#80CBC4</color>
<color name="sliding_key_input_preview_color_lxx_dark">#B380CBC4</color>
- <color name="keyboard_background_lxx_dark">#263238</color>
<color name="key_background_lxx_dark">#263238</color>
<color name="key_background_pressed_lxx_dark">#19FFFFFF</color>
- <color name="suggestions_strip_background_lxx_dark">#21272B</color>
<color name="suggested_word_background_selected_lxx_dark">#19FFFFFF</color>
<color name="gesture_floating_preview_color_lxx_dark">#E621272B</color>
<color name="emoji_tab_page_indicator_background_lxx_dark">#21272B</color>
@@ -86,4 +82,6 @@
<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>
+ <!-- Accent color for the notification. We need to match this to the OS build -->
+ <color name="notification_accent_color">#FF607D8B</color>
</resources>
diff --git a/java/res/values/config-common.xml b/java/res/values/config-common.xml
index 063fbfb37..36fd30aef 100644
--- a/java/res/values/config-common.xml
+++ b/java/res/values/config-common.xml
@@ -24,7 +24,7 @@
at input history to suggest a hopefully helpful suggestions for the next word? -->
<bool name="config_default_next_word_prediction">true</bool>
- <integer name="config_delay_update_shift_state">100</integer>
+ <integer name="config_delay_in_milliseconds_to_update_shift_state">100</integer>
<integer name="config_double_space_period_timeout">1100</integer>
<integer name="config_key_repeat_start_timeout">400</integer>
@@ -107,8 +107,8 @@
<!-- Common suggestion strip configuration. -->
<integer name="config_suggestions_count_in_strip">3</integer>
<fraction name="config_center_suggestion_percentile">36%</fraction>
- <integer name="config_delay_update_suggestions">100</integer>
- <integer name="config_delay_update_old_suggestions">300</integer>
+ <integer name="config_delay_in_milliseconds_to_update_suggestions">100</integer>
+ <integer name="config_delay_in_milliseconds_to_update_old_suggestions">300</integer>
<!-- Common more suggestions configuraion. -->
<dimen name="config_more_suggestions_key_horizontal_padding">12dp</dimen>
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index d748c9179..40760f686 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -43,16 +43,22 @@
<!-- config_more_keys_keyboard_key_height x -0.5 -->
<dimen name="config_more_keys_keyboard_vertical_correction_holo">-26.4dp</dimen>
<dimen name="config_key_preview_offset_holo">8.0dp</dimen>
-
- <dimen name="config_key_preview_height">80dp</dimen>
+ <dimen name="config_key_preview_height_holo">80dp</dimen>
+ <dimen name="config_key_preview_offset_lxx">50.0dp</dimen>
+ <dimen name="config_key_preview_height_lxx">122dp</dimen>
<fraction name="config_key_preview_text_ratio">82%</fraction>
- <fraction name="config_key_letter_ratio">55%</fraction>
- <fraction name="config_key_large_letter_ratio">65%</fraction>
- <fraction name="config_key_label_ratio">34%</fraction>
- <fraction name="config_key_large_label_ratio">40%</fraction>
- <fraction name="config_key_hint_letter_ratio">25%</fraction>
- <fraction name="config_key_hint_label_ratio">44%</fraction>
- <fraction name="config_key_shifted_letter_hint_ratio">35%</fraction>
+ <fraction name="config_key_letter_ratio_holo">55%</fraction>
+ <fraction name="config_key_letter_ratio_lxx">55%</fraction>
+ <fraction name="config_key_large_letter_ratio_holo">65%</fraction>
+ <fraction name="config_key_large_letter_ratio_lxx">90%</fraction>
+ <fraction name="config_key_label_ratio_holo">34%</fraction>
+ <fraction name="config_key_label_ratio_lxx">34%</fraction>
+ <fraction name="config_key_hint_letter_ratio_holo">25%</fraction>
+ <fraction name="config_key_hint_letter_ratio_lxx">25%</fraction>
+ <fraction name="config_key_hint_label_ratio_holo">44%</fraction>
+ <fraction name="config_key_hint_label_ratio_lxx">30%</fraction>
+ <fraction name="config_key_shifted_letter_hint_ratio_holo">35%</fraction>
+ <fraction name="config_key_shifted_letter_hint_ratio_lxx">35%</fraction>
<fraction name="config_language_on_spacebar_text_ratio">33.735%</fraction>
<dimen name="config_key_hint_letter_padding">1dp</dimen>
<dimen name="config_key_shifted_letter_hint_padding">2dp</dimen>
diff --git a/java/res/values/donottranslate-debug-settings.xml b/java/res/values/donottranslate-debug-settings.xml
new file mode 100644
index 000000000..35e6efa77
--- /dev/null
+++ b/java/res/values/donottranslate-debug-settings.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Title for Android keyboard debug settings activity / dialog -->
+ <string name="english_ime_debug_settings">Android Keyboard Debug settings</string>
+ <string name="prefs_debug_mode">Debug Mode</string>
+ <string name="prefs_force_non_distinct_multitouch">Force non-distinct multitouch</string>
+ <string name="prefs_force_physical_keyboard_special_key">Force physical keyboard special key</string>
+ <string name="prefs_show_ui_to_accept_typed_word">Show UI to accept typed word</string>
+ <!-- Option to enable sliding key input indicator. The user can see a rubber band-like effect during sliding key input. [CHAR LIMIT=30]-->
+ <string name="sliding_key_input_preview">Show slide indicator</string>
+ <!-- Option summary to enable sliding key input indicator. The user can see a rubber band-like effect during sliding key input. [CHAR LIMIT=66]-->
+ <string name="sliding_key_input_preview_summary">Display visual cue while sliding from Shift or Symbol keys</string>
+ <!-- Title of the settings for key long press delay [CHAR LIMIT=35] -->
+ <string name="prefs_key_longpress_timeout_settings">Key long press delay</string>
+ <!-- Title of the settings for customize key popup animation parameters [CHAR LIMIT=35] -->
+ <string name="prefs_customize_key_preview_animation">Customize key preview animation</string>
+ <!-- Title of the settings for key popup show up animation duration (in milliseconds) [CHAR LIMIT=35] -->
+ <string name="prefs_key_popup_show_up_duration_settings">Key popup show up duration</string>
+ <!-- Title of the settings for key popup dismiss animation duration (in milliseconds) [CHAR LIMIT=35] -->
+ <string name="prefs_key_popup_dismiss_duration_settings">Key popup dismiss duration</string>
+ <!-- Title of the settings for key popup show up animation start X-scale (in percentile) [CHAR LIMIT=35] -->
+ <string name="prefs_key_popup_show_up_start_x_scale_settings">Key popup show up start X scale</string>
+ <!-- Title of the settings for key popup show up animation start Y-scale (in percentile) [CHAR LIMIT=35] -->
+ <string name="prefs_key_popup_show_up_start_y_scale_settings">Key popup show up start Y scale</string>
+ <!-- Title of the settings for key popup dismiss animation end X-scale (in percentile) [CHAR LIMIT=35] -->
+ <string name="prefs_key_popup_dismiss_end_x_scale_settings">Key popup dismiss end X scale</string>
+ <!-- Title of the settings for key popup dismiss animation end Y-scale (in percentile) [CHAR LIMIT=35] -->
+ <string name="prefs_key_popup_dismiss_end_y_scale_settings">Key popup dismiss end Y scale</string>
+ <!-- Title of the settings for reading an external dictionary file -->
+ <string name="prefs_read_external_dictionary">Read external dictionary file</string>
+ <!-- Message to show when there are no files to install as an external dictionary [CHAR LIMIT=100] -->
+ <string name="read_external_dictionary_no_files_message">No dictionary files in the Downloads folder</string>
+ <!-- Title of the dialog that selects a file to install as an external dictionary [CHAR LIMIT=50] -->
+ <string name="read_external_dictionary_multiple_files_title">Select a dictionary file to install</string>
+ <!-- Title of the confirmation dialog to install a file as an external dictionary [CHAR LIMIT=50] -->
+ <string name="read_external_dictionary_confirm_install_message">Really install this file for <xliff:g id="LANGUAGE_NAME" example="English">%s</xliff:g>?</string>
+ <!-- Title for an error dialog that contains the details of the error in the body [CHAR LIMIT=80] -->
+ <string name="read_external_dictionary_error">There was an error</string>
+ <!-- Title of the settings group for dumpping dictionary files that have been created on the device [CHAR LIMIT=35] -->
+ <string name="prefs_dump_dynamic_dicts">Dump dictionary</string>
+</resources>
diff --git a/java/res/values/donottranslate-text-decorator.xml b/java/res/values/donottranslate-text-decorator.xml
new file mode 100644
index 000000000..269364573
--- /dev/null
+++ b/java/res/values/donottranslate-text-decorator.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources>
+ <!-- The extra margin in dp around the hit area of the commit/add-to-dictionary indicator -->
+ <integer name="text_decorator_hit_area_margin_in_dp">
+ 4
+ </integer>
+
+ <!-- Background color to be used to highlight the target text when the add-to-dictionary
+ indicator is visible. -->
+ <color name="text_decorator_add_to_dictionary_indicator_text_highlight_color">
+ #D1E7B7
+ </color>
+
+ <!-- Foreground color of the commit indicator. -->
+ <color name="text_decorator_add_to_dictionary_indicator_background_color">
+ #4EB848
+ </color>
+
+ <!-- Foreground color of the add-to-dictionary indicator. -->
+ <color name="text_decorator_add_to_dictionary_indicator_foreground_color">
+ #FFFFFF
+ </color>
+
+ <!-- Viewport size of "text_decorator_add_to_dictionary_indicator_path". -->
+ <integer name="text_decorator_add_to_dictionary_indicator_path_size">
+ 480
+ </integer>
+
+ <!-- Coordinates of the closed path to be used to render the add-to-dictionary indicator.
+ The format is: X[0], Y[0], X[1], Y[1], ..., X[N-1], Y[N-1] -->
+ <integer-array name="text_decorator_add_to_dictionary_indicator_path">
+ <item>380</item>
+ <item>260</item>
+ <item>260</item>
+ <item>260</item>
+ <item>260</item>
+ <item>380</item>
+ <item>220</item>
+ <item>380</item>
+ <item>220</item>
+ <item>260</item>
+ <item>100</item>
+ <item>260</item>
+ <item>100</item>
+ <item>220</item>
+ <item>220</item>
+ <item>220</item>
+ <item>220</item>
+ <item>100</item>
+ <item>260</item>
+ <item>100</item>
+ <item>260</item>
+ <item>220</item>
+ <item>380</item>
+ <item>220</item>
+ </integer-array>
+</resources>
diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml
index e3f0aeade..c54b995f8 100644
--- a/java/res/values/donottranslate.xml
+++ b/java/res/values/donottranslate.xml
@@ -22,11 +22,6 @@
See {@link SettingsValues#needsToShowVoiceInputKey(SharedPreferences,Resources)} -->
<string name="voice_mode_main">0</string>
- <!-- Title for Latin keyboard debug settings activity / dialog -->
- <string name="english_ime_debug_settings">Android keyboard Debug settings</string>
- <string name="prefs_debug_mode">Debug Mode</string>
- <string name="prefs_force_non_distinct_multitouch">Force non-distinct multitouch</string>
-
<!-- Subtype locale display name exceptions.
For each exception, there should be related string resources for display name that may have
explicit keyboard layout. The string resource name must be "subtype_<locale>" or
diff --git a/java/res/values/keyboard-icons-holo.xml b/java/res/values/keyboard-icons-holo.xml
index d95ff8201..f5484bf4e 100644
--- a/java/res/values/keyboard-icons-holo.xml
+++ b/java/res/values/keyboard-icons-holo.xml
@@ -35,6 +35,7 @@
<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>
+ <item name="iconEmojiActionKey">@drawable/sym_keyboard_smiley_holo_dark</item>
+ <item name="iconEmojiNormalKey">@drawable/sym_keyboard_smiley_holo_dark</item>
</style>
</resources>
diff --git a/java/res/values/keyboard-icons-lxx-dark.xml b/java/res/values/keyboard-icons-lxx-dark.xml
index 15d267cb2..2e2fd0abb 100644
--- a/java/res/values/keyboard-icons-lxx-dark.xml
+++ b/java/res/values/keyboard-icons-lxx-dark.xml
@@ -24,7 +24,7 @@
<item name="iconShiftKey">@drawable/sym_keyboard_shift_lxx_dark</item>
<item name="iconDeleteKey">@drawable/sym_keyboard_delete_lxx_dark</item>
<item name="iconSettingsKey">@drawable/sym_keyboard_settings_lxx_dark</item>
- <item name="iconSpaceKey">@drawable/sym_keyboard_spacebar_lxx_dark</item>
+ <item name="iconSpaceKey">@null</item>
<item name="iconEnterKey">@drawable/sym_keyboard_return_lxx_dark</item>
<item name="iconGoKey">@drawable/sym_keyboard_go_lxx_dark</item>
<item name="iconSearchKey">@drawable/sym_keyboard_search_lxx_dark</item>
@@ -34,13 +34,13 @@
<item name="iconPreviousKey">@drawable/sym_keyboard_previous_lxx_dark</item>
<item name="iconTabKey">@drawable/sym_keyboard_tab_lxx_dark</item>
<item name="iconShortcutKey">@drawable/sym_keyboard_voice_lxx_dark</item>
- <!-- TODO: Update this icon for LXX_Dark theme. -->
- <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space_holo_dark</item>
+ <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space_lxx_dark</item>
<item name="iconShiftKeyShifted">@drawable/sym_keyboard_shift_locked_lxx_dark</item>
<item name="iconShortcutKeyDisabled">@drawable/sym_keyboard_voice_off_lxx_dark</item>
<item name="iconLanguageSwitchKey">@drawable/sym_keyboard_language_switch_lxx_dark</item>
<item name="iconZwnjKey">@drawable/sym_keyboard_zwnj_lxx_dark</item>
<item name="iconZwjKey">@drawable/sym_keyboard_zwj_lxx_dark</item>
- <item name="iconEmojiKey">@drawable/sym_keyboard_smiley_lxx_dark</item>
+ <item name="iconEmojiActionKey">@drawable/sym_keyboard_smiley_lxx_dark</item>
+ <item name="iconEmojiNormalKey">@drawable/sym_keyboard_smiley_lxx_dark</item>
</style>
</resources>
diff --git a/java/res/values/keyboard-icons-lxx-light.xml b/java/res/values/keyboard-icons-lxx-light.xml
index 60853ca31..099a706fe 100644
--- a/java/res/values/keyboard-icons-lxx-light.xml
+++ b/java/res/values/keyboard-icons-lxx-light.xml
@@ -24,7 +24,7 @@
<item name="iconShiftKey">@drawable/sym_keyboard_shift_lxx_light</item>
<item name="iconDeleteKey">@drawable/sym_keyboard_delete_lxx_light</item>
<item name="iconSettingsKey">@drawable/sym_keyboard_settings_lxx_light</item>
- <item name="iconSpaceKey">@drawable/sym_keyboard_spacebar_lxx_light</item>
+ <item name="iconSpaceKey">@null</item>
<item name="iconEnterKey">@drawable/sym_keyboard_return_lxx_light</item>
<item name="iconGoKey">@drawable/sym_keyboard_go_lxx_light</item>
<item name="iconSearchKey">@drawable/sym_keyboard_search_lxx_light</item>
@@ -34,13 +34,15 @@
<item name="iconPreviousKey">@drawable/sym_keyboard_previous_lxx_light</item>
<item name="iconTabKey">@drawable/sym_keyboard_tab_lxx_light</item>
<item name="iconShortcutKey">@drawable/sym_keyboard_voice_lxx_light</item>
- <!-- TODO: Update this icon for LXX_Light theme. -->
- <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space_holo_dark</item>
+ <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space_lxx_light</item>
<item name="iconShiftKeyShifted">@drawable/sym_keyboard_shift_locked_lxx_light</item>
<item name="iconShortcutKeyDisabled">@drawable/sym_keyboard_voice_off_lxx_light</item>
<item name="iconLanguageSwitchKey">@drawable/sym_keyboard_language_switch_lxx_light</item>
<item name="iconZwnjKey">@drawable/sym_keyboard_zwnj_lxx_light</item>
<item name="iconZwjKey">@drawable/sym_keyboard_zwj_lxx_light</item>
- <item name="iconEmojiKey">@drawable/sym_keyboard_smiley_lxx_light</item>
+ <!-- Use white emoji icon (for lxx_dark) because an action key has green/dark color background. -->
+ <item name="iconEmojiActionKey">@drawable/sym_keyboard_smiley_lxx_dark</item>
+ <!-- Use dark green emoji icon (for lxx_light) because a normal key has white color background. -->
+ <item name="iconEmojiNormalKey">@drawable/sym_keyboard_smiley_lxx_light</item>
</style>
</resources>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index b6601c8c2..2f8b3800d 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -36,18 +36,20 @@
<!-- Option to control whether or not to show a popup with a larger font on each key press. -->
<string name="popup_on_keypress">Popup on keypress</string>
- <!-- Settings screen title for input preferences [CHAR LIMIT=33]-->
- <string name="settings_screen_input">Input preferences</string>
- <!-- Settings screen title for appearance preferences [CHAR LIMIT=33] -->
- <string name="settings_screen_appearances">Appearance</string>
- <!-- Settings screen title for multi lingual options [CHAR_LIMIT=33] -->
- <string name="settings_screen_multi_lingual">Multi lingual options</string>
+ <!-- Settings screen title for preferences [CHAR LIMIT=33]-->
+ <string name="settings_screen_preferences">Preferences</string>
+ <!-- Settings screen title for appearance & layouts preferences [CHAR LIMIT=33] -->
+ <string name="settings_screen_appearance">Appearance &amp; layouts</string>
+ <!-- Settings screen title for multilingual options [CHAR_LIMIT=33] -->
+ <string name="settings_screen_multilingual">Multilingual options</string>
<!-- Settings screen title for gesture typing preferences [CHAR_LIMIT=33] -->
- <string name="settings_screen_gesture">Gesture typing preferences</string>
+ <string name="settings_screen_gesture">Gesture Typing</string>
<!-- Settings screen title for text correction options [CHAR_LIMIT=33] -->
<string name="settings_screen_correction">Text correction</string>
<!-- Settings screen title for advanced settings [CHAR LIMIT=33] -->
<string name="settings_screen_advanced">Advanced</string>
+ <!-- Settings screen title for keyboard theme settings [CHAR LIMIT=33] -->
+ <string name="settings_screen_theme">Theme</string>
<!-- Option name for including other IMEs in the language switch list [CHAR LIMIT=30] -->
<string name="include_other_imes_in_language_switch_list">Switch to other input methods</string>
@@ -58,11 +60,6 @@
<!-- Option summary for showing language switch key [CHAR LIMIT=65] -->
<string name="show_language_switch_key_summary">Show when multiple input languages are enabled</string>
- <!-- Option to enable sliding key input indicator. The user can see a rubber band-like effect during sliding key input. [CHAR LIMIT=30]-->
- <string name="sliding_key_input_preview">Show slide indicator</string>
- <!-- Option summary to enable sliding key input indicator. The user can see a rubber band-like effect during sliding key input. [CHAR LIMIT=66]-->
- <string name="sliding_key_input_preview_summary">Display visual cue while sliding from Shift or Symbol keys</string>
-
<!-- Option for the dismiss delay of the key popup [CHAR LIMIT=25] -->
<string name="key_preview_popup_dismiss_delay">Key popup dismiss delay</string>
<!-- Description for delay for dismissing a popup on keypress: no delay [CHAR LIMIT=15] -->
@@ -157,16 +154,19 @@
<string name="configure_input_method">Configure input methods</string>
<!-- Title for input language selection screen -->
- <string name="language_selection_title">Input languages</string>
+ <string name="language_selection_title">Languages</string>
- <!-- Title of a preference to send feedback. [CHAR LIMIT=30]-->
- <string name="send_feedback">Send feedback</string>
+ <!-- Title for the 'Help & feedback' settings fragment which shows a help page and has a button
+ for submitting feedback. [CHAR LIMIT=35] -->
+ <string name="help_and_feedback">Help &amp; feedback</string>
<!-- Preference for input language selection -->
- <string name="select_language">Input languages</string>
+ <string name="select_language">Languages</string>
<!-- Add to dictionary hint -->
<string name="hint_add_to_dictionary">Touch again to save</string>
+ <!-- Add to dictionary hint -->
+ <string name="hint_add_to_dictionary_without_word">Touch here to save</string>
<!-- Inform the user that a particular language has an available dictionary -->
<string name="has_dictionary">Dictionary available</string>
@@ -322,32 +322,10 @@ mobile devices. [CHAR LIMIT=25] -->
<!-- Toast text to describe the same input style already exists [CHAR LIMIT=64]-->
<string name="custom_input_style_already_exists">"The same input style already exists: <xliff:g id="INPUT_STYLE_NAME" example="English (Dvorak)">%s</xliff:g>"</string>
- <!-- Title of the settings for key long press delay [CHAR LIMIT=35] -->
- <string name="prefs_key_longpress_timeout_settings">Key long press delay</string>
<!-- Title of the settings for keypress vibration duration [CHAR LIMIT=35] -->
<string name="prefs_keypress_vibration_duration_settings">Keypress vibration duration</string>
<!-- Title of the settings for keypress sound volume [CHAR LIMIT=35] -->
<string name="prefs_keypress_sound_volume_settings">Keypress sound volume</string>
- <!-- Title of the settings for key popup show up animation duration (in milliseconds) [CHAR LIMIT=35] -->
- <string name="prefs_key_popup_show_up_duration_settings" translatable="false">Key popup show up duration</string>
- <!-- Title of the settings for key popup dismiss animation duration (in milliseconds) [CHAR LIMIT=35] -->
- <string name="prefs_key_popup_dismiss_duration_settings" translatable="false">Key popup dismiss duration</string>
- <!-- Title of the settings for key popup show up animation start scale (in percentile) [CHAR LIMIT=35] -->
- <string name="prefs_key_popup_show_up_start_scale_settings" translatable="false">Key popup show up start scale</string>
- <!-- Title of the settings for key popup dismiss animation end scale (in percentile) [CHAR LIMIT=35] -->
- <string name="prefs_key_popup_dismiss_end_scale_settings" translatable="false">Key popup dismiss end scale</string>
- <!-- Title of the settings for reading an external dictionary file -->
- <string name="prefs_read_external_dictionary">Read external dictionary file</string>
- <!-- Message to show when there are no files to install as an external dictionary [CHAR LIMIT=100] -->
- <string name="read_external_dictionary_no_files_message">No dictionary files in the Downloads folder</string>
- <!-- Title of the dialog that selects a file to install as an external dictionary [CHAR LIMIT=50] -->
- <string name="read_external_dictionary_multiple_files_title">Select a dictionary file to install</string>
- <!-- Title of the confirmation dialog to install a file as an external dictionary [CHAR LIMIT=50] -->
- <string name="read_external_dictionary_confirm_install_message">Really install this file for <xliff:g id="LANGUAGE_NAME" example="English">%s</xliff:g>?</string>
- <!-- Title for an error dialog that contains the details of the error in the body [CHAR LIMIT=80] -->
- <string name="error">There was an error</string>
- <!-- Title of the settings group for dumpping dictionary files that have been created on the device [CHAR LIMIT=35] -->
- <string name="prefs_dump_dynamic_dicts" translatable="false">Dump dictionary</string>
<!-- Title of the button to revert to the default value of the device in the settings dialog [CHAR LIMIT=15] -->
<string name="button_default">Default</string>
diff --git a/java/res/values/themes-common.xml b/java/res/values/themes-common.xml
index b139110ca..110f6b792 100644
--- a/java/res/values/themes-common.xml
+++ b/java/res/values/themes-common.xml
@@ -22,23 +22,24 @@
<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="horizontalGap">@fraction/config_key_horizontal_gap_holo</item>
+ <item name="verticalGap">@fraction/config_key_vertical_gap_holo</item>
+ <item name="touchPositionCorrectionData">@array/touch_position_correction_data_holo</item>
+ <item name="keyboardTopPadding">@fraction/config_keyboard_top_padding_holo</item>
+ <item name="keyboardBottomPadding">@fraction/config_keyboard_bottom_padding_holo</item>
<item name="keyboardLeftPadding">@fraction/config_keyboard_left_padding</item>
<item name="keyboardRightPadding">@fraction/config_keyboard_right_padding</item>
+ <item name="moreKeysTemplate">@xml/kbd_more_keys_keyboard_template</item>
<item name="maxMoreKeysColumn">@integer/config_max_more_keys_column</item>
</style>
<style name="KeyboardView">
+ <!-- This keyBackground is needed to run unit tests based on {@link InputTestBase}. -->
+ <!-- TODO: Apply default {@link KeyboardTheme} to {@link InputTestBase} and remove this. -->
<item name="keyBackground">@drawable/btn_keyboard_key_klp</item>
- <item name="keyLetterSize">@fraction/config_key_letter_ratio</item>
- <item name="keyLargeLetterRatio">@fraction/config_key_large_letter_ratio</item>
- <item name="keyLabelSize">@fraction/config_key_label_ratio</item>
- <item name="keyLargeLabelRatio">@fraction/config_key_large_label_ratio</item>
- <item name="keyHintLetterRatio">@fraction/config_key_hint_letter_ratio</item>
- <item name="keyHintLabelRatio">@fraction/config_key_hint_label_ratio</item>
- <item name="keyShiftedLetterHintRatio">@fraction/config_key_shifted_letter_hint_ratio</item>
<item name="keyTypeface">normal</item>
+ <!-- A negative value to disable key text shadow layer. -->
+ <item name="keyTextShadowRadius">-1.0</item>
<item name="keyHintLetterPadding">@dimen/config_key_hint_letter_padding</item>
<item name="keyPopupHintLetterPadding">@dimen/config_key_popup_hint_letter_padding</item>
<item name="keyShiftedLetterHintPadding">@dimen/config_key_shifted_letter_hint_padding</item>
@@ -74,7 +75,6 @@
<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/config_key_preview_height</item>
<!-- TODO: consolidate key preview linger timeout with the key preview animation parameters. -->
<item name="keyPreviewLingerTimeout">@integer/config_key_preview_linger_timeout</item>
<item name="moreKeysKeyboardLayout">@layout/more_keys_keyboard</item>
@@ -108,10 +108,7 @@
for instance delete button, need themed {@link KeyboardView} attributes. -->
<style name="EmojiPalettesView" />
<style name="MoreKeysKeyboard" />
- <style
- name="MoreKeysKeyboardView"
- parent="MainKeyboardView" />
- <style name="MoreKeysKeyboardContainer" />
+ <style name="MoreKeysKeyboardView" />
<style name="SuggestionStripView" />
<style name="SuggestionWord">
<item name="android:minWidth">@dimen/config_suggestion_min_width</item>
@@ -130,8 +127,4 @@
<item name="android:singleLine">true</item>
<item name="android:ellipsize">none</item>
</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-holo.xml b/java/res/values/themes-holo.xml
new file mode 100644
index 000000000..9f1bd2f78
--- /dev/null
+++ b/java/res/values/themes-holo.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Holo KeyboardView theme (ICS and KLP) -->
+ <style
+ name="KeyboardView.Holo"
+ parent="KeyboardView"
+ >
+ <item name="keyTypeface">bold</item>
+ <item name="keyLetterSize">@fraction/config_key_letter_ratio_holo</item>
+ <item name="keyLabelSize">@fraction/config_key_label_ratio_holo</item>
+ <item name="keyHintLetterRatio">@fraction/config_key_hint_letter_ratio_holo</item>
+ <item name="keyShiftedLetterHintRatio">@fraction/config_key_shifted_letter_hint_ratio_holo</item>
+ <item name="keyLargeLetterRatio">@fraction/config_key_large_letter_ratio_holo</item>
+ <item name="keyLabelOffCenterRatio">-175%</item>
+ <item name="keyHintLabelRatio">@fraction/config_key_hint_label_ratio_holo</item>
+ <item name="keyHintLabelOffCenterRatio">200%</item>
+ <!-- U+2026: "…" HORIZONTAL ELLIPSIS -->
+ <item name="keyPopupHintLetter">&#x2026;</item>
+ </style>
+</resources>
diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml
index 6118ce177..bfbac0a94 100644
--- a/java/res/values/themes-ics.xml
+++ b/java/res/values/themes-ics.xml
@@ -25,7 +25,9 @@
<item name="mainKeyboardViewStyle">@style/MainKeyboardView.ICS</item>
<item name="emojiPalettesViewStyle">@style/EmojiPalettesView.ICS</item>
<item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.ICS</item>
+ <!-- Note: ICS theme uses the same style for both general more keys and action more keys. -->
<item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.ICS</item>
+ <item name="moreKeysKeyboardViewForActionStyle">@style/MoreKeysKeyboardView.ICS</item>
<item name="suggestionStripViewStyle">@style/SuggestionStripView.ICS</item>
<item name="suggestionWordStyle">@style/SuggestionWord.ICS</item>
</style>
@@ -33,23 +35,17 @@
name="Keyboard.ICS"
parent="Keyboard"
>
- <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] -->
- <item name="themeId">2</item>
- <item name="keyboardTopPadding">@fraction/config_keyboard_top_padding_holo</item>
- <item name="keyboardBottomPadding">@fraction/config_keyboard_bottom_padding_holo</item>
- <item name="horizontalGap">@fraction/config_key_horizontal_gap_holo</item>
- <item name="verticalGap">@fraction/config_key_vertical_gap_holo</item>
- <item name="touchPositionCorrectionData">@array/touch_position_correction_data_holo</item>
+ <!-- This should be aligned with KeyboardTheme.THEME_ID_* -->
+ <item name="themeId">ICS</item>
</style>
<style
name="KeyboardView.ICS"
- parent="KeyboardView"
+ parent="KeyboardView.Holo"
>
<item name="android:background">@drawable/keyboard_background_holo</item>
<item name="keyBackground">@drawable/btn_keyboard_key_ics</item>
<item name="functionalKeyBackground">@drawable/btn_keyboard_key_functional_ics</item>
<item name="spacebarBackground">@drawable/btn_keyboard_spacebar_ics</item>
- <item name="keyTypeface">bold</item>
<item name="keyTextColor">@color/key_text_color_holo</item>
<item name="keyTextInactivatedColor">@color/key_text_inactivated_color_holo</item>
<item name="functionalTextColor">@color/key_text_color_holo</item>
@@ -58,15 +54,16 @@
<item name="keyShiftedLetterHintInactivatedColor">@color/key_shifted_letter_hint_inactivated_color_holo</item>
<item name="keyShiftedLetterHintActivatedColor">@color/key_shifted_letter_hint_activated_color_holo</item>
<item name="keyPreviewTextColor">@color/key_text_color_holo</item>
- <!-- A negative value to disable key text shadow layer. -->
- <item name="keyTextShadowRadius">-1.0</item>
</style>
<style
name="MainKeyboardView.ICS"
parent="KeyboardView.ICS"
>
<item name="keyPreviewBackground">@drawable/keyboard_key_feedback_ics</item>
+ <item name="keyPreviewHeight">@dimen/config_key_preview_height_holo</item>
<item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item>
+ <item name="keyPreviewShowUpAnimator">@anim/key_preview_show_up_holo</item>
+ <item name="keyPreviewDismissAnimator">@anim/key_preview_dismiss_holo</item>
<item name="gestureFloatingPreviewTextColor">@color/highlight_color_ics</item>
<item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_holo</item>
<item name="gestureTrailColor">@color/highlight_color_ics</item>
@@ -109,6 +106,7 @@
>
<item name="android:background">@drawable/keyboard_popup_panel_background_ics</item>
<item name="keyBackground">@drawable/btn_keyboard_key_popup_ics</item>
+ <item name="divider">@drawable/more_keys_divider</item>
<item name="keyTypeface">normal</item>
<item name="verticalCorrection">@dimen/config_more_keys_keyboard_vertical_correction_holo</item>
</style>
diff --git a/java/res/values/themes-klp.xml b/java/res/values/themes-klp.xml
index 193386062..36b1fc117 100644
--- a/java/res/values/themes-klp.xml
+++ b/java/res/values/themes-klp.xml
@@ -25,7 +25,9 @@
<item name="mainKeyboardViewStyle">@style/MainKeyboardView.KLP</item>
<item name="emojiPalettesViewStyle">@style/EmojiPalettesView.KLP</item>
<item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.KLP</item>
+ <!-- Note: KLP theme uses the same style for both general more keys and action more keys. -->
<item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.KLP</item>
+ <item name="moreKeysKeyboardViewForActionStyle">@style/MoreKeysKeyboardView.KLP</item>
<item name="suggestionStripViewStyle">@style/SuggestionStripView.KLP</item>
<item name="suggestionWordStyle">@style/SuggestionWord.KLP</item>
</style>
@@ -33,23 +35,17 @@
name="Keyboard.KLP"
parent="Keyboard"
>
- <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] -->
- <item name="themeId">0</item>
- <item name="keyboardTopPadding">@fraction/config_keyboard_top_padding_holo</item>
- <item name="keyboardBottomPadding">@fraction/config_keyboard_bottom_padding_holo</item>
- <item name="horizontalGap">@fraction/config_key_horizontal_gap_holo</item>
- <item name="verticalGap">@fraction/config_key_vertical_gap_holo</item>
- <item name="touchPositionCorrectionData">@array/touch_position_correction_data_holo</item>
+ <!-- This should be aligned with KeyboardTheme.THEME_ID_* -->
+ <item name="themeId">KLP</item>
</style>
<style
name="KeyboardView.KLP"
- parent="KeyboardView"
+ parent="KeyboardView.Holo"
>
<item name="android:background">@drawable/keyboard_background_holo</item>
<item name="keyBackground">@drawable/btn_keyboard_key_klp</item>
<item name="functionalKeyBackground">@drawable/btn_keyboard_key_functional_klp</item>
<item name="spacebarBackground">@drawable/btn_keyboard_spacebar_klp</item>
- <item name="keyTypeface">bold</item>
<item name="keyTextColor">@color/key_text_color_holo</item>
<item name="keyTextInactivatedColor">@color/key_text_inactivated_color_holo</item>
<item name="functionalTextColor">@color/key_text_color_holo</item>
@@ -58,15 +54,16 @@
<item name="keyShiftedLetterHintInactivatedColor">@color/key_shifted_letter_hint_inactivated_color_holo</item>
<item name="keyShiftedLetterHintActivatedColor">@color/key_shifted_letter_hint_activated_color_holo</item>
<item name="keyPreviewTextColor">@color/key_text_color_holo</item>
- <!-- A negative value to disable key text shadow layer. -->
- <item name="keyTextShadowRadius">-1.0</item>
</style>
<style
name="MainKeyboardView.KLP"
parent="KeyboardView.KLP"
>
<item name="keyPreviewBackground">@drawable/keyboard_key_feedback_klp</item>
+ <item name="keyPreviewHeight">@dimen/config_key_preview_height_holo</item>
<item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item>
+ <item name="keyPreviewShowUpAnimator">@anim/key_preview_show_up_holo</item>
+ <item name="keyPreviewDismissAnimator">@anim/key_preview_dismiss_holo</item>
<item name="gestureFloatingPreviewTextColor">@color/highlight_color_klp</item>
<item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_holo</item>
<item name="gestureTrailColor">@color/highlight_color_klp</item>
@@ -109,6 +106,7 @@
>
<item name="android:background">@drawable/keyboard_popup_panel_background_klp</item>
<item name="keyBackground">@drawable/btn_keyboard_key_popup_klp</item>
+ <item name="divider">@drawable/more_keys_divider</item>
<item name="keyTypeface">normal</item>
<item name="verticalCorrection">@dimen/config_more_keys_keyboard_vertical_correction_holo</item>
</style>
diff --git a/java/res/values/themes-lxx-dark.xml b/java/res/values/themes-lxx-dark.xml
index f5630102d..67f94f329 100644
--- a/java/res/values/themes-lxx-dark.xml
+++ b/java/res/values/themes-lxx-dark.xml
@@ -26,6 +26,7 @@
<item name="emojiPalettesViewStyle">@style/EmojiPalettesView.LXX_Dark</item>
<item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.LXX_Dark</item>
<item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.LXX_Dark</item>
+ <item name="moreKeysKeyboardViewForActionStyle">@style/MoreKeysKeyboardView.LXX_Dark.Action</item>
<item name="suggestionStripViewStyle">@style/SuggestionStripView.LXX_Dark</item>
<item name="suggestionWordStyle">@style/SuggestionWord.LXX_Dark</item>
</style>
@@ -33,24 +34,17 @@
name="Keyboard.LXX_Dark"
parent="Keyboard"
>
- <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] -->
- <item name="themeId">4</item>
- <item name="keyboardTopPadding">@fraction/config_keyboard_top_padding_holo</item>
- <item name="keyboardBottomPadding">@fraction/config_keyboard_bottom_padding_holo</item>
- <item name="horizontalGap">@fraction/config_key_horizontal_gap_holo</item>
- <item name="verticalGap">@fraction/config_key_vertical_gap_holo</item>
- <item name="touchPositionCorrectionData">@array/touch_position_correction_data_holo</item>
+ <!-- This should be aligned with KeyboardTheme.THEME_ID_* -->
+ <item name="themeId">LXXDark</item>
</style>
<style
name="KeyboardView.LXX_Dark"
- parent="KeyboardView"
+ parent="KeyboardView.LXX"
>
- <item name="android:background">@color/keyboard_background_lxx_dark</item>
+ <item name="android:background">@drawable/keyboard_background_lxx_dark</item>
<item name="keyBackground">@drawable/btn_keyboard_key_lxx_dark</item>
<item name="functionalKeyBackground">@drawable/btn_keyboard_key_functional_lxx_dark</item>
<item name="spacebarBackground">@drawable/btn_keyboard_spacebar_lxx_dark</item>
- <item name="spacebarIconWidthRatio">0.9</item>
- <item name="keyTypeface">normal</item>
<item name="keyTextColor">@color/key_text_color_lxx_dark</item>
<item name="keyTextInactivatedColor">@color/key_functional_text_color_lxx_dark</item>
<item name="functionalTextColor">@color/key_text_color_lxx_dark</item>
@@ -59,15 +53,17 @@
<item name="keyShiftedLetterHintInactivatedColor">@color/key_text_inactive_color_lxx_dark</item>
<item name="keyShiftedLetterHintActivatedColor">@color/key_text_color_lxx_dark</item>
<item name="keyPreviewTextColor">@color/key_text_color_lxx_dark</item>
- <!-- A negative value to disable key text shadow layer. -->
- <item name="keyTextShadowRadius">-1.0</item>
</style>
<style
name="MainKeyboardView.LXX_Dark"
parent="KeyboardView.LXX_Dark"
>
+ <item name="moreKeysKeyboardForActionLayout">@layout/more_keys_keyboard_for_action_lxx</item>
<item name="keyPreviewBackground">@drawable/keyboard_key_feedback_lxx_dark</item>
- <item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item>
+ <item name="keyPreviewHeight">@dimen/config_key_preview_height_lxx</item>
+ <item name="keyPreviewOffset">@dimen/config_key_preview_offset_lxx</item>
+ <item name="keyPreviewShowUpAnimator">@anim/key_preview_show_up_lxx</item>
+ <item name="keyPreviewDismissAnimator">@anim/key_preview_dismiss_lxx</item>
<item name="gestureFloatingPreviewTextColor">@color/auto_correct_color_lxx_dark</item>
<item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_lxx_dark</item>
<item name="gestureTrailColor">@color/gesture_trail_color_lxx_dark</item>
@@ -108,10 +104,20 @@
>
<item name="android:background">@drawable/keyboard_popup_panel_background_lxx_dark</item>
<item name="keyBackground">@drawable/btn_keyboard_key_popup_lxx_dark</item>
+ <item name="divider">@drawable/more_keys_divider</item>
<item name="keyTypeface">normal</item>
<item name="verticalCorrection">@dimen/config_more_keys_keyboard_vertical_correction_holo</item>
</style>
<style
+ name="MoreKeysKeyboardView.LXX_Dark.Action"
+ parent="MoreKeysKeyboardView.LXX_Dark"
+ >
+ <item name="android:background">@android:color/transparent</item>
+ <item name="keyBackground">@drawable/btn_keyboard_key_popup_action_lxx_dark</item>
+ <item name="divider">@null</item>
+ <item name="keyLabelFlags">keepBackgroundAspectRatio</item>
+ </style>
+ <style
name="SuggestionStripView.LXX_Dark"
parent="KeyboardView.LXX_Dark"
>
@@ -119,7 +125,7 @@
<item name="centerSuggestionPercentile">@fraction/config_center_suggestion_percentile</item>
<item name="maxMoreSuggestionsRow">@integer/config_max_more_suggestions_row</item>
<item name="minMoreSuggestionsWidth">@fraction/config_min_more_suggestions_width</item>
- <item name="android:background">@color/suggestions_strip_background_lxx_dark</item>
+ <item name="android:background">@drawable/keyboard_suggest_strip_lxx_dark</item>
<item name="android:src">@drawable/suggestions_strip_divider_lxx_dark</item>
<item name="suggestionStripOptions">autoCorrectBold|validTypedWordBold</item>
<item name="colorValidTypedWord">@color/typed_word_color_lxx_dark</item>
diff --git a/java/res/values/themes-lxx-light.xml b/java/res/values/themes-lxx-light.xml
index 48bd313f0..be817f46a 100644
--- a/java/res/values/themes-lxx-light.xml
+++ b/java/res/values/themes-lxx-light.xml
@@ -26,6 +26,7 @@
<item name="emojiPalettesViewStyle">@style/EmojiPalettesView.LXX_Light</item>
<item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.LXX_Light</item>
<item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.LXX_Light</item>
+ <item name="moreKeysKeyboardViewForActionStyle">@style/MoreKeysKeyboardView.LXX_Light.Action</item>
<item name="suggestionStripViewStyle">@style/SuggestionStripView.LXX_Light</item>
<item name="suggestionWordStyle">@style/SuggestionWord.LXX_Light</item>
</style>
@@ -33,24 +34,17 @@
name="Keyboard.LXX_Light"
parent="Keyboard"
>
- <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] -->
- <item name="themeId">3</item>
- <item name="keyboardTopPadding">@fraction/config_keyboard_top_padding_holo</item>
- <item name="keyboardBottomPadding">@fraction/config_keyboard_bottom_padding_holo</item>
- <item name="horizontalGap">@fraction/config_key_horizontal_gap_holo</item>
- <item name="verticalGap">@fraction/config_key_vertical_gap_holo</item>
- <item name="touchPositionCorrectionData">@array/touch_position_correction_data_holo</item>
+ <!-- This should be aligned with KeyboardTheme.THEME_ID_* -->
+ <item name="themeId">LXXLight</item>
</style>
<style
name="KeyboardView.LXX_Light"
- parent="KeyboardView"
+ parent="KeyboardView.LXX"
>
- <item name="android:background">@color/keyboard_background_lxx_light</item>
+ <item name="android:background">@drawable/keyboard_background_lxx_light</item>
<item name="keyBackground">@drawable/btn_keyboard_key_lxx_light</item>
<item name="functionalKeyBackground">@drawable/btn_keyboard_key_functional_lxx_light</item>
<item name="spacebarBackground">@drawable/btn_keyboard_spacebar_lxx_light</item>
- <item name="spacebarIconWidthRatio">0.9</item>
- <item name="keyTypeface">normal</item>
<item name="keyTextColor">@color/key_text_color_lxx_light</item>
<item name="keyTextInactivatedColor">@color/key_text_inactive_color_lxx_light</item>
<item name="functionalTextColor">@color/key_functional_text_color_lxx_light</item>
@@ -59,15 +53,17 @@
<item name="keyShiftedLetterHintInactivatedColor">@color/key_text_inactive_color_lxx_light</item>
<item name="keyShiftedLetterHintActivatedColor">@color/key_text_color_lxx_light</item>
<item name="keyPreviewTextColor">@color/key_text_color_lxx_light</item>
- <!-- A negative value to disable key text shadow layer. -->
- <item name="keyTextShadowRadius">-1.0</item>
</style>
<style
name="MainKeyboardView.LXX_Light"
parent="KeyboardView.LXX_Light"
>
+ <item name="moreKeysKeyboardForActionLayout">@layout/more_keys_keyboard_for_action_lxx</item>
<item name="keyPreviewBackground">@drawable/keyboard_key_feedback_lxx_light</item>
- <item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item>
+ <item name="keyPreviewHeight">@dimen/config_key_preview_height_lxx</item>
+ <item name="keyPreviewOffset">@dimen/config_key_preview_offset_lxx</item>
+ <item name="keyPreviewShowUpAnimator">@anim/key_preview_show_up_lxx</item>
+ <item name="keyPreviewDismissAnimator">@anim/key_preview_dismiss_lxx</item>
<item name="gestureFloatingPreviewTextColor">@color/auto_correct_color_lxx_light</item>
<item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_lxx_light</item>
<item name="gestureTrailColor">@color/gesture_trail_color_lxx_light</item>
@@ -107,12 +103,21 @@
parent="KeyboardView.LXX_Light"
>
<item name="android:background">@drawable/keyboard_popup_panel_background_lxx_light</item>
- <!-- Reuse KLP key background -->
- <item name="keyBackground">@drawable/btn_keyboard_key_popup_klp</item>
+ <item name="keyBackground">@drawable/btn_keyboard_key_popup_lxx_light</item>
+ <item name="divider">@drawable/more_keys_divider</item>
<item name="keyTypeface">normal</item>
<item name="verticalCorrection">@dimen/config_more_keys_keyboard_vertical_correction_holo</item>
</style>
<style
+ name="MoreKeysKeyboardView.LXX_Light.Action"
+ parent="MoreKeysKeyboardView.LXX_Light"
+ >
+ <item name="android:background">@android:color/transparent</item>
+ <item name="keyBackground">@drawable/btn_keyboard_key_popup_action_lxx_light</item>
+ <item name="divider">@null</item>
+ <item name="keyLabelFlags">keepBackgroundAspectRatio</item>
+ </style>
+ <style
name="SuggestionStripView.LXX_Light"
parent="KeyboardView.LXX_Light"
>
@@ -120,7 +125,7 @@
<item name="centerSuggestionPercentile">@fraction/config_center_suggestion_percentile</item>
<item name="maxMoreSuggestionsRow">@integer/config_max_more_suggestions_row</item>
<item name="minMoreSuggestionsWidth">@fraction/config_min_more_suggestions_width</item>
- <item name="android:background">@color/suggestions_strip_background_lxx_light</item>
+ <item name="android:background">@drawable/keyboard_suggest_strip_lxx_light</item>
<item name="android:src">@drawable/suggestions_strip_divider_lxx_light</item>
<item name="suggestionStripOptions">autoCorrectBold|validTypedWordBold</item>
<item name="colorValidTypedWord">@color/typed_word_color_lxx_light</item>
diff --git a/java/res/values/themes-lxx.xml b/java/res/values/themes-lxx.xml
new file mode 100644
index 000000000..c72188871
--- /dev/null
+++ b/java/res/values/themes-lxx.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- LXX KeyboardView theme (LXX_Light and LXX_Dark) -->
+ <style
+ name="KeyboardView.LXX"
+ parent="KeyboardView"
+ >
+ <item name="keyTypeface">normal</item>
+ <item name="keyLetterSize">@fraction/config_key_letter_ratio_lxx</item>
+ <item name="keyLabelSize">@fraction/config_key_label_ratio_lxx</item>
+ <item name="keyHintLetterRatio">@fraction/config_key_hint_letter_ratio_lxx</item>
+ <item name="keyShiftedLetterHintRatio">@fraction/config_key_shifted_letter_hint_ratio_lxx</item>
+ <item name="keyLargeLetterRatio">@fraction/config_key_large_letter_ratio_lxx</item>
+ <item name="keyLabelOffCenterRatio">-80%</item>
+ <item name="keyHintLabelRatio">@fraction/config_key_hint_label_ratio_lxx</item>
+ <item name="keyHintLabelOffCenterRatio">300%</item>
+ <item name="keyLabelFlags">alignHintLabelToBottom</item>
+ <item name="spacebarIconWidthRatio">0.9</item>
+ <!-- No popup hint letter -->
+ <item name="keyPopupHintLetter"></item>
+ </style>
+</resources>
diff --git a/java/res/xml-sw600dp/key_comma.xml b/java/res/xml-sw600dp/key_comma.xml
index 67199e237..e616a8d70 100644
--- a/java/res/xml-sw600dp/key_comma.xml
+++ b/java/res/xml-sw600dp/key_comma.xml
@@ -2,7 +2,7 @@
<!--
/*
**
-** Copyright 2014, The Android Open Source Project
+** Copyright 2012, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -21,27 +21,36 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <!-- The table comma key which may have settings as popup key. -->
- <!-- Kept as a separate file for cleaner overriding by an overlay. -->
- <key-style
- latin:styleName="baseTabletCommaKeyStyle"
- latin:keySpec="!text/keyspec_tablet_comma"
- latin:keyHintLabel="!text/keyhintlabel_tablet_comma"
- latin:keyLabelFlags="hasPopupHint"
- latin:parentStyle="hasShiftedLetterHintStyle" />
<switch>
<case
- latin:clobberSettingsKey="true"
+ latin:mode="url"
>
<Key
- latin:moreKeys="!text/morekeys_tablet_comma"
- latin:keyStyle="baseTabletCommaKeyStyle" />
+ latin:keySpec="/"
+ latin:keyStyle="settingsMoreKeysStyle" />
+ </case>
+ <case
+ latin:mode="email"
+ >
+ <Key
+ latin:keySpec="\@"
+ latin:keyStyle="settingsMoreKeysStyle" />
+ </case>
+ <case
+ latin:keyboardLayoutSet="dvorak"
+ >
+ <Key
+ latin:keySpec="!"
+ latin:moreKeys="!text/morekeys_exclamation,%"
+ latin:keyStyle="settingsMoreKeysStyle" />
</case>
- <!-- clobberSettingsKey="false" -->
<default>
<Key
- latin:moreKeys="!text/morekeys_tablet_comma,!text/keyspec_settings"
- latin:keyStyle="baseTabletCommaKeyStyle" />
+ latin:keySpec="!text/keyspec_tablet_comma"
+ latin:moreKeys="!text/morekeys_tablet_comma,%"
+ latin:keyHintLabel="!text/keyhintlabel_tablet_comma"
+ latin:keyLabelFlags="hasPopupHint"
+ latin:keyStyle="settingsMoreKeysStyle" />
</default>
</switch>
</merge>
diff --git a/java/res/xml-sw600dp/key_period.xml b/java/res/xml-sw600dp/key_period.xml
index d2909d82d..df1daf792 100644
--- a/java/res/xml-sw600dp/key_period.xml
+++ b/java/res/xml-sw600dp/key_period.xml
@@ -35,6 +35,13 @@
latin:moreKeys="!autoColumnOrder!8,\\,,.,',#,),(,/,;,@,:,-,&quot;,+,\\%,&amp;"
latin:backgroundType="functional" />
</case>
+ <case
+ latin:keyboardLayoutSet="dvorak"
+ >
+ <Key
+ latin:keySpec="\?"
+ latin:moreKeys="!text/morekeys_tablet_period,!text/morekeys_question" />
+ </case>
<default>
<Key
latin:keySpec="!text/keyspec_tablet_period"
diff --git a/java/res/xml-sw600dp/key_space_5kw.xml b/java/res/xml-sw600dp/key_space_7kw.xml
index 8302184c7..3311f812a 100644
--- a/java/res/xml-sw600dp/key_space_5kw.xml
+++ b/java/res/xml-sw600dp/key_space_7kw.xml
@@ -34,7 +34,7 @@
latin:keyStyle="languageSwitchKeyStyle" />
<Key
latin:keyStyle="spaceKeyStyle"
- latin:keyWidth="27.0%p" />
+ latin:keyWidth="45.0%p" />
<Key
latin:keyStyle="zwnjKeyStyle" />
</case>
@@ -44,7 +44,7 @@
>
<Key
latin:keyStyle="spaceKeyStyle"
- latin:keyWidth="36.0%p" />
+ latin:keyWidth="54.0%p" />
<Key
latin:keyStyle="zwnjKeyStyle" />
</case>
@@ -55,13 +55,13 @@
latin:keyStyle="languageSwitchKeyStyle" />
<Key
latin:keyStyle="spaceKeyStyle"
- latin:keyWidth="36.0%p" />
+ latin:keyWidth="54.0%p" />
</case>
<!-- languageSwitchKeyEnabled="false" -->
<default>
<Key
latin:keyStyle="spaceKeyStyle"
- latin:keyWidth="45.0%p" />
+ latin:keyWidth="63.0%p" />
</default>
</switch>
</merge>
diff --git a/java/res/xml-sw600dp/key_styles_common.xml b/java/res/xml-sw600dp/key_styles_common.xml
index 877c796c7..006cda370 100644
--- a/java/res/xml-sw600dp/key_styles_common.xml
+++ b/java/res/xml-sw600dp/key_styles_common.xml
@@ -36,6 +36,9 @@
</default>
</switch>
<!-- Base key style for the key which may have settings key as more keys. -->
+ <key-style
+ latin:styleName="baseSettingsMoreKeysStyle"
+ latin:parentStyle="hasShiftedLetterHintStyle" />
<include
latin:keyboardLayout="@xml/key_styles_settings" />
<!-- Functional key styles -->
@@ -83,6 +86,7 @@
<key-style
latin:styleName="spaceKeyStyle"
latin:keySpec="!icon/space_key|!code/key_space"
+ latin:backgroundType="spacebar"
latin:keyActionFlags="noKeyPreview|enableLongPress" />
<!-- U+200C: ZERO WIDTH NON-JOINER
U+200D: ZERO WIDTH JOINER -->
@@ -105,7 +109,7 @@
latin:altCode="!code/key_space" />
<key-style
latin:styleName="emojiKeyStyle"
- latin:keySpec="!icon/emoji_key|!code/key_emoji"
+ latin:keySpec="!icon/emoji_normal_key|!code/key_emoji"
latin:keyActionFlags="noKeyPreview"
latin:backgroundType="functional" />
<key-style
diff --git a/java/res/xml-sw600dp/key_styles_enter.xml b/java/res/xml-sw600dp/key_styles_enter.xml
index 740bf3543..63ef2f8f9 100644
--- a/java/res/xml-sw600dp/key_styles_enter.xml
+++ b/java/res/xml-sw600dp/key_styles_enter.xml
@@ -21,22 +21,19 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <!-- TODO: Stop using many conditional cases for keyspec_emoji_key. There are way too many to maintain. -->
<!-- Navigate more keys style -->
+ <include latin:keyboardLayout="@xml/key_styles_navigate_more_keys" />
<switch>
- <!-- latin:passwordInput="true" -->
<case
latin:imeAction="actionNext"
latin:navigatePrevious="true"
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!text/keyspec_action_previous" />
+ latin:parentStyle="navigatePreviousMoreKeysStyle" />
</case>
<case
latin:imeAction="actionNext"
- latin:navigatePrevious="false"
>
<key-style
latin:styleName="navigateMoreKeysStyle" />
@@ -47,12 +44,10 @@
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!text/keyspec_action_next" />
+ latin:parentStyle="navigateNextMoreKeysStyle" />
</case>
<case
latin:imeAction="actionPrevious"
- latin:navigateNext="false"
>
<key-style
latin:styleName="navigateMoreKeysStyle" />
@@ -63,47 +58,50 @@
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_action_previous,!text/keyspec_action_next" />
+ latin:parentStyle="navigatePreviousNextMoreKeysStyle" />
</case>
<case
latin:navigateNext="true"
- latin:navigatePrevious="false"
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!text/keyspec_action_next" />
+ latin:parentStyle="navigateNextMoreKeysStyle" />
</case>
<case
- latin:navigateNext="false"
latin:navigatePrevious="true"
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!text/keyspec_action_previous" />
+ latin:parentStyle="navigatePreviousMoreKeysStyle" />
</case>
- <case
- latin:navigateNext="false"
- latin:navigatePrevious="false"
- >
+ <default>
<key-style
latin:styleName="navigateMoreKeysStyle" />
+ </default>
+ </switch>
+ <!-- Enter key style -->
+ <switch>
+ <case latin:keyboardTheme="ICS|KLP">
+ <key-style
+ latin:styleName="defaultEnterKeyStyle"
+ latin:keySpec="!icon/enter_key|!code/key_enter"
+ latin:keyLabelFlags="preserveCase|autoXScale|followKeyLabelRatio|followFunctionalTextColor"
+ latin:keyActionFlags="noKeyPreview"
+ latin:backgroundType="action"
+ latin:parentStyle="navigateMoreKeysStyle" />
</case>
+ <!-- keyboardTheme="LXXLight|LXXDark" -->
<default>
<key-style
- latin:styleName="navigateMoreKeysStyle" />
+ latin:styleName="defaultEnterKeyStyle"
+ latin:keySpec="!icon/enter_key|!code/key_enter"
+ latin:keyLabelFlags="preserveCase|autoXScale|followKeyLabelRatio|followFunctionalTextColor|keepBackgroundAspectRatio"
+ latin:keyActionFlags="noKeyPreview"
+ latin:backgroundType="action"
+ latin:parentStyle="navigateMoreKeysStyle" />
</default>
</switch>
- <!-- Enter key style -->
- <key-style
- latin:styleName="defaultEnterKeyStyle"
- latin:keySpec="!icon/enter_key|!code/key_enter"
- latin:keyLabelFlags="preserveCase|autoXScale|followKeyLabelRatio|followFunctionalTextColor"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="action"
- latin:parentStyle="navigateMoreKeysStyle" />
+ <include latin:keyboardLayout="@xml/key_styles_actions" />
<switch>
<!-- Shift + Enter in textMultiLine field. -->
<case
@@ -117,120 +115,52 @@
</case>
<case
latin:imeAction="actionGo"
- latin:isIconDefined="go_key"
- >
- <key-style
- latin:styleName="enterKeyStyle"
- latin:keySpec="!icon/go_key|!code/key_enter"
- latin:backgroundType="action"
- latin:parentStyle="defaultEnterKeyStyle" />
- </case>
- <case
- latin:imeAction="actionGo"
>
<key-style
latin:styleName="enterKeyStyle"
- latin:keySpec="!text/label_go_key|!code/key_enter"
- latin:parentStyle="defaultEnterKeyStyle" />
+ latin:parentStyle="goActionKeyStyle" />
</case>
<case
latin:imeAction="actionNext"
- latin:isIconDefined="next_key"
>
<key-style
latin:styleName="enterKeyStyle"
- latin:keySpec="!icon/next_key|!code/key_enter"
- latin:backgroundType="action"
- latin:parentStyle="defaultEnterKeyStyle" />
- </case>
- <case
- latin:imeAction="actionNext"
- >
- <key-style
- latin:styleName="enterKeyStyle"
- latin:keySpec="!text/label_next_key|!code/key_enter"
- latin:parentStyle="defaultEnterKeyStyle" />
+ latin:parentStyle="nextActionKeyStyle" />
</case>
<case
latin:imeAction="actionPrevious"
- latin:isIconDefined="previous_key"
>
<key-style
latin:styleName="enterKeyStyle"
- latin:keySpec="!icon/previous_key|!code/key_enter"
- latin:backgroundType="action"
- latin:parentStyle="defaultEnterKeyStyle" />
- </case>
- <case
- latin:imeAction="actionPrevious"
- >
- <key-style
- latin:styleName="enterKeyStyle"
- latin:keySpec="!text/label_previous_key|!code/key_enter"
- latin:parentStyle="defaultEnterKeyStyle" />
+ latin:parentStyle="previousActionKeyStyle" />
</case>
<case
latin:imeAction="actionDone"
- latin:isIconDefined="done_key"
>
<key-style
latin:styleName="enterKeyStyle"
- latin:keySpec="!icon/done_key|!code/key_enter"
- latin:backgroundType="action"
- latin:parentStyle="defaultEnterKeyStyle" />
- </case>
- <case
- latin:imeAction="actionDone"
- >
- <key-style
- latin:styleName="enterKeyStyle"
- latin:keySpec="!text/label_done_key|!code/key_enter"
- latin:parentStyle="defaultEnterKeyStyle" />
+ latin:parentStyle="doneActionKeyStyle" />
</case>
<case
latin:imeAction="actionSend"
- latin:isIconDefined="send_key"
>
<key-style
latin:styleName="enterKeyStyle"
- latin:keySpec="!icon/send_key|!code/key_enter"
- latin:backgroundType="action"
- latin:parentStyle="defaultEnterKeyStyle" />
- </case>
- <case
- latin:imeAction="actionSend"
- >
- <key-style
- latin:styleName="enterKeyStyle"
- latin:keySpec="!text/label_send_key|!code/key_enter"
- latin:parentStyle="defaultEnterKeyStyle" />
- </case>
- <case
- latin:imeAction="actionSearch"
- latin:isIconDefined="search_key"
- >
- <key-style
- latin:styleName="enterKeyStyle"
- latin:keySpec="!icon/search_key|!code/key_enter"
- latin:backgroundType="action"
- latin:parentStyle="defaultEnterKeyStyle" />
+ latin:parentStyle="sendActionKeyStyle" />
</case>
<case
latin:imeAction="actionSearch"
>
<key-style
latin:styleName="enterKeyStyle"
- latin:keySpec="!text/label_search_key|!code/key_enter"
- latin:parentStyle="defaultEnterKeyStyle" />
+ latin:parentStyle="searchActionKeyStyle" />
</case>
<case
latin:imeAction="actionCustomLabel"
>
<key-style
latin:styleName="enterKeyStyle"
- latin:keySpec="dummy_label|!code/key_enter"
- latin:keyLabelFlags="fromCustomActionLabel"
- latin:parentStyle="defaultEnterKeyStyle" />
+ latin:parentStyle="customLabelActionKeyStyle" />
</case>
<!-- imeAction is either actionNone or actionUnspecified. -->
<default>
diff --git a/java/res/xml-sw600dp/row_dvorak4.xml b/java/res/xml-sw600dp/row_dvorak4.xml
deleted file mode 100644
index ab2b5603d..000000000
--- a/java/res/xml-sw600dp/row_dvorak4.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="9.0%p"
- latin:backgroundType="functional"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyWidth="10.0%p" />
- <include
- latin:keyboardLayout="@xml/key_settings" />
- <Key
- latin:keySpec="_"
- latin:keyHintLabel="-"
- latin:moreKeys="-"
- latin:keyStyle="hasShiftedLetterHintStyle" />
- <include
- latin:keyXPos="28.0%p"
- latin:keyboardLayout="@xml/key_space_5kw"
- latin:backgroundType="normal" />
- <include
- latin:keyboardLayout="@xml/key_f1" />
- <include
- latin:keyboardLayout="@xml/key_question_exclamation" />
- <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 ac07f11c2..4dcae1455 100644
--- a/java/res/xml-sw600dp/row_pcqwerty5.xml
+++ b/java/res/xml-sw600dp/row_pcqwerty5.xml
@@ -50,6 +50,6 @@
latin:keyXPos="-9.0%p"
latin:keyWidth="9.0%p"
latin:backgroundType="functional"
- latin:keyboardLayout="@xml/key_f2" />
+ latin:keyboardLayout="@xml/key_emoji" />
</Row>
</merge>
diff --git a/java/res/xml-sw600dp/row_qwerty4.xml b/java/res/xml-sw600dp/row_qwerty4.xml
index 0eb86f2d4..ed7150de4 100644
--- a/java/res/xml-sw600dp/row_qwerty4.xml
+++ b/java/res/xml-sw600dp/row_qwerty4.xml
@@ -30,18 +30,14 @@
latin:keyWidth="10.0%p" />
<include
latin:keyboardLayout="@xml/key_comma" />
- <Key
- latin:keySpec="_" />
<!-- Space key. -->
<include
- latin:keyXPos="28.0%p"
- latin:keyboardLayout="@xml/key_space_5kw"
+ latin:keyXPos="19.0%p"
+ latin:keyboardLayout="@xml/key_space_7kw"
latin:backgroundType="normal" />
<include
- latin:keyboardLayout="@xml/key_f1" />
- <include
latin:keyboardLayout="@xml/key_period" />
<include
- latin:keyboardLayout="@xml/key_f2" />
+ latin:keyboardLayout="@xml/key_emoji" />
</Row>
</merge>
diff --git a/java/res/xml-sw600dp/rows_dvorak.xml b/java/res/xml-sw600dp/rows_dvorak.xml
index 88592676d..c8f5e3aa2 100644
--- a/java/res/xml-sw600dp/rows_dvorak.xml
+++ b/java/res/xml-sw600dp/rows_dvorak.xml
@@ -53,6 +53,8 @@
latin:keyStyle="shiftKeyStyle"
latin:keyWidth="fillRight" />
</Row>
+ <!-- Dvorak layout shares almost the same row with Qwerty layout.
+ The difference is defined in xml-sw600dp/row_qwerty4.xml. -->
<include
- latin:keyboardLayout="@xml/row_dvorak4" />
+ latin:keyboardLayout="@xml/row_qwerty4" />
</merge>
diff --git a/java/res/xml-sw600dp/rows_number_normal.xml b/java/res/xml-sw600dp/rows_number_normal.xml
index 757e77933..7a4700d5a 100644
--- a/java/res/xml-sw600dp/rows_number_normal.xml
+++ b/java/res/xml-sw600dp/rows_number_normal.xml
@@ -141,9 +141,8 @@
</Row>
<Row>
<Key
- latin:keyStyle="spaceKeyStyle"
- latin:keyWidth="30%p"
- latin:backgroundType="functional" />
+ latin:keyStyle="tabletNumSpaceKeyStyle"
+ latin:keyWidth="30%p" />
<Key
latin:keyStyle="numStarKeyStyle"
latin:keyXPos="31%p" />
diff --git a/java/res/xml-sw600dp/rows_phone.xml b/java/res/xml-sw600dp/rows_phone.xml
index 9022bc532..612397a90 100644
--- a/java/res/xml-sw600dp/rows_phone.xml
+++ b/java/res/xml-sw600dp/rows_phone.xml
@@ -107,9 +107,8 @@
</Row>
<Row>
<Key
- latin:keyStyle="spaceKeyStyle"
- latin:keyWidth="30%p"
- latin:backgroundType="functional" />
+ latin:keyStyle="tabletNumSpaceKeyStyle"
+ latin:keyWidth="30%p" />
<Key
latin:keyStyle="numStarKeyStyle"
latin:keyXPos="31%p" />
diff --git a/java/res/xml-sw600dp/rows_symbols.xml b/java/res/xml-sw600dp/rows_symbols.xml
index a915c3351..05e7c685e 100644
--- a/java/res/xml-sw600dp/rows_symbols.xml
+++ b/java/res/xml-sw600dp/rows_symbols.xml
@@ -70,6 +70,6 @@
<include
latin:keyboardLayout="@xml/row_symbols4" />
<include
- latin:keyboardLayout="@xml/key_f2" />
+ latin:keyboardLayout="@xml/key_emoji" />
</Row>
</merge>
diff --git a/java/res/xml-sw600dp/rows_symbols_shift.xml b/java/res/xml-sw600dp/rows_symbols_shift.xml
index 7ead4d5b1..70ac42eb9 100644
--- a/java/res/xml-sw600dp/rows_symbols_shift.xml
+++ b/java/res/xml-sw600dp/rows_symbols_shift.xml
@@ -72,6 +72,6 @@
<include
latin:keyboardLayout="@xml/row_symbols_shift4" />
<include
- latin:keyboardLayout="@xml/key_f2" />
+ latin:keyboardLayout="@xml/key_emoji" />
</Row>
</merge>
diff --git a/java/res/xml/key_f1.xml b/java/res/xml/key_comma.xml
index 7bd7385a1..cf919a85d 100644
--- a/java/res/xml/key_f1.xml
+++ b/java/res/xml/key_comma.xml
@@ -23,6 +23,15 @@
>
<switch>
<case
+ latin:keyboardLayoutSet="dvorak"
+ >
+ <Key
+ latin:keySpec="q"
+ latin:moreKeys="!text/morekeys_q,%"
+ latin:backgroundType="normal"
+ latin:keyStyle="settingsMoreKeysStyle" />
+ </case>
+ <case
latin:mode="url"
>
<Key
diff --git a/java/res/xml/key_f2.xml b/java/res/xml/key_emoji.xml
index 473dd210a..473dd210a 100644
--- a/java/res/xml/key_f2.xml
+++ b/java/res/xml/key_emoji.xml
diff --git a/java/res/xml/key_period.xml b/java/res/xml/key_period.xml
index e1d4bbdf7..fc27c0235 100644
--- a/java/res/xml/key_period.xml
+++ b/java/res/xml/key_period.xml
@@ -48,6 +48,14 @@
latin:moreKeys="!text/morekeys_punctuation"
latin:backgroundType="functional" />
</case>
+ <case
+ latin:keyboardLayoutSet="dvorak"
+ >
+ <Key
+ latin:keySpec="z"
+ latin:keyLabelFlags="hasPopupHint"
+ latin:moreKeys="!text/morekeys_punctuation,!text/morekeys_z" />
+ </case>
<default>
<Key
latin:keySpec="!text/keyspec_period"
diff --git a/java/res/xml/key_space_symbols.xml b/java/res/xml/key_space_symbols.xml
index 0ce522889..047de9f24 100644
--- a/java/res/xml/key_space_symbols.xml
+++ b/java/res/xml/key_space_symbols.xml
@@ -22,7 +22,6 @@
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
<Key
- latin:backgroundType="normal"
latin:keyStyle="spaceKeyStyle"
latin:keyWidth="30%p" />
</merge>
diff --git a/java/res/xml/key_styles_actions.xml b/java/res/xml/key_styles_actions.xml
new file mode 100644
index 000000000..83901cad9
--- /dev/null
+++ b/java/res/xml/key_styles_actions.xml
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- Go key -->
+ <switch>
+ <case latin:isIconDefined="go_key">
+ <key-style
+ latin:styleName="goActionKeyStyle"
+ latin:keySpec="!icon/go_key|!code/key_enter"
+ latin:parentStyle="defaultEnterKeyStyle" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="goActionKeyStyle"
+ latin:keySpec="!text/label_go_key|!code/key_enter"
+ latin:parentStyle="defaultEnterKeyStyle" />
+ </default>
+ </switch>
+ <!-- Next key -->
+ <switch>
+ <case latin:isIconDefined="next_key">
+ <key-style
+ latin:styleName="nextActionKeyStyle"
+ latin:keySpec="!icon/next_key|!code/key_enter"
+ latin:parentStyle="defaultEnterKeyStyle" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="nextActionKeyStyle"
+ latin:keySpec="!text/label_next_key|!code/key_enter"
+ latin:parentStyle="defaultEnterKeyStyle" />
+ </default>
+ </switch>
+ <!-- Previous key -->
+ <switch>
+ <case latin:isIconDefined="previous_key">
+ <key-style
+ latin:styleName="previousActionKeyStyle"
+ latin:keySpec="!icon/previous_key|!code/key_enter"
+ latin:parentStyle="defaultEnterKeyStyle" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="previousActionKeyStyle"
+ latin:keySpec="!text/label_previous_key|!code/key_enter"
+ latin:parentStyle="defaultEnterKeyStyle" />
+ </default>
+ </switch>
+ <!-- Done key -->
+ <switch>
+ <case latin:isIconDefined="done_key">
+ <key-style
+ latin:styleName="doneActionKeyStyle"
+ latin:keySpec="!icon/done_key|!code/key_enter"
+ latin:parentStyle="defaultEnterKeyStyle" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="doneActionKeyStyle"
+ latin:keySpec="!text/label_done_key|!code/key_enter"
+ latin:parentStyle="defaultEnterKeyStyle" />
+ </default>
+ </switch>
+ <!-- Send key -->
+ <switch>
+ <case latin:isIconDefined="send_key">
+ <key-style
+ latin:styleName="sendActionKeyStyle"
+ latin:keySpec="!icon/send_key|!code/key_enter"
+ latin:parentStyle="defaultEnterKeyStyle" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="sendActionKeyStyle"
+ latin:keySpec="!text/label_send_key|!code/key_enter"
+ latin:parentStyle="defaultEnterKeyStyle" />
+ </default>
+ </switch>
+ <!-- Seartch key -->
+ <switch>
+ <case latin:isIconDefined="search_key">
+ <key-style
+ latin:styleName="searchActionKeyStyle"
+ latin:keySpec="!icon/search_key|!code/key_enter"
+ latin:parentStyle="defaultEnterKeyStyle" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="searchActionKeyStyle"
+ latin:keySpec="!text/label_search_key|!code/key_enter"
+ latin:parentStyle="defaultEnterKeyStyle" />
+ </default>
+ </switch>
+ <switch>
+ <case latin:keyboardTheme="ICS|KLP">
+ <key-style
+ latin:styleName="customLabelActionKeyStyle"
+ latin:keySpec="dummy_label|!code/key_enter"
+ latin:keyLabelFlags="fromCustomActionLabel"
+ latin:backgroundType="action"
+ latin:parentStyle="defaultEnterKeyStyle" />
+ </case>
+ <!-- keyboardTheme="LXXLight|LXXDark" -->
+ <default>
+ <key-style
+ latin:styleName="customLabelActionKeyStyle"
+ latin:keySpec="dummy_label|!code/key_enter"
+ latin:keyLabelFlags="fromCustomActionLabel"
+ latin:backgroundType="functional"
+ latin:parentStyle="defaultEnterKeyStyle" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/key_styles_common.xml b/java/res/xml/key_styles_common.xml
index bc739f7d0..b36ddf236 100644
--- a/java/res/xml/key_styles_common.xml
+++ b/java/res/xml/key_styles_common.xml
@@ -36,6 +36,8 @@
</default>
</switch>
<!-- Base key style for the key which may have settings key as more keys. -->
+ <key-style
+ latin:styleName="baseSettingsMoreKeysStyle" />
<include
latin:keyboardLayout="@xml/key_styles_settings" />
<!-- Functional key styles -->
@@ -78,17 +80,31 @@
latin:keyActionFlags="isRepeatable|noKeyPreview"
latin:backgroundType="functional" />
<!-- emojiKeyStyle must be defined before including @xml/key_syles_enter. -->
- <key-style
- latin:styleName="emojiKeyStyle"
- latin:keySpec="!icon/emoji_key|!code/key_emoji"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="action" />
+ <switch>
+ <case latin:keyboardTheme="ICS|KLP">
+ <key-style
+ latin:styleName="emojiKeyStyle"
+ latin:keySpec="!icon/emoji_action_key|!code/key_emoji"
+ latin:keyActionFlags="noKeyPreview"
+ latin:backgroundType="action" />
+ </case>
+ <!-- keyboardTheme="LXXLight|LXXDark" -->
+ <default>
+ <key-style
+ latin:styleName="emojiKeyStyle"
+ latin:keySpec="!icon/emoji_action_key|!code/key_emoji"
+ latin:keyLabelFlags="keepBackgroundAspectRatio"
+ latin:keyActionFlags="noKeyPreview"
+ latin:backgroundType="action" />
+ </default>
+ </switch>
<include
latin:keyboardLayout="@xml/key_styles_enter" />
<!-- TODO: Currently there is no way to specify icon alignment per theme. -->
<key-style
latin:styleName="spaceKeyStyle"
latin:keySpec="!icon/space_key|!code/key_space"
+ latin:backgroundType="spacebar"
latin:keyActionFlags="noKeyPreview|enableLongPress" />
<!-- U+200C: ZERO WIDTH NON-JOINER
U+200D: ZERO WIDTH JOINER -->
diff --git a/java/res/xml/key_styles_currency.xml b/java/res/xml/key_styles_currency.xml
index 900c9bb7a..cfe9a90a1 100644
--- a/java/res/xml/key_styles_currency.xml
+++ b/java/res/xml/key_styles_currency.xml
@@ -84,7 +84,6 @@
lo: Lao (Kip)
mn: Mongolian (Tugrik)
ne: Nepali (Nepalese Rupee)
- ta_IN: Tamil (Tamil Rupee)
th: Thai (Baht)
uk: Ukrainian (Hryvnia)
vi: Vietnamese (Dong) -->
@@ -92,29 +91,24 @@
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|lo|mn|ne|ta|th|uk|vi">
- <!-- U+00A3: "£" POUND SIGN
- U+20AC: "€" EURO SIGN
- U+00A2: "¢" CENT SIGN -->
- <key-style
- latin:styleName="currencyKeyStyle"
- latin:keySpec="!text/keyspec_currency"
- latin:moreKeys="!text/morekeys_currency" />
- <key-style
- latin:styleName="moreCurrency1KeyStyle"
- latin:keySpec="&#x00A3;" />
- <key-style
- latin:styleName="moreCurrency2KeyStyle"
- latin:keySpec="&#x20AC;" />
- <key-style
- latin:styleName="moreCurrency3KeyStyle"
- latin:keySpec="$"
- latin:moreKeys="&#x00A2;" />
- <key-style
- latin:styleName="moreCurrency4KeyStyle"
- latin:keySpec="&#x00A2;" />
+ <!-- TODO: The currency sign of Russian Ruble was created in 2014 and assigned U+20BD for
+ its unicode, although there is no font glyph for it as of August 2014. -->
+ <case latin:languageCode="fa|hi|iw|lo|mn|ne|th|uk|vi">
+ <include latin:keyboardLayout="@xml/key_styles_currency_generic" />
+ </case>
+ <!-- si_LK: Sinhala (Sri Lanka) (Sri Lanka Rupee)
+ ta_LK: Tamil (Sri Lanka) (Sri Lanka Rupee) -->
+ <case latin:countryCode="LK">
+ <include latin:keyboardLayout="@xml/key_styles_currency_generic" />
</case>
- <!-- IN: India (Rupee) -->
+ <!-- bn_IN: Bengali (India) (Indian Rupee)
+ en_IN: English (India) (Indian Rupee)
+ kn_IN: Kannada (India) (Indian Rupee)
+ ml_IN: Malayalam (India) (Indian Rupee)
+ mr_IN: Marathi (India) (Indian Rupee)
+ ta_IN: Tamil (India) (Indian Rupee)
+ te_IN: Telugu (India) (Indian Rupee)
+ -->
<case latin:countryCode="IN">
<!-- U+20B9: "₹" INDIAN RUPEE SIGN
U+00A3: "£" POUND SIGN
@@ -123,7 +117,7 @@
<key-style
latin:styleName="currencyKeyStyle"
latin:keySpec="&#x20B9;"
- latin:moreKeys="!text/morekeys_currency" />
+ latin:moreKeys="!text/morekeys_currency_generic" />
<key-style
latin:styleName="moreCurrency1KeyStyle"
latin:keySpec="&#x00A3;" />
diff --git a/java/res/xml/key_styles_currency_generic.xml b/java/res/xml/key_styles_currency_generic.xml
new file mode 100644
index 000000000..888b5b2c9
--- /dev/null
+++ b/java/res/xml/key_styles_currency_generic.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <!-- U+00A3: "£" POUND SIGN
+ U+20AC: "€" EURO SIGN
+ U+00A2: "¢" CENT SIGN -->
+ <key-style
+ latin:styleName="currencyKeyStyle"
+ latin:keySpec="!text/keyspec_currency"
+ latin:moreKeys="!text/morekeys_currency_generic" />
+ <key-style
+ latin:styleName="moreCurrency1KeyStyle"
+ latin:keySpec="&#x00A3;" />
+ <key-style
+ latin:styleName="moreCurrency2KeyStyle"
+ latin:keySpec="&#x20AC;" />
+ <key-style
+ latin:styleName="moreCurrency3KeyStyle"
+ latin:keySpec="$"
+ latin:moreKeys="&#x00A2;" />
+ <key-style
+ latin:styleName="moreCurrency4KeyStyle"
+ latin:keySpec="&#x00A2;" />
+</merge>
diff --git a/java/res/xml/key_styles_enter.xml b/java/res/xml/key_styles_enter.xml
index 50530e1bf..564f465e9 100644
--- a/java/res/xml/key_styles_enter.xml
+++ b/java/res/xml/key_styles_enter.xml
@@ -21,8 +21,8 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <!-- TODO: Stop using many conditional cases for keyspec_emoji_key. There are way too many to maintain. -->
<!-- Navigate more keys style -->
+ <include latin:keyboardLayout="@xml/key_styles_navigate_more_keys" />
<switch>
<!-- latin:passwordInput="true" -->
<case
@@ -32,12 +32,10 @@
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!text/keyspec_action_previous" />
+ latin:parentStyle="navigatePreviousMoreKeysStyle" />
</case>
<case
latin:imeAction="actionNext"
- latin:navigatePrevious="false"
latin:passwordInput="true"
>
<key-style
@@ -50,12 +48,10 @@
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!text/keyspec_action_next" />
+ latin:parentStyle="navigateNextMoreKeysStyle" />
</case>
<case
latin:imeAction="actionPrevious"
- latin:navigateNext="false"
latin:passwordInput="true"
>
<key-style
@@ -68,32 +64,25 @@
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_action_previous,!text/keyspec_action_next" />
+ latin:parentStyle="navigatePreviousNextMoreKeysStyle" />
</case>
<case
latin:navigateNext="true"
- latin:navigatePrevious="false"
latin:passwordInput="true"
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!text/keyspec_action_next" />
+ latin:parentStyle="navigateNextMoreKeysStyle" />
</case>
<case
- latin:navigateNext="false"
latin:navigatePrevious="true"
latin:passwordInput="true"
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!text/keyspec_action_previous" />
+ latin:parentStyle="navigatePreviousMoreKeysStyle" />
</case>
<case
- latin:navigateNext="false"
- latin:navigatePrevious="false"
latin:passwordInput="true"
>
<key-style
@@ -107,12 +96,10 @@
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!text/keyspec_action_previous" />
+ latin:parentStyle="navigatePreviousMoreKeysStyle" />
</case>
<case
latin:imeAction="actionNext"
- latin:navigatePrevious="false"
latin:mode="email|url|phone|number|date|time|datetime"
>
<key-style
@@ -125,12 +112,10 @@
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!text/keyspec_action_next" />
+ latin:parentStyle="navigateNextMoreKeysStyle" />
</case>
<case
latin:imeAction="actionPrevious"
- latin:navigateNext="false"
latin:mode="email|url|phone|number|date|time|datetime"
>
<key-style
@@ -143,32 +128,25 @@
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_action_previous,!text/keyspec_action_next" />
+ latin:parentStyle="navigatePreviousNextMoreKeysStyle" />
</case>
<case
latin:navigateNext="true"
- latin:navigatePrevious="false"
latin:mode="email|url|phone|number|date|time|datetime"
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!text/keyspec_action_next" />
+ latin:parentStyle="navigateNextMoreKeysStyle" />
</case>
<case
- latin:navigateNext="false"
latin:navigatePrevious="true"
latin:mode="email|url|phone|number|date|time|datetime"
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!text/keyspec_action_previous" />
+ latin:parentStyle="navigatePreviousMoreKeysStyle" />
</case>
<case
- latin:navigateNext="false"
- latin:navigatePrevious="false"
latin:mode="email|url|phone|number|date|time|datetime"
>
<key-style
@@ -181,17 +159,14 @@
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_emoji_key,!text/keyspec_action_previous" />
+ latin:parentStyle="navigateEmojiPreviousMoreKeysStyle" />
</case>
<case
latin:imeAction="actionNext"
- latin:navigatePrevious="false"
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!text/keyspec_emoji_key" />
+ latin:parentStyle="navigateEmojiMoreKeysStyle" />
</case>
<case
latin:imeAction="actionPrevious"
@@ -199,17 +174,14 @@
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_emoji_key,!text/keyspec_action_next" />
+ latin:parentStyle="navigateEmojiNextMoreKeysStyle" />
</case>
<case
latin:imeAction="actionPrevious"
- latin:navigateNext="false"
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!text/keyspec_emoji_key" />
+ latin:parentStyle="navigateEmojiMoreKeysStyle" />
</case>
<case
latin:navigateNext="true"
@@ -217,52 +189,51 @@
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!fixedColumnOrder!3,!needsDividers!,!text/keyspec_emoji_key,!text/keyspec_action_previous,!text/keyspec_action_next" />
+ latin:parentStyle="navigateEmojiPreviousNextMoreKeysStyle" />
</case>
<case
latin:navigateNext="true"
- latin:navigatePrevious="false"
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_emoji_key,!text/keyspec_action_next" />
+ latin:parentStyle="navigateEmojiNextMoreKeysStyle" />
</case>
<case
- latin:navigateNext="false"
latin:navigatePrevious="true"
>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_emoji_key,!text/keyspec_action_previous" />
+ latin:parentStyle="navigateEmojiPreviousMoreKeysStyle" />
</case>
- <case
- latin:navigateNext="false"
- latin:navigatePrevious="false"
- >
+ <default>
<key-style
latin:styleName="navigateMoreKeysStyle"
- latin:keyLabelFlags="hasPopupHint|preserveCase"
- latin:moreKeys="!text/keyspec_emoji_key" />
+ latin:parentStyle="navigateEmojiMoreKeysStyle" />
+ </default>
+ </switch>
+ <!-- Enter key style -->
+ <switch>
+ <case latin:keyboardTheme="ICS|KLP">
+ <key-style
+ latin:styleName="defaultEnterKeyStyle"
+ latin:keySpec="!icon/enter_key|!code/key_enter"
+ latin:keyLabelFlags="preserveCase|autoXScale|followKeyLabelRatio|followFunctionalTextColor"
+ latin:keyActionFlags="noKeyPreview"
+ latin:backgroundType="action"
+ latin:parentStyle="navigateMoreKeysStyle" />
</case>
+ <!-- keyboardTheme="LXXLight|LXXDark" -->
<default>
<key-style
- latin:styleName="navigateMoreKeysStyle" />
+ latin:styleName="defaultEnterKeyStyle"
+ latin:keySpec="!icon/enter_key|!code/key_enter"
+ latin:keyLabelFlags="preserveCase|autoXScale|followKeyLabelRatio|followFunctionalTextColor|keepBackgroundAspectRatio"
+ latin:keyActionFlags="noKeyPreview"
+ latin:backgroundType="action"
+ latin:parentStyle="navigateMoreKeysStyle" />
</default>
</switch>
- <!-- Enter key style -->
- <key-style
- latin:styleName="defaultEnterKeyStyle"
- latin:keyLabelFlags="preserveCase|autoXScale|followKeyLabelRatio|followFunctionalTextColor"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="action"
- latin:parentStyle="navigateMoreKeysStyle" />
- <key-style
- latin:styleName="shiftEnterKeyStyle"
- latin:keySpec="!icon/enter_key|!code/key_shift_enter"
- latin:parentStyle="defaultEnterKeyStyle" />
+ <include latin:keyboardLayout="@xml/key_styles_actions" />
<switch>
<!-- Shift + Enter in textMultiLine field. -->
<case
@@ -271,7 +242,8 @@
>
<key-style
latin:styleName="enterKeyStyle"
- latin:parentStyle="shiftEnterKeyStyle" />
+ latin:keySpec="!icon/enter_key|!code/key_shift_enter"
+ latin:parentStyle="defaultEnterKeyStyle" />
</case>
<!-- Smiley in textShortMessage field.
This <case> should be after Shift + Enter <case> and before any of action <case>. -->
@@ -284,126 +256,57 @@
</case>
<case
latin:imeAction="actionGo"
- latin:isIconDefined="go_key"
- >
- <key-style
- latin:styleName="enterKeyStyle"
- latin:keySpec="!icon/go_key|!code/key_enter"
- latin:backgroundType="action"
- latin:parentStyle="defaultEnterKeyStyle" />
- </case>
- <case
- latin:imeAction="actionGo"
- >
- <key-style
- latin:styleName="enterKeyStyle"
- latin:keySpec="!text/label_go_key|!code/key_enter"
- latin:parentStyle="defaultEnterKeyStyle" />
- </case>
- <case
- latin:imeAction="actionNext"
- latin:isIconDefined="next_key"
>
<key-style
latin:styleName="enterKeyStyle"
- latin:keySpec="!icon/next_key|!code/key_enter"
- latin:backgroundType="action"
- latin:parentStyle="defaultEnterKeyStyle" />
+ latin:parentStyle="goActionKeyStyle" />
</case>
<case
latin:imeAction="actionNext"
>
<key-style
latin:styleName="enterKeyStyle"
- latin:keySpec="!text/label_next_key|!code/key_enter"
- latin:parentStyle="defaultEnterKeyStyle" />
+ latin:parentStyle="nextActionKeyStyle" />
</case>
<case
latin:imeAction="actionPrevious"
- latin:isIconDefined="previous_key"
>
<key-style
latin:styleName="enterKeyStyle"
- latin:keySpec="!icon/previous_key|!code/key_enter"
- latin:backgroundType="action"
- latin:parentStyle="defaultEnterKeyStyle" />
- </case>
- <case
- latin:imeAction="actionPrevious"
- >
- <key-style
- latin:styleName="enterKeyStyle"
- latin:keySpec="!text/label_previous_key|!code/key_enter"
- latin:parentStyle="defaultEnterKeyStyle" />
- </case>
- <case
- latin:imeAction="actionDone"
- latin:isIconDefined="done_key"
- >
- <key-style
- latin:styleName="enterKeyStyle"
- latin:keySpec="!icon/done_key|!code/key_enter"
- latin:backgroundType="action"
- latin:parentStyle="defaultEnterKeyStyle" />
+ latin:parentStyle="previousActionKeyStyle" />
</case>
<case
latin:imeAction="actionDone"
>
<key-style
latin:styleName="enterKeyStyle"
- latin:keySpec="!text/label_done_key|!code/key_enter"
- latin:parentStyle="defaultEnterKeyStyle" />
+ latin:parentStyle="doneActionKeyStyle" />
</case>
<case
latin:imeAction="actionSend"
- latin:isIconDefined="send_key"
>
<key-style
latin:styleName="enterKeyStyle"
- latin:keySpec="!icon/send_key|!code/key_enter"
- latin:backgroundType="action"
- latin:parentStyle="defaultEnterKeyStyle" />
- </case>
- <case
- latin:imeAction="actionSend"
- >
- <key-style
- latin:styleName="enterKeyStyle"
- latin:keySpec="!text/label_send_key|!code/key_enter"
- latin:parentStyle="defaultEnterKeyStyle" />
+ latin:parentStyle="sendActionKeyStyle" />
</case>
<case
latin:imeAction="actionSearch"
- latin:isIconDefined="search_key"
>
<key-style
latin:styleName="enterKeyStyle"
- latin:keySpec="!icon/search_key|!code/key_enter"
- latin:backgroundType="action"
- latin:parentStyle="defaultEnterKeyStyle" />
- </case>
- <case
- latin:imeAction="actionSearch"
- >
- <key-style
- latin:styleName="enterKeyStyle"
- latin:keySpec="!text/label_search_key|!code/key_enter"
- latin:parentStyle="defaultEnterKeyStyle" />
+ latin:parentStyle="searchActionKeyStyle" />
</case>
<case
latin:imeAction="actionCustomLabel"
>
<key-style
latin:styleName="enterKeyStyle"
- latin:keySpec="dummy_label|!code/key_enter"
- latin:keyLabelFlags="fromCustomActionLabel"
- latin:parentStyle="defaultEnterKeyStyle" />
+ latin:parentStyle="customLabelActionKeyStyle" />
</case>
<!-- imeAction is either actionNone or actionUnspecified. -->
<default>
<key-style
latin:styleName="enterKeyStyle"
- latin:keySpec="!icon/enter_key|!code/key_enter"
latin:parentStyle="defaultEnterKeyStyle" />
</default>
</switch>
diff --git a/java/res/xml/key_styles_navigate_more_keys.xml b/java/res/xml/key_styles_navigate_more_keys.xml
new file mode 100644
index 000000000..f97114db9
--- /dev/null
+++ b/java/res/xml/key_styles_navigate_more_keys.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case latin:keyboardTheme="ICS|KLP">
+ <key-style
+ latin:styleName="navigateNextMoreKeysStyle"
+ latin:keyLabelFlags="hasPopupHint|preserveCase"
+ latin:moreKeys="!text/keyspec_action_next" />
+ <key-style
+ latin:styleName="navigatePreviousMoreKeysStyle"
+ latin:keyLabelFlags="hasPopupHint|preserveCase"
+ latin:moreKeys="!text/keyspec_action_previous" />
+ <key-style
+ latin:styleName="navigatePreviousNextMoreKeysStyle"
+ latin:keyLabelFlags="hasPopupHint|preserveCase"
+ latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_action_previous,!text/keyspec_action_next" />
+ <key-style
+ latin:styleName="navigateEmojiMoreKeysStyle"
+ latin:keyLabelFlags="hasPopupHint|preserveCase"
+ latin:moreKeys="!text/keyspec_emoji_action_key" />
+ <key-style
+ latin:styleName="navigateEmojiNextMoreKeysStyle"
+ latin:keyLabelFlags="hasPopupHint|preserveCase"
+ latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_emoji_action_key,!text/keyspec_action_next" />
+ <key-style
+ latin:styleName="navigateEmojiPreviousMoreKeysStyle"
+ latin:keyLabelFlags="hasPopupHint|preserveCase"
+ latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_emoji_action_key,!text/keyspec_action_previous" />
+ <key-style
+ latin:styleName="navigateEmojiPreviousNextMoreKeysStyle"
+ latin:keyLabelFlags="hasPopupHint|preserveCase"
+ latin:moreKeys="!fixedColumnOrder!3,!needsDividers!,!text/keyspec_emoji_action_key,!text/keyspec_action_previous,!text/keyspec_action_next" />
+ </case>
+ <default>
+ <key-style
+ latin:styleName="navigateNextMoreKeysStyle"
+ latin:keyLabelFlags="hasPopupHint|preserveCase"
+ latin:moreKeys="!icon/next_key|!code/key_action_next" />
+ <key-style
+ latin:styleName="navigatePreviousMoreKeysStyle"
+ latin:keyLabelFlags="hasPopupHint|preserveCase"
+ latin:moreKeys="!icon/previous_key|!code/key_action_previous" />
+ <key-style
+ latin:styleName="navigatePreviousNextMoreKeysStyle"
+ latin:keyLabelFlags="hasPopupHint|preserveCase"
+ latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!icon/previous_key|!code/key_action_previous,!icon/next_key|!code/key_action_next" />
+ <key-style
+ latin:styleName="navigateEmojiMoreKeysStyle"
+ latin:keyLabelFlags="hasPopupHint|preserveCase"
+ latin:moreKeys="!text/keyspec_emoji_action_key" />
+ <key-style
+ latin:styleName="navigateEmojiNextMoreKeysStyle"
+ latin:keyLabelFlags="hasPopupHint|preserveCase"
+ latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_emoji_action_key,!icon/next_key|!code/key_action_next" />
+ <key-style
+ latin:styleName="navigateEmojiPreviousMoreKeysStyle"
+ latin:keyLabelFlags="hasPopupHint|preserveCase"
+ latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_emoji_action_key,!icon/previous_key|!code/key_action_previous" />
+ <key-style
+ latin:styleName="navigateEmojiPreviousNextMoreKeysStyle"
+ latin:keyLabelFlags="hasPopupHint|preserveCase"
+ latin:moreKeys="!fixedColumnOrder!3,!needsDividers!,!text/keyspec_emoji_action_key,!icon/previous_key|!code/key_action_previous,!icon/next_key|!code/key_action_next" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/key_styles_number.xml b/java/res/xml/key_styles_number.xml
index df4448c25..97ae6c6c3 100644
--- a/java/res/xml/key_styles_number.xml
+++ b/java/res/xml/key_styles_number.xml
@@ -39,7 +39,7 @@
latin:parentStyle="numKeyBaseStyle" />
<key-style
latin:styleName="numberKeyStyle"
- latin:keyLabelFlags="alignLeftOfCenter|hasHintLabel"
+ latin:keyLabelFlags="alignLabelOffCenter|hasHintLabel"
latin:parentStyle="numKeyStyle" />
<key-style
latin:styleName="num0KeyStyle"
@@ -120,14 +120,27 @@
<key-style
latin:styleName="numSpaceKeyStyle"
latin:keySpec="!icon/space_key_for_number_layout|!code/key_space"
+ latin:keyLabelFlags="alignIconToBottom"
latin:keyActionFlags="enableLongPress"
latin:parentStyle="numKeyBaseStyle" />
- <!-- Override defaultEnterKeyStyle in key_styles_enter.xml -->
- <key-style
- latin:styleName="defaultEnterKeyStyle"
- latin:keySpec="!icon/enter_key|!code/key_enter"
- latin:keyLabelFlags="preserveCase|autoXScale|followKeyLargeLabelRatio"
- latin:keyActionFlags="noKeyPreview"
- latin:backgroundType="functional"
- latin:parentStyle="navigateMoreKeysStyle" />
+ <!-- TODO: Consolidate these space key styles with numSpaceKeyStyle above by introducing <case>
+ predicator that checks device form-factor. -->
+ <switch>
+ <case latin:keyboardTheme="ICS|KLP">
+ <key-style
+ latin:styleName="tabletNumSpaceKeyStyle"
+ latin:keySpec="!icon/space_key|!code/key_space"
+ latin:backgroundType="functional"
+ latin:keyActionFlags="enableLongPress"
+ latin:parentStyle="numKeyBaseStyle" />
+ </case>
+ <case latin:keyboardTheme="LXXLight|LXXDark">
+ <key-style
+ latin:styleName="tabletNumSpaceKeyStyle"
+ latin:keySpec="!icon/space_key|!code/key_space"
+ latin:backgroundType="spacebar"
+ latin:keyActionFlags="enableLongPress"
+ latin:parentStyle="numKeyBaseStyle" />
+ </case>
+ </switch>
</merge>
diff --git a/java/res/xml/key_styles_settings.xml b/java/res/xml/key_styles_settings.xml
index 956b40235..a504bed78 100644
--- a/java/res/xml/key_styles_settings.xml
+++ b/java/res/xml/key_styles_settings.xml
@@ -29,15 +29,17 @@
>
<key-style
latin:styleName="settingsMoreKeysStyle"
- latin:backgroundType="functional" />
+ latin:backgroundType="functional"
+ latin:parentStyle="baseSettingsMoreKeysStyle" />
</case>
<!-- clobberSettingsKey="false" -->
<default>
<key-style
latin:styleName="settingsMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint"
- latin:moreKeys="!text/keyspec_settings"
- latin:backgroundType="functional" />
+ latin:additionalMoreKeys="!text/keyspec_settings"
+ latin:backgroundType="functional"
+ latin:parentStyle="baseSettingsMoreKeysStyle" />
</default>
</switch>
</merge>
diff --git a/java/res/xml/keyboard_layout_set_bengali.xml b/java/res/xml/keyboard_layout_set_bengali.xml
index 6e40e6de4..de48a0ceb 100644
--- a/java/res/xml/keyboard_layout_set_bengali.xml
+++ b/java/res/xml/keyboard_layout_set_bengali.xml
@@ -20,6 +20,8 @@
<KeyboardLayoutSet
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <Feature
+ latin:supportedScript="bengali" />
<Element
latin:elementName="alphabet"
latin:elementKeyboard="@xml/kbd_bengali"
diff --git a/java/res/xml/keyboard_layout_set_hindi.xml b/java/res/xml/keyboard_layout_set_hindi.xml
index e850c7ebc..ee41b2ae7 100644
--- a/java/res/xml/keyboard_layout_set_hindi.xml
+++ b/java/res/xml/keyboard_layout_set_hindi.xml
@@ -20,6 +20,8 @@
<KeyboardLayoutSet
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <Feature
+ latin:supportedScript="devanagari" />
<Element
latin:elementName="alphabet"
latin:elementKeyboard="@xml/kbd_hindi"
diff --git a/java/res/xml/keyboard_layout_set_hindi_compact.xml b/java/res/xml/keyboard_layout_set_hindi_compact.xml
index 77d02fbbc..147b2993f 100644
--- a/java/res/xml/keyboard_layout_set_hindi_compact.xml
+++ b/java/res/xml/keyboard_layout_set_hindi_compact.xml
@@ -20,6 +20,8 @@
<KeyboardLayoutSet
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <Feature
+ latin:supportedScript="devanagari" />
<Element
latin:elementName="alphabet"
latin:elementKeyboard="@xml/kbd_hindi_compact"
diff --git a/java/res/xml/keyboard_layout_set_kannada.xml b/java/res/xml/keyboard_layout_set_kannada.xml
index 8dcf99657..14323e7ef 100644
--- a/java/res/xml/keyboard_layout_set_kannada.xml
+++ b/java/res/xml/keyboard_layout_set_kannada.xml
@@ -20,6 +20,8 @@
<KeyboardLayoutSet
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <Feature
+ latin:supportedScript="kannada" />
<Element
latin:elementName="alphabet"
latin:elementKeyboard="@xml/kbd_kannada"
diff --git a/java/res/xml/keyboard_layout_set_khmer.xml b/java/res/xml/keyboard_layout_set_khmer.xml
index 181f98b3d..752c8520a 100644
--- a/java/res/xml/keyboard_layout_set_khmer.xml
+++ b/java/res/xml/keyboard_layout_set_khmer.xml
@@ -20,6 +20,8 @@
<KeyboardLayoutSet
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <Feature
+ latin:supportedScript="khmer" />
<Element
latin:elementName="alphabet"
latin:elementKeyboard="@xml/kbd_khmer"
diff --git a/java/res/xml/keyboard_layout_set_lao.xml b/java/res/xml/keyboard_layout_set_lao.xml
index 2ffde45db..6285f87f9 100644
--- a/java/res/xml/keyboard_layout_set_lao.xml
+++ b/java/res/xml/keyboard_layout_set_lao.xml
@@ -20,6 +20,8 @@
<KeyboardLayoutSet
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <Feature
+ latin:supportedScript="lao" />
<Element
latin:elementName="alphabet"
latin:elementKeyboard="@xml/kbd_lao"
diff --git a/java/res/xml/keyboard_layout_set_malayalam.xml b/java/res/xml/keyboard_layout_set_malayalam.xml
index 14c76baf0..f6086f6cb 100644
--- a/java/res/xml/keyboard_layout_set_malayalam.xml
+++ b/java/res/xml/keyboard_layout_set_malayalam.xml
@@ -20,6 +20,8 @@
<KeyboardLayoutSet
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <Feature
+ latin:supportedScript="malayalam" />
<Element
latin:elementName="alphabet"
latin:elementKeyboard="@xml/kbd_malayalam"
diff --git a/java/res/xml/keyboard_layout_set_marathi.xml b/java/res/xml/keyboard_layout_set_marathi.xml
index e5c68e7ce..6aea17546 100644
--- a/java/res/xml/keyboard_layout_set_marathi.xml
+++ b/java/res/xml/keyboard_layout_set_marathi.xml
@@ -20,6 +20,8 @@
<KeyboardLayoutSet
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <Feature
+ latin:supportedScript="devanagari" />
<Element
latin:elementName="alphabet"
latin:elementKeyboard="@xml/kbd_marathi"
diff --git a/java/res/xml/keyboard_layout_set_myanmar.xml b/java/res/xml/keyboard_layout_set_myanmar.xml
index 5c823b263..5af8c064e 100644
--- a/java/res/xml/keyboard_layout_set_myanmar.xml
+++ b/java/res/xml/keyboard_layout_set_myanmar.xml
@@ -20,6 +20,8 @@
<KeyboardLayoutSet
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <Feature
+ latin:supportedScript="myanmar" />
<Element
latin:elementName="alphabet"
latin:elementKeyboard="@xml/kbd_myanmar"
diff --git a/java/res/xml/keyboard_layout_set_nepali_romanized.xml b/java/res/xml/keyboard_layout_set_nepali_romanized.xml
index fbbc6a5a0..5bad83537 100644
--- a/java/res/xml/keyboard_layout_set_nepali_romanized.xml
+++ b/java/res/xml/keyboard_layout_set_nepali_romanized.xml
@@ -20,6 +20,8 @@
<KeyboardLayoutSet
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <Feature
+ latin:supportedScript="devanagari" />
<Element
latin:elementName="alphabet"
latin:elementKeyboard="@xml/kbd_nepali_romanized"
diff --git a/java/res/xml/keyboard_layout_set_nepali_traditional.xml b/java/res/xml/keyboard_layout_set_nepali_traditional.xml
index 4a3b60153..6f11dee58 100644
--- a/java/res/xml/keyboard_layout_set_nepali_traditional.xml
+++ b/java/res/xml/keyboard_layout_set_nepali_traditional.xml
@@ -20,6 +20,8 @@
<KeyboardLayoutSet
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <Feature
+ latin:supportedScript="devanagari" />
<Element
latin:elementName="alphabet"
latin:elementKeyboard="@xml/kbd_nepali_traditional"
diff --git a/java/res/xml/keyboard_layout_set_sinhala.xml b/java/res/xml/keyboard_layout_set_sinhala.xml
index 8e6e619d2..1955d218f 100644
--- a/java/res/xml/keyboard_layout_set_sinhala.xml
+++ b/java/res/xml/keyboard_layout_set_sinhala.xml
@@ -20,6 +20,8 @@
<KeyboardLayoutSet
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <Feature
+ latin:supportedScript="sinhala" />
<Element
latin:elementName="alphabet"
latin:elementKeyboard="@xml/kbd_sinhala"
diff --git a/java/res/xml/keyboard_layout_set_tamil.xml b/java/res/xml/keyboard_layout_set_tamil.xml
index 5c0491505..27f4a3266 100644
--- a/java/res/xml/keyboard_layout_set_tamil.xml
+++ b/java/res/xml/keyboard_layout_set_tamil.xml
@@ -20,6 +20,8 @@
<KeyboardLayoutSet
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <Feature
+ latin:supportedScript="tamil" />
<Element
latin:elementName="alphabet"
latin:elementKeyboard="@xml/kbd_tamil"
diff --git a/java/res/xml/keyboard_layout_set_telugu.xml b/java/res/xml/keyboard_layout_set_telugu.xml
index aca47b9d9..2bf65bcbd 100644
--- a/java/res/xml/keyboard_layout_set_telugu.xml
+++ b/java/res/xml/keyboard_layout_set_telugu.xml
@@ -20,6 +20,8 @@
<KeyboardLayoutSet
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <Feature
+ latin:supportedScript="telugu" />
<Element
latin:elementName="alphabet"
latin:elementKeyboard="@xml/kbd_telugu"
diff --git a/java/res/xml/keyboard_layout_set_thai.xml b/java/res/xml/keyboard_layout_set_thai.xml
index b8f99971b..f69dfa6bd 100644
--- a/java/res/xml/keyboard_layout_set_thai.xml
+++ b/java/res/xml/keyboard_layout_set_thai.xml
@@ -20,6 +20,8 @@
<KeyboardLayoutSet
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <Feature
+ latin:supportedScript="thai" />
<Element
latin:elementName="alphabet"
latin:elementKeyboard="@xml/kbd_thai"
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index 5021f33ee..4f8efa8d6 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -28,7 +28,7 @@
be_BY: Belarusian (Belarus)/east_slavic
bg: Bulgarian/bulgarian
bg: Bulgarian/bulgarian_bds
- (bn_IN: Bengali (India)/bengali) # This is a preliminary keyboard layout.
+ bn_IN: Bengali (India)/bengali
ca: Catalan/spanish
cs: Czech/qwertz
da: Danish/nordic
@@ -51,7 +51,7 @@
fr_CH: French (Switzerland)/swiss
gl_ES: Galician (Spain)/spanish
hi: Hindi/hindi
- (hi: Hindi/hindi_compact) # This is a preliminary keyboard layout.
+ hi: Hindi/hindi_compact
hr: Croatian/qwertz
hu: Hungarian/qwertz
hy_AM: Armenian (Armenia) Phonetic/armenian_phonetic
@@ -63,15 +63,15 @@
ka_GE: Georgian (Georgia)/georgian
kk: Kazakh/east_slavic
km_KH: Khmer (Cambodia)/khmer
- (kn_IN: Kannada (India)/kannada) # This is a preliminary keyboard layout.
+ kn_IN: Kannada (India)/kannada
ky: Kyrgyz/east_slavic
lo_LA: Lao (Laos)/lao
lt: Lithuanian/qwerty
lv: Latvian/qwerty
mk: Macedonian/south_slavic
- (ml_IN: Malayalam (India)/malayalam) # This is a preliminary keyboard layout.
+ ml_IN: Malayalam (India)/malayalam
mn_MN: Mongolian (Mongolia)/mongolian
- (mr_IN: Marathi (India)/marathi) # This is a preliminary keyboard layout.
+ mr_IN: Marathi (India)/marathi
ms_MY: Malay (Malaysia)/qwerty
(my_MM: Myanmar (Myanmar)/myanmar) # This is a preliminary keyboard layout.
nb: Norwegian Bokmål/nordic
@@ -91,8 +91,10 @@
(sr-Latn: Serbian/qwerty) # not yet implemented.
sv: Swedish/nordic
sw: Swahili/qwerty
- (ta_IN: Tamil (India)/tamil) # This is a preliminary keyboard layout.
- (te_IN: Telugu (India)/telugu) # This is a preliminary keyboard layout.
+ ta_IN: Tamil (India)/tamil
+ (ta_LK: Tamil (Sri Lanka)/tamil) # Disabled in conjunction with si_LK.
+ ta_SG: Tamil (Singapore)/tamil
+ te_IN: Telugu (India)/telugu
th: Thai/thai
tl: Tagalog/spanish
tr: Turkish/qwerty
@@ -176,8 +178,6 @@
android:imeSubtypeExtraValue="KeyboardLayoutSet=bulgarian_bds,EmojiCapable"
android:isAsciiCapable="false"
/>
- <!-- TODO: This bengali keyboard is a preliminary layout.
- This isn't based on the final specification. -->
<subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0xbff5986c"
@@ -346,8 +346,6 @@
android:imeSubtypeExtraValue="KeyboardLayoutSet=hindi,EmojiCapable"
android:isAsciiCapable="false"
/>
- <!-- TODO: This hindi_compact keyboard is a preliminary layout.
- This isn't based on the final specification. -->
<subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic_compact"
android:subtypeId="0xe49c89a1"
@@ -446,8 +444,6 @@
android:imeSubtypeExtraValue="KeyboardLayoutSet=khmer,EmojiCapable"
android:isAsciiCapable="false"
/>
- <!-- TODO: This kannada keyboard is a preliminary layout.
- This isn't based on the final specification. -->
<subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x8c78064f"
@@ -496,8 +492,6 @@
android:imeSubtypeExtraValue="KeyboardLayoutSet=south_slavic,EmojiCapable"
android:isAsciiCapable="false"
/>
- <!-- TODO: This malayalam keyboard is a preliminary layout.
- This isn't based on the final specification. -->
<subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0xc182ebd4"
@@ -514,8 +508,6 @@
android:imeSubtypeExtraValue="KeyboardLayoutSet=mongolian,EmojiCapable"
android:isAsciiCapable="false"
/>
- <!-- TODO: This marathi keyboard is a preliminary layout.
- This isn't based on the final specification. -->
<subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x747b9f03"
@@ -534,6 +526,7 @@
/>
<!-- TODO: This Myanmar keyboard is a preliminary layout.
This isn't based on the final specification. -->
+ <!--
<subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0xea266ea4"
@@ -542,6 +535,7 @@
android:imeSubtypeExtraValue="KeyboardLayoutSet=myanmar,EmojiCapable,CombiningRules=MyanmarReordering"
android:isAsciiCapable="false"
/>
+ -->
<subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x3f12ee14"
@@ -622,8 +616,9 @@
android:imeSubtypeExtraValue="SupportTouchPositionCorrection,EmojiCapable"
android:isAsciiCapable="false"
/>
- <!-- TODO: This sinhala keyboard is a preliminary layout.
+ <!-- TODO: This Sinhala keyboard is a preliminary layout.
This isn't based on the final specification. -->
+ <!--
<subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x5c6b3bde"
@@ -632,6 +627,7 @@
android:imeSubtypeExtraValue="KeyboardLayoutSet=sinhala,EmojiCapable"
android:isAsciiCapable="false"
/>
+ -->
<subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x8e94d413"
@@ -690,8 +686,6 @@
android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable"
android:isAsciiCapable="true"
/>
- <!-- TODO: This tamil keyboard is a preliminary layout.
- This isn't based on the final specification. -->
<subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x67acea2a"
@@ -700,8 +694,25 @@
android:imeSubtypeExtraValue="KeyboardLayoutSet=tamil,EmojiCapable"
android:isAsciiCapable="false"
/>
- <!-- TODO: This telugu keyboard is a preliminary layout.
- This isn't based on the final specification. -->
+ <!-- TODO: Enable ta_LK subtype when si_LK subtype is ready -->
+ <!--
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
+ android:label="@string/subtype_generic"
+ android:subtypeId="0x6ca12d84"
+ android:imeSubtypeLocale="ta_LK"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=tamil,EmojiCapable"
+ android:isAsciiCapable="false"
+ />
+ -->
+ <subtype android:icon="@drawable/ic_ime_switcher_dark"
+ android:label="@string/subtype_generic"
+ android:subtypeId="0x785abbd9"
+ android:imeSubtypeLocale="ta_SG"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=tamil,EmojiCapable"
+ android:isAsciiCapable="false"
+ />
<subtype android:icon="@drawable/ic_ime_switcher_dark"
android:label="@string/subtype_generic"
android:subtypeId="0x1e177389"
diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml
index 6493d0cbd..c14cd645a 100644
--- a/java/res/xml/prefs.xml
+++ b/java/res/xml/prefs.xml
@@ -19,139 +19,27 @@
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
android:key="english_ime_settings">
<PreferenceScreen
- android:fragment="com.android.inputmethod.latin.settings.InputSettingsFragment"
- android:title="@string/settings_screen_input"
- android:key="screen_input" />
- <ListPreference
- android:key="pref_keyboard_theme"
- android:title="@string/keyboard_theme"
- android:entryValues="@array/keyboard_theme_ids"
- android:entries="@array/keyboard_theme_names"
- android:persistent="true" />
+ android:fragment="com.android.inputmethod.latin.settings.PreferencesSettingsFragment"
+ android:title="@string/settings_screen_preferences"
+ android:key="screen_preferences" />
+ <PreferenceScreen
+ android:fragment="com.android.inputmethod.latin.settings.AppearanceSettingsFragment"
+ android:title="@string/settings_screen_appearance"
+ android:key="screen_appearance" />
<PreferenceScreen
android:fragment="com.android.inputmethod.latin.settings.MultiLingualSettingsFragment"
- android:title="@string/settings_screen_multi_lingual"
- android:key="screen_multi_lingual" />
+ android:title="@string/settings_screen_multilingual"
+ android:key="screen_multilingual" />
<PreferenceScreen
+ android:fragment="com.android.inputmethod.latin.settings.GestureSettingsFragment"
android:title="@string/settings_screen_gesture"
- android:key="screen_gesture">
- <CheckBoxPreference
- android:key="gesture_input"
- android:title="@string/gesture_input"
- android:summary="@string/gesture_input_summary"
- android:defaultValue="true"
- android:persistent="true" />
- <CheckBoxPreference
- android:key="pref_gesture_floating_preview_text"
- android:dependency="gesture_input"
- android:title="@string/gesture_floating_preview_text"
- android:summary="@string/gesture_floating_preview_text_summary"
- android:defaultValue="true"
- android:persistent="true" />
- <CheckBoxPreference
- android:key="pref_gesture_preview_trail"
- android:dependency="gesture_input"
- android:title="@string/gesture_preview_trail"
- android:defaultValue="true"
- android:persistent="true" />
- <CheckBoxPreference
- android:key="pref_gesture_space_aware"
- android:dependency="gesture_input"
- android:title="@string/gesture_space_aware"
- android:summary="@string/gesture_space_aware_summary"
- android:defaultValue="true"
- android:persistent="true" />
- </PreferenceScreen>
+ android:key="screen_gesture" />
<PreferenceScreen
+ android:fragment="com.android.inputmethod.latin.settings.CorrectionSettingsFragment"
android:title="@string/settings_screen_correction"
- android:key="screen_correction">
- <PreferenceScreen
- android:key="edit_personal_dictionary"
- android:title="@string/edit_personal_dictionary">
- <intent android:action="android.settings.USER_DICTIONARY_SETTINGS" />
- </PreferenceScreen>
- <PreferenceScreen
- android:key="configure_dictionaries_key"
- android:title="@string/configure_dictionaries_title">
- <intent
- android:action="android.intent.action.MAIN"
- android:targetClass="@string/dictionary_pack_settings_activity">
- <extra
- android:name="clientId"
- android:value="@string/dictionary_pack_client_id" />
- </intent>
- </PreferenceScreen>
- <CheckBoxPreference
- android:key="pref_key_block_potentially_offensive"
- android:title="@string/prefs_block_potentially_offensive_title"
- android:summary="@string/prefs_block_potentially_offensive_summary"
- android:defaultValue="@bool/config_block_potentially_offensive"
- android:persistent="true" />
- <ListPreference
- android:key="auto_correction_threshold"
- android:title="@string/auto_correction"
- android:summary="@string/auto_correction_summary"
- android:entryValues="@array/auto_correction_threshold_mode_indexes"
- android:entries="@array/auto_correction_threshold_modes"
- android:defaultValue="@string/auto_correction_threshold_mode_index_modest"
- android:persistent="true" />
- <CheckBoxPreference
- android:key="show_suggestions"
- android:summary="@string/prefs_show_suggestions_summary"
- android:title="@string/prefs_show_suggestions"
- android:defaultValue="true"
- android:persistent="true" />
- <CheckBoxPreference
- android:key="pref_key_use_personalized_dicts"
- android:title="@string/use_personalized_dicts"
- android:summary="@string/use_personalized_dicts_summary"
- android:defaultValue="true"
- android:persistent="true" />
- <CheckBoxPreference
- android:key="pref_key_use_contacts_dict"
- android:title="@string/use_contacts_dict"
- android:summary="@string/use_contacts_dict_summary"
- android:defaultValue="true"
- android:persistent="true" />
- <CheckBoxPreference
- android:key="next_word_prediction"
- android:title="@string/bigram_prediction"
- android:summary="@string/bigram_prediction_summary"
- android:defaultValue="true"
- android:persistent="true" />
- </PreferenceScreen>
+ android:key="screen_correction" />
<PreferenceScreen
+ android:fragment="com.android.inputmethod.latin.settings.AdvancedSettingsFragment"
android:title="@string/settings_screen_advanced"
- android:key="screen_advanced">
- <!-- TODO: consolidate key preview dismiss delay with the key preview animation parameters. -->
- <ListPreference
- android:key="pref_key_preview_popup_dismiss_delay"
- android:title="@string/key_preview_popup_dismiss_delay" />
- <com.android.inputmethod.latin.settings.SeekBarDialogPreference
- android:key="pref_vibration_duration_settings"
- android:title="@string/prefs_keypress_vibration_duration_settings"
- latin:maxValue="@integer/config_max_vibration_duration" />
- <com.android.inputmethod.latin.settings.SeekBarDialogPreference
- android:key="pref_keypress_sound_volume"
- android:title="@string/prefs_keypress_sound_volume_settings"
- latin:maxValue="100" /> <!-- percent -->
- <!-- The settigs for showing setup wizard application icon shouldn't be persistent and
- the default value is added programmatically. -->
- <CheckBoxPreference
- android:key="pref_show_setup_wizard_icon"
- android:title="@string/show_setup_wizard_icon"
- android:summary="@string/show_setup_wizard_icon_summary" />
- <!-- title will be set programmatically to embed application name -->
- <CheckBoxPreference
- android:key="pref_enable_metrics_logging"
- android:summary="@string/enable_metrics_logging_summary"
- android:defaultValue="true"
- android:persistent="true" />
- <PreferenceScreen
- android:fragment="com.android.inputmethod.latin.settings.DebugSettings"
- android:key="screen_debug"
- android:title="Debug settings"
- android:defaultValue="false"
- android:persistent="true" />
- </PreferenceScreen>
+ android:key="screen_advanced" />
</PreferenceScreen>
diff --git a/java/res/xml/prefs_screen_advanced.xml b/java/res/xml/prefs_screen_advanced.xml
new file mode 100644
index 000000000..5aefcc8d5
--- /dev/null
+++ b/java/res/xml/prefs_screen_advanced.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ android:title="@string/settings_screen_advanced"
+ android:key="screen_advanced">
+ <!-- TODO: consolidate key preview dismiss delay with the key preview animation parameters. -->
+ <ListPreference
+ android:key="pref_key_preview_popup_dismiss_delay"
+ android:title="@string/key_preview_popup_dismiss_delay" />
+ <com.android.inputmethod.latin.settings.SeekBarDialogPreference
+ android:key="pref_vibration_duration_settings"
+ android:title="@string/prefs_keypress_vibration_duration_settings"
+ latin:maxValue="@integer/config_max_vibration_duration" />
+ <com.android.inputmethod.latin.settings.SeekBarDialogPreference
+ android:key="pref_keypress_sound_volume"
+ android:title="@string/prefs_keypress_sound_volume_settings"
+ latin:maxValue="100" /> <!-- percent -->
+ <!-- The settings for showing setup wizard application icon shouldn't be persistent and
+ the default value is added programmatically. -->
+ <CheckBoxPreference
+ android:key="pref_show_setup_wizard_icon"
+ android:title="@string/show_setup_wizard_icon"
+ android:summary="@string/show_setup_wizard_icon_summary" />
+ <!-- title will be set programmatically to embed application name -->
+ <CheckBoxPreference
+ android:key="pref_enable_metrics_logging"
+ android:summary="@string/enable_metrics_logging_summary"
+ android:defaultValue="true"
+ android:persistent="true" />
+ <PreferenceScreen
+ android:fragment="com.android.inputmethod.latin.settings.DebugSettingsFragment"
+ android:key="screen_debug"
+ android:title="Debug settings"
+ android:defaultValue="false"
+ android:persistent="true" />
+</PreferenceScreen>
diff --git a/java/res/xml/prefs_screen_appearance.xml b/java/res/xml/prefs_screen_appearance.xml
new file mode 100644
index 000000000..7719c058b
--- /dev/null
+++ b/java/res/xml/prefs_screen_appearance.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:key="screen_appearance"
+ android:title="@string/settings_screen_appearance">
+ <PreferenceScreen
+ android:fragment="com.android.inputmethod.latin.settings.ThemeSettingsFragment"
+ android:key="screen_theme"
+ android:title="@string/settings_screen_theme" />
+ <PreferenceScreen
+ android:fragment="com.android.inputmethod.latin.settings.CustomInputStyleSettingsFragment"
+ android:key="custom_input_styles"
+ android:title="@string/custom_input_styles_title" />
+</PreferenceScreen>
diff --git a/java/res/xml/prefs_screen_correction.xml b/java/res/xml/prefs_screen_correction.xml
new file mode 100644
index 000000000..dd5ba540c
--- /dev/null
+++ b/java/res/xml/prefs_screen_correction.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ android:title="@string/settings_screen_correction"
+ android:key="screen_correction">
+ <PreferenceScreen
+ android:key="edit_personal_dictionary"
+ android:title="@string/edit_personal_dictionary">
+ <intent android:action="android.settings.USER_DICTIONARY_SETTINGS" />
+ </PreferenceScreen>
+ <PreferenceScreen
+ android:key="configure_dictionaries_key"
+ android:title="@string/configure_dictionaries_title">
+ <intent
+ android:action="android.intent.action.MAIN"
+ android:targetClass="@string/dictionary_pack_settings_activity">
+ <extra
+ android:name="clientId"
+ android:value="@string/dictionary_pack_client_id" />
+ </intent>
+ </PreferenceScreen>
+ <CheckBoxPreference
+ android:key="pref_key_block_potentially_offensive"
+ android:title="@string/prefs_block_potentially_offensive_title"
+ android:summary="@string/prefs_block_potentially_offensive_summary"
+ android:defaultValue="@bool/config_block_potentially_offensive"
+ android:persistent="true" />
+ <ListPreference
+ android:key="auto_correction_threshold"
+ android:title="@string/auto_correction"
+ android:summary="@string/auto_correction_summary"
+ android:entryValues="@array/auto_correction_threshold_mode_indexes"
+ android:entries="@array/auto_correction_threshold_modes"
+ android:defaultValue="@string/auto_correction_threshold_mode_index_modest"
+ android:persistent="true" />
+ <CheckBoxPreference
+ android:key="show_suggestions"
+ android:summary="@string/prefs_show_suggestions_summary"
+ android:title="@string/prefs_show_suggestions"
+ android:defaultValue="true"
+ android:persistent="true" />
+ <CheckBoxPreference
+ android:key="pref_key_use_personalized_dicts"
+ android:title="@string/use_personalized_dicts"
+ android:summary="@string/use_personalized_dicts_summary"
+ android:defaultValue="true"
+ android:persistent="true" />
+ <CheckBoxPreference
+ android:key="pref_key_use_contacts_dict"
+ android:title="@string/use_contacts_dict"
+ android:summary="@string/use_contacts_dict_summary"
+ android:defaultValue="true"
+ android:persistent="true" />
+ <CheckBoxPreference
+ android:key="next_word_prediction"
+ android:title="@string/bigram_prediction"
+ android:summary="@string/bigram_prediction_summary"
+ android:defaultValue="true"
+ android:persistent="true" />
+</PreferenceScreen>
diff --git a/java/res/xml/prefs_screen_debug.xml b/java/res/xml/prefs_screen_debug.xml
index ae29a8a82..c47740268 100644
--- a/java/res/xml/prefs_screen_debug.xml
+++ b/java/res/xml/prefs_screen_debug.xml
@@ -31,6 +31,16 @@
android:defaultValue="false"
android:persistent="true" />
<CheckBoxPreference
+ android:key="force_physical_keyboard_special_key"
+ android:title="@string/prefs_force_physical_keyboard_special_key"
+ android:defaultValue="false"
+ android:persistent="true" />
+ <CheckBoxPreference
+ android:key="pref_show_ui_to_accept_typed_word"
+ android:title="@string/prefs_show_ui_to_accept_typed_word"
+ android:defaultValue="true"
+ android:persistent="true" />
+ <CheckBoxPreference
android:key="pref_sliding_key_input_preview"
android:title="@string/sliding_key_input_preview"
android:summary="@string/sliding_key_input_preview_summary"
@@ -42,19 +52,38 @@
latin:minValue="@integer/config_min_longpress_timeout"
latin:maxValue="@integer/config_max_longpress_timeout"
latin:stepValue="@integer/config_longpress_timeout_step" />
+ <CheckBoxPreference
+ android:key="pref_has_custom_key_preview_animation_params"
+ android:title="@string/prefs_customize_key_preview_animation"
+ android:defaultValue="false"
+ android:persistent="true" />
+ <com.android.inputmethod.latin.settings.SeekBarDialogPreference
+ android:dependency="pref_has_custom_key_preview_animation_params"
+ android:key="pref_key_preview_show_up_start_x_scale"
+ android:title="@string/prefs_key_popup_show_up_start_x_scale_settings"
+ latin:maxValue="100" /> <!-- percent -->
+ <com.android.inputmethod.latin.settings.SeekBarDialogPreference
+ android:dependency="pref_has_custom_key_preview_animation_params"
+ android:key="pref_key_preview_show_up_start_y_scale"
+ android:title="@string/prefs_key_popup_show_up_start_y_scale_settings"
+ latin:maxValue="100" /> <!-- percent -->
<com.android.inputmethod.latin.settings.SeekBarDialogPreference
- android:key="pref_key_preview_show_up_start_scale"
- android:title="@string/prefs_key_popup_show_up_start_scale_settings"
+ android:dependency="pref_has_custom_key_preview_animation_params"
+ android:key="pref_key_preview_dismiss_end_x_scale"
+ android:title="@string/prefs_key_popup_dismiss_end_x_scale_settings"
latin:maxValue="100" /> <!-- percent -->
<com.android.inputmethod.latin.settings.SeekBarDialogPreference
- android:key="pref_key_preview_dismiss_end_scale"
- android:title="@string/prefs_key_popup_dismiss_end_scale_settings"
+ android:dependency="pref_has_custom_key_preview_animation_params"
+ android:key="pref_key_preview_dismiss_end_y_scale"
+ android:title="@string/prefs_key_popup_dismiss_end_y_scale_settings"
latin:maxValue="100" /> <!-- percent -->
<com.android.inputmethod.latin.settings.SeekBarDialogPreference
+ android:dependency="pref_has_custom_key_preview_animation_params"
android:key="pref_key_preview_show_up_duration"
android:title="@string/prefs_key_popup_show_up_duration_settings"
latin:maxValue="100" /> <!-- milliseconds -->
<com.android.inputmethod.latin.settings.SeekBarDialogPreference
+ android:dependency="pref_has_custom_key_preview_animation_params"
android:key="pref_key_preview_dismiss_duration"
android:title="@string/prefs_key_popup_dismiss_duration_settings"
latin:maxValue="100" /> <!-- milliseconds -->
diff --git a/java/res/xml/prefs_screen_gesture.xml b/java/res/xml/prefs_screen_gesture.xml
new file mode 100644
index 000000000..c87316dfa
--- /dev/null
+++ b/java/res/xml/prefs_screen_gesture.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:title="@string/settings_screen_gesture"
+ android:key="screen_gesture">
+ <CheckBoxPreference
+ android:key="gesture_input"
+ android:title="@string/gesture_input"
+ android:summary="@string/gesture_input_summary"
+ android:defaultValue="true"
+ android:persistent="true" />
+ <CheckBoxPreference
+ android:key="pref_gesture_floating_preview_text"
+ android:dependency="gesture_input"
+ android:title="@string/gesture_floating_preview_text"
+ android:summary="@string/gesture_floating_preview_text_summary"
+ android:defaultValue="true"
+ android:persistent="true" />
+ <CheckBoxPreference
+ android:key="pref_gesture_preview_trail"
+ android:dependency="gesture_input"
+ android:title="@string/gesture_preview_trail"
+ android:defaultValue="true"
+ android:persistent="true" />
+ <CheckBoxPreference
+ android:key="pref_gesture_space_aware"
+ android:dependency="gesture_input"
+ android:title="@string/gesture_space_aware"
+ android:summary="@string/gesture_space_aware_summary"
+ android:defaultValue="true"
+ android:persistent="true" />
+</PreferenceScreen>
diff --git a/java/res/xml/prefs_screen_multi_lingual.xml b/java/res/xml/prefs_screen_multilingual.xml
index 937d439d6..07a4b701c 100644
--- a/java/res/xml/prefs_screen_multi_lingual.xml
+++ b/java/res/xml/prefs_screen_multilingual.xml
@@ -16,8 +16,8 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
- android:title="@string/settings_screen_multi_lingual"
- android:key="screen_multi_lingual">
+ android:title="@string/settings_screen_multilingual"
+ android:key="screen_multilingual">
<CheckBoxPreference
android:key="pref_show_language_switch_key"
android:title="@string/show_language_switch_key"
@@ -31,8 +31,4 @@
android:summary="@string/include_other_imes_in_language_switch_list_summary"
android:defaultValue="false"
android:persistent="true" />
- <PreferenceScreen
- android:fragment="com.android.inputmethod.latin.settings.CustomInputStyleSettingsFragment"
- android:key="custom_input_styles"
- android:title="@string/custom_input_styles_title" />
</PreferenceScreen>
diff --git a/java/res/xml/prefs_screen_input.xml b/java/res/xml/prefs_screen_preferences.xml
index 7704e3f80..101edc855 100644
--- a/java/res/xml/prefs_screen_input.xml
+++ b/java/res/xml/prefs_screen_preferences.xml
@@ -17,7 +17,7 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
- android:title="@string/settings_screen_input">
+ android:title="@string/settings_screen_preferences">
<CheckBoxPreference
android:key="auto_cap"
android:title="@string/auto_cap"
diff --git a/java/res/xml/prefs_screen_theme.xml b/java/res/xml/prefs_screen_theme.xml
new file mode 100644
index 000000000..677a6ea3b
--- /dev/null
+++ b/java/res/xml/prefs_screen_theme.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ android:title="@string/settings_screen_theme"
+ android:key="screen_theme">
+ <!-- Keyboard theme list will be populated programmatically here. -->
+</PreferenceScreen>
diff --git a/java/res/xml/row_dvorak4.xml b/java/res/xml/row_dvorak4.xml
deleted file mode 100644
index e7a3ee736..000000000
--- a/java/res/xml/row_dvorak4.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"
->
- <Row
- latin:keyWidth="10%p"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyWidth="15%p" />
- <Key
- latin:keySpec="q"
- latin:backgroundType="normal"
- latin:keyStyle="settingsMoreKeysStyle" />
- <include
- latin:keyXPos="25%p"
- latin:keyboardLayout="@xml/key_space_5kw" />
- <Key
- latin:keySpec="z"
- latin:keyLabelFlags="hasPopupHint"
- latin:moreKeys="!text/morekeys_punctuation,!text/morekeys_z" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
- </Row>
-</merge>
diff --git a/java/res/xml/row_qwerty4.xml b/java/res/xml/row_qwerty4.xml
index 509092d96..5bc104f69 100644
--- a/java/res/xml/row_qwerty4.xml
+++ b/java/res/xml/row_qwerty4.xml
@@ -28,7 +28,7 @@
latin:keyStyle="toSymbolKeyStyle"
latin:keyWidth="15%p" />
<include
- latin:keyboardLayout="@xml/key_f1" />
+ latin:keyboardLayout="@xml/key_comma" />
<include
latin:keyXPos="25%p"
latin:keyboardLayout="@xml/key_space_5kw" />
diff --git a/java/res/xml/rowkeys_kannada3.xml b/java/res/xml/rowkeys_kannada3.xml
index 0f1aecbac..03fa05551 100644
--- a/java/res/xml/rowkeys_kannada3.xml
+++ b/java/res/xml/rowkeys_kannada3.xml
@@ -29,13 +29,12 @@
<Key
latin:keySpec="&#x0C82;"
latin:moreKeys="&#x0C8E;" />
- <!-- U+0CAE: "ಮ" KANNADA LETTER MA
+ <!-- U+0CAE: "ಮ" KANNADA LETTER MA -->
+ <Key latin:keySpec="&#x0CAE;" />
+ <!-- U+0CA8: "ನ" KANNADA LETTER NA
U+0CA3: "ಣ" KANNADA LETTER NNA -->
- <Key
- latin:keySpec="&#x0CAE;"
+ <Key latin:keySpec="&#x0CA8;"
latin:moreKeys="&#x0CA3;" />
- <!-- U+0CA8: "ನ" KANNADA LETTER NA -->
- <Key latin:keySpec="&#x0CA8;" />
<!-- U+0CB5: "ವ" KANNADA LETTER VA -->
<Key latin:keySpec="&#x0CB5;" />
<!-- U+0CB2: "ಲ" KANNADA LETTER LA
diff --git a/java/res/xml/rowkeys_tamil1.xml b/java/res/xml/rowkeys_tamil1.xml
index 4debd9e3e..d6a5cfaf9 100644
--- a/java/res/xml/rowkeys_tamil1.xml
+++ b/java/res/xml/rowkeys_tamil1.xml
@@ -19,29 +19,39 @@
-->
<merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
- <!-- U+0B94: "ஔ" TAMIL LETTER AU -->
+ <!-- U+0B94: "ஔ" TAMIL LETTER AU
+ U+0BCC: "ௌ" TAMIL VOWEL SIGN AU -->
<Key
latin:keySpec="&#x0B94;"
+ latin:moreKeys="&#x0BCC;,%"
latin:keyHintLabel="1"
latin:additionalMoreKeys="1" />
- <!-- U+0B90: "ஐ" TAMIL LETTER AI -->
+ <!-- U+0B90: "ஐ" TAMIL LETTER AI
+ U+0BC8: "ை" TAMIL VOWEL SIGN AI -->
<Key
latin:keySpec="&#x0B90;"
+ latin:moreKeys="&#x0BC8;,%"
latin:keyHintLabel="2"
latin:additionalMoreKeys="2" />
- <!-- U+0B86: "ஆ" TAMIL LETTER AA -->
+ <!-- U+0B86: "ஆ" TAMIL LETTER AA
+ U+0BBE: "ா" TAMIL VOWEL SIGN AA -->
<Key
latin:keySpec="&#x0B86;"
+ latin:moreKeys="&#x0BBE;,%"
latin:keyHintLabel="3"
latin:additionalMoreKeys="3" />
- <!-- U+0B88: "ஈ" TAMIL LETTER II -->
+ <!-- U+0B88: "ஈ" TAMIL LETTER II
+ U+0BC0: "ீ" TAMIL VOWEL SIGN II -->
<Key
latin:keySpec="&#x0B88;"
+ latin:moreKeys="&#x0BC0;,%"
latin:keyHintLabel="4"
latin:additionalMoreKeys="4" />
- <!-- U+0B8A: "ஊ" TAMIL LETTER UU -->
+ <!-- U+0B8A: "ஊ" TAMIL LETTER UU
+ U+0BC2: "ூ" TAMIL VOWEL SIGN UU -->
<Key
latin:keySpec="&#x0B8A;"
+ latin:moreKeys="&#x0BC2;,%"
latin:keyHintLabel="5"
latin:additionalMoreKeys="5" />
<!-- U+0BAE: "ம" TAMIL LETTER MA -->
diff --git a/java/res/xml/rowkeys_tamil2.xml b/java/res/xml/rowkeys_tamil2.xml
index 894825cb4..ec0b2a83c 100644
--- a/java/res/xml/rowkeys_tamil2.xml
+++ b/java/res/xml/rowkeys_tamil2.xml
@@ -20,21 +20,31 @@
<merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
<!-- U+0B93: "ஓ" TAMIL LETTER OO
+ U+0BCB: "ோ" TAMIL VOWEL SIGN OO
U+0BD0: "ௐ" TAMIL OM -->
<Key
latin:keySpec="&#x0B93;"
- latin:moreKeys="&#x0BD0;" />
- <!-- U+0B8F: "ஏ" TAMIL LETTER EE -->
- <Key latin:keySpec="&#x0B8F;" />
+ latin:moreKeys="&#x0BCB;,&#x0BD0;" />
+ <!-- U+0B8F: "ஏ" TAMIL LETTER EE
+ U+0BC7: "ே" TAMIL VOWEL SIGN EE -->
+ <Key
+ latin:keySpec="&#x0B8F;"
+ latin:moreKeys="&#x0BC7;" />
<!-- U+0B85: "அ" TAMIL LETTER A
U+0B83: "ஃ" TAMIL SIGN VISARGA -->
<Key
latin:keySpec="&#x0B85;"
latin:moreKeys="&#x0B83;" />
- <!-- U+0B87: "இ" TAMIL LETTER I -->
- <Key latin:keySpec="&#x0B87;" />
- <!-- U+0B89: "உ" TAMIL LETTER U -->
- <Key latin:keySpec="&#x0B89;" />
+ <!-- U+0B87: "இ" TAMIL LETTER I
+ U+0BBF: "ி" TAMIL VOWEL SIGN I -->
+ <Key
+ latin:keySpec="&#x0B87;"
+ latin:moreKeys="&#x0BBF;" />
+ <!-- U+0B89: "உ" TAMIL LETTER U
+ U+0BC1: "ு" TAMIL VOWEL SIGN U -->
+ <Key
+ latin:keySpec="&#x0B89;"
+ latin:moreKeys="&#x0BC1;" />
<!-- U+0BB1: "ற" TAMIL LETTER RRA -->
<Key latin:keySpec="&#x0BB1;" />
<!-- U+0BAA: "ப" TAMIL LETTER PA -->
diff --git a/java/res/xml/rowkeys_tamil3.xml b/java/res/xml/rowkeys_tamil3.xml
index 5386e61cf..e517e142b 100644
--- a/java/res/xml/rowkeys_tamil3.xml
+++ b/java/res/xml/rowkeys_tamil3.xml
@@ -19,10 +19,16 @@
-->
<merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
- <!-- U+0B92: "ஒ" TAMIL LETTER O -->
- <Key latin:keySpec="&#x0B92;" />
- <!-- U+0B8E: "எ" TAMIL LETTER E -->
- <Key latin:keySpec="&#x0B8E;" />
+ <!-- U+0B92: "ஒ" TAMIL LETTER O
+ U+0BCA: "ொ" TAMIL VOWEL SIGN O -->
+ <Key
+ latin:keySpec="&#x0B92;"
+ latin:moreKeys="&#x0BCA;" />
+ <!-- U+0B8E: "எ" TAMIL LETTER E
+ U+0BC6: "ெ" TAMIL VOWEL SIGN E -->
+ <Key
+ latin:keySpec="&#x0B8E;"
+ latin:moreKeys="&#x0BC6;" />
<!-- U+0BCD: "்" TAMIL SIGN VIRAMA -->
<Key latin:keySpec="&#x0BCD;" />
<!-- U+0BB0: "ர" TAMIL LETTER RA -->
diff --git a/java/res/xml/rows_dvorak.xml b/java/res/xml/rows_dvorak.xml
index 13d70210d..f656613ec 100644
--- a/java/res/xml/rows_dvorak.xml
+++ b/java/res/xml/rows_dvorak.xml
@@ -49,6 +49,8 @@
latin:keyWidth="fillRight"
latin:visualInsetsLeft="1%p" />
</Row>
+ <!-- Dvorak layout shares almost the same row with Qwerty layout.
+ The difference is defined in xml/row_qwerty4.xml. -->
<include
- latin:keyboardLayout="@xml/row_dvorak4" />
+ latin:keyboardLayout="@xml/row_qwerty4" />
</merge>
diff --git a/java/src/com/android/inputmethod/compat/BuildCompatUtils.java b/java/src/com/android/inputmethod/compat/BuildCompatUtils.java
new file mode 100644
index 000000000..7d1717bd1
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/BuildCompatUtils.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.compat;
+
+import android.os.Build;
+
+public final class BuildCompatUtils {
+ private BuildCompatUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ private static final boolean IS_RELEASE_BUILD = Build.VERSION.CODENAME.equals("REL");
+
+ /**
+ * The "effective" API version.
+ * {@link android.os.Build.VERSION#SDK_INT} if the platform is a release build.
+ * {@link android.os.Build.VERSION#SDK_INT} plus 1 if the platform is a development build.
+ */
+ public static final int EFFECTIVE_SDK_INT = IS_RELEASE_BUILD
+ ? Build.VERSION.SDK_INT
+ : Build.VERSION.SDK_INT + 1;
+
+ /**
+ * API version for L-release.
+ */
+ // TODO: Substitute this constant reference with Build.VERSION_CODES.L* once the *next* version
+ // becomes available.
+ public static final int VERSION_CODES_LXX = 21;
+}
diff --git a/java/src/com/android/inputmethod/compat/CompatUtils.java b/java/src/com/android/inputmethod/compat/CompatUtils.java
index 660029baf..6aa2736c1 100644
--- a/java/src/com/android/inputmethod/compat/CompatUtils.java
+++ b/java/src/com/android/inputmethod/compat/CompatUtils.java
@@ -21,6 +21,7 @@ import android.util.Log;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public final class CompatUtils {
@@ -33,31 +34,31 @@ public final class CompatUtils {
public static Class<?> getClass(final String className) {
try {
return Class.forName(className);
- } catch (ClassNotFoundException e) {
+ } catch (final ClassNotFoundException e) {
return null;
}
}
public static Method getMethod(final Class<?> targetClass, final String name,
final Class<?>... parameterTypes) {
- if (targetClass == null || TextUtils.isEmpty(name)) return null;
+ if (targetClass == null || TextUtils.isEmpty(name)) {
+ return null;
+ }
try {
return targetClass.getMethod(name, parameterTypes);
- } catch (SecurityException e) {
- // ignore
- } catch (NoSuchMethodException e) {
+ } catch (final SecurityException | NoSuchMethodException e) {
// ignore
}
return null;
}
public static Field getField(final Class<?> targetClass, final String name) {
- if (targetClass == null || TextUtils.isEmpty(name)) return null;
+ if (targetClass == null || TextUtils.isEmpty(name)) {
+ return null;
+ }
try {
return targetClass.getField(name);
- } catch (SecurityException e) {
- // ignore
- } catch (NoSuchFieldException e) {
+ } catch (final SecurityException | NoSuchFieldException e) {
// ignore
}
return null;
@@ -65,22 +66,25 @@ public final class CompatUtils {
public static Constructor<?> getConstructor(final Class<?> targetClass,
final Class<?> ... types) {
- if (targetClass == null || types == null) return null;
+ if (targetClass == null || types == null) {
+ return null;
+ }
try {
return targetClass.getConstructor(types);
- } catch (SecurityException e) {
- // ignore
- } catch (NoSuchMethodException e) {
+ } catch (final SecurityException | NoSuchMethodException e) {
// ignore
}
return null;
}
public static Object newInstance(final Constructor<?> constructor, final Object ... args) {
- if (constructor == null) return null;
+ if (constructor == null) {
+ return null;
+ }
try {
return constructor.newInstance(args);
- } catch (Exception e) {
+ } catch (final InstantiationException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e) {
Log.e(TAG, "Exception in newInstance", e);
}
return null;
@@ -88,10 +92,13 @@ public final class CompatUtils {
public static Object invoke(final Object receiver, final Object defaultValue,
final Method method, final Object... args) {
- if (method == null) return defaultValue;
+ if (method == null) {
+ return defaultValue;
+ }
try {
return method.invoke(receiver, args);
- } catch (Exception e) {
+ } catch (final IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e) {
Log.e(TAG, "Exception in invoke", e);
}
return defaultValue;
@@ -99,21 +106,113 @@ public final class CompatUtils {
public static Object getFieldValue(final Object receiver, final Object defaultValue,
final Field field) {
- if (field == null) return defaultValue;
+ if (field == null) {
+ return defaultValue;
+ }
try {
return field.get(receiver);
- } catch (Exception e) {
+ } catch (final IllegalAccessException | IllegalArgumentException e) {
Log.e(TAG, "Exception in getFieldValue", e);
}
return defaultValue;
}
public static void setFieldValue(final Object receiver, final Field field, final Object value) {
- if (field == null) return;
+ if (field == null) {
+ return;
+ }
try {
field.set(receiver, value);
- } catch (Exception e) {
+ } catch (final IllegalAccessException | IllegalArgumentException e) {
Log.e(TAG, "Exception in setFieldValue", e);
}
}
+
+ public static ClassWrapper getClassWrapper(final String className) {
+ return new ClassWrapper(getClass(className));
+ }
+
+ public static final class ClassWrapper {
+ private final Class<?> mClass;
+ public ClassWrapper(final Class<?> targetClass) {
+ mClass = targetClass;
+ }
+
+ public boolean exists() {
+ return mClass != null;
+ }
+
+ public <T> ToObjectMethodWrapper<T> getMethod(final String name,
+ final T defaultValue, final Class<?>... parameterTypes) {
+ return new ToObjectMethodWrapper<T>(CompatUtils.getMethod(mClass, name, parameterTypes),
+ defaultValue);
+ }
+
+ public ToIntMethodWrapper getPrimitiveMethod(final String name, final int defaultValue,
+ final Class<?>... parameterTypes) {
+ return new ToIntMethodWrapper(CompatUtils.getMethod(mClass, name, parameterTypes),
+ defaultValue);
+ }
+
+ public ToFloatMethodWrapper getPrimitiveMethod(final String name, final float defaultValue,
+ final Class<?>... parameterTypes) {
+ return new ToFloatMethodWrapper(CompatUtils.getMethod(mClass, name, parameterTypes),
+ defaultValue);
+ }
+
+ public ToBooleanMethodWrapper getPrimitiveMethod(final String name,
+ final boolean defaultValue, final Class<?>... parameterTypes) {
+ return new ToBooleanMethodWrapper(CompatUtils.getMethod(mClass, name, parameterTypes),
+ defaultValue);
+ }
+ }
+
+ public static final class ToObjectMethodWrapper<T> {
+ private final Method mMethod;
+ private final T mDefaultValue;
+ public ToObjectMethodWrapper(final Method method, final T defaultValue) {
+ mMethod = method;
+ mDefaultValue = defaultValue;
+ }
+ @SuppressWarnings("unchecked")
+ public T invoke(final Object receiver, final Object... args) {
+ return (T) CompatUtils.invoke(receiver, mDefaultValue, mMethod, args);
+ }
+ }
+
+ public static final class ToIntMethodWrapper {
+ private final Method mMethod;
+ private final int mDefaultValue;
+ public ToIntMethodWrapper(final Method method, final int defaultValue) {
+ mMethod = method;
+ mDefaultValue = defaultValue;
+ }
+ public int invoke(final Object receiver, final Object... args) {
+ return (int) CompatUtils.invoke(receiver, mDefaultValue, mMethod, args);
+ }
+ }
+
+ public static final class ToFloatMethodWrapper {
+ private final Method mMethod;
+ private final float mDefaultValue;
+ public ToFloatMethodWrapper(final Method method, final float defaultValue) {
+ mMethod = method;
+ mDefaultValue = defaultValue;
+ }
+ public float invoke(final Object receiver, final Object... args) {
+ return (float) CompatUtils.invoke(receiver, mDefaultValue, mMethod, args);
+ }
+ }
+
+ public static final class ToBooleanMethodWrapper {
+ private final Method mMethod;
+ private final boolean mDefaultValue;
+ public ToBooleanMethodWrapper(final Method method, final boolean defaultValue) {
+ mMethod = method;
+ mDefaultValue = defaultValue;
+ }
+ public boolean invoke(final Object receiver, final Object... args) {
+ return (boolean) CompatUtils.invoke(receiver, mDefaultValue, mMethod, args);
+ }
+ }
}
diff --git a/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java b/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java
new file mode 100644
index 000000000..5af31795c
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.compat;
+
+import android.graphics.Matrix;
+import android.graphics.RectF;
+
+import com.android.inputmethod.annotations.UsedForTesting;
+
+@UsedForTesting
+public final class CursorAnchorInfoCompatWrapper {
+
+ /**
+ * The insertion marker or character bounds have at least one visible region.
+ */
+ public static final int FLAG_HAS_VISIBLE_REGION = 0x01;
+
+ /**
+ * The insertion marker or character bounds have at least one invisible (clipped) region.
+ */
+ public static final int FLAG_HAS_INVISIBLE_REGION = 0x02;
+
+ /**
+ * The insertion marker or character bounds is placed at right-to-left (RTL) character.
+ */
+ public static final int FLAG_IS_RTL = 0x04;
+
+ // Note that CursorAnchorInfo has been introduced in API level XX (Build.VERSION_CODE.LXX).
+ private static final CompatUtils.ClassWrapper sCursorAnchorInfoClass;
+ private static final CompatUtils.ToIntMethodWrapper sGetSelectionStartMethod;
+ private static final CompatUtils.ToIntMethodWrapper sGetSelectionEndMethod;
+ private static final CompatUtils.ToObjectMethodWrapper<RectF> sGetCharacterBoundsMethod;
+ private static final CompatUtils.ToIntMethodWrapper sGetCharacterBoundsFlagsMethod;
+ private static final CompatUtils.ToObjectMethodWrapper<CharSequence> sGetComposingTextMethod;
+ private static final CompatUtils.ToIntMethodWrapper sGetComposingTextStartMethod;
+ private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerBaselineMethod;
+ private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerBottomMethod;
+ private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerHorizontalMethod;
+ private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerTopMethod;
+ private static final CompatUtils.ToObjectMethodWrapper<Matrix> sGetMatrixMethod;
+ private static final CompatUtils.ToIntMethodWrapper sGetInsertionMarkerFlagsMethod;
+
+ private static int INVALID_TEXT_INDEX = -1;
+ static {
+ sCursorAnchorInfoClass = CompatUtils.getClassWrapper(
+ "android.view.inputmethod.CursorAnchorInfo");
+ sGetSelectionStartMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
+ "getSelectionStart", INVALID_TEXT_INDEX);
+ sGetSelectionEndMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
+ "getSelectionEnd", INVALID_TEXT_INDEX);
+ sGetCharacterBoundsMethod = sCursorAnchorInfoClass.getMethod(
+ "getCharacterBounds", (RectF)null, int.class);
+ sGetCharacterBoundsFlagsMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
+ "getCharacterBoundsFlags", 0, int.class);
+ sGetComposingTextMethod = sCursorAnchorInfoClass.getMethod(
+ "getComposingText", (CharSequence)null);
+ sGetComposingTextStartMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
+ "getComposingTextStart", INVALID_TEXT_INDEX);
+ sGetInsertionMarkerBaselineMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
+ "getInsertionMarkerBaseline", 0.0f);
+ sGetInsertionMarkerBottomMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
+ "getInsertionMarkerBottom", 0.0f);
+ sGetInsertionMarkerHorizontalMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
+ "getInsertionMarkerHorizontal", 0.0f);
+ sGetInsertionMarkerTopMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
+ "getInsertionMarkerTop", 0.0f);
+ sGetMatrixMethod = sCursorAnchorInfoClass.getMethod("getMatrix", (Matrix)null);
+ sGetInsertionMarkerFlagsMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
+ "getInsertionMarkerFlags", 0);
+ }
+
+ @UsedForTesting
+ public boolean isAvailable() {
+ return sCursorAnchorInfoClass.exists() && mInstance != null;
+ }
+
+ private Object mInstance;
+
+ private CursorAnchorInfoCompatWrapper(final Object instance) {
+ mInstance = instance;
+ }
+
+ @UsedForTesting
+ public static CursorAnchorInfoCompatWrapper fromObject(final Object instance) {
+ if (!sCursorAnchorInfoClass.exists()) {
+ return new CursorAnchorInfoCompatWrapper(null);
+ }
+ return new CursorAnchorInfoCompatWrapper(instance);
+ }
+
+ private static final class FakeHolder {
+ static CursorAnchorInfoCompatWrapper sInstance = new CursorAnchorInfoCompatWrapper(null);
+ }
+
+ @UsedForTesting
+ public static CursorAnchorInfoCompatWrapper getFake() {
+ return FakeHolder.sInstance;
+ }
+
+ public int getSelectionStart() {
+ return sGetSelectionStartMethod.invoke(mInstance);
+ }
+
+ public int getSelectionEnd() {
+ return sGetSelectionEndMethod.invoke(mInstance);
+ }
+
+ public CharSequence getComposingText() {
+ return sGetComposingTextMethod.invoke(mInstance);
+ }
+
+ public int getComposingTextStart() {
+ return sGetComposingTextStartMethod.invoke(mInstance);
+ }
+
+ public Matrix getMatrix() {
+ return sGetMatrixMethod.invoke(mInstance);
+ }
+
+ public RectF getCharacterBounds(final int index) {
+ return sGetCharacterBoundsMethod.invoke(mInstance, index);
+ }
+
+ public int getCharacterBoundsFlags(final int index) {
+ return sGetCharacterBoundsFlagsMethod.invoke(mInstance, index);
+ }
+
+ public float getInsertionMarkerBaseline() {
+ return sGetInsertionMarkerBaselineMethod.invoke(mInstance);
+ }
+
+ public float getInsertionMarkerBottom() {
+ return sGetInsertionMarkerBottomMethod.invoke(mInstance);
+ }
+
+ public float getInsertionMarkerHorizontal() {
+ return sGetInsertionMarkerHorizontalMethod.invoke(mInstance);
+ }
+
+ public float getInsertionMarkerTop() {
+ return sGetInsertionMarkerTopMethod.invoke(mInstance);
+ }
+
+ public int getInsertionMarkerFlags() {
+ return sGetInsertionMarkerFlagsMethod.invoke(mInstance);
+ }
+}
diff --git a/java/src/com/android/inputmethod/compat/DownloadManagerCompatUtils.java b/java/src/com/android/inputmethod/compat/DownloadManagerCompatUtils.java
index d0b9c5da6..6209b60b3 100644
--- a/java/src/com/android/inputmethod/compat/DownloadManagerCompatUtils.java
+++ b/java/src/com/android/inputmethod/compat/DownloadManagerCompatUtils.java
@@ -24,7 +24,7 @@ public final class DownloadManagerCompatUtils {
// DownloadManager.Request#setAllowedOverMetered() has been introduced
// in API level 16 (Build.VERSION_CODES.JELLY_BEAN).
private static final Method METHOD_setAllowedOverMetered = CompatUtils.getMethod(
- DownloadManager.Request.class, "setAllowedOverMetered", Boolean.TYPE);
+ DownloadManager.Request.class, "setAllowedOverMetered", boolean.class);
public static DownloadManager.Request setAllowedOverMetered(
final DownloadManager.Request request, final boolean allowOverMetered) {
diff --git a/java/src/com/android/inputmethod/compat/InputConnectionCompatUtils.java b/java/src/com/android/inputmethod/compat/InputConnectionCompatUtils.java
index be7bf402d..a5c71b22f 100644
--- a/java/src/com/android/inputmethod/compat/InputConnectionCompatUtils.java
+++ b/java/src/com/android/inputmethod/compat/InputConnectionCompatUtils.java
@@ -16,67 +16,34 @@
package com.android.inputmethod.compat;
-import android.util.Log;
import android.view.inputmethod.InputConnection;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
+import android.view.inputmethod.InputMethodManager;
public final class InputConnectionCompatUtils {
- private static final String TAG = InputConnectionCompatUtils.class.getSimpleName();
-
- // Note that CursorAnchorInfoRequest is supposed to be available in API level 21 and later.
- private static Class<?> getCursorAnchorInfoRequestClass() {
- try {
- return Class.forName("android.view.inputmethod.CursorAnchorInfoRequest");
- } catch (ClassNotFoundException e) {
- return null;
- }
- }
-
- private static final Class<?> TYPE_CursorAnchorInfoRequest;
- private static final Constructor<?> CONSTRUCTOR_CursorAnchorInfoRequest;
- private static final Method METHOD_requestCursorAnchorInfo;
+ private static final CompatUtils.ClassWrapper sInputConnectionType;
+ private static final CompatUtils.ToBooleanMethodWrapper sRequestCursorUpdatesMethod;
static {
- TYPE_CursorAnchorInfoRequest = getCursorAnchorInfoRequestClass();
- CONSTRUCTOR_CursorAnchorInfoRequest = CompatUtils.getConstructor(
- TYPE_CursorAnchorInfoRequest, int.class, int.class);
- METHOD_requestCursorAnchorInfo = CompatUtils.getMethod(InputConnection.class,
- "requestCursorAnchorInfo", TYPE_CursorAnchorInfoRequest);
+ sInputConnectionType = new CompatUtils.ClassWrapper(InputConnection.class);
+ sRequestCursorUpdatesMethod = sInputConnectionType.getPrimitiveMethod(
+ "requestCursorUpdates", false, int.class);
}
- public static boolean isRequestCursorAnchorInfoAvailable() {
- return METHOD_requestCursorAnchorInfo != null &&
- CONSTRUCTOR_CursorAnchorInfoRequest != null;
+ public static boolean isRequestCursorUpdatesAvailable() {
+ return sRequestCursorUpdatesMethod != null;
}
/**
- * Local copies of some constants in CursorAnchorInfoRequest until the SDK becomes publicly
- * available.
+ * Local copies of some constants in InputConnection until the SDK becomes publicly available.
*/
- private final static int RESULT_NOT_HANDLED = 0;
- private final static int RESULT_SCHEDULED = 1;
- private final static int TYPE_CURSOR_ANCHOR_INFO = 1;
- private final static int FLAG_CURSOR_ANCHOR_INFO_MONITOR = 1;
- private final static int FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE = 2;
- private final static int TYPE_CURSOR_RECT = 2;
- private final static int FLAG_CURSOR_RECT_MONITOR = 1;
- private final static int FLAG_CURSOR_RECT_IN_SCREEN_COORDINATES = 2;
- private final static int FLAG_CURSOR_RECT_WITH_VIEW_MATRIX = 4;
+ private static int CURSOR_UPDATE_IMMEDIATE = 1 << 0;
+ private static int CURSOR_UPDATE_MONITOR = 1 << 1;
- private static int requestCursorAnchorInfoImpl(final InputConnection inputConnection,
- final int type, final int flags) {
- if (!isRequestCursorAnchorInfoAvailable()) {
- return RESULT_NOT_HANDLED;
- }
- final Object requestObject = CompatUtils.newInstance(
- CONSTRUCTOR_CursorAnchorInfoRequest, type, flags);
- if (requestObject == null) {
- return RESULT_NOT_HANDLED;
+ private static boolean requestCursorUpdatesImpl(final InputConnection inputConnection,
+ final int cursorUpdateMode) {
+ if (!isRequestCursorUpdatesAvailable()) {
+ return false;
}
- return (Integer) CompatUtils.invoke(inputConnection,
- RESULT_NOT_HANDLED /* defaultValue */,
- METHOD_requestCursorAnchorInfo, requestObject);
+ return sRequestCursorUpdatesMethod.invoke(inputConnection, cursorUpdateMode);
}
/**
@@ -88,47 +55,10 @@ public final class InputConnectionCompatUtils {
* as soon as possible to notify the current cursor/anchor position to the input method.
* @return {@code false} if the request is not handled. Otherwise returns {@code true}.
*/
- public static boolean requestCursorAnchorInfo(final InputConnection inputConnection,
+ public static boolean requestCursorUpdates(final InputConnection inputConnection,
final boolean enableMonitor, final boolean requestImmediateCallback) {
- final int requestFlags = (enableMonitor ? FLAG_CURSOR_ANCHOR_INFO_MONITOR : 0)
- | (requestImmediateCallback ? FLAG_CURSOR_ANCHOR_INFO_IMMEDIATE : 0);
- final int requestResult = requestCursorAnchorInfoImpl(inputConnection,
- TYPE_CURSOR_ANCHOR_INFO, requestFlags);
- switch (requestResult) {
- case RESULT_NOT_HANDLED:
- return false;
- case RESULT_SCHEDULED:
- return true;
- default:
- Log.w(TAG, "requestCursorAnchorInfo returned unknown result=" + requestResult
- + " for type=TYPE_CURSOR_ANCHOR_INFO flags=" + requestFlags);
- return true;
- }
- }
-
- /**
- * Requests the editor to call back {@link InputMethodManager#updateCursor}.
- * @param inputConnection the input connection to which the request is to be sent.
- * @param enableMonitor {@code true} to request the editor to call back the method whenever the
- * cursor position is changed.
- * @return {@code false} if the request is not handled. Otherwise returns {@code true}.
- */
- public static boolean requestCursorRect(final InputConnection inputConnection,
- final boolean enableMonitor) {
- final int requestFlags = enableMonitor ?
- FLAG_CURSOR_RECT_MONITOR | FLAG_CURSOR_RECT_IN_SCREEN_COORDINATES |
- FLAG_CURSOR_RECT_WITH_VIEW_MATRIX : 0;
- final int requestResult = requestCursorAnchorInfoImpl(inputConnection, TYPE_CURSOR_RECT,
- requestFlags);
- switch (requestResult) {
- case RESULT_NOT_HANDLED:
- return false;
- case RESULT_SCHEDULED:
- return true;
- default:
- Log.w(TAG, "requestCursorAnchorInfo returned unknown result=" + requestResult
- + " for type=TYPE_CURSOR_RECT flags=" + requestFlags);
- return true;
- }
+ final int cursorUpdateMode = (enableMonitor ? CURSOR_UPDATE_MONITOR : 0)
+ | (requestImmediateCallback ? CURSOR_UPDATE_IMMEDIATE : 0);
+ return requestCursorUpdatesImpl(inputConnection, cursorUpdateMode);
}
}
diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
index 18b3a6060..aa20c0336 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java
@@ -26,7 +26,7 @@ public final class InputMethodManagerCompatWrapper {
// Note that InputMethodManager.switchToNextInputMethod() has been introduced
// in API level 16 (Build.VERSION_CODES.JELLY_BEAN).
private static final Method METHOD_switchToNextInputMethod = CompatUtils.getMethod(
- InputMethodManager.class, "switchToNextInputMethod", IBinder.class, Boolean.TYPE);
+ InputMethodManager.class, "switchToNextInputMethod", IBinder.class, boolean.class);
// Note that InputMethodManager.shouldOfferSwitchingToNextInputMethod() has been introduced
// in API level 19 (Build.VERSION_CODES.KITKAT).
diff --git a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java
index ee9125a07..365867257 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java
@@ -32,8 +32,8 @@ public final class InputMethodSubtypeCompatUtils {
// has been introduced in API level 17 (Build.VERSION_CODE.JELLY_BEAN_MR1).
private static final Constructor<?> CONSTRUCTOR_INPUT_METHOD_SUBTYPE =
CompatUtils.getConstructor(InputMethodSubtype.class,
- Integer.TYPE, Integer.TYPE, String.class, String.class, String.class,
- Boolean.TYPE, Boolean.TYPE, Integer.TYPE);
+ int.class, int.class, String.class, String.class, String.class, boolean.class,
+ boolean.class, int.class);
static {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if (CONSTRUCTOR_INPUT_METHOD_SUBTYPE == null) {
diff --git a/java/src/com/android/inputmethod/compat/NotificationCompatUtils.java b/java/src/com/android/inputmethod/compat/NotificationCompatUtils.java
new file mode 100644
index 000000000..eb180071e
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/NotificationCompatUtils.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.compat;
+
+import android.app.Notification;
+import android.os.Build;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+public class NotificationCompatUtils {
+ // Note that TextInfo.getCharSequence() is supposed to be available in API level 21 and later.
+ private static final Method METHOD_setColor =
+ CompatUtils.getMethod(Notification.Builder.class, "setColor", int.class);
+ private static final Method METHOD_setVisibility =
+ CompatUtils.getMethod(Notification.Builder.class, "setVisibility", int.class);
+ private static final Method METHOD_setCategory =
+ CompatUtils.getMethod(Notification.Builder.class, "setCategory", String.class);
+ private static final Method METHOD_setPriority =
+ CompatUtils.getMethod(Notification.Builder.class, "setPriority", int.class);
+ private static final Method METHOD_build =
+ CompatUtils.getMethod(Notification.Builder.class, "build");
+ private static final Field FIELD_VISIBILITY_SECRET =
+ CompatUtils.getField(Notification.class, "VISIBILITY_SECRET");
+ private static final int VISIBILITY_SECRET = null == FIELD_VISIBILITY_SECRET ? 0
+ : (Integer) CompatUtils.getFieldValue(null /* receiver */, null /* defaultValue */,
+ FIELD_VISIBILITY_SECRET);
+ private static final Field FIELD_CATEGORY_RECOMMENDATION =
+ CompatUtils.getField(Notification.class, "CATEGORY_RECOMMENDATION");
+ private static final String CATEGORY_RECOMMENDATION = null == FIELD_CATEGORY_RECOMMENDATION ? ""
+ : (String) CompatUtils.getFieldValue(null /* receiver */, null /* defaultValue */,
+ FIELD_CATEGORY_RECOMMENDATION);
+ private static final Field FIELD_PRIORITY_LOW =
+ CompatUtils.getField(Notification.class, "PRIORITY_LOW");
+ private static final int PRIORITY_LOW = null == FIELD_PRIORITY_LOW ? 0
+ : (Integer) CompatUtils.getFieldValue(null /* receiver */, null /* defaultValue */,
+ FIELD_PRIORITY_LOW);
+
+ private NotificationCompatUtils() {
+ // This class is non-instantiable.
+ }
+
+ // Sets the accent color
+ public static void setColor(final Notification.Builder builder, final int color) {
+ CompatUtils.invoke(builder, null, METHOD_setColor, color);
+ }
+
+ public static void setVisibilityToSecret(final Notification.Builder builder) {
+ CompatUtils.invoke(builder, null, METHOD_setVisibility, VISIBILITY_SECRET);
+ }
+
+ public static void setCategoryToRecommendation(final Notification.Builder builder) {
+ CompatUtils.invoke(builder, null, METHOD_setCategory, CATEGORY_RECOMMENDATION);
+ }
+
+ public static void setPriorityToLow(final Notification.Builder builder) {
+ CompatUtils.invoke(builder, null, METHOD_setPriority, PRIORITY_LOW);
+ }
+
+ public static Notification build(final Notification.Builder builder) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ // #build was added in API level 16, JELLY_BEAN
+ return (Notification) CompatUtils.invoke(builder, null, METHOD_build);
+ } else {
+ // #getNotification was deprecated in API level 16, JELLY_BEAN
+ return builder.getNotification();
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
index 4c7663527..c33c01552 100644
--- a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
+++ b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
@@ -34,9 +34,9 @@ import java.util.ArrayList;
public final class SuggestionSpanUtils {
// Note that SuggestionSpan.FLAG_AUTO_CORRECTION has been introduced
// in API level 15 (Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1).
- public static final Field FIELD_FLAG_AUTO_CORRECTION = CompatUtils.getField(
+ private static final Field FIELD_FLAG_AUTO_CORRECTION = CompatUtils.getField(
SuggestionSpan.class, "FLAG_AUTO_CORRECTION");
- public static final Integer OBJ_FLAG_AUTO_CORRECTION = (Integer) CompatUtils.getFieldValue(
+ private static final Integer OBJ_FLAG_AUTO_CORRECTION = (Integer) CompatUtils.getFieldValue(
null /* receiver */, null /* defaultValue */, FIELD_FLAG_AUTO_CORRECTION);
static {
@@ -68,7 +68,7 @@ public final class SuggestionSpanUtils {
public static CharSequence getTextWithSuggestionSpan(final Context context,
final String pickedWord, final SuggestedWords suggestedWords) {
if (TextUtils.isEmpty(pickedWord) || suggestedWords.isEmpty()
- || suggestedWords.mIsPrediction || suggestedWords.isPunctuationSuggestions()) {
+ || suggestedWords.isPrediction() || suggestedWords.isPunctuationSuggestions()) {
return pickedWord;
}
diff --git a/java/src/com/android/inputmethod/compat/UserDictionaryCompatUtils.java b/java/src/com/android/inputmethod/compat/UserDictionaryCompatUtils.java
index 6e32e74ab..1fb597ba6 100644
--- a/java/src/com/android/inputmethod/compat/UserDictionaryCompatUtils.java
+++ b/java/src/com/android/inputmethod/compat/UserDictionaryCompatUtils.java
@@ -26,7 +26,7 @@ public final class UserDictionaryCompatUtils {
// UserDictionary.Words#addWord(Context, String, int, String, Locale) was introduced
// in API level 16 (Build.VERSION_CODES.JELLY_BEAN).
private static final Method METHOD_addWord = CompatUtils.getMethod(Words.class, "addWord",
- Context.class, String.class, Integer.TYPE, String.class, Locale.class);
+ Context.class, String.class, int.class, String.class, Locale.class);
@SuppressWarnings("deprecation")
public static void addWord(final Context context, final String word,
diff --git a/java/src/com/android/inputmethod/compat/ViewCompatUtils.java b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
index 767cc423d..0f00be133 100644
--- a/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
+++ b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
@@ -30,7 +30,13 @@ public final class ViewCompatUtils {
View.class, "getPaddingEnd");
private static final Method METHOD_setPaddingRelative = CompatUtils.getMethod(
View.class, "setPaddingRelative",
- Integer.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE);
+ int.class, int.class, int.class, int.class);
+ // Note that View.setElevation(float) has been introduced in API level 21.
+ private static final Method METHOD_setElevation = CompatUtils.getMethod(
+ View.class, "setElevation", float.class);
+ // Note that View.setTextAlignment(int) has been introduced in API level 17.
+ private static final Method METHOD_setTextAlignment = CompatUtils.getMethod(
+ View.class, "setTextAlignment", int.class);
private ViewCompatUtils() {
// This utility class is not publicly instantiable.
@@ -51,4 +57,21 @@ public final class ViewCompatUtils {
}
CompatUtils.invoke(view, null, METHOD_setPaddingRelative, start, top, end, bottom);
}
+
+ public static void setElevation(final View view, final float elevation) {
+ CompatUtils.invoke(view, null, METHOD_setElevation, elevation);
+ }
+
+ // These TEXT_ALIGNMENT_* constants have been introduced in API 17.
+ public static final int TEXT_ALIGNMENT_INHERIT = 0;
+ public static final int TEXT_ALIGNMENT_GRAVITY = 1;
+ public static final int TEXT_ALIGNMENT_TEXT_START = 2;
+ public static final int TEXT_ALIGNMENT_TEXT_END = 3;
+ public static final int TEXT_ALIGNMENT_CENTER = 4;
+ public static final int TEXT_ALIGNMENT_VIEW_START = 5;
+ public static final int TEXT_ALIGNMENT_VIEW_END = 6;
+
+ public static void setTextAlignment(final View view, final int textAlignment) {
+ CompatUtils.invoke(view, null, METHOD_setTextAlignment, textAlignment);
+ }
}
diff --git a/java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java b/java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java
index 75cc7d4cb..3dbbc9b9b 100644
--- a/java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java
+++ b/java/src/com/android/inputmethod/dictionarypack/DownloadManagerWrapper.java
@@ -54,15 +54,13 @@ public class DownloadManagerWrapper {
if (null != mDownloadManager) {
mDownloadManager.remove(ids);
}
+ } catch (IllegalArgumentException e) {
+ // This is expected to happen on boot when the device is encrypted.
} catch (SQLiteException e) {
// We couldn't remove the file from DownloadManager. Apparently, the database can't
// be opened. It may be a problem with file system corruption. In any case, there is
// not much we can do apart from avoiding crashing.
Log.e(TAG, "Can't remove files with ID " + ids + " from download manager", e);
- } catch (IllegalArgumentException e) {
- // Not sure how this can happen, but it could be another case where the provider
- // is disabled. Or it could be a bug in older versions of the framework.
- Log.e(TAG, "Can't find the content URL for DownloadManager?", e);
}
}
@@ -71,10 +69,10 @@ public class DownloadManagerWrapper {
if (null != mDownloadManager) {
return mDownloadManager.openDownloadedFile(fileId);
}
+ } catch (IllegalArgumentException e) {
+ // This is expected to happen on boot when the device is encrypted.
} catch (SQLiteException e) {
Log.e(TAG, "Can't open downloaded file with ID " + fileId, e);
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Can't find the content URL for DownloadManager?", e);
}
// We come here if mDownloadManager is null or if an exception was thrown.
throw new FileNotFoundException();
@@ -85,10 +83,10 @@ public class DownloadManagerWrapper {
if (null != mDownloadManager) {
return mDownloadManager.query(query);
}
+ } catch (IllegalArgumentException e) {
+ // This is expected to happen on boot when the device is encrypted.
} catch (SQLiteException e) {
Log.e(TAG, "Can't query the download manager", e);
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Can't find the content URL for DownloadManager?", e);
}
// We come here if mDownloadManager is null or if an exception was thrown.
return null;
@@ -99,10 +97,10 @@ public class DownloadManagerWrapper {
if (null != mDownloadManager) {
return mDownloadManager.enqueue(request);
}
+ } catch (IllegalArgumentException e) {
+ // This is expected to happen on boot when the device is encrypted.
} catch (SQLiteException e) {
Log.e(TAG, "Can't enqueue a request with the download manager", e);
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Can't find the content URL for DownloadManager?", e);
}
return 0;
}
diff --git a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
index 95a094232..6fbca44c5 100644
--- a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
+++ b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
@@ -31,12 +31,14 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.ConnectivityManager;
import android.net.Uri;
+import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.text.TextUtils;
import android.util.Log;
import com.android.inputmethod.compat.ConnectivityManagerCompatUtils;
import com.android.inputmethod.compat.DownloadManagerCompatUtils;
+import com.android.inputmethod.compat.NotificationCompatUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.utils.ApplicationUtils;
import com.android.inputmethod.latin.utils.DebugLogUtils;
@@ -858,7 +860,7 @@ public final class UpdateHandler {
final String language = (null == locale ? "" : locale.getDisplayLanguage());
final String titleFormat = context.getString(R.string.dict_available_notification_title);
final String notificationTitle = String.format(titleFormat, language);
- final Notification notification = new Notification.Builder(context)
+ final Notification.Builder builder = new Notification.Builder(context)
.setAutoCancel(true)
.setContentIntent(notificationIntent)
.setContentTitle(notificationTitle)
@@ -866,8 +868,13 @@ public final class UpdateHandler {
.setTicker(notificationTitle)
.setOngoing(false)
.setOnlyAlertOnce(true)
- .setSmallIcon(R.drawable.ic_notify_dictionary)
- .getNotification();
+ .setSmallIcon(R.drawable.ic_notify_dictionary);
+ NotificationCompatUtils.setColor(builder,
+ context.getResources().getColor(R.color.notification_accent_color));
+ NotificationCompatUtils.setPriorityToLow(builder);
+ NotificationCompatUtils.setVisibilityToSecret(builder);
+ NotificationCompatUtils.setCategoryToRecommendation(builder);
+ final Notification notification = NotificationCompatUtils.build(builder);
notificationManager.notify(DICT_AVAILABLE_NOTIFICATION_ID, notification);
}
diff --git a/java/src/com/android/inputmethod/event/Combiner.java b/java/src/com/android/inputmethod/event/Combiner.java
index 8b808c6b3..fee93f0c6 100644
--- a/java/src/com/android/inputmethod/event/Combiner.java
+++ b/java/src/com/android/inputmethod/event/Combiner.java
@@ -18,6 +18,8 @@ package com.android.inputmethod.event;
import java.util.ArrayList;
+import javax.annotation.Nonnull;
+
/**
* A generic interface for combiners. Combiners are objects that transform chains of input events
* into committable strings and manage feedback to show to the user on the combining state.
@@ -33,6 +35,7 @@ public interface Combiner {
* @param event the event to combine with the existing state.
* @return the resulting event.
*/
+ @Nonnull
Event processEvent(ArrayList<Event> previousEvents, Event event);
/**
diff --git a/java/src/com/android/inputmethod/event/CombinerChain.java b/java/src/com/android/inputmethod/event/CombinerChain.java
index 61bc11b39..2d2731f21 100644
--- a/java/src/com/android/inputmethod/event/CombinerChain.java
+++ b/java/src/com/android/inputmethod/event/CombinerChain.java
@@ -24,6 +24,8 @@ import com.android.inputmethod.latin.Constants;
import java.util.ArrayList;
import java.util.HashMap;
+import javax.annotation.Nonnull;
+
/**
* This class implements the logic chain between receiving events and generating code points.
*
@@ -80,23 +82,43 @@ public class CombinerChain {
}
}
+ private void updateStateFeedback() {
+ mStateFeedback.clear();
+ for (int i = mCombiners.size() - 1; i >= 0; --i) {
+ mStateFeedback.append(mCombiners.get(i).getCombiningStateFeedback());
+ }
+ }
+
/**
- * Pass a new event through the whole chain.
+ * Process an event through the combining chain, and return a processed event to apply.
* @param previousEvents the list of previous events in this composition
* @param newEvent the new event to process
+ * @return the processed event. It may be the same event, or a consumed event, or a completely
+ * new event. However it may never be null.
*/
- public void processEvent(final ArrayList<Event> previousEvents, final Event newEvent) {
+ @Nonnull
+ public Event processEvent(final ArrayList<Event> previousEvents, final Event newEvent) {
final ArrayList<Event> modifiablePreviousEvents = new ArrayList<>(previousEvents);
Event event = newEvent;
for (final Combiner combiner : mCombiners) {
// A combiner can never return more than one event; it can return several
// code points, but they should be encapsulated within one event.
event = combiner.processEvent(modifiablePreviousEvents, event);
- if (null == event) {
- // Combiners return null if they eat the event.
+ if (event.isConsumed()) {
+ // If the event is consumed, then we don't pass it to subsequent combiners:
+ // they should not see it at all.
break;
}
}
+ updateStateFeedback();
+ return event;
+ }
+
+ /**
+ * Apply a processed event.
+ * @param event the event to be applied
+ */
+ public void applyProcessedEvent(final Event event) {
if (null != event) {
// TODO: figure out the generic way of doing this
if (Constants.CODE_DELETE == event.mKeyCode) {
@@ -112,10 +134,7 @@ public class CombinerChain {
}
}
}
- mStateFeedback.clear();
- for (int i = mCombiners.size() - 1; i >= 0; --i) {
- mStateFeedback.append(mCombiners.get(i).getCombiningStateFeedback());
- }
+ updateStateFeedback();
}
/**
diff --git a/java/src/com/android/inputmethod/event/DeadKeyCombiner.java b/java/src/com/android/inputmethod/event/DeadKeyCombiner.java
index bef4d8594..4f3f4d25f 100644
--- a/java/src/com/android/inputmethod/event/DeadKeyCombiner.java
+++ b/java/src/com/android/inputmethod/event/DeadKeyCombiner.java
@@ -23,6 +23,8 @@ import com.android.inputmethod.latin.Constants;
import java.util.ArrayList;
+import javax.annotation.Nonnull;
+
/**
* A combiner that handles dead keys.
*/
@@ -31,12 +33,18 @@ public class DeadKeyCombiner implements Combiner {
final StringBuilder mDeadSequence = new StringBuilder();
@Override
+ @Nonnull
public Event processEvent(final ArrayList<Event> previousEvents, final Event event) {
- if (null == event) return null; // Just in case some combiner is broken
if (TextUtils.isEmpty(mDeadSequence)) {
+ // No dead char is currently being tracked: this is the most common case.
if (event.isDead()) {
+ // The event was a dead key. Start tracking it.
mDeadSequence.appendCodePoint(event.mCodePoint);
+ return Event.createConsumedEvent(event);
}
+ // Regular keystroke when not keeping track of a dead key. Simply said, there are
+ // no dead keys at all in the current input, so this combiner has nothing to do and
+ // simply returns the event as is. The majority of events will go through this path.
return event;
} else {
// TODO: Allow combining for several dead chars rather than only the first one.
diff --git a/java/src/com/android/inputmethod/event/Event.java b/java/src/com/android/inputmethod/event/Event.java
index d257441e0..ef5b04747 100644
--- a/java/src/com/android/inputmethod/event/Event.java
+++ b/java/src/com/android/inputmethod/event/Event.java
@@ -67,6 +67,8 @@ public class Event {
final private static int FLAG_DEAD = 0x1;
// This event is coming from a key repeat, software or hardware.
final private static int FLAG_REPEAT = 0x2;
+ // This event has already been consumed.
+ final private static int FLAG_CONSUMED = 0x4;
final private int mEventType; // The type of event - one of the constants above
// The code point associated with the event, if relevant. This is a unicode code point, and
@@ -219,6 +221,18 @@ public class Event {
null /* next */);
}
+ /**
+ * Creates an event identical to the passed event, but that has already been consumed.
+ * @param source the event to copy the properties of.
+ * @return an identical event marked as consumed.
+ */
+ public static Event createConsumedEvent(final Event source) {
+ // A consumed event should not input any text at all, so we pass the empty string as text.
+ return new Event(source.mEventType, source.mText, source.mCodePoint, source.mKeyCode,
+ source.mX, source.mY, source.mSuggestedWordInfo, source.mFlags | FLAG_CONSUMED,
+ source.mNextEvent);
+ }
+
public static Event createNotHandledEvent() {
return new Event(EVENT_TYPE_NOT_HANDLED, null /* text */, NOT_A_CODE_POINT, NOT_A_KEY_CODE,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE,
@@ -241,6 +255,10 @@ public class Event {
return 0 != (FLAG_REPEAT & mFlags);
}
+ public boolean isConsumed() { return 0 != (FLAG_CONSUMED & mFlags); }
+
+ public boolean isGesture() { return EVENT_TYPE_GESTURE == mEventType; }
+
// Returns whether this is a fake key press from the suggestion strip. This happens with
// punctuation signs selected from the suggestion strip.
public boolean isSuggestionStripPress() {
@@ -252,6 +270,9 @@ public class Event {
}
public CharSequence getTextToCommit() {
+ if (isConsumed()) {
+ return ""; // A consumed event should input no text.
+ }
switch (mEventType) {
case EVENT_TYPE_MODE_KEY:
case EVENT_TYPE_NOT_HANDLED:
diff --git a/java/src/com/android/inputmethod/event/InputTransaction.java b/java/src/com/android/inputmethod/event/InputTransaction.java
index cdff265c6..5bc9111de 100644
--- a/java/src/com/android/inputmethod/event/InputTransaction.java
+++ b/java/src/com/android/inputmethod/event/InputTransaction.java
@@ -42,6 +42,7 @@ public class InputTransaction {
private int mRequiredShiftUpdate = SHIFT_NO_UPDATE;
private boolean mRequiresUpdateSuggestions = false;
private boolean mDidAffectContents = false;
+ private boolean mDidAutoCorrect = false;
public InputTransaction(final SettingsValues settingsValues, final Event event,
final long timestamp, final int spaceState, final int shiftState) {
@@ -97,4 +98,19 @@ public class InputTransaction {
public boolean didAffectContents() {
return mDidAffectContents;
}
+
+ /**
+ * Indicate that this transaction performed an auto-correction.
+ */
+ public void setDidAutoCorrect() {
+ mDidAutoCorrect = true;
+ }
+
+ /**
+ * Find out whether this transaction performed an auto-correction.
+ * @return Whether this transaction performed an auto-correction.
+ */
+ public boolean didAutoCorrect() {
+ return mDidAutoCorrect;
+ }
}
diff --git a/java/src/com/android/inputmethod/event/MyanmarReordering.java b/java/src/com/android/inputmethod/event/MyanmarReordering.java
index 32919932d..dcd06c899 100644
--- a/java/src/com/android/inputmethod/event/MyanmarReordering.java
+++ b/java/src/com/android/inputmethod/event/MyanmarReordering.java
@@ -21,6 +21,8 @@ import com.android.inputmethod.latin.Constants;
import java.util.ArrayList;
import java.util.Arrays;
+import javax.annotation.Nonnull;
+
/**
* A combiner that reorders input for Myanmar.
*/
@@ -111,7 +113,7 @@ public class MyanmarReordering implements Combiner {
* Clears the currently combining stream of events and returns the resulting software text
* event corresponding to the stream. Optionally adds a new event to the cleared stream.
* @param newEvent the new event to add to the stream. null if none.
- * @return the resulting software text event. Null if none.
+ * @return the resulting software text event. Never null.
*/
private Event clearAndGetResultingEvent(final Event newEvent) {
final CharSequence combinedText;
@@ -124,18 +126,19 @@ public class MyanmarReordering implements Combiner {
if (null != newEvent) {
mCurrentEvents.add(newEvent);
}
- return null == combinedText ? null
+ return null == combinedText ? Event.createConsumedEvent(newEvent)
: Event.createSoftwareTextEvent(combinedText, Event.NOT_A_KEY_CODE);
}
@Override
+ @Nonnull
public Event processEvent(ArrayList<Event> previousEvents, Event newEvent) {
final int codePoint = newEvent.mCodePoint;
if (VOWEL_E == codePoint) {
final Event lastEvent = getLastEvent();
if (null == lastEvent) {
mCurrentEvents.add(newEvent);
- return null;
+ return Event.createConsumedEvent(newEvent);
} else if (isConsonantOrMedial(lastEvent.mCodePoint)) {
final Event resultingEvent = clearAndGetResultingEvent(null);
mCurrentEvents.add(Event.createSoftwareKeypressEvent(ZERO_WIDTH_NON_JOINER,
@@ -151,7 +154,7 @@ public class MyanmarReordering implements Combiner {
final Event lastEvent = getLastEvent();
if (null == lastEvent) {
mCurrentEvents.add(newEvent);
- return null;
+ return Event.createConsumedEvent(newEvent);
} else if (VOWEL_E == lastEvent.mCodePoint) {
final int eventSize = mCurrentEvents.size();
if (eventSize >= 2
@@ -162,7 +165,7 @@ public class MyanmarReordering implements Combiner {
mCurrentEvents.remove(eventSize - 2);
mCurrentEvents.add(newEvent);
mCurrentEvents.add(lastEvent);
- return null;
+ return Event.createConsumedEvent(newEvent);
}
// If there is already a consonant, then we are starting a new syllable.
for (int i = eventSize - 2; i >= 0; --i) {
@@ -174,7 +177,7 @@ public class MyanmarReordering implements Combiner {
mCurrentEvents.remove(eventSize - 1);
mCurrentEvents.add(newEvent);
mCurrentEvents.add(lastEvent);
- return null;
+ return Event.createConsumedEvent(newEvent);
} else { // lastCodePoint is a consonant/medial. But if it's something else it's fine
return clearAndGetResultingEvent(newEvent);
}
@@ -182,7 +185,7 @@ public class MyanmarReordering implements Combiner {
final Event lastEvent = getLastEvent();
if (null == lastEvent) {
mCurrentEvents.add(newEvent);
- return null;
+ return Event.createConsumedEvent(newEvent);
} else if (VOWEL_E == lastEvent.mCodePoint) {
final int eventSize = mCurrentEvents.size();
// If there is already a consonant, then we are in the middle of a syllable, and we
@@ -198,7 +201,7 @@ public class MyanmarReordering implements Combiner {
mCurrentEvents.remove(eventSize - 1);
mCurrentEvents.add(newEvent);
mCurrentEvents.add(lastEvent);
- return null;
+ return Event.createConsumedEvent(newEvent);
}
// Otherwise, we just commit everything.
return clearAndGetResultingEvent(null);
@@ -228,10 +231,10 @@ public class MyanmarReordering implements Combiner {
mCurrentEvents.remove(eventSize - 1);
}
}
- return null;
+ return Event.createConsumedEvent(newEvent);
} else if (eventSize > 0) {
mCurrentEvents.remove(eventSize - 1);
- return null;
+ return Event.createConsumedEvent(newEvent);
}
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index af54fb674..81ea90a4d 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -58,7 +58,9 @@ public class Key implements Comparable<Key> {
private final String mHintLabel;
/** Flags of the label */
private final int mLabelFlags;
- private static final int LABEL_FLAGS_ALIGN_LEFT_OF_CENTER = 0x08;
+ private static final int LABEL_FLAGS_ALIGN_HINT_LABEL_TO_BOTTOM = 0x02;
+ private static final int LABEL_FLAGS_ALIGN_ICON_TO_BOTTOM = 0x04;
+ private static final int LABEL_FLAGS_ALIGN_LABEL_OFF_CENTER = 0x08;
// Font typeface specification.
private static final int LABEL_FLAGS_FONT_MASK = 0x30;
private static final int LABEL_FLAGS_FONT_NORMAL = 0x10;
@@ -69,7 +71,6 @@ public class Key implements Comparable<Key> {
private static final int LABEL_FLAGS_FOLLOW_KEY_LARGE_LETTER_RATIO = 0x40;
private static final int LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO = 0x80;
private static final int LABEL_FLAGS_FOLLOW_KEY_LABEL_RATIO = 0xC0;
- private static final int LABEL_FLAGS_FOLLOW_KEY_LARGE_LABEL_RATIO = 0x100;
private static final int LABEL_FLAGS_FOLLOW_KEY_HINT_LABEL_RATIO = 0x140;
// End of key text ratio mask enum values
private static final int LABEL_FLAGS_HAS_POPUP_HINT = 0x200;
@@ -86,6 +87,7 @@ public class Key implements Comparable<Key> {
private static final int LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED = 0x20000;
private static final int LABEL_FLAGS_FROM_CUSTOM_ACTION_LABEL = 0x40000;
private static final int LABEL_FLAGS_FOLLOW_FUNCTIONAL_TEXT_COLOR = 0x80000;
+ private static final int LABEL_FLAGS_KEEP_BACKGROUND_ASPECT_RATIO = 0x100000;
private static final int LABEL_FLAGS_DISABLE_HINT_LABEL = 0x40000000;
private static final int LABEL_FLAGS_DISABLE_ADDITIONAL_MORE_KEYS = 0x80000000;
@@ -107,11 +109,23 @@ public class Key implements Comparable<Key> {
private final MoreKeySpec[] mMoreKeys;
/** More keys column number and flags */
private final int mMoreKeysColumnAndFlags;
- private static final int MORE_KEYS_COLUMN_MASK = 0x000000ff;
- private static final int MORE_KEYS_FLAGS_FIXED_COLUMN_ORDER = 0x80000000;
+ private static final int MORE_KEYS_COLUMN_NUMBER_MASK = 0x000000ff;
+ // If this flag is specified, more keys keyboard should have the specified number of columns.
+ // Otherwise more keys keyboard should have less than or equal to the specified maximum number
+ // of columns.
+ private static final int MORE_KEYS_FLAGS_FIXED_COLUMN = 0x00000100;
+ // If this flag is specified, the order of more keys is determined by the order in the more
+ // keys' specification. Otherwise the order of more keys is automatically determined.
+ private static final int MORE_KEYS_FLAGS_FIXED_ORDER = 0x00000200;
+ private static final int MORE_KEYS_MODE_MAX_COLUMN_WITH_AUTO_ORDER = 0;
+ private static final int MORE_KEYS_MODE_FIXED_COLUMN_WITH_AUTO_ORDER =
+ MORE_KEYS_FLAGS_FIXED_COLUMN;
+ private static final int MORE_KEYS_MODE_FIXED_COLUMN_WITH_FIXED_ORDER =
+ (MORE_KEYS_FLAGS_FIXED_COLUMN | MORE_KEYS_FLAGS_FIXED_ORDER);
private static final int MORE_KEYS_FLAGS_HAS_LABELS = 0x40000000;
private static final int MORE_KEYS_FLAGS_NEEDS_DIVIDERS = 0x20000000;
private static final int MORE_KEYS_FLAGS_NO_PANEL_AUTO_MORE_KEY = 0x10000000;
+ // TODO: Rename these specifiers to !autoOrder! and !fixedOrder! respectively.
private static final String MORE_KEYS_AUTO_COLUMN_ORDER = "!autoColumnOrder!";
private static final String MORE_KEYS_FIXED_COLUMN_ORDER = "!fixedColumnOrder!";
private static final String MORE_KEYS_HAS_LABELS = "!hasLabels!";
@@ -123,9 +137,10 @@ public class Key implements Comparable<Key> {
public static final int BACKGROUND_TYPE_EMPTY = 0;
public static final int BACKGROUND_TYPE_NORMAL = 1;
public static final int BACKGROUND_TYPE_FUNCTIONAL = 2;
- public static final int BACKGROUND_TYPE_ACTION = 3;
- public static final int BACKGROUND_TYPE_STICKY_OFF = 4;
- public static final int BACKGROUND_TYPE_STICKY_ON = 5;
+ public static final int BACKGROUND_TYPE_STICKY_OFF = 3;
+ public static final int BACKGROUND_TYPE_STICKY_ON = 4;
+ public static final int BACKGROUND_TYPE_ACTION = 5;
+ public static final int BACKGROUND_TYPE_SPACEBAR = 6;
private final int mActionFlags;
private static final int ACTION_FLAGS_IS_REPEATABLE = 0x01;
@@ -253,25 +268,31 @@ public class Key implements Comparable<Key> {
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,
- R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMoreKeysKeyboardColumn);
+ // Get maximum column order number and set a relevant mode value.
+ int moreKeysColumnAndFlags = MORE_KEYS_MODE_MAX_COLUMN_WITH_AUTO_ORDER
+ | style.getInt(keyAttr, R.styleable.Keyboard_Key_maxMoreKeysColumn,
+ params.mMaxMoreKeysKeyboardColumn);
int value;
if ((value = MoreKeySpec.getIntValue(moreKeys, MORE_KEYS_AUTO_COLUMN_ORDER, -1)) > 0) {
- moreKeysColumn = value & MORE_KEYS_COLUMN_MASK;
+ // Override with fixed column order number and set a relevant mode value.
+ moreKeysColumnAndFlags = MORE_KEYS_MODE_FIXED_COLUMN_WITH_AUTO_ORDER
+ | (value & MORE_KEYS_COLUMN_NUMBER_MASK);
}
if ((value = MoreKeySpec.getIntValue(moreKeys, MORE_KEYS_FIXED_COLUMN_ORDER, -1)) > 0) {
- moreKeysColumn = MORE_KEYS_FLAGS_FIXED_COLUMN_ORDER | (value & MORE_KEYS_COLUMN_MASK);
+ // Override with fixed column order number and set a relevant mode value.
+ moreKeysColumnAndFlags = MORE_KEYS_MODE_FIXED_COLUMN_WITH_FIXED_ORDER
+ | (value & MORE_KEYS_COLUMN_NUMBER_MASK);
}
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_HAS_LABELS)) {
- moreKeysColumn |= MORE_KEYS_FLAGS_HAS_LABELS;
+ moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_HAS_LABELS;
}
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_NEEDS_DIVIDERS)) {
- moreKeysColumn |= MORE_KEYS_FLAGS_NEEDS_DIVIDERS;
+ moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_NEEDS_DIVIDERS;
}
if (MoreKeySpec.getBooleanValue(moreKeys, MORE_KEYS_NO_PANEL_AUTO_MORE_KEY)) {
- moreKeysColumn |= MORE_KEYS_FLAGS_NO_PANEL_AUTO_MORE_KEY;
+ moreKeysColumnAndFlags |= MORE_KEYS_FLAGS_NO_PANEL_AUTO_MORE_KEY;
}
- mMoreKeysColumnAndFlags = moreKeysColumn;
+ mMoreKeysColumnAndFlags = moreKeysColumnAndFlags;
final String[] additionalMoreKeys;
if ((mLabelFlags & LABEL_FLAGS_DISABLE_ADDITIONAL_MORE_KEYS) != 0) {
@@ -483,9 +504,10 @@ public class Key implements Comparable<Key> {
case BACKGROUND_TYPE_EMPTY: return "empty";
case BACKGROUND_TYPE_NORMAL: return "normal";
case BACKGROUND_TYPE_FUNCTIONAL: return "functional";
- case BACKGROUND_TYPE_ACTION: return "action";
case BACKGROUND_TYPE_STICKY_OFF: return "stickyOff";
case BACKGROUND_TYPE_STICKY_ON: return "stickyOn";
+ case BACKGROUND_TYPE_ACTION: return "action";
+ case BACKGROUND_TYPE_SPACEBAR: return "spacebar";
default: return null;
}
}
@@ -526,6 +548,10 @@ public class Key implements Comparable<Key> {
return this instanceof Spacer;
}
+ public final boolean isActionKey() {
+ return mBackgroundType == BACKGROUND_TYPE_ACTION;
+ }
+
public final boolean isShift() {
return mCode == CODE_SHIFT;
}
@@ -577,8 +603,6 @@ public class Key implements Comparable<Key> {
return params.mLargeLetterSize;
case LABEL_FLAGS_FOLLOW_KEY_LABEL_RATIO:
return params.mLabelSize;
- case LABEL_FLAGS_FOLLOW_KEY_LARGE_LABEL_RATIO:
- return params.mLargeLabelSize;
case LABEL_FLAGS_FOLLOW_KEY_HINT_LABEL_RATIO:
return params.mHintLabelSize;
default: // No follow key ratio flag specified.
@@ -641,8 +665,16 @@ public class Key implements Comparable<Key> {
return Typeface.DEFAULT_BOLD;
}
- public final boolean isAlignLeftOfCenter() {
- return (mLabelFlags & LABEL_FLAGS_ALIGN_LEFT_OF_CENTER) != 0;
+ public final boolean isAlignHintLabelToBottom(final int defaultFlags) {
+ return ((mLabelFlags | defaultFlags) & LABEL_FLAGS_ALIGN_HINT_LABEL_TO_BOTTOM) != 0;
+ }
+
+ public final boolean isAlignIconToBottom() {
+ return (mLabelFlags & LABEL_FLAGS_ALIGN_ICON_TO_BOTTOM) != 0;
+ }
+
+ public final boolean isAlignLabelOffCenter() {
+ return (mLabelFlags & LABEL_FLAGS_ALIGN_LABEL_OFF_CENTER) != 0;
}
public final boolean hasPopupHint() {
@@ -666,17 +698,29 @@ public class Key implements Comparable<Key> {
return (mLabelFlags & LABEL_FLAGS_AUTO_SCALE) == LABEL_FLAGS_AUTO_SCALE;
}
+ public final boolean needsToKeepBackgroundAspectRatio(final int defaultFlags) {
+ return ((mLabelFlags | defaultFlags) & LABEL_FLAGS_KEEP_BACKGROUND_ASPECT_RATIO) != 0;
+ }
+
+ public final boolean hasCustomActionLabel() {
+ return (mLabelFlags & LABEL_FLAGS_FROM_CUSTOM_ACTION_LABEL) != 0;
+ }
+
private final boolean isShiftedLetterActivated() {
return (mLabelFlags & LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED) != 0
&& !TextUtils.isEmpty(mHintLabel);
}
- public final int getMoreKeysColumn() {
- return mMoreKeysColumnAndFlags & MORE_KEYS_COLUMN_MASK;
+ public final int getMoreKeysColumnNumber() {
+ return mMoreKeysColumnAndFlags & MORE_KEYS_COLUMN_NUMBER_MASK;
}
- public final boolean isFixedColumnOrderMoreKeys() {
- return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_FIXED_COLUMN_ORDER) != 0;
+ public final boolean isMoreKeysFixedColumn() {
+ return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_FIXED_COLUMN) != 0;
+ }
+
+ public final boolean isMoreKeysFixedOrder() {
+ return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_FIXED_ORDER) != 0;
}
public final boolean hasLabelsInMoreKeys() {
@@ -684,9 +728,10 @@ public class Key implements Comparable<Key> {
}
public final int getMoreKeyLabelFlags() {
- return hasLabelsInMoreKeys()
+ final int labelSizeFlag = hasLabelsInMoreKeys()
? LABEL_FLAGS_FOLLOW_KEY_LABEL_RATIO
: LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO;
+ return labelSizeFlag | LABEL_FLAGS_AUTO_X_SCALE;
}
public final boolean needsDividersInMoreKeys() {
@@ -814,47 +859,37 @@ public class Key implements Comparable<Key> {
return dx * dx + dy * dy;
}
- private final static int[] KEY_STATE_NORMAL_HIGHLIGHT_ON = {
- android.R.attr.state_checkable,
- android.R.attr.state_checked
- };
-
- private final static int[] KEY_STATE_PRESSED_HIGHLIGHT_ON = {
- android.R.attr.state_pressed,
- android.R.attr.state_checkable,
- android.R.attr.state_checked
- };
-
- private final static int[] KEY_STATE_NORMAL_HIGHLIGHT_OFF = {
- android.R.attr.state_checkable
- };
-
- private final static int[] KEY_STATE_PRESSED_HIGHLIGHT_OFF = {
- android.R.attr.state_pressed,
- android.R.attr.state_checkable
- };
-
- private final static int[] KEY_STATE_NORMAL = {
- };
+ static class KeyBackgroundState {
+ private final int[] mReleasedState;
+ private final int[] mPressedState;
- private final static int[] KEY_STATE_PRESSED = {
- android.R.attr.state_pressed
- };
-
- private final static int[] KEY_STATE_EMPTY = {
- android.R.attr.state_empty
- };
+ private KeyBackgroundState(final int ... attrs) {
+ mReleasedState = attrs;
+ mPressedState = Arrays.copyOf(attrs, attrs.length + 1);
+ mPressedState[attrs.length] = android.R.attr.state_pressed;
+ }
- // action normal state (with properties)
- private static final int[] KEY_STATE_ACTIVE_NORMAL = {
- android.R.attr.state_active
- };
+ public int[] getState(final boolean pressed) {
+ return pressed ? mPressedState : mReleasedState;
+ }
- // action pressed state (with properties)
- private static final int[] KEY_STATE_ACTIVE_PRESSED = {
- android.R.attr.state_active,
- android.R.attr.state_pressed
- };
+ public static final KeyBackgroundState[] STATES = {
+ // 0: BACKGROUND_TYPE_EMPTY
+ new KeyBackgroundState(android.R.attr.state_empty),
+ // 1: BACKGROUND_TYPE_NORMAL
+ new KeyBackgroundState(),
+ // 2: BACKGROUND_TYPE_FUNCTIONAL
+ new KeyBackgroundState(),
+ // 3: BACKGROUND_TYPE_STICKY_OFF
+ new KeyBackgroundState(android.R.attr.state_checkable),
+ // 4: BACKGROUND_TYPE_STICKY_ON
+ new KeyBackgroundState(android.R.attr.state_checkable, android.R.attr.state_checked),
+ // 5: BACKGROUND_TYPE_ACTION
+ new KeyBackgroundState(android.R.attr.state_active),
+ // 6: BACKGROUND_TYPE_SPACEBAR
+ new KeyBackgroundState(),
+ };
+ }
/**
* Returns the background drawable for the key, based on the current state and type of the key.
@@ -866,33 +901,13 @@ public class Key implements Comparable<Key> {
final Drawable background;
if (mBackgroundType == BACKGROUND_TYPE_FUNCTIONAL) {
background = functionalKeyBackground;
- } else if (getCode() == Constants.CODE_SPACE) {
+ } else if (mBackgroundType == BACKGROUND_TYPE_SPACEBAR) {
background = spacebarBackground;
} else {
background = keyBackground;
}
- final int[] stateSet;
- switch (mBackgroundType) {
- case BACKGROUND_TYPE_ACTION:
- stateSet = mPressed ? KEY_STATE_ACTIVE_PRESSED : KEY_STATE_ACTIVE_NORMAL;
- break;
- case BACKGROUND_TYPE_STICKY_OFF:
- stateSet = mPressed ? KEY_STATE_PRESSED_HIGHLIGHT_OFF : KEY_STATE_NORMAL_HIGHLIGHT_OFF;
- break;
- case BACKGROUND_TYPE_STICKY_ON:
- stateSet = mPressed ? KEY_STATE_PRESSED_HIGHLIGHT_ON : KEY_STATE_NORMAL_HIGHLIGHT_ON;
- break;
- case BACKGROUND_TYPE_EMPTY:
- stateSet = mPressed ? KEY_STATE_PRESSED : KEY_STATE_EMPTY;
- break;
- case BACKGROUND_TYPE_FUNCTIONAL:
- stateSet = mPressed ? KEY_STATE_PRESSED : KEY_STATE_NORMAL;
- break;
- default: /* BACKGROUND_TYPE_NORMAL */
- stateSet = mPressed ? KEY_STATE_PRESSED : KEY_STATE_NORMAL;
- break;
- }
- background.setState(stateSet);
+ final int[] state = KeyBackgroundState.STATES[mBackgroundType].getState(mPressed);
+ background.setState(state);
return background;
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index 870ac86e1..feb79efe9 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -113,13 +113,21 @@ public final class KeyboardLayoutSet {
boolean mIsSpellChecker;
int mKeyboardWidth;
int mKeyboardHeight;
- int mScriptId;
+ int mScriptId = ScriptUtils.SCRIPT_LATIN;
// Sparse array of KeyboardLayoutSet element parameters indexed by element's id.
final SparseArray<ElementParams> mKeyboardLayoutSetElementIdToParamsMap =
new SparseArray<>();
}
- public static void clearKeyboardCache() {
+ public static void onSystemLocaleChanged() {
+ clearKeyboardCache();
+ }
+
+ public static void onKeyboardThemeChanged() {
+ clearKeyboardCache();
+ }
+
+ private static void clearKeyboardCache() {
sKeyboardCache.clear();
sKeysCache.clear();
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index f35126750..60665f8de 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -37,6 +37,7 @@ import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.RichInputMethodManager;
import com.android.inputmethod.latin.SubtypeSwitcher;
import com.android.inputmethod.latin.WordComposer;
+import com.android.inputmethod.latin.settings.Settings;
import com.android.inputmethod.latin.settings.SettingsValues;
import com.android.inputmethod.latin.utils.ResourceUtils;
import com.android.inputmethod.latin.utils.ScriptUtils;
@@ -59,7 +60,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
private KeyboardLayoutSet mKeyboardLayoutSet;
// TODO: The following {@link KeyboardTextsSet} should be in {@link KeyboardLayoutSet}.
private final KeyboardTextsSet mKeyboardTextsSet = new KeyboardTextsSet();
- private SettingsValues mCurrentSettingsValues;
private KeyboardTheme mKeyboardTheme;
private Context mThemeContext;
@@ -101,7 +101,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
if (mThemeContext == null || !keyboardTheme.equals(mKeyboardTheme)) {
mKeyboardTheme = keyboardTheme;
mThemeContext = new ContextThemeWrapper(context, keyboardTheme.mStyleId);
- KeyboardLayoutSet.clearKeyboardCache();
+ KeyboardLayoutSet.onKeyboardThemeChanged();
return true;
}
return false;
@@ -119,7 +119,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
builder.setVoiceInputKeyEnabled(settingsValues.mShowsVoiceInputKey);
builder.setLanguageSwitchKeyEnabled(mLatinIME.shouldShowLanguageSwitchKey());
mKeyboardLayoutSet = builder.build();
- mCurrentSettingsValues = settingsValues;
try {
mState.onLoadKeyboard(currentAutoCapsState, currentRecapitalizeState);
mKeyboardTextsSet.setLocale(mSubtypeSwitcher.getCurrentSubtypeLocale(), mThemeContext);
@@ -143,19 +142,24 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
private void setKeyboard(final Keyboard keyboard) {
// Make {@link MainKeyboardView} visible and hide {@link EmojiPalettesView}.
- setMainKeyboardFrame();
+ final SettingsValues currentSettingsValues = Settings.getInstance().getCurrent();
+ setMainKeyboardFrame(currentSettingsValues);
+ // TODO: pass this object to setKeyboard instead of getting the current values.
final MainKeyboardView keyboardView = mKeyboardView;
final Keyboard oldKeyboard = keyboardView.getKeyboard();
keyboardView.setKeyboard(keyboard);
mCurrentInputView.setKeyboardTopPadding(keyboard.mTopPadding);
keyboardView.setKeyPreviewPopupEnabled(
- mCurrentSettingsValues.mKeyPreviewPopupOn,
- mCurrentSettingsValues.mKeyPreviewPopupDismissDelay);
+ currentSettingsValues.mKeyPreviewPopupOn,
+ currentSettingsValues.mKeyPreviewPopupDismissDelay);
keyboardView.setKeyPreviewAnimationParams(
- mCurrentSettingsValues.mKeyPreviewShowUpStartScale,
- mCurrentSettingsValues.mKeyPreviewShowUpDuration,
- mCurrentSettingsValues.mKeyPreviewDismissEndScale,
- mCurrentSettingsValues.mKeyPreviewDismissDuration);
+ currentSettingsValues.mHasCustomKeyPreviewAnimationParams,
+ currentSettingsValues.mKeyPreviewShowUpStartXScale,
+ currentSettingsValues.mKeyPreviewShowUpStartYScale,
+ currentSettingsValues.mKeyPreviewShowUpDuration,
+ currentSettingsValues.mKeyPreviewDismissEndXScale,
+ currentSettingsValues.mKeyPreviewDismissEndYScale,
+ currentSettingsValues.mKeyPreviewDismissDuration);
keyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady());
final boolean subtypeChanged = (oldKeyboard == null)
|| !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale);
@@ -232,8 +236,9 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS));
}
- private void setMainKeyboardFrame() {
- mMainKeyboardFrame.setVisibility(View.VISIBLE);
+ private void setMainKeyboardFrame(final SettingsValues settingsValues) {
+ mMainKeyboardFrame.setVisibility(
+ settingsValues.mHasHardwareKeyboard ? View.GONE : View.VISIBLE);
mEmojiPalettesView.setVisibility(View.GONE);
mEmojiPalettesView.stopEmojiPalettes();
}
@@ -249,6 +254,16 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mEmojiPalettesView.setVisibility(View.VISIBLE);
}
+ public void onToggleEmojiKeyboard() {
+ if (mKeyboardLayoutSet == null || !isShowingEmojiPalettes()) {
+ mLatinIME.startShowingInputView();
+ setEmojiKeyboard();
+ } else {
+ mLatinIME.stopShowingInputView();
+ setAlphabetKeyboard();
+ }
+ }
+
// Implements {@link KeyboardState.SwitchActions}.
@Override
public void setSymbolsShiftedKeyboard() {
@@ -337,7 +352,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
R.layout.input_view, null);
mMainKeyboardFrame = mCurrentInputView.findViewById(R.id.main_keyboard_frame);
mEmojiPalettesView = (EmojiPalettesView)mCurrentInputView.findViewById(
- R.id.emoji_keyboard_view);
+ R.id.emoji_palettes_view);
mKeyboardView = (MainKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view);
mKeyboardView.setHardwareAcceleratedDrawingEnabled(isHardwareAcceleratedDrawingEnabled);
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
index 4c2e0dd1d..7161d3f26 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
@@ -17,11 +17,11 @@
package com.android.inputmethod.keyboard;
import android.content.SharedPreferences;
-import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.util.Log;
import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.compat.BuildCompatUtils;
import com.android.inputmethod.latin.R;
import java.util.Arrays;
@@ -32,6 +32,8 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
static final String KLP_KEYBOARD_THEME_KEY = "pref_keyboard_layout_20110916";
static final String LXX_KEYBOARD_THEME_KEY = "pref_keyboard_theme_20140509";
+ // These should be aligned with Keyboard.themeId and Keyboard.Case.keyboardTheme
+ // attributes' values in attrs.xml.
public static final int THEME_ID_ICS = 0;
public static final int THEME_ID_KLP = 2;
public static final int THEME_ID_LXX_LIGHT = 3;
@@ -39,17 +41,16 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
public static final int DEFAULT_THEME_ID = THEME_ID_KLP;
private static final KeyboardTheme[] KEYBOARD_THEMES = {
- new KeyboardTheme(THEME_ID_ICS, R.style.KeyboardTheme_ICS,
+ new KeyboardTheme(THEME_ID_ICS, "ICS", R.style.KeyboardTheme_ICS,
// This has never been selected because we support ICS or later.
VERSION_CODES.BASE),
- new KeyboardTheme(THEME_ID_KLP, R.style.KeyboardTheme_KLP,
+ new KeyboardTheme(THEME_ID_KLP, "KLP", R.style.KeyboardTheme_KLP,
// Default theme for ICS, JB, and KLP.
VERSION_CODES.ICE_CREAM_SANDWICH),
- new KeyboardTheme(THEME_ID_LXX_LIGHT, R.style.KeyboardTheme_LXX_Light,
+ new KeyboardTheme(THEME_ID_LXX_LIGHT, "LXXLight", R.style.KeyboardTheme_LXX_Light,
// Default theme for LXX.
- // TODO: Update this constant once the *next* version becomes available.
- VERSION_CODES.CUR_DEVELOPMENT),
- new KeyboardTheme(THEME_ID_LXX_DARK, R.style.KeyboardTheme_LXX_Dark,
+ BuildCompatUtils.VERSION_CODES_LXX),
+ new KeyboardTheme(THEME_ID_LXX_DARK, "LXXDark", R.style.KeyboardTheme_LXX_Dark,
VERSION_CODES.BASE),
};
@@ -60,12 +61,15 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
public final int mThemeId;
public final int mStyleId;
+ public final String mThemeName;
private final int mMinApiVersion;
// Note: The themeId should be aligned with "themeId" attribute of Keyboard style
// in values/themes-<style>.xml.
- private KeyboardTheme(final int themeId, final int styleId, final int minApiVersion) {
+ private KeyboardTheme(final int themeId, final String themeName, final int styleId,
+ final int minApiVersion) {
mThemeId = themeId;
+ mThemeName = themeName;
mStyleId = styleId;
mMinApiVersion = minApiVersion;
}
@@ -99,15 +103,6 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
return null;
}
- private static int getSdkVersion() {
- final int sdkVersion = Build.VERSION.SDK_INT;
- // TODO: Consider to remove this check once the *next* version becomes available.
- if (sdkVersion > VERSION_CODES.KITKAT) {
- return VERSION_CODES.CUR_DEVELOPMENT;
- }
- return sdkVersion;
- }
-
@UsedForTesting
static KeyboardTheme getDefaultKeyboardTheme(final SharedPreferences prefs,
final int sdkVersion) {
@@ -138,9 +133,14 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
return searchKeyboardThemeById(DEFAULT_THEME_ID);
}
+ public static String getKeyboardThemeName(final int themeId) {
+ final KeyboardTheme theme = searchKeyboardThemeById(themeId);
+ return theme.mThemeName;
+ }
+
public static void saveKeyboardThemeId(final String themeIdString,
final SharedPreferences prefs) {
- saveKeyboardThemeId(themeIdString, prefs, getSdkVersion());
+ saveKeyboardThemeId(themeIdString, prefs, BuildCompatUtils.EFFECTIVE_SDK_INT);
}
@UsedForTesting
@@ -159,7 +159,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
}
public static KeyboardTheme getKeyboardTheme(final SharedPreferences prefs) {
- return getKeyboardTheme(prefs, getSdkVersion());
+ return getKeyboardTheme(prefs, BuildCompatUtils.EFFECTIVE_SDK_INT);
}
@UsedForTesting
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index f967f620a..98cd1da54 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -29,6 +29,7 @@ import android.graphics.Region;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
@@ -47,7 +48,9 @@ import java.util.HashSet;
* @attr ref R.styleable#KeyboardView_functionalKeyBackground
* @attr ref R.styleable#KeyboardView_spacebarBackground
* @attr ref R.styleable#KeyboardView_spacebarIconWidthRatio
+ * @attr ref R.styleable#Keyboard_Key_keyLabelFlags
* @attr ref R.styleable#KeyboardView_keyHintLetterPadding
+ * @attr ref R.styleable#KeyboardView_keyPopupHintLetter
* @attr ref R.styleable#KeyboardView_keyPopupHintLetterPadding
* @attr ref R.styleable#KeyboardView_keyShiftedLetterHintPadding
* @attr ref R.styleable#KeyboardView_keyTextShadowRadius
@@ -60,6 +63,8 @@ import java.util.HashSet;
* @attr ref R.styleable#Keyboard_Key_keyHintLetterRatio
* @attr ref R.styleable#Keyboard_Key_keyShiftedLetterHintRatio
* @attr ref R.styleable#Keyboard_Key_keyHintLabelRatio
+ * @attr ref R.styleable#Keyboard_Key_keyLabelOffCenterRatio
+ * @attr ref R.styleable#Keyboard_Key_keyHintLabelOffCenterRatio
* @attr ref R.styleable#Keyboard_Key_keyPreviewTextRatio
* @attr ref R.styleable#Keyboard_Key_keyTextColor
* @attr ref R.styleable#Keyboard_Key_keyTextColorDisabled
@@ -73,7 +78,11 @@ import java.util.HashSet;
public class KeyboardView extends View {
// XML attributes
private final KeyVisualAttributes mKeyVisualAttributes;
+ // Default keyLabelFlags from {@link KeyboardTheme}.
+ // Currently only "alignHintLabelToBottom" is supported.
+ private final int mDefaultKeyLabelFlags;
private final float mKeyHintLetterPadding;
+ private final String mKeyPopupHintLetter;
private final float mKeyPopupHintLetterPadding;
private final float mKeyShiftedLetterHintPadding;
private final float mKeyTextShadowRadius;
@@ -85,9 +94,6 @@ public class KeyboardView extends View {
private final Rect mKeyBackgroundPadding = new Rect();
private static final float KET_TEXT_SHADOW_RADIUS_DISABLED = -1.0f;
- // HORIZONTAL ELLIPSIS "...", character for popup hint.
- private static final String POPUP_HINT_CHAR = "\u2026";
-
// The maximum key label width in the proportion to the key width.
private static final float MAX_LABEL_RATIO = 0.90f;
@@ -132,6 +138,8 @@ public class KeyboardView extends View {
R.styleable.KeyboardView_spacebarIconWidthRatio, 1.0f);
mKeyHintLetterPadding = keyboardViewAttr.getDimension(
R.styleable.KeyboardView_keyHintLetterPadding, 0.0f);
+ mKeyPopupHintLetter = keyboardViewAttr.getString(
+ R.styleable.KeyboardView_keyPopupHintLetter);
mKeyPopupHintLetterPadding = keyboardViewAttr.getDimension(
R.styleable.KeyboardView_keyPopupHintLetterPadding, 0.0f);
mKeyShiftedLetterHintPadding = keyboardViewAttr.getDimension(
@@ -144,6 +152,7 @@ public class KeyboardView extends View {
final TypedArray keyAttr = context.obtainStyledAttributes(attrs,
R.styleable.Keyboard_Key, defStyle, R.style.KeyboardView);
+ mDefaultKeyLabelFlags = keyAttr.getInt(R.styleable.Keyboard_Key_keyLabelFlags, 0);
mKeyVisualAttributes = KeyVisualAttributes.newInstance(keyAttr);
keyAttr.recycle();
@@ -331,11 +340,27 @@ public class KeyboardView extends View {
// Draw key background.
protected void onDrawKeyBackground(final Key key, final Canvas canvas,
final Drawable background) {
- final Rect padding = mKeyBackgroundPadding;
- final int bgWidth = key.getDrawWidth() + padding.left + padding.right;
- final int bgHeight = key.getHeight() + padding.top + padding.bottom;
- final int bgX = -padding.left;
- final int bgY = -padding.top;
+ final int keyWidth = key.getDrawWidth();
+ final int keyHeight = key.getHeight();
+ final int bgWidth, bgHeight, bgX, bgY;
+ if (key.needsToKeepBackgroundAspectRatio(mDefaultKeyLabelFlags)
+ // HACK: To disable expanding normal/functional key background.
+ && !key.hasCustomActionLabel()) {
+ final int intrinsicWidth = background.getIntrinsicWidth();
+ final int intrinsicHeight = background.getIntrinsicHeight();
+ final float minScale = Math.min(
+ keyWidth / (float)intrinsicWidth, keyHeight / (float)intrinsicHeight);
+ bgWidth = (int)(intrinsicWidth * minScale);
+ bgHeight = (int)(intrinsicHeight * minScale);
+ bgX = (keyWidth - bgWidth) / 2;
+ bgY = (keyHeight - bgHeight) / 2;
+ } else {
+ final Rect padding = mKeyBackgroundPadding;
+ bgWidth = keyWidth + padding.left + padding.right;
+ bgHeight = keyHeight + padding.top + padding.bottom;
+ bgX = -padding.left;
+ bgY = -padding.top;
+ }
final Rect bounds = background.getBounds();
if (bgWidth != bounds.right || bgHeight != bounds.bottom) {
background.setBounds(0, 0, bgWidth, bgHeight);
@@ -355,7 +380,8 @@ public class KeyboardView extends View {
// Draw key label.
final Drawable icon = key.getIcon(mKeyboard.mIconsSet, params.mAnimAlpha);
- float positionX = centerX;
+ float labelX = centerX;
+ float labelBaseline = centerY;
final String label = key.getLabel();
if (label != null) {
paint.setTypeface(key.selectTypeface(params));
@@ -364,15 +390,15 @@ public class KeyboardView extends View {
final float labelCharWidth = TypefaceUtils.getReferenceCharWidth(paint);
// Vertical label text alignment.
- final float baseline = centerY + labelCharHeight / 2.0f;
+ labelBaseline = centerY + labelCharHeight / 2.0f;
// Horizontal label text alignment
- if (key.isAlignLeftOfCenter()) {
- // TODO: Parameterise this?
- positionX = centerX - labelCharWidth * 7.0f / 4.0f;
+ if (key.isAlignLabelOffCenter()) {
+ // The label is placed off center of the key. Used mainly on "phone number" layout.
+ labelX = centerX + params.mLabelOffCenterRatio * labelCharWidth;
paint.setTextAlign(Align.LEFT);
} else {
- positionX = centerX;
+ labelX = centerX;
paint.setTextAlign(Align.CENTER);
}
if (key.needsAutoXScale()) {
@@ -400,7 +426,7 @@ public class KeyboardView extends View {
paint.clearShadowLayer();
}
blendAlpha(paint, params.mAnimAlpha);
- canvas.drawText(label, 0, label.length(), positionX, baseline, paint);
+ canvas.drawText(label, 0, label.length(), labelX, labelBaseline, paint);
// Turn off drop shadow and reset x-scale.
paint.clearShadowLayer();
paint.setTextScaleX(1.0f);
@@ -416,22 +442,22 @@ public class KeyboardView extends View {
blendAlpha(paint, params.mAnimAlpha);
final float labelCharHeight = TypefaceUtils.getReferenceCharHeight(paint);
final float labelCharWidth = TypefaceUtils.getReferenceCharWidth(paint);
- final KeyVisualAttributes visualAttr = key.getVisualAttributes();
- final float adjustmentY = (visualAttr == null) ? 0.0f
- : visualAttr.mHintLabelVerticalAdjustment * labelCharHeight;
- final float hintX, hintY;
+ final float hintX, hintBaseline;
if (key.hasHintLabel()) {
// The hint label is placed just right of the key label. Used mainly on
// "phone number" layout.
- // TODO: Generalize the following calculations.
- hintX = positionX + labelCharWidth * 2.0f;
- hintY = centerY + labelCharHeight / 2.0f;
+ hintX = labelX + params.mHintLabelOffCenterRatio * labelCharWidth;
+ if (key.isAlignHintLabelToBottom(mDefaultKeyLabelFlags)) {
+ hintBaseline = labelBaseline;
+ } else {
+ hintBaseline = centerY + labelCharHeight / 2.0f;
+ }
paint.setTextAlign(Align.LEFT);
} else if (key.hasShiftedLetterHint()) {
// The hint label is placed at top-right corner of the key. Used mainly on tablet.
hintX = keyWidth - mKeyShiftedLetterHintPadding - labelCharWidth / 2.0f;
paint.getFontMetrics(mFontMetrics);
- hintY = -mFontMetrics.top;
+ hintBaseline = -mFontMetrics.top;
paint.setTextAlign(Align.CENTER);
} else { // key.hasHintLetter()
// The hint letter is placed at top-right corner of the key. Used mainly on phone.
@@ -439,10 +465,12 @@ public class KeyboardView extends View {
final float hintLabelWidth = TypefaceUtils.getStringWidth(hintLabel, paint);
hintX = keyWidth - mKeyHintLetterPadding
- Math.max(hintDigitWidth, hintLabelWidth) / 2.0f;
- hintY = -paint.ascent();
+ hintBaseline = -paint.ascent();
paint.setTextAlign(Align.CENTER);
}
- canvas.drawText(hintLabel, 0, hintLabel.length(), hintX, hintY + adjustmentY, paint);
+ final float adjustmentY = params.mHintLabelVerticalAdjustment * labelCharHeight;
+ canvas.drawText(
+ hintLabel, 0, hintLabel.length(), hintX, hintBaseline + adjustmentY, paint);
}
// Draw key icon.
@@ -454,9 +482,13 @@ public class KeyboardView extends View {
iconWidth = Math.min(icon.getIntrinsicWidth(), keyWidth);
}
final int iconHeight = icon.getIntrinsicHeight();
- // Align center.
- final int iconY = (keyHeight - iconHeight) / 2;
- final int iconX = (keyWidth - iconWidth) / 2;
+ final int iconY;
+ if (key.isAlignIconToBottom()) {
+ iconY = keyHeight - iconHeight;
+ } else {
+ iconY = (keyHeight - iconHeight) / 2; // Align vertically center.
+ }
+ final int iconX = (keyWidth - iconWidth) / 2; // Align horizontally center.
drawIcon(canvas, icon, iconX, iconY, iconWidth, iconHeight);
}
@@ -468,6 +500,9 @@ public class KeyboardView extends View {
// Draw popup hint "..." at the bottom right corner of the key.
protected void drawKeyPopupHint(final Key key, final Canvas canvas, final Paint paint,
final KeyDrawParams params) {
+ if (TextUtils.isEmpty(mKeyPopupHintLetter)) {
+ return;
+ }
final int keyWidth = key.getDrawWidth();
final int keyHeight = key.getHeight();
@@ -478,7 +513,7 @@ public class KeyboardView extends View {
final float hintX = keyWidth - mKeyHintLetterPadding
- TypefaceUtils.getReferenceCharWidth(paint) / 2.0f;
final float hintY = keyHeight - mKeyPopupHintLetterPadding;
- canvas.drawText(POPUP_HINT_CHAR, hintX, hintY, paint);
+ canvas.drawText(mKeyPopupHintLetter, hintX, hintY, paint);
}
protected static void drawIcon(final Canvas canvas, final Drawable icon, final int x,
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 702efb3d7..2b16785c2 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -46,6 +46,7 @@ import com.android.inputmethod.keyboard.internal.GestureTrailsDrawingPreview;
import com.android.inputmethod.keyboard.internal.KeyDrawParams;
import com.android.inputmethod.keyboard.internal.KeyPreviewChoreographer;
import com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams;
+import com.android.inputmethod.keyboard.internal.KeyPreviewView;
import com.android.inputmethod.keyboard.internal.LanguageOnSpacebarHelper;
import com.android.inputmethod.keyboard.internal.MoreKeySpec;
import com.android.inputmethod.keyboard.internal.NonDistinctMultitouchHelper;
@@ -85,7 +86,10 @@ import java.util.WeakHashMap;
* @attr ref R.styleable#MainKeyboardView_keyPreviewOffset
* @attr ref R.styleable#MainKeyboardView_keyPreviewHeight
* @attr ref R.styleable#MainKeyboardView_keyPreviewLingerTimeout
+ * @attr ref R.styleable#MainKeyboardView_keyPreviewShowUpAnimator
+ * @attr ref R.styleable#MainKeyboardView_keyPreviewDismissAnimator
* @attr ref R.styleable#MainKeyboardView_moreKeysKeyboardLayout
+ * @attr ref R.styleable#MainKeyboardView_moreKeysKeyboardForActionLayout
* @attr ref R.styleable#MainKeyboardView_backgroundDimAlpha
* @attr ref R.styleable#MainKeyboardView_showMoreKeysKeyboardAtTouchPoint
* @attr ref R.styleable#MainKeyboardView_gestureFloatingPreviewTextLingerTimeout
@@ -145,6 +149,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
private final Paint mBackgroundDimAlphaPaint = new Paint();
private boolean mNeedsToDimEntireKeyboard;
private final View mMoreKeysKeyboardContainer;
+ private final View mMoreKeysKeyboardForActionContainer;
private final WeakHashMap<Key, Keyboard> mMoreKeysKeyboardCache = new WeakHashMap<>();
private final boolean mConfigShowMoreKeysKeyboardAtTouchedPoint;
// More keys panel (used by both more keys keyboard and more suggestions view)
@@ -229,6 +234,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
final int moreKeysKeyboardLayoutId = mainKeyboardViewAttr.getResourceId(
R.styleable.MainKeyboardView_moreKeysKeyboardLayout, 0);
+ final int moreKeysKeyboardForActionLayoutId = mainKeyboardViewAttr.getResourceId(
+ R.styleable.MainKeyboardView_moreKeysKeyboardForActionLayout,
+ moreKeysKeyboardLayoutId);
mConfigShowMoreKeysKeyboardAtTouchedPoint = mainKeyboardViewAttr.getBoolean(
R.styleable.MainKeyboardView_showMoreKeysKeyboardAtTouchedPoint, false);
@@ -246,8 +254,10 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
mSlidingKeyInputDrawingPreview.setDrawingView(mDrawingPreviewPlacerView);
mainKeyboardViewAttr.recycle();
- mMoreKeysKeyboardContainer = LayoutInflater.from(getContext())
- .inflate(moreKeysKeyboardLayoutId, null);
+ final LayoutInflater inflater = LayoutInflater.from(getContext());
+ mMoreKeysKeyboardContainer = inflater.inflate(moreKeysKeyboardLayoutId, null);
+ mMoreKeysKeyboardForActionContainer = inflater.inflate(
+ moreKeysKeyboardForActionLayoutId, null);
mLanguageOnSpacebarFadeoutAnimator = loadObjectAnimator(
languageOnSpacebarFadeoutAnimatorResId, this);
mAltCodeKeyWhileTypingFadeoutAnimator = loadObjectAnimator(
@@ -390,20 +400,34 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
}
/**
- * Enables or disables the key feedback popup. This is a popup that shows a magnified
+ * Enables or disables the key preview popup. This is a popup that shows a magnified
* version of the depressed key. By default the preview is enabled.
* @param previewEnabled whether or not to enable the key feedback preview
* @param delay the delay after which the preview is dismissed
- * @see #isKeyPreviewPopupEnabled()
*/
public void setKeyPreviewPopupEnabled(final boolean previewEnabled, final int delay) {
mKeyPreviewDrawParams.setPopupEnabled(previewEnabled, delay);
}
- public void setKeyPreviewAnimationParams(final float showUpStartScale, final int showUpDuration,
- final float dismissEndScale, final int dismissDuration) {
- mKeyPreviewDrawParams.setAnimationParams(
- showUpStartScale, showUpDuration, dismissEndScale, dismissDuration);
+ /**
+ * Enables or disables the key preview popup animations and set animations' parameters.
+ *
+ * @param hasCustomAnimationParams false to use the default key preview popup animations
+ * specified by keyPreviewShowUpAnimator and keyPreviewDismissAnimator attributes.
+ * true to override the default animations with the specified parameters.
+ * @param showUpStartXScale from this x-scale the show up animation will start.
+ * @param showUpStartYScale from this y-scale the show up animation will start.
+ * @param showUpDuration the duration of the show up animation in milliseconds.
+ * @param dismissEndXScale to this x-scale the dismiss animation will end.
+ * @param dismissEndYScale to this y-scale the dismiss animation will end.
+ * @param dismissDuration the duration of the dismiss animation in milliseconds.
+ */
+ public void setKeyPreviewAnimationParams(final boolean hasCustomAnimationParams,
+ final float showUpStartXScale, final float showUpStartYScale, final int showUpDuration,
+ final float dismissEndXScale, final float dismissEndYScale, final int dismissDuration) {
+ mKeyPreviewDrawParams.setAnimationParams(hasCustomAnimationParams,
+ showUpStartXScale, showUpStartYScale, showUpDuration,
+ dismissEndXScale, dismissEndYScale, dismissDuration);
}
private void locatePreviewPlacerView() {
@@ -565,7 +589,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
mMoreKeysKeyboardCache.put(key, moreKeysKeyboard);
}
- final View container = mMoreKeysKeyboardContainer;
+ final View container = key.isActionKey() ? mMoreKeysKeyboardForActionContainer
+ : mMoreKeysKeyboardContainer;
final MoreKeysKeyboardView moreKeysKeyboardView =
(MoreKeysKeyboardView)container.findViewById(R.id.more_keys_keyboard_view);
moreKeysKeyboardView.setKeyboard(moreKeysKeyboard);
@@ -731,7 +756,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
public void onHideWindow() {
onDismissMoreKeysPanel();
final MainKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate;
- if (accessibilityDelegate != null) {
+ if (accessibilityDelegate != null
+ && AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
accessibilityDelegate.onHideWindow();
}
}
@@ -742,7 +768,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
@Override
public boolean onHoverEvent(final MotionEvent event) {
final MainKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate;
- if (accessibilityDelegate != null) {
+ if (accessibilityDelegate != null
+ && AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
return accessibilityDelegate.onHoverEvent(event);
}
return super.onHoverEvent(event);
@@ -764,6 +791,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
public void startDisplayLanguageOnSpacebar(final boolean subtypeChanged,
final int languageOnSpacebarFormatType,
final boolean hasMultipleEnabledIMEsOrSubtypes) {
+ if (subtypeChanged) {
+ KeyPreviewView.clearTextCache();
+ }
mLanguageOnSpacebarFormatType = languageOnSpacebarFormatType;
mHasMultipleEnabledIMEsOrSubtypes = hasMultipleEnabledIMEsOrSubtypes;
final ObjectAnimator animator = mLanguageOnSpacebarFadeoutAnimator;
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
index e0184d7f1..abcfff8a6 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
@@ -18,11 +18,9 @@ package com.android.inputmethod.keyboard;
import android.content.Context;
import android.graphics.Paint;
-import android.graphics.drawable.Drawable;
import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
-import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
import com.android.inputmethod.keyboard.internal.KeyboardParams;
import com.android.inputmethod.keyboard.internal.MoreKeySpec;
import com.android.inputmethod.latin.R;
@@ -43,7 +41,7 @@ public final class MoreKeysKeyboard extends Keyboard {
@UsedForTesting
static class MoreKeysKeyboardParams extends KeyboardParams {
- public boolean mIsFixedOrder;
+ public boolean mIsMoreKeysFixedOrder;
/* package */int mTopRowAdjustment;
public int mNumRows;
public int mNumColumns;
@@ -61,29 +59,35 @@ public final class MoreKeysKeyboard extends Keyboard {
* Set keyboard parameters of more keys keyboard.
*
* @param numKeys number of keys in this more keys keyboard.
- * @param maxColumns number of maximum columns of this more keys keyboard.
+ * @param numColumn number of columns of this more keys keyboard.
* @param keyWidth more keys keyboard key width in pixel, including horizontal gap.
* @param rowHeight more keys keyboard row height in pixel, including vertical gap.
* @param coordXInParent coordinate x of the key preview in parent keyboard.
* @param parentKeyboardWidth parent keyboard width in pixel.
- * @param isFixedColumnOrder if true, more keys should be laid out in fixed order.
+ * @param isMoreKeysFixedColumn true if more keys keyboard should have
+ * <code>numColumn</code> columns. Otherwise more keys keyboard should have
+ * <code>numColumn</code> columns at most.
+ * @param isMoreKeysFixedOrder true if the order of more keys is determined by the order in
+ * the more keys' specification. Otherwise the order of more keys is automatically
+ * determined.
* @param dividerWidth width of divider, zero for no dividers.
*/
- public void setParameters(final int numKeys, final int maxColumns, final int keyWidth,
+ public void setParameters(final int numKeys, final int numColumn, final int keyWidth,
final int rowHeight, final int coordXInParent, final int parentKeyboardWidth,
- final boolean isFixedColumnOrder, final int dividerWidth) {
- mIsFixedOrder = isFixedColumnOrder;
- if (parentKeyboardWidth / keyWidth < Math.min(numKeys, maxColumns)) {
+ final boolean isMoreKeysFixedColumn, final boolean isMoreKeysFixedOrder,
+ final int dividerWidth) {
+ mIsMoreKeysFixedOrder = isMoreKeysFixedOrder;
+ if (parentKeyboardWidth / keyWidth < Math.min(numKeys, numColumn)) {
throw new IllegalArgumentException("Keyboard is too small to hold more keys: "
- + parentKeyboardWidth + " " + keyWidth + " " + numKeys + " " + maxColumns);
+ + parentKeyboardWidth + " " + keyWidth + " " + numKeys + " " + numColumn);
}
mDefaultKeyWidth = keyWidth;
mDefaultRowHeight = rowHeight;
- final int numRows = (numKeys + maxColumns - 1) / maxColumns;
+ final int numRows = (numKeys + numColumn - 1) / numColumn;
mNumRows = numRows;
- final int numColumns = mIsFixedOrder ? Math.min(numKeys, maxColumns)
- : getOptimizedColumns(numKeys, maxColumns);
+ final int numColumns = isMoreKeysFixedColumn ? Math.min(numKeys, numColumn)
+ : getOptimizedColumns(numKeys, numColumn);
mNumColumns = numColumns;
final int topKeys = numKeys % numColumns;
mTopKeys = topKeys == 0 ? numColumns : topKeys;
@@ -120,7 +124,7 @@ public final class MoreKeysKeyboard extends Keyboard {
mRightKeys = rightKeys;
// Adjustment of the top row.
- mTopRowAdjustment = mIsFixedOrder ? getFixedOrderTopRowAdjustment()
+ mTopRowAdjustment = isMoreKeysFixedOrder ? getFixedOrderTopRowAdjustment()
: getAutoOrderTopRowAdjustment();
mDividerWidth = dividerWidth;
mColumnWidth = mDefaultKeyWidth + mDividerWidth;
@@ -148,7 +152,7 @@ public final class MoreKeysKeyboard extends Keyboard {
// Return key position according to column count (0 is default).
/* package */int getColumnPos(final int n) {
- return mIsFixedOrder ? getFixedOrderColumnPos(n) : getAutomaticColumnPos(n);
+ return mIsMoreKeysFixedOrder ? getFixedOrderColumnPos(n) : getAutomaticColumnPos(n);
}
private int getFixedOrderColumnPos(final int n) {
@@ -251,7 +255,6 @@ public final class MoreKeysKeyboard extends Keyboard {
public static class Builder extends KeyboardBuilder<MoreKeysKeyboardParams> {
private final Key mParentKey;
- private final Drawable mDivider;
private static final float LABEL_PADDING_RATIO = 0.2f;
private static final float DIVIDER_RATIO = 0.2f;
@@ -263,7 +266,8 @@ public final class MoreKeysKeyboard extends Keyboard {
* @param keyboard the {@link Keyboard} that contains the parentKey.
* @param isSingleMoreKeyWithPreview true if the <code>key</code> has just a single
* "more key" and its key popup preview is enabled.
- * @param keyPreviewDrawParams the parameter to place key preview.
+ * @param keyPreviewVisibleWidth the width of visible part of key popup preview.
+ * @param keyPreviewVisibleHeight the height of visible part of key popup preview
* @param paintToMeasure the {@link Paint} object to measure a "more key" width
*/
public Builder(final Context context, final Key key, final Keyboard keyboard,
@@ -299,16 +303,14 @@ public final class MoreKeysKeyboard extends Keyboard {
}
final int dividerWidth;
if (key.needsDividersInMoreKeys()) {
- mDivider = mResources.getDrawable(R.drawable.more_keys_divider);
dividerWidth = (int)(keyWidth * DIVIDER_RATIO);
} else {
- mDivider = null;
dividerWidth = 0;
}
final MoreKeySpec[] moreKeys = key.getMoreKeys();
- mParams.setParameters(moreKeys.length, key.getMoreKeysColumn(), keyWidth, rowHeight,
- key.getX() + key.getWidth() / 2, keyboard.mId.mWidth,
- key.isFixedColumnOrderMoreKeys(), dividerWidth);
+ mParams.setParameters(moreKeys.length, key.getMoreKeysColumnNumber(), keyWidth,
+ rowHeight, key.getX() + key.getWidth() / 2, keyboard.mId.mWidth,
+ key.isMoreKeysFixedColumn(), key.isMoreKeysFixedOrder(), dividerWidth);
}
private static int getMaxKeyWidth(final Key parentKey, final int minKeyWidth,
@@ -345,7 +347,8 @@ public final class MoreKeysKeyboard extends Keyboard {
if (params.mDividerWidth > 0 && pos != 0) {
final int dividerX = (pos > 0) ? x - params.mDividerWidth
: x + params.mDefaultKeyWidth;
- final Key divider = new MoreKeyDivider(params, mDivider, dividerX, y);
+ final Key divider = new MoreKeyDivider(
+ params, dividerX, y, params.mDividerWidth, params.mDefaultRowHeight);
params.onAddKey(divider);
}
}
@@ -353,22 +356,11 @@ public final class MoreKeysKeyboard extends Keyboard {
}
}
- private static class MoreKeyDivider extends Key.Spacer {
- private final Drawable mIcon;
-
- public MoreKeyDivider(final MoreKeysKeyboardParams params, final Drawable icon,
- final int x, final int y) {
- super(params, x, y, params.mDividerWidth, params.mDefaultRowHeight);
- mIcon = icon;
- }
-
- @Override
- public Drawable getIcon(final KeyboardIconsSet iconSet, final int alpha) {
- // KeyboardIconsSet and alpha are unused. Use the icon that has been passed to the
- // constructor.
- // TODO: Drawable itself should have an alpha value.
- mIcon.setAlpha(128);
- return mIcon;
+ // Used as a divider maker. A divider is drawn by {@link MoreKeysKeyboardView}.
+ public static class MoreKeyDivider extends Key.Spacer {
+ public MoreKeyDivider(final KeyboardParams params, final int x, final int y,
+ final int width, final int height) {
+ super(params, x, y, width, height);
}
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
index 5140c4ffc..841283b7f 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
@@ -17,6 +17,10 @@
package com.android.inputmethod.keyboard;
import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -24,6 +28,7 @@ import android.view.ViewGroup;
import com.android.inputmethod.accessibility.AccessibilityUtils;
import com.android.inputmethod.accessibility.MoreKeysKeyboardAccessibilityDelegate;
+import com.android.inputmethod.keyboard.internal.KeyDrawParams;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.utils.CoordinateUtils;
@@ -35,6 +40,7 @@ import com.android.inputmethod.latin.utils.CoordinateUtils;
public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel {
private final int[] mCoordinates = CoordinateUtils.newInstance();
+ private final Drawable mDivider;
protected final KeyDetector mKeyDetector;
private Controller mController = EMPTY_CONTROLLER;
protected KeyboardActionListener mListener;
@@ -53,6 +59,14 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel
public MoreKeysKeyboardView(final Context context, final AttributeSet attrs,
final int defStyle) {
super(context, attrs, defStyle);
+ final TypedArray moreKeysKeyboardViewAttr = context.obtainStyledAttributes(attrs,
+ R.styleable.MoreKeysKeyboardView, defStyle, R.style.MoreKeysKeyboardView);
+ mDivider = moreKeysKeyboardViewAttr.getDrawable(R.styleable.MoreKeysKeyboardView_divider);
+ if (mDivider != null) {
+ // TODO: Drawable itself should have an alpha value.
+ mDivider.setAlpha(128);
+ }
+ moreKeysKeyboardViewAttr.recycle();
mKeyDetector = new MoreKeysDetector(getResources().getDimension(
R.dimen.config_more_keys_keyboard_slide_allowance));
}
@@ -70,11 +84,28 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel
}
@Override
+ protected void onDrawKeyTopVisuals(final Key key, final Canvas canvas, final Paint paint,
+ final KeyDrawParams params) {
+ if (!key.isSpacer() || !(key instanceof MoreKeysKeyboard.MoreKeyDivider)
+ || mDivider == null) {
+ super.onDrawKeyTopVisuals(key, canvas, paint, params);
+ return;
+ }
+ final int keyWidth = key.getDrawWidth();
+ final int keyHeight = key.getHeight();
+ final int iconWidth = Math.min(mDivider.getIntrinsicWidth(), keyWidth);
+ final int iconHeight = mDivider.getIntrinsicHeight();
+ final int iconX = (keyWidth - iconWidth) / 2; // Align horizontally center
+ final int iconY = (keyHeight - iconHeight) / 2; // Align vertically center
+ drawIcon(canvas, mDivider, iconX, iconY, iconWidth, iconHeight);
+ }
+
+ @Override
public void setKeyboard(final Keyboard keyboard) {
super.setKeyboard(keyboard);
mKeyDetector.setKeyboard(
keyboard, -getPaddingLeft(), -getPaddingTop() + getVerticalCorrection());
- if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
+ if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
if (mAccessibilityDelegate == null) {
mAccessibilityDelegate = new MoreKeysKeyboardAccessibilityDelegate(
this, mKeyDetector);
@@ -111,7 +142,8 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel
mOriginY = y + container.getPaddingTop();
controller.onShowMoreKeysPanel(this);
final MoreKeysKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate;
- if (accessibilityDelegate != null) {
+ if (accessibilityDelegate != null
+ && AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
accessibilityDelegate.onShowMoreKeysKeyboard();
}
}
@@ -208,7 +240,8 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel
return;
}
final MoreKeysKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate;
- if (accessibilityDelegate != null) {
+ if (accessibilityDelegate != null
+ && AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
accessibilityDelegate.onDismissMoreKeysKeyboard();
}
mController.onDismissMoreKeysPanel();
@@ -254,7 +287,8 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel
@Override
public boolean onHoverEvent(final MotionEvent event) {
final MoreKeysKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate;
- if (accessibilityDelegate != null) {
+ if (accessibilityDelegate != null
+ && AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
return accessibilityDelegate.onHoverEvent(event);
}
return super.onHoverEvent(event);
diff --git a/java/src/com/android/inputmethod/keyboard/TextDecorator.java b/java/src/com/android/inputmethod/keyboard/TextDecorator.java
new file mode 100644
index 000000000..c22717f95
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/TextDecorator.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard;
+
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.inputmethodservice.InputMethodService;
+import android.os.Message;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.view.inputmethod.CursorAnchorInfo;
+
+import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper;
+import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A controller class of the add-to-dictionary indicator (a.k.a. TextDecorator). This class
+ * is designed to be independent of UI subsystems such as {@link View}. All the UI related
+ * operations are delegated to {@link TextDecoratorUi} via {@link TextDecoratorUiOperator}.
+ */
+public class TextDecorator {
+ private static final String TAG = TextDecorator.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
+ private static final int INVALID_CURSOR_INDEX = -1;
+
+ private static final int MODE_MONITOR = 0;
+ private static final int MODE_WAITING_CURSOR_INDEX = 1;
+ private static final int MODE_SHOWING_INDICATOR = 2;
+
+ private int mMode = MODE_MONITOR;
+
+ private String mLastComposingText = null;
+ private boolean mHasRtlCharsInLastComposingText = false;
+ private RectF mComposingTextBoundsForLastComposingText = new RectF();
+
+ private boolean mIsFullScreenMode = false;
+ private String mWaitingWord = null;
+ private int mWaitingCursorStart = INVALID_CURSOR_INDEX;
+ private int mWaitingCursorEnd = INVALID_CURSOR_INDEX;
+ private CursorAnchorInfoCompatWrapper mCursorAnchorInfoWrapper = null;
+
+ @Nonnull
+ private final Listener mListener;
+
+ @Nonnull
+ private TextDecoratorUiOperator mUiOperator = EMPTY_UI_OPERATOR;
+
+ public interface Listener {
+ /**
+ * Called when the user clicks the indicator to add the word into the dictionary.
+ * @param word the word which the user clicked on.
+ */
+ void onClickComposingTextToAddToDictionary(final String word);
+ }
+
+ public TextDecorator(final Listener listener) {
+ mListener = (listener != null) ? listener : EMPTY_LISTENER;
+ }
+
+ /**
+ * Sets the UI operator for {@link TextDecorator}. Any user visible operations will be
+ * delegated to the associated UI operator.
+ * @param uiOperator the UI operator to be associated.
+ */
+ public void setUiOperator(final TextDecoratorUiOperator uiOperator) {
+ mUiOperator.disposeUi();
+ mUiOperator = uiOperator;
+ mUiOperator.setOnClickListener(getOnClickHandler());
+ }
+
+ private final Runnable mDefaultOnClickHandler = new Runnable() {
+ @Override
+ public void run() {
+ onClickIndicator();
+ }
+ };
+
+ @UsedForTesting
+ final Runnable getOnClickHandler() {
+ return mDefaultOnClickHandler;
+ }
+
+ /**
+ * Shows the "Add to dictionary" indicator and associates it with associating the given word.
+ *
+ * @param word the word which should be associated with the indicator. This object will be
+ * passed back in {@link Listener#onClickComposingTextToAddToDictionary(String)}.
+ * @param selectionStart the cursor index (inclusive) when the indicator should be displayed.
+ * @param selectionEnd the cursor index (exclusive) when the indicator should be displayed.
+ */
+ public void showAddToDictionaryIndicator(final String word, final int selectionStart,
+ final int selectionEnd) {
+ mWaitingWord = word;
+ mWaitingCursorStart = selectionStart;
+ mWaitingCursorEnd = selectionEnd;
+ mMode = MODE_WAITING_CURSOR_INDEX;
+ layoutLater();
+ return;
+ }
+
+ /**
+ * Must be called when the input method is about changing to for from the full screen mode.
+ * @param fullScreenMode {@code true} if the input method is entering the full screen mode.
+ * {@code false} is the input method is finishing the full screen mode.
+ */
+ public void notifyFullScreenMode(final boolean fullScreenMode) {
+ final boolean fullScreenModeChanged = (mIsFullScreenMode != fullScreenMode);
+ mIsFullScreenMode = fullScreenMode;
+ if (fullScreenModeChanged) {
+ layoutLater();
+ }
+ }
+
+ /**
+ * Resets previous requests and makes indicator invisible.
+ */
+ public void reset() {
+ mWaitingWord = null;
+ mMode = MODE_MONITOR;
+ mWaitingCursorStart = INVALID_CURSOR_INDEX;
+ mWaitingCursorEnd = INVALID_CURSOR_INDEX;
+ cancelLayoutInternalExpectedly("Resetting internal state.");
+ }
+
+ /**
+ * Must be called when the {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)}
+ * is called.
+ *
+ * <p>CAVEAT: Currently the input method author is responsible for ignoring
+ * {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)} called in full screen
+ * mode.</p>
+ * @param info the compatibility wrapper object for the received {@link CursorAnchorInfo}.
+ */
+ public void onUpdateCursorAnchorInfo(final CursorAnchorInfoCompatWrapper info) {
+ mCursorAnchorInfoWrapper = info;
+ // Do not use layoutLater() to minimize the latency.
+ layoutImmediately();
+ }
+
+ private void cancelLayoutInternalUnexpectedly(final String message) {
+ mUiOperator.hideUi();
+ Log.d(TAG, message);
+ }
+
+ private void cancelLayoutInternalExpectedly(final String message) {
+ mUiOperator.hideUi();
+ if (DEBUG) {
+ Log.d(TAG, message);
+ }
+ }
+
+ private void layoutLater() {
+ mLayoutInvalidator.invalidateLayout();
+ }
+
+
+ private void layoutImmediately() {
+ // Clear pending layout requests.
+ mLayoutInvalidator.cancelInvalidateLayout();
+ layoutMain();
+ }
+
+ private void layoutMain() {
+ final CursorAnchorInfoCompatWrapper info = mCursorAnchorInfoWrapper;
+
+ if (info == null || !info.isAvailable()) {
+ cancelLayoutInternalExpectedly("CursorAnchorInfo isn't available.");
+ return;
+ }
+
+ final Matrix matrix = info.getMatrix();
+ if (matrix == null) {
+ cancelLayoutInternalUnexpectedly("Matrix is null");
+ }
+
+ final CharSequence composingText = info.getComposingText();
+ if (!TextUtils.isEmpty(composingText)) {
+ final int composingTextStart = info.getComposingTextStart();
+ final int lastCharRectIndex = composingTextStart + composingText.length() - 1;
+ final RectF lastCharRect = info.getCharacterBounds(lastCharRectIndex);
+ final int lastCharRectFlags = info.getCharacterBoundsFlags(lastCharRectIndex);
+ final boolean hasInvisibleRegionInLastCharRect =
+ (lastCharRectFlags & CursorAnchorInfoCompatWrapper.FLAG_HAS_INVISIBLE_REGION)
+ != 0;
+ if (lastCharRect == null || matrix == null || hasInvisibleRegionInLastCharRect) {
+ mUiOperator.hideUi();
+ return;
+ }
+
+ // Note that the following layout information is fragile, and must be invalidated
+ // even when surrounding text next to the composing text is changed because it can
+ // affect how the composing text is rendered.
+ // TODO: Investigate if we can change the input logic to make the target text
+ // composing state so that we can retrieve the character bounds reliably.
+ final String composingTextString = composingText.toString();
+ final float top = lastCharRect.top;
+ final float bottom = lastCharRect.bottom;
+ float left = lastCharRect.left;
+ float right = lastCharRect.right;
+ boolean useRtlLayout = false;
+ for (int i = composingText.length() - 1; i >= 0; --i) {
+ final int characterIndex = composingTextStart + i;
+ final RectF characterBounds = info.getCharacterBounds(characterIndex);
+ final int characterBoundsFlags = info.getCharacterBoundsFlags(characterIndex);
+ if (characterBounds == null) {
+ break;
+ }
+ if (characterBounds.top != top) {
+ break;
+ }
+ if (characterBounds.bottom != bottom) {
+ break;
+ }
+ if ((characterBoundsFlags & CursorAnchorInfoCompatWrapper.FLAG_IS_RTL) != 0) {
+ // This is for both RTL text and bi-directional text. RTL languages usually mix
+ // RTL characters with LTR characters and in this case we should display the
+ // indicator on the left, while in LTR languages that normally never happens.
+ // TODO: Try to come up with a better algorithm.
+ useRtlLayout = true;
+ }
+ left = Math.min(characterBounds.left, left);
+ right = Math.max(characterBounds.right, right);
+ }
+ mLastComposingText = composingTextString;
+ mHasRtlCharsInLastComposingText = useRtlLayout;
+ mComposingTextBoundsForLastComposingText.set(left, top, right, bottom);
+ }
+
+ final int selectionStart = info.getSelectionStart();
+ final int selectionEnd = info.getSelectionEnd();
+ switch (mMode) {
+ case MODE_MONITOR:
+ mUiOperator.hideUi();
+ return;
+ case MODE_WAITING_CURSOR_INDEX:
+ if (selectionStart != mWaitingCursorStart || selectionEnd != mWaitingCursorEnd) {
+ mUiOperator.hideUi();
+ return;
+ }
+ mMode = MODE_SHOWING_INDICATOR;
+ break;
+ case MODE_SHOWING_INDICATOR:
+ if (selectionStart != mWaitingCursorStart || selectionEnd != mWaitingCursorEnd) {
+ mUiOperator.hideUi();
+ mMode = MODE_MONITOR;
+ mWaitingCursorStart = INVALID_CURSOR_INDEX;
+ mWaitingCursorEnd = INVALID_CURSOR_INDEX;
+ return;
+ }
+ break;
+ default:
+ cancelLayoutInternalUnexpectedly("Unexpected internal mode=" + mMode);
+ return;
+ }
+
+ if (!TextUtils.equals(mLastComposingText, mWaitingWord)) {
+ cancelLayoutInternalUnexpectedly("mLastComposingText doesn't match mWaitingWord");
+ return;
+ }
+
+ if ((info.getInsertionMarkerFlags() &
+ CursorAnchorInfoCompatWrapper.FLAG_HAS_INVISIBLE_REGION) != 0) {
+ mUiOperator.hideUi();
+ return;
+ }
+
+ mUiOperator.layoutUi(matrix, mComposingTextBoundsForLastComposingText,
+ mHasRtlCharsInLastComposingText);
+ }
+
+ private void onClickIndicator() {
+ if (mMode != MODE_SHOWING_INDICATOR) {
+ return;
+ }
+ mListener.onClickComposingTextToAddToDictionary(mWaitingWord);
+ }
+
+ private final LayoutInvalidator mLayoutInvalidator = new LayoutInvalidator(this);
+
+ /**
+ * Used for managing pending layout tasks for {@link TextDecorator#layoutLater()}.
+ */
+ private static final class LayoutInvalidator {
+ private final HandlerImpl mHandler;
+ public LayoutInvalidator(final TextDecorator ownerInstance) {
+ mHandler = new HandlerImpl(ownerInstance);
+ }
+
+ private static final int MSG_LAYOUT = 0;
+
+ private static final class HandlerImpl
+ extends LeakGuardHandlerWrapper<TextDecorator> {
+ public HandlerImpl(final TextDecorator ownerInstance) {
+ super(ownerInstance);
+ }
+
+ @Override
+ public void handleMessage(final Message msg) {
+ final TextDecorator owner = getOwnerInstance();
+ if (owner == null) {
+ return;
+ }
+ switch (msg.what) {
+ case MSG_LAYOUT:
+ owner.layoutMain();
+ break;
+ }
+ }
+ }
+
+ /**
+ * Puts a layout task into the scheduler. Does nothing if one or more layout tasks are
+ * already scheduled.
+ */
+ public void invalidateLayout() {
+ if (!mHandler.hasMessages(MSG_LAYOUT)) {
+ mHandler.obtainMessage(MSG_LAYOUT).sendToTarget();
+ }
+ }
+
+ /**
+ * Clears the pending layout tasks.
+ */
+ public void cancelInvalidateLayout() {
+ mHandler.removeMessages(MSG_LAYOUT);
+ }
+ }
+
+ private final static Listener EMPTY_LISTENER = new Listener() {
+ @Override
+ public void onClickComposingTextToAddToDictionary(final String word) {
+ }
+ };
+
+ private final static TextDecoratorUiOperator EMPTY_UI_OPERATOR = new TextDecoratorUiOperator() {
+ @Override
+ public void disposeUi() {
+ }
+ @Override
+ public void hideUi() {
+ }
+ @Override
+ public void setOnClickListener(Runnable listener) {
+ }
+ @Override
+ public void layoutUi(Matrix matrix, RectF composingTextBounds, boolean useRtlLayout) {
+ }
+ };
+}
diff --git a/java/src/com/android/inputmethod/keyboard/TextDecoratorUi.java b/java/src/com/android/inputmethod/keyboard/TextDecoratorUi.java
new file mode 100644
index 000000000..d87dc1bfa
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/TextDecoratorUi.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.graphics.drawable.ColorDrawable;
+import android.inputmethodservice.InputMethodService;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.ViewParent;
+import android.widget.PopupWindow;
+import android.widget.RelativeLayout;
+
+import com.android.inputmethod.latin.R;
+
+/**
+ * Used as the UI component of {@link TextDecorator}.
+ */
+public final class TextDecoratorUi implements TextDecoratorUiOperator {
+ private static final boolean VISUAL_DEBUG = false;
+ private static final int VISUAL_DEBUG_HIT_AREA_COLOR = 0x80ff8000;
+
+ private final RelativeLayout mLocalRootView;
+ private final AddToDictionaryIndicatorView mAddToDictionaryIndicatorView;
+ private final PopupWindow mTouchEventWindow;
+ private final View mTouchEventWindowClickListenerView;
+ private final float mHitAreaMarginInPixels;
+ private final RectF mDisplayRect;
+
+ /**
+ * This constructor is designed to be called from {@link InputMethodService#setInputView(View)}.
+ * Other usages are not supported.
+ *
+ * @param context the context of the input method.
+ * @param inputView the view that is passed to {@link InputMethodService#setInputView(View)}.
+ */
+ public TextDecoratorUi(final Context context, final View inputView) {
+ final Resources resources = context.getResources();
+ final int hitAreaMarginInDP = resources.getInteger(
+ R.integer.text_decorator_hit_area_margin_in_dp);
+ mHitAreaMarginInPixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ hitAreaMarginInDP, resources.getDisplayMetrics());
+ final DisplayMetrics displayMetrics = resources.getDisplayMetrics();
+ mDisplayRect = new RectF(0.0f, 0.0f, displayMetrics.widthPixels,
+ displayMetrics.heightPixels);
+
+ mLocalRootView = new RelativeLayout(context);
+ mLocalRootView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.MATCH_PARENT));
+ // TODO: Use #setBackground(null) for API Level >= 16.
+ mLocalRootView.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+
+ final ViewGroup contentView = getContentView(inputView);
+ mAddToDictionaryIndicatorView = new AddToDictionaryIndicatorView(context);
+ mLocalRootView.addView(mAddToDictionaryIndicatorView);
+ if (contentView != null) {
+ contentView.addView(mLocalRootView);
+ }
+
+ // This popup window is used to avoid the limitation that the input method is not able to
+ // observe the touch events happening outside of InputMethodService.Insets#touchableRegion.
+ // We don't use this popup window for rendering the UI for performance reasons though.
+ mTouchEventWindow = new PopupWindow(context);
+ if (VISUAL_DEBUG) {
+ mTouchEventWindow.setBackgroundDrawable(new ColorDrawable(VISUAL_DEBUG_HIT_AREA_COLOR));
+ } else {
+ mTouchEventWindow.setBackgroundDrawable(null);
+ }
+ mTouchEventWindowClickListenerView = new View(context);
+ mTouchEventWindow.setContentView(mTouchEventWindowClickListenerView);
+ }
+
+ @Override
+ public void disposeUi() {
+ if (mLocalRootView != null) {
+ final ViewParent parent = mLocalRootView.getParent();
+ if (parent != null && parent instanceof ViewGroup) {
+ ((ViewGroup) parent).removeView(mLocalRootView);
+ }
+ mLocalRootView.removeAllViews();
+ }
+ if (mTouchEventWindow != null) {
+ mTouchEventWindow.dismiss();
+ }
+ }
+
+ @Override
+ public void hideUi() {
+ mAddToDictionaryIndicatorView.setVisibility(View.GONE);
+ mTouchEventWindow.dismiss();
+ }
+
+ private static final RectF getIndicatorBoundsInScreenCoordinates(final Matrix matrix,
+ final RectF composingTextBounds, final boolean showAtLeftSide) {
+ final float indicatorSize = composingTextBounds.height();
+ final RectF indicatorBounds;
+ if (showAtLeftSide) {
+ indicatorBounds = new RectF(composingTextBounds.left - indicatorSize,
+ composingTextBounds.top, composingTextBounds.left,
+ composingTextBounds.top + indicatorSize);
+ } else {
+ indicatorBounds = new RectF(composingTextBounds.right, composingTextBounds.top,
+ composingTextBounds.right + indicatorSize,
+ composingTextBounds.top + indicatorSize);
+ }
+ matrix.mapRect(indicatorBounds);
+ return indicatorBounds;
+ }
+
+ @Override
+ public void layoutUi(final Matrix matrix, final RectF composingTextBounds,
+ final boolean useRtlLayout) {
+ RectF indicatorBoundsInScreenCoordinates = getIndicatorBoundsInScreenCoordinates(matrix,
+ composingTextBounds, useRtlLayout /* showAtLeftSide */);
+ if (indicatorBoundsInScreenCoordinates.left < mDisplayRect.left ||
+ mDisplayRect.right < indicatorBoundsInScreenCoordinates.right) {
+ // The indicator is clipped by the screen. Show the indicator at the opposite side.
+ indicatorBoundsInScreenCoordinates = getIndicatorBoundsInScreenCoordinates(matrix,
+ composingTextBounds, !useRtlLayout /* showAtLeftSide */);
+ }
+
+ mAddToDictionaryIndicatorView.setBounds(indicatorBoundsInScreenCoordinates);
+
+ final RectF hitAreaBoundsInScreenCoordinates = new RectF();
+ matrix.mapRect(hitAreaBoundsInScreenCoordinates, composingTextBounds);
+ hitAreaBoundsInScreenCoordinates.union(indicatorBoundsInScreenCoordinates);
+ hitAreaBoundsInScreenCoordinates.inset(-mHitAreaMarginInPixels, -mHitAreaMarginInPixels);
+
+ final int[] originScreen = new int[2];
+ mLocalRootView.getLocationOnScreen(originScreen);
+ final int viewOriginX = originScreen[0];
+ final int viewOriginY = originScreen[1];
+ mAddToDictionaryIndicatorView.setX(indicatorBoundsInScreenCoordinates.left - viewOriginX);
+ mAddToDictionaryIndicatorView.setY(indicatorBoundsInScreenCoordinates.top - viewOriginY);
+ mAddToDictionaryIndicatorView.setVisibility(View.VISIBLE);
+
+ if (mTouchEventWindow.isShowing()) {
+ mTouchEventWindow.update((int)hitAreaBoundsInScreenCoordinates.left - viewOriginX,
+ (int)hitAreaBoundsInScreenCoordinates.top - viewOriginY,
+ (int)hitAreaBoundsInScreenCoordinates.width(),
+ (int)hitAreaBoundsInScreenCoordinates.height());
+ } else {
+ mTouchEventWindow.setWidth((int)hitAreaBoundsInScreenCoordinates.width());
+ mTouchEventWindow.setHeight((int)hitAreaBoundsInScreenCoordinates.height());
+ mTouchEventWindow.showAtLocation(mLocalRootView, Gravity.NO_GRAVITY,
+ (int)hitAreaBoundsInScreenCoordinates.left - viewOriginX,
+ (int)hitAreaBoundsInScreenCoordinates.top - viewOriginY);
+ }
+ }
+
+ @Override
+ public void setOnClickListener(final Runnable listener) {
+ mTouchEventWindowClickListenerView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(final View arg0) {
+ listener.run();
+ }
+ });
+ }
+
+ private static class IndicatorView extends View {
+ private final Path mPath;
+ private final Path mTmpPath = new Path();
+ private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final Matrix mMatrix = new Matrix();
+ private final int mBackgroundColor;
+ private final int mForegroundColor;
+ private final RectF mBounds = new RectF();
+ public IndicatorView(Context context, final int pathResourceId,
+ final int sizeResourceId, final int backgroundColorResourceId,
+ final int foregroundColroResourceId) {
+ super(context);
+ final Resources resources = context.getResources();
+ mPath = createPath(resources, pathResourceId, sizeResourceId);
+ mBackgroundColor = resources.getColor(backgroundColorResourceId);
+ mForegroundColor = resources.getColor(foregroundColroResourceId);
+ }
+
+ public void setBounds(final RectF rect) {
+ mBounds.set(rect);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ mPaint.setColor(mBackgroundColor);
+ mPaint.setStyle(Paint.Style.FILL);
+ canvas.drawRect(0.0f, 0.0f, mBounds.width(), mBounds.height(), mPaint);
+
+ mMatrix.reset();
+ mMatrix.postScale(mBounds.width(), mBounds.height());
+ mPath.transform(mMatrix, mTmpPath);
+ mPaint.setColor(mForegroundColor);
+ canvas.drawPath(mTmpPath, mPaint);
+ }
+
+ private static Path createPath(final Resources resources, final int pathResourceId,
+ final int sizeResourceId) {
+ final int size = resources.getInteger(sizeResourceId);
+ final float normalizationFactor = 1.0f / size;
+ final int[] array = resources.getIntArray(pathResourceId);
+
+ final Path path = new Path();
+ for (int i = 0; i < array.length; i += 2) {
+ if (i == 0) {
+ path.moveTo(array[i] * normalizationFactor, array[i + 1] * normalizationFactor);
+ } else {
+ path.lineTo(array[i] * normalizationFactor, array[i + 1] * normalizationFactor);
+ }
+ }
+ path.close();
+ return path;
+ }
+ }
+
+ private static ViewGroup getContentView(final View view) {
+ final View rootView = view.getRootView();
+ if (rootView == null) {
+ return null;
+ }
+
+ final ViewGroup windowContentView = (ViewGroup)rootView.findViewById(android.R.id.content);
+ if (windowContentView == null) {
+ return null;
+ }
+ return windowContentView;
+ }
+
+ private static final class AddToDictionaryIndicatorView extends TextDecoratorUi.IndicatorView {
+ public AddToDictionaryIndicatorView(final Context context) {
+ super(context, R.array.text_decorator_add_to_dictionary_indicator_path,
+ R.integer.text_decorator_add_to_dictionary_indicator_path_size,
+ R.color.text_decorator_add_to_dictionary_indicator_background_color,
+ R.color.text_decorator_add_to_dictionary_indicator_foreground_color);
+ }
+ }
+} \ No newline at end of file
diff --git a/java/src/com/android/inputmethod/keyboard/TextDecoratorUiOperator.java b/java/src/com/android/inputmethod/keyboard/TextDecoratorUiOperator.java
new file mode 100644
index 000000000..9e30e417e
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/TextDecoratorUiOperator.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard;
+
+import android.graphics.Matrix;
+import android.graphics.RectF;
+
+/**
+ * This interface defines how UI operations required for {@link TextDecorator} are delegated to
+ * the actual UI implementation class.
+ */
+public interface TextDecoratorUiOperator {
+ /**
+ * Called to notify that the UI is ready to be disposed.
+ */
+ void disposeUi();
+
+ /**
+ * Called when the UI should become invisible.
+ */
+ void hideUi();
+
+ /**
+ * Called to set the new click handler.
+ * @param onClickListener the callback object whose {@link Runnable#run()} should be called when
+ * the indicator is clicked.
+ */
+ void setOnClickListener(final Runnable onClickListener);
+
+ /**
+ * Called when the layout should be updated.
+ * @param matrix The matrix that transforms the local coordinates into the screen coordinates.
+ * @param composingTextBounds The bounding box of the composing text, in local coordinates.
+ * @param useRtlLayout {@code true} if the indicator should be optimized for RTL layout.
+ */
+ void layoutUi(final Matrix matrix, final RectF composingTextBounds, final boolean useRtlLayout);
+}
diff --git a/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java
index 512d4615d..0f9dc855b 100644
--- a/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java
+++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java
@@ -24,6 +24,7 @@ import android.os.Build;
import android.util.Log;
import android.util.Pair;
+import com.android.inputmethod.compat.BuildCompatUtils;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardId;
@@ -121,9 +122,7 @@ final class EmojiCategory {
sCategoryTabIconAttr[i], 0);
}
addShownCategoryId(EmojiCategory.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")) {
+ if (BuildCompatUtils.EFFECTIVE_SDK_INT >= Build.VERSION_CODES.KITKAT) {
addShownCategoryId(EmojiCategory.ID_PEOPLE);
addShownCategoryId(EmojiCategory.ID_OBJECTS);
addShownCategoryId(EmojiCategory.ID_NATURE);
diff --git a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java
index 17dfc9cce..925ec6bfb 100644
--- a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java
@@ -104,7 +104,8 @@ final class EmojiPageKeyboardView extends KeyboardView implements
public boolean onHoverEvent(final MotionEvent event) {
final KeyboardAccessibilityDelegate<EmojiPageKeyboardView> accessibilityDelegate =
mAccessibilityDelegate;
- if (accessibilityDelegate != null) {
+ if (accessibilityDelegate != null
+ && AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
return accessibilityDelegate.onHoverEvent(event);
}
return super.onHoverEvent(event);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java
index 07ac06bab..df50efdc1 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java
@@ -26,7 +26,6 @@ public final class KeyDrawParams {
public int mLetterSize;
public int mLabelSize;
public int mLargeLetterSize;
- public int mLargeLabelSize;
public int mHintLetterSize;
public int mShiftedLetterHintSize;
public int mHintLabelSize;
@@ -42,6 +41,10 @@ public final class KeyDrawParams {
public int mShiftedLetterHintActivatedColor;
public int mPreviewTextColor;
+ public float mHintLabelVerticalAdjustment;
+ public float mLabelOffCenterRatio;
+ public float mHintLabelOffCenterRatio;
+
public int mAnimAlpha;
public KeyDrawParams() {}
@@ -52,7 +55,6 @@ public final class KeyDrawParams {
mLetterSize = copyFrom.mLetterSize;
mLabelSize = copyFrom.mLabelSize;
mLargeLetterSize = copyFrom.mLargeLetterSize;
- mLargeLabelSize = copyFrom.mLargeLabelSize;
mHintLetterSize = copyFrom.mHintLetterSize;
mShiftedLetterHintSize = copyFrom.mShiftedLetterHintSize;
mHintLabelSize = copyFrom.mHintLabelSize;
@@ -68,6 +70,10 @@ public final class KeyDrawParams {
mShiftedLetterHintActivatedColor = copyFrom.mShiftedLetterHintActivatedColor;
mPreviewTextColor = copyFrom.mPreviewTextColor;
+ mHintLabelVerticalAdjustment = copyFrom.mHintLabelVerticalAdjustment;
+ mLabelOffCenterRatio = copyFrom.mLabelOffCenterRatio;
+ mHintLabelOffCenterRatio = copyFrom.mHintLabelOffCenterRatio;
+
mAnimAlpha = copyFrom.mAnimAlpha;
}
@@ -84,7 +90,6 @@ public final class KeyDrawParams {
attr.mLetterSize, attr.mLetterRatio, mLetterSize);
mLabelSize = selectTextSizeFromDimensionOrRatio(keyHeight,
attr.mLabelSize, attr.mLabelRatio, mLabelSize);
- mLargeLabelSize = selectTextSize(keyHeight, attr.mLargeLabelRatio, mLargeLabelSize);
mLargeLetterSize = selectTextSize(keyHeight, attr.mLargeLetterRatio, mLargeLetterSize);
mHintLetterSize = selectTextSize(keyHeight, attr.mHintLetterRatio, mHintLetterSize);
mShiftedLetterHintSize = selectTextSize(keyHeight,
@@ -103,6 +108,13 @@ public final class KeyDrawParams {
mShiftedLetterHintActivatedColor = selectColor(
attr.mShiftedLetterHintActivatedColor, mShiftedLetterHintActivatedColor);
mPreviewTextColor = selectColor(attr.mPreviewTextColor, mPreviewTextColor);
+
+ mHintLabelVerticalAdjustment = selectFloatIfNonZero(
+ attr.mHintLabelVerticalAdjustment, mHintLabelVerticalAdjustment);
+ mLabelOffCenterRatio = selectFloatIfNonZero(
+ attr.mLabelOffCenterRatio, mLabelOffCenterRatio);
+ mHintLabelOffCenterRatio = selectFloatIfNonZero(
+ attr.mHintLabelOffCenterRatio, mHintLabelOffCenterRatio);
}
public KeyDrawParams mayCloneAndUpdateParams(final int keyHeight,
@@ -115,7 +127,7 @@ public final class KeyDrawParams {
return newParams;
}
- private static final int selectTextSizeFromDimensionOrRatio(final int keyHeight,
+ private static int selectTextSizeFromDimensionOrRatio(final int keyHeight,
final int dimens, final float ratio, final int defaultDimens) {
if (ResourceUtils.isValidDimensionPixelSize(dimens)) {
return dimens;
@@ -126,7 +138,7 @@ public final class KeyDrawParams {
return defaultDimens;
}
- private static final int selectTextSize(final int keyHeight, final float ratio,
+ private static int selectTextSize(final int keyHeight, final float ratio,
final int defaultSize) {
if (ResourceUtils.isValidFraction(ratio)) {
return (int)(keyHeight * ratio);
@@ -134,10 +146,17 @@ public final class KeyDrawParams {
return defaultSize;
}
- private static final int selectColor(final int attrColor, final int defaultColor) {
+ private static int selectColor(final int attrColor, final int defaultColor) {
if (attrColor != 0) {
return attrColor;
}
return defaultColor;
}
+
+ private static float selectFloatIfNonZero(final float attrFloat, final float defaultFloat) {
+ if (attrFloat != 0) {
+ return attrFloat;
+ }
+ return defaultFloat;
+ }
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java
index cd29c8d17..5005b7d7d 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewChoreographer.java
@@ -18,13 +18,9 @@ package com.android.inputmethod.keyboard.internal;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.latin.utils.CoordinateUtils;
@@ -89,9 +85,9 @@ public final class KeyPreviewChoreographer {
}
final Object tag = keyPreviewView.getTag();
if (withAnimation) {
- if (tag instanceof KeyPreviewAnimations) {
- final KeyPreviewAnimations animation = (KeyPreviewAnimations)tag;
- animation.startDismiss();
+ if (tag instanceof KeyPreviewAnimators) {
+ final KeyPreviewAnimators animators = (KeyPreviewAnimators)tag;
+ animators.startDismiss();
return;
}
}
@@ -161,87 +157,60 @@ public final class KeyPreviewChoreographer {
}
// Show preview with animation.
- final Animator showUpAnimation = createShowUpAniation(key, keyPreviewView);
- final Animator dismissAnimation = createDismissAnimation(key, keyPreviewView);
- final KeyPreviewAnimations animation = new KeyPreviewAnimations(
- showUpAnimation, dismissAnimation);
- keyPreviewView.setTag(animation);
- animation.startShowUp();
+ final Animator showUpAnimator = createShowUpAnimator(key, keyPreviewView);
+ final Animator dismissAnimator = createDismissAnimator(key, keyPreviewView);
+ final KeyPreviewAnimators animators = new KeyPreviewAnimators(
+ showUpAnimator, dismissAnimator);
+ keyPreviewView.setTag(animators);
+ animators.startShowUp();
}
- private static final float KEY_PREVIEW_SHOW_UP_END_SCALE = 1.0f;
- private static final AccelerateInterpolator ACCELERATE_INTERPOLATOR =
- new AccelerateInterpolator();
- private static final DecelerateInterpolator DECELERATE_INTERPOLATOR =
- new DecelerateInterpolator();
-
- private Animator createShowUpAniation(final Key key, final KeyPreviewView keyPreviewView) {
- // TODO: Optimization for no scale animation and no duration.
- final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat(
- keyPreviewView, View.SCALE_X, mParams.getShowUpStartScale(),
- KEY_PREVIEW_SHOW_UP_END_SCALE);
- final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat(
- keyPreviewView, View.SCALE_Y, mParams.getShowUpStartScale(),
- KEY_PREVIEW_SHOW_UP_END_SCALE);
- final AnimatorSet showUpAnimation = new AnimatorSet();
- showUpAnimation.play(scaleXAnimation).with(scaleYAnimation);
- showUpAnimation.setDuration(mParams.getShowUpDuration());
- showUpAnimation.setInterpolator(DECELERATE_INTERPOLATOR);
- showUpAnimation.addListener(new AnimatorListenerAdapter() {
+ public Animator createShowUpAnimator(final Key key, final KeyPreviewView keyPreviewView) {
+ final Animator animator = mParams.createShowUpAnimator(keyPreviewView);
+ animator.addListener(new AnimatorListenerAdapter() {
@Override
- public void onAnimationStart(final Animator animation) {
+ public void onAnimationStart(final Animator animator) {
showKeyPreview(key, keyPreviewView, false /* withAnimation */);
}
});
- return showUpAnimation;
+ return animator;
}
- private Animator createDismissAnimation(final Key key, final KeyPreviewView keyPreviewView) {
- // TODO: Optimization for no scale animation and no duration.
- final ObjectAnimator scaleXAnimation = ObjectAnimator.ofFloat(
- keyPreviewView, View.SCALE_X, mParams.getDismissEndScale());
- final ObjectAnimator scaleYAnimation = ObjectAnimator.ofFloat(
- keyPreviewView, View.SCALE_Y, mParams.getDismissEndScale());
- final AnimatorSet dismissAnimation = new AnimatorSet();
- dismissAnimation.play(scaleXAnimation).with(scaleYAnimation);
- final int dismissDuration = Math.min(
- mParams.getDismissDuration(), mParams.getLingerTimeout());
- dismissAnimation.setDuration(dismissDuration);
- dismissAnimation.setInterpolator(ACCELERATE_INTERPOLATOR);
- dismissAnimation.addListener(new AnimatorListenerAdapter() {
+ private Animator createDismissAnimator(final Key key, final KeyPreviewView keyPreviewView) {
+ final Animator animator = mParams.createDismissAnimator(keyPreviewView);
+ animator.addListener(new AnimatorListenerAdapter() {
@Override
- public void onAnimationEnd(final Animator animation) {
+ public void onAnimationEnd(final Animator animator) {
dismissKeyPreview(key, false /* withAnimation */);
}
});
- return dismissAnimation;
+ return animator;
}
- private static class KeyPreviewAnimations extends AnimatorListenerAdapter {
- private final Animator mShowUpAnimation;
- private final Animator mDismissAnimation;
+ private static class KeyPreviewAnimators extends AnimatorListenerAdapter {
+ private final Animator mShowUpAnimator;
+ private final Animator mDismissAnimator;
- public KeyPreviewAnimations(final Animator showUpAnimation,
- final Animator dismissAnimation) {
- mShowUpAnimation = showUpAnimation;
- mDismissAnimation = dismissAnimation;
+ public KeyPreviewAnimators(final Animator showUpAnimator, final Animator dismissAnimator) {
+ mShowUpAnimator = showUpAnimator;
+ mDismissAnimator = dismissAnimator;
}
public void startShowUp() {
- mShowUpAnimation.start();
+ mShowUpAnimator.start();
}
public void startDismiss() {
- if (mShowUpAnimation.isRunning()) {
- mShowUpAnimation.addListener(this);
+ if (mShowUpAnimator.isRunning()) {
+ mShowUpAnimator.addListener(this);
return;
}
- mDismissAnimation.start();
+ mDismissAnimator.start();
}
@Override
- public void onAnimationEnd(final Animator animation) {
- mDismissAnimation.start();
+ public void onAnimationEnd(final Animator animator) {
+ mDismissAnimator.start();
}
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java
index 68c9831fa..5ed39f986 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewDrawParams.java
@@ -16,8 +16,14 @@
package com.android.inputmethod.keyboard.internal;
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.content.res.TypedArray;
import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
import com.android.inputmethod.latin.R;
@@ -26,10 +32,15 @@ public final class KeyPreviewDrawParams {
public final int mPreviewOffset;
public final int mPreviewHeight;
public final int mPreviewBackgroundResId;
+ private final int mShowUpAnimatorResId;
+ private final int mDismissAnimatorResId;
+ private boolean mHasCustomAnimationParams;
private int mShowUpDuration;
private int mDismissDuration;
- private float mShowUpStartScale;
- private float mDismissEndScale;
+ private float mShowUpStartXScale;
+ private float mShowUpStartYScale;
+ private float mDismissEndXScale;
+ private float mDismissEndYScale;
private int mLingerTimeout;
private boolean mShowPopup = true;
@@ -67,6 +78,10 @@ public final class KeyPreviewDrawParams {
R.styleable.MainKeyboardView_keyPreviewBackground, 0);
mLingerTimeout = mainKeyboardViewAttr.getInt(
R.styleable.MainKeyboardView_keyPreviewLingerTimeout, 0);
+ mShowUpAnimatorResId = mainKeyboardViewAttr.getResourceId(
+ R.styleable.MainKeyboardView_keyPreviewShowUpAnimator, 0);
+ mDismissAnimatorResId = mainKeyboardViewAttr.getResourceId(
+ R.styleable.MainKeyboardView_keyPreviewDismissAnimator, 0);
}
public void setVisibleOffset(final int previewVisibleOffset) {
@@ -112,27 +127,62 @@ public final class KeyPreviewDrawParams {
return mLingerTimeout;
}
- public void setAnimationParams(final float showUpStartScale, final int showUpDuration,
- final float dismissEndScale, final int dismissDuration) {
- mShowUpStartScale = showUpStartScale;
+ public void setAnimationParams(final boolean hasCustomAnimationParams,
+ final float showUpStartXScale, final float showUpStartYScale, final int showUpDuration,
+ final float dismissEndXScale, final float dismissEndYScale, final int dismissDuration) {
+ mHasCustomAnimationParams = hasCustomAnimationParams;
+ mShowUpStartXScale = showUpStartXScale;
+ mShowUpStartYScale = showUpStartYScale;
mShowUpDuration = showUpDuration;
- mDismissEndScale = dismissEndScale;
+ mDismissEndXScale = dismissEndXScale;
+ mDismissEndYScale = dismissEndYScale;
mDismissDuration = dismissDuration;
}
- public float getShowUpStartScale() {
- return mShowUpStartScale;
+ private static final float KEY_PREVIEW_SHOW_UP_END_SCALE = 1.0f;
+ private static final AccelerateInterpolator ACCELERATE_INTERPOLATOR =
+ new AccelerateInterpolator();
+ private static final DecelerateInterpolator DECELERATE_INTERPOLATOR =
+ new DecelerateInterpolator();
+
+ public Animator createShowUpAnimator(final View target) {
+ if (mHasCustomAnimationParams) {
+ final ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(
+ target, View.SCALE_X, mShowUpStartXScale,
+ KEY_PREVIEW_SHOW_UP_END_SCALE);
+ final ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(
+ target, View.SCALE_Y, mShowUpStartYScale,
+ KEY_PREVIEW_SHOW_UP_END_SCALE);
+ final AnimatorSet showUpAnimator = new AnimatorSet();
+ showUpAnimator.play(scaleXAnimator).with(scaleYAnimator);
+ showUpAnimator.setDuration(mShowUpDuration);
+ showUpAnimator.setInterpolator(DECELERATE_INTERPOLATOR);
+ return showUpAnimator;
+ }
+ final Animator animator = AnimatorInflater.loadAnimator(
+ target.getContext(), mShowUpAnimatorResId);
+ animator.setTarget(target);
+ animator.setInterpolator(DECELERATE_INTERPOLATOR);
+ return animator;
}
- public int getShowUpDuration() {
- return mShowUpDuration;
- }
-
- public float getDismissEndScale() {
- return mDismissEndScale;
- }
-
- public int getDismissDuration() {
- return mDismissDuration;
+ public Animator createDismissAnimator(final View target) {
+ if (mHasCustomAnimationParams) {
+ final ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(
+ target, View.SCALE_X, mDismissEndXScale);
+ final ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(
+ target, View.SCALE_Y, mDismissEndYScale);
+ final AnimatorSet dismissAnimator = new AnimatorSet();
+ dismissAnimator.play(scaleXAnimator).with(scaleYAnimator);
+ final int dismissDuration = Math.min(mDismissDuration, mLingerTimeout);
+ dismissAnimator.setDuration(dismissDuration);
+ dismissAnimator.setInterpolator(ACCELERATE_INTERPOLATOR);
+ return dismissAnimator;
+ }
+ final Animator animator = AnimatorInflater.loadAnimator(
+ target.getContext(), mDismissAnimatorResId);
+ animator.setTarget(target);
+ animator.setInterpolator(ACCELERATE_INTERPOLATOR);
+ return animator;
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java
index 360faf829..24538605a 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java
@@ -17,7 +17,10 @@
package com.android.inputmethod.keyboard.internal;
import android.content.Context;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.text.TextPaint;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
@@ -26,6 +29,8 @@ import android.widget.TextView;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.latin.R;
+import java.util.HashSet;
+
/**
* The pop up key preview view.
*/
@@ -34,6 +39,9 @@ public class KeyPreviewView extends TextView {
public static final int POSITION_LEFT = 1;
public static final int POSITION_RIGHT = 2;
+ private final Rect mBackgroundPadding = new Rect();
+ private static final HashSet<String> sNoScaleXTextSet = new HashSet<>();
+
public KeyPreviewView(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}
@@ -58,7 +66,48 @@ public class KeyPreviewView extends TextView {
setTextSize(TypedValue.COMPLEX_UNIT_PX, key.selectPreviewTextSize(drawParams));
setTypeface(key.selectPreviewTypeface(drawParams));
// TODO Should take care of temporaryShiftLabel here.
- setText(key.getPreviewLabel());
+ setTextAndScaleX(key.getPreviewLabel());
+ }
+
+ private void setTextAndScaleX(final String text) {
+ setTextScaleX(1.0f);
+ setText(text);
+ if (sNoScaleXTextSet.contains(text)) {
+ return;
+ }
+ // TODO: Override {@link #setBackground(Drawable)} that is supported from API 16 and
+ // calculate maximum text width.
+ final Drawable background = getBackground();
+ if (background == null) {
+ return;
+ }
+ background.getPadding(mBackgroundPadding);
+ final int maxWidth = background.getIntrinsicWidth() - mBackgroundPadding.left
+ - mBackgroundPadding.right;
+ final float width = getTextWidth(text, getPaint());
+ if (width <= maxWidth) {
+ sNoScaleXTextSet.add(text);
+ return;
+ }
+ setTextScaleX(maxWidth / width);
+ }
+
+ public static void clearTextCache() {
+ sNoScaleXTextSet.clear();
+ }
+
+ private static float getTextWidth(final String text, final TextPaint paint) {
+ if (TextUtils.isEmpty(text)) {
+ return 0.0f;
+ }
+ final int len = text.length();
+ final float[] widths = new float[len];
+ final int count = paint.getTextWidths(text, 0, len, widths);
+ float width = 0;
+ for (int i = 0; i < count; i++) {
+ width += widths[i];
+ }
+ return width;
}
// Background state set
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java b/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java
index 133462ac7..c60d587db 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java
@@ -31,7 +31,6 @@ public final class KeyVisualAttributes {
public final float mLabelRatio;
public final int mLabelSize;
public final float mLargeLetterRatio;
- public final float mLargeLabelRatio;
public final float mHintLetterRatio;
public final float mShiftedLetterHintRatio;
public final float mHintLabelRatio;
@@ -48,13 +47,14 @@ public final class KeyVisualAttributes {
public final int mPreviewTextColor;
public final float mHintLabelVerticalAdjustment;
+ public final float mLabelOffCenterRatio;
+ public final float mHintLabelOffCenterRatio;
private static final int[] VISUAL_ATTRIBUTE_IDS = {
R.styleable.Keyboard_Key_keyTypeface,
R.styleable.Keyboard_Key_keyLetterSize,
R.styleable.Keyboard_Key_keyLabelSize,
R.styleable.Keyboard_Key_keyLargeLetterRatio,
- R.styleable.Keyboard_Key_keyLargeLabelRatio,
R.styleable.Keyboard_Key_keyHintLetterRatio,
R.styleable.Keyboard_Key_keyShiftedLetterHintRatio,
R.styleable.Keyboard_Key_keyHintLabelRatio,
@@ -69,6 +69,8 @@ public final class KeyVisualAttributes {
R.styleable.Keyboard_Key_keyShiftedLetterHintActivatedColor,
R.styleable.Keyboard_Key_keyPreviewTextColor,
R.styleable.Keyboard_Key_keyHintLabelVerticalAdjustment,
+ R.styleable.Keyboard_Key_keyLabelOffCenterRatio,
+ R.styleable.Keyboard_Key_keyHintLabelOffCenterRatio
};
private static final SparseIntArray sVisualAttributeIds = new SparseIntArray();
private static final int ATTR_DEFINED = 1;
@@ -109,8 +111,6 @@ public final class KeyVisualAttributes {
R.styleable.Keyboard_Key_keyLabelSize);
mLargeLetterRatio = ResourceUtils.getFraction(keyAttr,
R.styleable.Keyboard_Key_keyLargeLetterRatio);
- mLargeLabelRatio = ResourceUtils.getFraction(keyAttr,
- R.styleable.Keyboard_Key_keyLargeLabelRatio);
mHintLetterRatio = ResourceUtils.getFraction(keyAttr,
R.styleable.Keyboard_Key_keyHintLetterRatio);
mShiftedLetterHintRatio = ResourceUtils.getFraction(keyAttr,
@@ -135,5 +135,9 @@ public final class KeyVisualAttributes {
mHintLabelVerticalAdjustment = ResourceUtils.getFraction(keyAttr,
R.styleable.Keyboard_Key_keyHintLabelVerticalAdjustment, 0.0f);
+ mLabelOffCenterRatio = ResourceUtils.getFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyLabelOffCenterRatio, 0.0f);
+ mHintLabelOffCenterRatio = ResourceUtils.getFraction(keyAttr,
+ R.styleable.Keyboard_Key_keyHintLabelOffCenterRatio, 0.0f);
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
index 8bff27574..fa4192790 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
@@ -31,6 +31,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.keyboard.KeyboardTheme;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.utils.ResourceUtils;
@@ -643,6 +644,9 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
final boolean keyboardLayoutSetElementMatched = matchTypedValue(caseAttr,
R.styleable.Keyboard_Case_keyboardLayoutSetElement, id.mElementId,
KeyboardId.elementIdToName(id.mElementId));
+ final boolean keyboardThemeMacthed = matchTypedValue(caseAttr,
+ R.styleable.Keyboard_Case_keyboardTheme, mParams.mThemeId,
+ KeyboardTheme.getKeyboardThemeName(mParams.mThemeId));
final boolean modeMatched = matchTypedValue(caseAttr,
R.styleable.Keyboard_Case_mode, id.mMode, KeyboardId.modeName(id.mMode));
final boolean navigateNextMatched = matchBoolean(caseAttr,
@@ -671,19 +675,21 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
final boolean countryCodeMatched = matchString(caseAttr,
R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry());
final boolean selected = keyboardLayoutSetMatched && keyboardLayoutSetElementMatched
- && modeMatched && navigateNextMatched && navigatePreviousMatched
- && passwordInputMatched && clobberSettingsKeyMatched && hasShortcutKeyMatched
- && languageSwitchKeyEnabledMatched && isMultiLineMatched && imeActionMatched
- && isIconDefinedMatched && localeCodeMatched && languageCodeMatched
- && countryCodeMatched;
+ && keyboardThemeMacthed && modeMatched && navigateNextMatched
+ && navigatePreviousMatched && passwordInputMatched && clobberSettingsKeyMatched
+ && hasShortcutKeyMatched && languageSwitchKeyEnabledMatched
+ && isMultiLineMatched && imeActionMatched && isIconDefinedMatched
+ && 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"),
+ textAttr(caseAttr.getString(
+ R.styleable.Keyboard_Case_keyboardTheme), "keyboardTheme"),
textAttr(caseAttr.getString(R.styleable.Keyboard_Case_mode), "mode"),
textAttr(caseAttr.getString(R.styleable.Keyboard_Case_imeAction),
"imeAction"),
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
index 09550c4cb..e1f302c1e 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
@@ -53,7 +53,8 @@ public final class KeyboardIconsSet {
public static final String NAME_LANGUAGE_SWITCH_KEY = "language_switch_key";
public static final String NAME_ZWNJ_KEY = "zwnj_key";
public static final String NAME_ZWJ_KEY = "zwj_key";
- public static final String NAME_EMOJI_KEY = "emoji_key";
+ public static final String NAME_EMOJI_ACTION_KEY = "emoji_action_key";
+ public static final String NAME_EMOJI_NORMAL_KEY = "emoji_normal_key";
private static final SparseIntArray ATTR_ID_TO_ICON_ID = new SparseIntArray();
@@ -81,7 +82,8 @@ public final class KeyboardIconsSet {
NAME_LANGUAGE_SWITCH_KEY, R.styleable.Keyboard_iconLanguageSwitchKey,
NAME_ZWNJ_KEY, R.styleable.Keyboard_iconZwnjKey,
NAME_ZWJ_KEY, R.styleable.Keyboard_iconZwjKey,
- NAME_EMOJI_KEY, R.styleable.Keyboard_iconEmojiKey,
+ NAME_EMOJI_ACTION_KEY, R.styleable.Keyboard_iconEmojiActionKey,
+ NAME_EMOJI_NORMAL_KEY, R.styleable.Keyboard_iconEmojiNormalKey,
};
private static int NUM_ICONS = NAMES_AND_ATTR_IDS.length / 2;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
index f18ebd1fe..31bc549ca 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
@@ -86,15 +86,15 @@ public final class KeyboardTextsTable {
/* 0:32 */ "morekeys_a",
/* 1:32 */ "morekeys_o",
/* 2:30 */ "morekeys_u",
- /* 3:29 */ "morekeys_e",
- /* 4:28 */ "morekeys_i",
- /* 5:28 */ "keylabel_to_alpha",
+ /* 3:30 */ "keylabel_to_alpha",
+ /* 4:29 */ "morekeys_e",
+ /* 5:28 */ "morekeys_i",
/* 6:23 */ "morekeys_c",
/* 7:23 */ "double_quotes",
/* 8:22 */ "morekeys_n",
/* 9:22 */ "single_quotes",
/* 10:20 */ "morekeys_s",
- /* 11:15 */ "keyspec_currency",
+ /* 11:17 */ "keyspec_currency",
/* 12:14 */ "morekeys_y",
/* 13:13 */ "morekeys_d",
/* 14:12 */ "morekeys_z",
@@ -209,7 +209,7 @@ public final class KeyboardTextsTable {
/* 123: 1 */ "morekeys_less_than",
/* 124: 1 */ "morekeys_greater_than",
/* 125: 1 */ "morekeys_exclamation",
- /* 126: 0 */ "morekeys_currency",
+ /* 126: 0 */ "morekeys_currency_generic",
/* 127: 0 */ "morekeys_symbols_1",
/* 128: 0 */ "morekeys_symbols_2",
/* 129: 0 */ "morekeys_symbols_3",
@@ -250,7 +250,7 @@ public final class KeyboardTextsTable {
/* 164: 0 */ "morekeys_single_quote",
/* 165: 0 */ "morekeys_double_quote",
/* 166: 0 */ "morekeys_tablet_double_quote",
- /* 167: 0 */ "keyspec_emoji_key",
+ /* 167: 0 */ "keyspec_emoji_action_key",
};
private static final String EMPTY = "";
@@ -258,11 +258,13 @@ public final class KeyboardTextsTable {
/* Default texts */
private static final String[] TEXTS_DEFAULT = {
/* morekeys_a ~ */
- EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
- /* ~ morekeys_i */
+ EMPTY, EMPTY, EMPTY,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
/* keylabel_to_alpha */ "ABC",
- /* morekeys_c */ EMPTY,
+ /* morekeys_e ~ */
+ EMPTY, EMPTY, EMPTY,
+ /* ~ morekeys_c */
/* double_quotes */ "!text/double_lqm_rqm",
/* morekeys_n */ EMPTY,
/* single_quotes */ "!text/single_lqm_rqm",
@@ -378,7 +380,7 @@ public final class KeyboardTextsTable {
/* morekeys_greater_than */ "!fixedColumnOrder!3,!text/keyspec_right_single_angle_quote,!text/keyspec_greater_than_equal,!text/keyspec_right_double_angle_quote",
// U+00A1: "¡" INVERTED EXCLAMATION MARK
/* morekeys_exclamation */ "\u00A1",
- /* morekeys_currency */ "$,\u00A2,\u20AC,\u00A3,\u00A5,\u20B1",
+ /* morekeys_currency_generic */ "$,\u00A2,\u20AC,\u00A3,\u00A5,\u20B1",
// U+00B9: "¹" SUPERSCRIPT ONE
// U+00BD: "½" VULGAR FRACTION ONE HALF
// U+2153: "⅓" VULGAR FRACTION ONE THIRD
@@ -462,7 +464,7 @@ public final class KeyboardTextsTable {
/* morekeys_single_quote */ "!fixedColumnOrder!5,!text/single_quotes,!text/single_angle_quotes",
/* morekeys_double_quote */ "!fixedColumnOrder!5,!text/double_quotes,!text/double_angle_quotes",
/* morekeys_tablet_double_quote */ "!fixedColumnOrder!6,!text/double_quotes,!text/single_quotes,!text/double_angle_quotes,!text/single_angle_quotes",
- /* keyspec_emoji_key */ "!icon/emoji_key|!code/key_emoji",
+ /* keyspec_emoji_action_key */ "!icon/emoji_action_key|!code/key_emoji",
};
/* Locale af: Afrikaans */
@@ -492,6 +494,7 @@ public final class KeyboardTextsTable {
// U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FA,\u00FB,\u00FC,\u00F9,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
@@ -508,9 +511,8 @@ public final class KeyboardTextsTable {
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
// U+0133: "ij" LATIN SMALL LIGATURE IJ
/* morekeys_i */ "\u00ED,\u00EC,\u00EF,\u00EE,\u012F,\u012B,\u0133",
- /* keylabel_to_alpha ~ */
- null, null, null,
- /* ~ double_quotes */
+ /* morekeys_c */ null,
+ /* double_quotes */ null,
// U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
// U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
/* morekeys_n */ "\u00F1,\u0144",
@@ -525,17 +527,17 @@ public final class KeyboardTextsTable {
/* Locale ar: Arabic */
private static final String[] TEXTS_ar = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0623: "أ" ARABIC LETTER ALEF WITH HAMZA ABOVE
// U+200C: ZERO WIDTH NON-JOINER
// U+0628: "ب" ARABIC LETTER BEH
// U+062C: "ج" ARABIC LETTER JEEM
/* keylabel_to_alpha */ "\u0623\u200C\u0628\u200C\u062C",
- /* morekeys_c ~ */
+ /* morekeys_e ~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null,
/* ~ morekeys_cyrillic_soft_sign */
// U+0661: "١" ARABIC-INDIC DIGIT ONE
/* keyspec_symbols_1 */ "\u0661",
@@ -673,6 +675,7 @@ public final class KeyboardTextsTable {
// U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FC,\u00FB,\u00F9,\u00FA,\u016B",
+ /* keylabel_to_alpha */ null,
// U+0259: "ə" LATIN SMALL LETTER SCHWA
/* morekeys_e */ "\u0259",
// U+0131: "ı" LATIN SMALL LETTER DOTLESS I
@@ -683,7 +686,6 @@ public final class KeyboardTextsTable {
// U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
/* morekeys_i */ "\u0131,\u00EE,\u00EF,\u00EC,\u00ED,\u012F,\u012B",
- /* keylabel_to_alpha */ null,
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
@@ -706,14 +708,16 @@ public final class KeyboardTextsTable {
/* Locale be_BY: Belarusian (Belarus) */
private static final String[] TEXTS_be_BY = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0410: "А" CYRILLIC CAPITAL LETTER A
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
/* keylabel_to_alpha */ "\u0410\u0411\u0412",
- /* morekeys_c */ null,
+ /* morekeys_e ~ */
+ null, null, null,
+ /* ~ morekeys_c */
/* double_quotes */ "!text/double_9qm_lqm",
/* morekeys_n */ null,
/* single_quotes */ "!text/single_9qm_lqm",
@@ -740,14 +744,16 @@ public final class KeyboardTextsTable {
/* Locale bg: Bulgarian */
private static final String[] TEXTS_bg = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0410: "А" CYRILLIC CAPITAL LETTER A
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
/* keylabel_to_alpha */ "\u0410\u0411\u0412",
- /* morekeys_c */ null,
+ /* morekeys_e ~ */
+ null, null, null,
+ /* ~ morekeys_c */
// single_quotes of Bulgarian is default single_quotes_right_left.
/* double_quotes */ "!text/double_9qm_lqm",
};
@@ -755,18 +761,18 @@ public final class KeyboardTextsTable {
/* Locale bn_IN: Bengali (India) */
private static final String[] TEXTS_bn_IN = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0995: "क" BENGALI LETTER KA
// U+0996: "ख" BENGALI LETTER KHA
// U+0997: "ग" BENGALI LETTER GA
/* keylabel_to_alpha */ "\u0995\u0996\u0997",
- /* morekeys_c ~ */
- null, null, null, null, null,
+ /* morekeys_e ~ */
+ null, null, null, null, null, null, null,
/* ~ morekeys_s */
- // U+09F3: "৳" BENGALI RUPEE SIGN
- /* keyspec_currency */ "\u09F3",
+ // U+20B9: "₹" INDIAN RUPEE SIGN
+ /* keyspec_currency */ "\u20B9",
};
/* Locale ca: Catalan */
@@ -798,6 +804,7 @@ public final class KeyboardTextsTable {
// U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
@@ -813,7 +820,6 @@ public final class KeyboardTextsTable {
// U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
/* morekeys_i */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B",
- /* keylabel_to_alpha */ null,
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
@@ -872,6 +878,7 @@ public final class KeyboardTextsTable {
// U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FA,\u016F,\u00FB,\u00FC,\u00F9,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+011B: "ě" LATIN SMALL LETTER E WITH CARON
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
@@ -888,7 +895,6 @@ public final class KeyboardTextsTable {
// U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
/* morekeys_i */ "\u00ED,\u00EE,\u00EF,\u00EC,\u012F,\u012B",
- /* keylabel_to_alpha */ null,
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
@@ -945,13 +951,13 @@ public final class KeyboardTextsTable {
// U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FA,\u00FC,\u00FB,\u00F9,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
/* morekeys_e */ "\u00E9,\u00EB",
// U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
// U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
/* morekeys_i */ "\u00ED,\u00EF",
- /* keylabel_to_alpha */ null,
/* morekeys_c */ null,
/* double_quotes */ "!text/double_9qm_lqm",
// U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
@@ -1020,15 +1026,15 @@ public final class KeyboardTextsTable {
// U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FC,%,\u00FB,\u00F9,\u00FA,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
// U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
// U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
/* morekeys_e */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0117",
- /* morekeys_i ~ */
- null, null, null,
- /* ~ morekeys_c */
+ /* morekeys_i */ null,
+ /* morekeys_c */ null,
/* double_quotes */ "!text/double_9qm_lqm",
// U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
// U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
@@ -1065,8 +1071,8 @@ public final class KeyboardTextsTable {
/* Locale el: Greek */
private static final String[] TEXTS_el = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0391: "Α" GREEK CAPITAL LETTER ALPHA
// U+0392: "Β" GREEK CAPITAL LETTER BETA
@@ -1100,6 +1106,7 @@ public final class KeyboardTextsTable {
// U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FA,\u00FB,\u00FC,\u00F9,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
@@ -1112,7 +1119,6 @@ public final class KeyboardTextsTable {
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
// U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
/* morekeys_i */ "\u00ED,\u00EE,\u00EF,\u012B,\u00EC",
- /* keylabel_to_alpha */ null,
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
/* morekeys_c */ "\u00E7",
/* double_quotes */ null,
@@ -1159,6 +1165,7 @@ public final class KeyboardTextsTable {
// U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK
// U+00B5: "µ" MICRO SIGN
/* morekeys_u */ "\u00FA,\u016F,\u00FB,\u00FC,\u00F9,\u016B,\u0169,\u0171,\u0173,\u00B5",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+011B: "ě" LATIN SMALL LETTER E WITH CARON
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
@@ -1178,7 +1185,6 @@ public final class KeyboardTextsTable {
// U+0131: "ı" LATIN SMALL LETTER DOTLESS I
// U+0133: "ij" LATIN SMALL LIGATURE IJ
/* morekeys_i */ "\u00ED,\u00EE,\u00EF,\u0129,\u00EC,\u012F,\u012B,\u0131,\u0133",
- /* keylabel_to_alpha */ null,
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
@@ -1300,6 +1306,7 @@ public final class KeyboardTextsTable {
// U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
@@ -1315,7 +1322,6 @@ public final class KeyboardTextsTable {
// U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
/* morekeys_i */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B",
- /* keylabel_to_alpha */ null,
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
@@ -1364,6 +1370,7 @@ public final class KeyboardTextsTable {
// U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE
// U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE
/* morekeys_u */ "\u00FC,\u016B,\u0173,\u00F9,\u00FA,\u00FB,\u016F,\u0171",
+ /* keylabel_to_alpha */ null,
// U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
@@ -1381,7 +1388,6 @@ public final class KeyboardTextsTable {
// U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
// U+0131: "ı" LATIN SMALL LETTER DOTLESS I
/* morekeys_i */ "\u012B,\u00EC,\u012F,\u00ED,\u00EE,\u00EF,\u0131",
- /* keylabel_to_alpha */ null,
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
@@ -1466,6 +1472,7 @@ public final class KeyboardTextsTable {
// U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
@@ -1481,7 +1488,6 @@ public final class KeyboardTextsTable {
// U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
/* morekeys_i */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B",
- /* keylabel_to_alpha */ null,
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
@@ -1495,16 +1501,16 @@ public final class KeyboardTextsTable {
/* Locale fa: Persian */
private static final String[] TEXTS_fa = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0627: "ا" ARABIC LETTER ALEF
// U+200C: ZERO WIDTH NON-JOINER
// U+0628: "ب" ARABIC LETTER BEH
// U+067E: "پ" ARABIC LETTER PEH
/* keylabel_to_alpha */ "\u0627\u200C\u0628\u200C\u067E",
- /* morekeys_c ~ */
- null, null, null, null, null,
+ /* morekeys_e ~ */
+ null, null, null, null, null, null, null,
/* ~ morekeys_s */
// U+FDFC: "﷼" RIAL SIGN
/* keyspec_currency */ "\uFDFC",
@@ -1655,7 +1661,7 @@ public final class KeyboardTextsTable {
/* morekeys_o */ "\u00F8,\u00F4,\u00F2,\u00F3,\u00F5,\u0153,\u014D",
// U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
/* morekeys_u */ "\u00FC",
- /* morekeys_e ~ */
+ /* keylabel_to_alpha ~ */
null, null, null, null, null, null, null,
/* ~ single_quotes */
// U+0161: "š" LATIN SMALL LETTER S WITH CARON
@@ -1716,6 +1722,7 @@ public final class KeyboardTextsTable {
// U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00F9,\u00FB,%,\u00FC,\u00FA,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
@@ -1731,7 +1738,6 @@ public final class KeyboardTextsTable {
// U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
/* morekeys_i */ "\u00EE,%,\u00EF,\u00EC,\u00ED,\u012F,\u012B",
- /* keylabel_to_alpha */ null,
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
@@ -1789,6 +1795,7 @@ public final class KeyboardTextsTable {
// U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
@@ -1804,7 +1811,6 @@ public final class KeyboardTextsTable {
// U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
/* morekeys_i */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B",
- /* keylabel_to_alpha */ null,
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
@@ -1818,15 +1824,15 @@ public final class KeyboardTextsTable {
/* Locale hi: Hindi */
private static final String[] TEXTS_hi = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0915: "क" DEVANAGARI LETTER KA
// U+0916: "ख" DEVANAGARI LETTER KHA
// U+0917: "ग" DEVANAGARI LETTER GA
/* keylabel_to_alpha */ "\u0915\u0916\u0917",
- /* morekeys_c ~ */
- null, null, null, null, null,
+ /* morekeys_e ~ */
+ null, null, null, null, null, null, null,
/* ~ morekeys_s */
// U+20B9: "₹" INDIAN RUPEE SIGN
/* keyspec_currency */ "\u20B9",
@@ -1872,7 +1878,7 @@ public final class KeyboardTextsTable {
private static final String[] TEXTS_hr = {
/* morekeys_a ~ */
null, null, null, null, null, null,
- /* ~ keylabel_to_alpha */
+ /* ~ morekeys_i */
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
@@ -1929,6 +1935,7 @@ public final class KeyboardTextsTable {
// U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FA,\u00FC,\u0171,\u00FB,\u00F9,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
@@ -1944,7 +1951,6 @@ public final class KeyboardTextsTable {
// U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
/* morekeys_i */ "\u00ED,\u00EE,\u00EF,\u00EC,\u012F,\u012B",
- /* keylabel_to_alpha */ null,
/* morekeys_c */ null,
/* double_quotes */ "!text/double_9qm_rqm",
/* morekeys_n */ null,
@@ -1959,18 +1965,18 @@ public final class KeyboardTextsTable {
/* Locale hy_AM: Armenian (Armenia) */
private static final String[] TEXTS_hy_AM = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0531: "Ա" ARMENIAN CAPITAL LETTER AYB
// U+0532: "Բ" ARMENIAN CAPITAL LETTER BEN
// U+0533: "Գ" ARMENIAN CAPITAL LETTER GIM
/* keylabel_to_alpha */ "\u0531\u0532\u0533",
- /* morekeys_c ~ */
+ /* morekeys_e ~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null,
+ null, null, null, null, null,
/* ~ morekeys_nordic_row2_11 */
// U+055E: "՞" ARMENIAN QUESTION MARK
// U+055C: "՜" ARMENIAN EXCLAMATION MARK
@@ -2043,6 +2049,7 @@ public final class KeyboardTextsTable {
// U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FA,\u00FC,\u00FB,\u00F9,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
@@ -2058,7 +2065,6 @@ public final class KeyboardTextsTable {
// U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
/* morekeys_i */ "\u00ED,\u00EF,\u00EE,\u00EC,\u012F,\u012B",
- /* keylabel_to_alpha */ null,
/* morekeys_c */ null,
/* double_quotes */ "!text/double_9qm_lqm",
/* morekeys_n */ null,
@@ -2103,6 +2109,7 @@ public final class KeyboardTextsTable {
// U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00F9,\u00FA,\u00FB,\u00FC,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
@@ -2118,11 +2125,11 @@ public final class KeyboardTextsTable {
// U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
/* morekeys_i */ "\u00EC,\u00ED,\u00EE,\u00EF,\u012F,\u012B",
- /* keylabel_to_alpha ~ */
+ /* morekeys_c ~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null,
+ null, null, null, null, null,
/* ~ keyspec_tablet_comma */
// U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
/* keyspec_swiss_row1_11 */ "\u00FC",
@@ -2141,14 +2148,16 @@ public final class KeyboardTextsTable {
/* Locale iw: Hebrew */
private static final String[] TEXTS_iw = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+05D0: "א" HEBREW LETTER ALEF
// U+05D1: "ב" HEBREW LETTER BET
// U+05D2: "ג" HEBREW LETTER GIMEL
/* keylabel_to_alpha */ "\u05D0\u05D1\u05D2",
- /* morekeys_c */ null,
+ /* morekeys_e ~ */
+ null, null, null,
+ /* ~ morekeys_c */
/* double_quotes */ "!text/double_rqm_9qm",
/* morekeys_n */ null,
/* single_quotes */ "!text/single_rqm_9qm",
@@ -2198,14 +2207,16 @@ public final class KeyboardTextsTable {
/* Locale ka_GE: Georgian (Georgia) */
private static final String[] TEXTS_ka_GE = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+10D0: "ა" GEORGIAN LETTER AN
// U+10D1: "ბ" GEORGIAN LETTER BAN
// U+10D2: "გ" GEORGIAN LETTER GAN
/* keylabel_to_alpha */ "\u10D0\u10D1\u10D2",
- /* morekeys_c */ null,
+ /* morekeys_e ~ */
+ null, null, null,
+ /* ~ morekeys_c */
/* double_quotes */ "!text/double_9qm_lqm",
/* morekeys_n */ null,
/* single_quotes */ "!text/single_9qm_lqm",
@@ -2214,16 +2225,16 @@ public final class KeyboardTextsTable {
/* Locale kk: Kazakh */
private static final String[] TEXTS_kk = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0410: "А" CYRILLIC CAPITAL LETTER A
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
/* keylabel_to_alpha */ "\u0410\u0411\u0412",
- /* morekeys_c ~ */
+ /* morekeys_e ~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null,
+ null, null, null,
/* ~ morekeys_k */
// U+0451: "ё" CYRILLIC SMALL LETTER IO
/* morekeys_cyrillic_ie */ "\u0451",
@@ -2272,14 +2283,14 @@ public final class KeyboardTextsTable {
/* Locale km_KH: Khmer (Cambodia) */
private static final String[] TEXTS_km_KH = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+1780: "ក" KHMER LETTER KA
// U+1781: "ខ" KHMER LETTER KHA
// U+1782: "គ" KHMER LETTER KO
/* keylabel_to_alpha */ "\u1780\u1781\u1782",
- /* morekeys_c ~ */
+ /* morekeys_e ~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
@@ -2287,7 +2298,7 @@ public final class KeyboardTextsTable {
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null,
/* ~ morekeys_cyrillic_a */
// U+17DB: "៛" KHMER CURRENCY SYMBOL RIEL
/* morekeys_currency_dollar */ "\u17DB,\u00A2,\u00A3,\u20AC,\u00A5,\u20B1",
@@ -2296,15 +2307,15 @@ public final class KeyboardTextsTable {
/* Locale kn_IN: Kannada (India) */
private static final String[] TEXTS_kn_IN = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0C85: "ಅ" KANNADA LETTER A
// U+0C86: "ಆ" KANNADA LETTER AA
// U+0C87: "ಇ" KANNADA LETTER I
/* keylabel_to_alpha */ "\u0C85\u0C86\u0C87",
- /* morekeys_c ~ */
- null, null, null, null, null,
+ /* morekeys_e ~ */
+ null, null, null, null, null, null, null,
/* ~ morekeys_s */
// U+20B9: "₹" INDIAN RUPEE SIGN
/* keyspec_currency */ "\u20B9",
@@ -2313,16 +2324,16 @@ public final class KeyboardTextsTable {
/* Locale ky: Kirghiz */
private static final String[] TEXTS_ky = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0410: "А" CYRILLIC CAPITAL LETTER A
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
/* keylabel_to_alpha */ "\u0410\u0411\u0412",
- /* morekeys_c ~ */
+ /* morekeys_e ~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null,
+ null, null, null,
/* ~ morekeys_k */
// U+0451: "ё" CYRILLIC SMALL LETTER IO
/* morekeys_cyrillic_ie */ "\u0451",
@@ -2357,15 +2368,15 @@ public final class KeyboardTextsTable {
/* Locale lo_LA: Lao (Laos) */
private static final String[] TEXTS_lo_LA = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0E81: "ກ" LAO LETTER KO
// U+0E82: "ຂ" LAO LETTER KHO SUNG
// U+0E84: "ຄ" LAO LETTER KHO TAM
/* keylabel_to_alpha */ "\u0E81\u0E82\u0E84",
- /* morekeys_c ~ */
- null, null, null, null, null,
+ /* morekeys_e ~ */
+ null, null, null, null, null, null, null,
/* ~ morekeys_s */
// U+20AD: "₭" KIP SIGN
/* keyspec_currency */ "\u20AD",
@@ -2402,6 +2413,7 @@ public final class KeyboardTextsTable {
// U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE
// U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE
/* morekeys_u */ "\u016B,\u0173,\u00FC,\u016B,\u00F9,\u00FA,\u00FB,\u016F,\u0171",
+ /* keylabel_to_alpha */ null,
// U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
// U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
// U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
@@ -2419,7 +2431,6 @@ public final class KeyboardTextsTable {
// U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
// U+0131: "ı" LATIN SMALL LETTER DOTLESS I
/* morekeys_i */ "\u012F,\u012B,\u00EC,\u00ED,\u00EE,\u00EF,\u0131",
- /* keylabel_to_alpha */ null,
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
@@ -2496,6 +2507,7 @@ public final class KeyboardTextsTable {
// U+016F: "ů" LATIN SMALL LETTER U WITH RING ABOVE
// U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE
/* morekeys_u */ "\u016B,\u0173,\u00F9,\u00FA,\u00FB,\u00FC,\u016F,\u0171",
+ /* keylabel_to_alpha */ null,
// U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
// U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
@@ -2513,7 +2525,6 @@ public final class KeyboardTextsTable {
// U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
// U+0131: "ı" LATIN SMALL LETTER DOTLESS I
/* morekeys_i */ "\u012B,\u012F,\u00EC,\u00ED,\u00EE,\u00EF,\u0131",
- /* keylabel_to_alpha */ null,
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
@@ -2563,14 +2574,16 @@ public final class KeyboardTextsTable {
/* Locale mk: Macedonian */
private static final String[] TEXTS_mk = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0410: "А" CYRILLIC CAPITAL LETTER A
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
/* keylabel_to_alpha */ "\u0410\u0411\u0412",
- /* morekeys_c */ null,
+ /* morekeys_e ~ */
+ null, null, null,
+ /* ~ morekeys_c */
/* double_quotes */ "!text/double_9qm_lqm",
/* morekeys_n */ null,
/* single_quotes */ "!text/single_9qm_lqm",
@@ -2601,13 +2614,13 @@ public final class KeyboardTextsTable {
/* Locale ml_IN: Malayalam (India) */
private static final String[] TEXTS_ml_IN = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0D05: "അ" MALAYALAM LETTER A
/* keylabel_to_alpha */ "\u0D05",
- /* morekeys_c ~ */
- null, null, null, null, null,
+ /* morekeys_e ~ */
+ null, null, null, null, null, null, null,
/* ~ morekeys_s */
// U+20B9: "₹" INDIAN RUPEE SIGN
/* keyspec_currency */ "\u20B9",
@@ -2616,15 +2629,15 @@ public final class KeyboardTextsTable {
/* Locale mn_MN: Mongolian (Mongolia) */
private static final String[] TEXTS_mn_MN = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0410: "А" CYRILLIC CAPITAL LETTER A
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
/* keylabel_to_alpha */ "\u0410\u0411\u0412",
- /* morekeys_c ~ */
- null, null, null, null, null,
+ /* morekeys_e ~ */
+ null, null, null, null, null, null, null,
/* ~ morekeys_s */
// U+20AE: "₮" TUGRIK SIGN
/* keyspec_currency */ "\u20AE",
@@ -2633,15 +2646,15 @@ public final class KeyboardTextsTable {
/* Locale mr_IN: Marathi (India) */
private static final String[] TEXTS_mr_IN = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0915: "क" DEVANAGARI LETTER KA
// U+0916: "ख" DEVANAGARI LETTER KHA
// U+0917: "ग" DEVANAGARI LETTER GA
/* keylabel_to_alpha */ "\u0915\u0916\u0917",
- /* morekeys_c ~ */
- null, null, null, null, null,
+ /* morekeys_e ~ */
+ null, null, null, null, null, null, null,
/* ~ morekeys_s */
// U+20B9: "₹" INDIAN RUPEE SIGN
/* keyspec_currency */ "\u20B9",
@@ -2686,18 +2699,18 @@ public final class KeyboardTextsTable {
/* Locale my_MM: Burmese (Myanmar) */
private static final String[] TEXTS_my_MM = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+1000: "က" MYANMAR LETTER KA
// U+1001: "ခ" MYANMAR LETTER KHA
// U+1002: "ဂ" MYANMAR LETTER GA
/* keylabel_to_alpha */ "\u1000\u1001\u1002",
- /* morekeys_c ~ */
+ /* morekeys_e ~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null,
+ null, null, null, null, null,
/* ~ morekeys_nordic_row2_11 */
/* morekeys_punctuation */ "!autoColumnOrder!9,\u104A,.,?,!,#,),(,/,;,...,',@,:,-,\",+,\\%,&",
// U+104A: "၊" MYANMAR SIGN LITTLE SECTION
@@ -2744,6 +2757,7 @@ public final class KeyboardTextsTable {
// U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FC,\u00FB,\u00F9,\u00FA,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
@@ -2752,9 +2766,8 @@ public final class KeyboardTextsTable {
// U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
// U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
/* morekeys_e */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0119,\u0117,\u0113",
- /* morekeys_i ~ */
- null, null, null,
- /* ~ morekeys_c */
+ /* morekeys_i */ null,
+ /* morekeys_c */ null,
/* double_quotes */ "!text/double_9qm_rqm",
/* morekeys_n */ null,
/* single_quotes */ "!text/single_9qm_rqm",
@@ -2780,15 +2793,15 @@ public final class KeyboardTextsTable {
/* Locale ne_NP: Nepali (Nepal) */
private static final String[] TEXTS_ne_NP = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0915: "क" DEVANAGARI LETTER KA
// U+0916: "ख" DEVANAGARI LETTER KHA
// U+0917: "ग" DEVANAGARI LETTER GA
/* keylabel_to_alpha */ "\u0915\u0916\u0917",
- /* morekeys_c ~ */
- null, null, null, null, null,
+ /* morekeys_e ~ */
+ null, null, null, null, null, null, null,
/* ~ morekeys_s */
// U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN
/* keyspec_currency */ "\u0930\u0941.",
@@ -2856,6 +2869,7 @@ public final class KeyboardTextsTable {
// U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FA,\u00FC,\u00FB,\u00F9,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
// U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
@@ -2872,7 +2886,6 @@ public final class KeyboardTextsTable {
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
// U+0133: "ij" LATIN SMALL LIGATURE IJ
/* morekeys_i */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B,\u0133",
- /* keylabel_to_alpha */ null,
/* morekeys_c */ null,
/* double_quotes */ "!text/double_9qm_rqm",
// U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
@@ -2907,6 +2920,7 @@ public final class KeyboardTextsTable {
// U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
/* morekeys_o */ "\u00F3,\u00F6,\u00F4,\u00F2,\u00F5,\u0153,\u00F8,\u014D",
/* morekeys_u */ null,
+ /* keylabel_to_alpha */ null,
// U+0119: "ę" LATIN SMALL LETTER E WITH OGONEK
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
@@ -2916,7 +2930,6 @@ public final class KeyboardTextsTable {
// U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
/* morekeys_e */ "\u0119,\u00E8,\u00E9,\u00EA,\u00EB,\u0117,\u0113",
/* morekeys_i */ null,
- /* keylabel_to_alpha */ null,
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
@@ -2969,6 +2982,7 @@ public final class KeyboardTextsTable {
// U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
@@ -2984,7 +2998,6 @@ public final class KeyboardTextsTable {
// U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
/* morekeys_i */ "\u00ED,\u00EE,\u00EC,\u00EF,\u012F,\u012B",
- /* keylabel_to_alpha */ null,
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
@@ -3017,7 +3030,7 @@ public final class KeyboardTextsTable {
// U+0101: "ā" LATIN SMALL LETTER A WITH MACRON
/* morekeys_a */ "\u00E2,\u00E3,\u0103,\u00E0,\u00E1,\u00E4,\u00E6,\u00E5,\u0101",
/* morekeys_o ~ */
- null, null, null,
+ null, null, null, null,
/* ~ morekeys_e */
// U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
// U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
@@ -3026,7 +3039,6 @@ public final class KeyboardTextsTable {
// U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
/* morekeys_i */ "\u00EE,\u00EF,\u00EC,\u00ED,\u012F,\u012B",
- /* keylabel_to_alpha */ null,
/* morekeys_c */ null,
/* double_quotes */ "!text/double_9qm_rqm",
/* morekeys_n */ null,
@@ -3046,14 +3058,16 @@ public final class KeyboardTextsTable {
/* Locale ru: Russian */
private static final String[] TEXTS_ru = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0410: "А" CYRILLIC CAPITAL LETTER A
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
/* keylabel_to_alpha */ "\u0410\u0411\u0412",
- /* morekeys_c */ null,
+ /* morekeys_e ~ */
+ null, null, null,
+ /* ~ morekeys_c */
/* double_quotes */ "!text/double_9qm_lqm",
/* morekeys_n */ null,
/* single_quotes */ "!text/single_9qm_lqm",
@@ -3080,12 +3094,17 @@ public final class KeyboardTextsTable {
/* Locale si_LK: Sinhalese (Sri Lanka) */
private static final String[] TEXTS_si_LK = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0D85: "අ" SINHALA LETTER AYANNA
// U+0D86: "ආ" SINHALA LETTER AAYANNA
/* keylabel_to_alpha */ "\u0D85,\u0D86",
+ /* morekeys_e ~ */
+ null, null, null, null, null, null, null,
+ /* ~ morekeys_s */
+ // U+0DBB/U+0DD4: "රු" SINHALA LETTER RAYANNA/SINHALA VOWEL SIGN KETTI PAA-PILLA
+ /* keyspec_currency */ "\u0DBB\u0DD4",
};
/* Locale sk: Slovak */
@@ -3118,6 +3137,7 @@ public final class KeyboardTextsTable {
// U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
// U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE
/* morekeys_u */ "\u00FA,\u016F,\u00FC,\u016B,\u0173,\u00F9,\u00FB,\u0171",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+011B: "ě" LATIN SMALL LETTER E WITH CARON
// U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
@@ -3135,7 +3155,6 @@ public final class KeyboardTextsTable {
// U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
// U+0131: "ı" LATIN SMALL LETTER DOTLESS I
/* morekeys_i */ "\u00ED,\u012B,\u012F,\u00EC,\u00EE,\u00EF,\u0131",
- /* keylabel_to_alpha */ null,
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
@@ -3187,7 +3206,7 @@ public final class KeyboardTextsTable {
private static final String[] TEXTS_sl = {
/* morekeys_a ~ */
null, null, null, null, null, null,
- /* ~ keylabel_to_alpha */
+ /* ~ morekeys_i */
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
/* morekeys_c */ "\u010D,\u0107",
@@ -3212,15 +3231,17 @@ public final class KeyboardTextsTable {
/* Locale sr: Serbian */
private static final String[] TEXTS_sr = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// END: More keys definitions for Serbian (Cyrillic)
// Label for "switch to alphabetic" key.
// U+0410: "А" CYRILLIC CAPITAL LETTER A
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
/* keylabel_to_alpha */ "\u0410\u0411\u0412",
- /* morekeys_c */ null,
+ /* morekeys_e ~ */
+ null, null, null,
+ /* ~ morekeys_c */
/* double_quotes */ "!text/double_9qm_lqm",
/* morekeys_n */ null,
/* single_quotes */ "!text/single_9qm_lqm",
@@ -3290,6 +3311,7 @@ public final class KeyboardTextsTable {
// U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FC,\u00FA,\u00F9,\u00FB,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
@@ -3301,7 +3323,6 @@ public final class KeyboardTextsTable {
// U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
// U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
/* morekeys_i */ "\u00ED,\u00EC,\u00EE,\u00EF",
- /* keylabel_to_alpha */ null,
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
@@ -3384,6 +3405,7 @@ public final class KeyboardTextsTable {
// U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FB,\u00FC,\u00F9,\u00FA,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
@@ -3396,7 +3418,6 @@ public final class KeyboardTextsTable {
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
// U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
/* morekeys_i */ "\u00EE,\u00EF,\u00ED,\u012B,\u00EC",
- /* keylabel_to_alpha */ null,
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
/* morekeys_c */ "\u00E7",
/* double_quotes */ null,
@@ -3414,32 +3435,61 @@ public final class KeyboardTextsTable {
/* Locale ta_IN: Tamil (India) */
private static final String[] TEXTS_ta_IN = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0BA4: "த" TAMIL LETTER TA
// U+0BAE/U+0BBF: "மி" TAMIL LETTER MA/TAMIL VOWEL SIGN I
// U+0BB4/U+0BCD: "ழ்" TAMIL LETTER LLLA/TAMIL SIGN VIRAMA
/* keylabel_to_alpha */ "\u0BA4\u0BAE\u0BBF\u0BB4\u0BCD",
- /* morekeys_c ~ */
- null, null, null, null, null,
+ /* morekeys_e ~ */
+ null, null, null, null, null, null, null,
/* ~ morekeys_s */
// U+0BF9: "௹" TAMIL RUPEE SIGN
/* keyspec_currency */ "\u0BF9",
};
+ /* Locale ta_LK: Tamil (Sri Lanka) */
+ private static final String[] TEXTS_ta_LK = {
+ /* morekeys_a ~ */
+ null, null, null,
+ /* ~ morekeys_u */
+ // Label for "switch to alphabetic" key.
+ // U+0BA4: "த" TAMIL LETTER TA
+ // U+0BAE/U+0BBF: "மி" TAMIL LETTER MA/TAMIL VOWEL SIGN I
+ // U+0BB4/U+0BCD: "ழ்" TAMIL LETTER LLLA/TAMIL SIGN VIRAMA
+ /* keylabel_to_alpha */ "\u0BA4\u0BAE\u0BBF\u0BB4\u0BCD",
+ /* morekeys_e ~ */
+ null, null, null, null, null, null, null,
+ /* ~ morekeys_s */
+ // U+0DBB/U+0DD4: "රු" SINHALA LETTER RAYANNA/SINHALA VOWEL SIGN KETTI PAA-PILLA
+ /* keyspec_currency */ "\u0DBB\u0DD4",
+ };
+
+ /* Locale ta_SG: Tamil (Singapore) */
+ private static final String[] TEXTS_ta_SG = {
+ /* morekeys_a ~ */
+ null, null, null,
+ /* ~ morekeys_u */
+ // Label for "switch to alphabetic" key.
+ // U+0BA4: "த" TAMIL LETTER TA
+ // U+0BAE/U+0BBF: "மி" TAMIL LETTER MA/TAMIL VOWEL SIGN I
+ // U+0BB4/U+0BCD: "ழ்" TAMIL LETTER LLLA/TAMIL SIGN VIRAMA
+ /* keylabel_to_alpha */ "\u0BA4\u0BAE\u0BBF\u0BB4\u0BCD",
+ };
+
/* Locale te_IN: Telugu (India) */
private static final String[] TEXTS_te_IN = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0C05: "అ" TELUGU LETTER A
// U+0C06: "ఆ" TELUGU LETTER AA
// U+0C07: "ఇ" TELUGU LETTER I
/* keylabel_to_alpha */ "\u0C05\u0C06\u0C07",
- /* morekeys_c ~ */
- null, null, null, null, null,
+ /* morekeys_e ~ */
+ null, null, null, null, null, null, null,
/* ~ morekeys_s */
// U+20B9: "₹" INDIAN RUPEE SIGN
/* keyspec_currency */ "\u20B9",
@@ -3448,15 +3498,15 @@ public final class KeyboardTextsTable {
/* Locale th: Thai */
private static final String[] TEXTS_th = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0E01: "ก" THAI CHARACTER KO KAI
// U+0E02: "ข" THAI CHARACTER KHO KHAI
// U+0E04: "ค" THAI CHARACTER KHO KHWAI
/* keylabel_to_alpha */ "\u0E01\u0E02\u0E04",
- /* morekeys_c ~ */
- null, null, null, null, null,
+ /* morekeys_e ~ */
+ null, null, null, null, null, null, null,
/* ~ morekeys_s */
// U+0E3F: "฿" THAI CURRENCY SYMBOL BAHT
/* keyspec_currency */ "\u0E3F",
@@ -3491,6 +3541,7 @@ public final class KeyboardTextsTable {
// U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FA,\u00FC,\u00F9,\u00FB,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
@@ -3506,7 +3557,6 @@ public final class KeyboardTextsTable {
// U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
/* morekeys_i */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B",
- /* keylabel_to_alpha */ null,
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
@@ -3536,6 +3586,7 @@ public final class KeyboardTextsTable {
// U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FC,\u00FB,\u00F9,\u00FA,\u016B",
+ /* keylabel_to_alpha */ null,
/* morekeys_e */ null,
// U+0131: "ı" LATIN SMALL LETTER DOTLESS I
// U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
@@ -3545,7 +3596,6 @@ public final class KeyboardTextsTable {
// U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
/* morekeys_i */ "\u0131,\u00EE,\u00EF,\u00EC,\u00ED,\u012F,\u012B",
- /* keylabel_to_alpha */ null,
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
// U+010D: "č" LATIN SMALL LETTER C WITH CARON
@@ -3568,14 +3618,16 @@ public final class KeyboardTextsTable {
/* Locale uk: Ukrainian */
private static final String[] TEXTS_uk = {
/* morekeys_a ~ */
- null, null, null, null, null,
- /* ~ morekeys_i */
+ null, null, null,
+ /* ~ morekeys_u */
// Label for "switch to alphabetic" key.
// U+0410: "А" CYRILLIC CAPITAL LETTER A
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
/* keylabel_to_alpha */ "\u0410\u0411\u0412",
- /* morekeys_c */ null,
+ /* morekeys_e ~ */
+ null, null, null,
+ /* ~ morekeys_c */
/* double_quotes */ "!text/double_9qm_lqm",
/* morekeys_n */ null,
/* single_quotes */ "!text/single_9qm_lqm",
@@ -3659,6 +3711,7 @@ public final class KeyboardTextsTable {
// U+1EEF: "ữ" LATIN SMALL LETTER U WITH HORN AND TILDE
// U+1EF1: "ự" LATIN SMALL LETTER U WITH HORN AND DOT BELOW
/* morekeys_u */ "\u00F9,\u00FA,\u1EE7,\u0169,\u1EE5,\u01B0,\u1EEB,\u1EE9,\u1EED,\u1EEF,\u1EF1",
+ /* keylabel_to_alpha */ null,
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+1EBB: "ẻ" LATIN SMALL LETTER E WITH HOOK ABOVE
@@ -3677,8 +3730,8 @@ public final class KeyboardTextsTable {
// U+0129: "ĩ" LATIN SMALL LETTER I WITH TILDE
// U+1ECB: "ị" LATIN SMALL LETTER I WITH DOT BELOW
/* morekeys_i */ "\u00EC,\u00ED,\u1EC9,\u0129,\u1ECB",
- /* keylabel_to_alpha ~ */
- null, null, null, null, null, null,
+ /* morekeys_c ~ */
+ null, null, null, null, null,
/* ~ morekeys_s */
// U+20AB: "₫" DONG SIGN
/* keyspec_currency */ "\u20AB",
@@ -3719,6 +3772,7 @@ public final class KeyboardTextsTable {
// U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
// U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
/* morekeys_u */ "\u00FA,\u00FB,\u00FC,\u00F9,\u016B",
+ /* keylabel_to_alpha */ null,
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
@@ -3731,7 +3785,6 @@ public final class KeyboardTextsTable {
// U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
// U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
/* morekeys_i */ "\u00ED,\u00EE,\u00EF,\u012B,\u00EC",
- /* keylabel_to_alpha */ null,
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
/* morekeys_c */ "\u00E7",
/* double_quotes */ null,
@@ -3779,6 +3832,7 @@ public final class KeyboardTextsTable {
// U+0171: "ű" LATIN SMALL LETTER U WITH DOUBLE ACUTE
// U+0173: "ų" LATIN SMALL LETTER U WITH OGONEK
/* morekeys_u */ "\u00F9,\u00FA,\u00FB,\u00FC,\u0169,\u016B,\u016D,\u016F,\u0171,\u0173",
+ /* keylabel_to_alpha */ null,
// U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
// U+00E9: "é" LATIN SMALL LETTER E WITH ACUTE
// U+00EA: "ê" LATIN SMALL LETTER E WITH CIRCUMFLEX
@@ -3800,7 +3854,6 @@ public final class KeyboardTextsTable {
// U+0131: "ı" LATIN SMALL LETTER DOTLESS I
// U+0133: "ij" LATIN SMALL LIGATURE IJ
/* morekeys_i */ "\u00EC,\u00ED,\u00EE,\u00EF,\u0129,\u012B,\u012D,\u012F,\u0131,\u0133",
- /* keylabel_to_alpha */ null,
// U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
// U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
// U+0109: "ĉ" LATIN SMALL LETTER C WITH CIRCUMFLEX
@@ -3893,7 +3946,7 @@ public final class KeyboardTextsTable {
"cs" , TEXTS_cs, /* 17/ 21 Czech */
"da" , TEXTS_da, /* 19/ 54 Danish */
"de" , TEXTS_de, /* 16/ 62 German */
- "el" , TEXTS_el, /* 1/ 6 Greek */
+ "el" , TEXTS_el, /* 1/ 4 Greek */
"en" , TEXTS_en, /* 8/ 11 English */
"eo" , TEXTS_eo, /* 26/118 Esperanto */
"es" , TEXTS_es, /* 8/ 55 Spanish */
@@ -3931,13 +3984,15 @@ public final class KeyboardTextsTable {
"rm" , TEXTS_rm, /* 1/ 2 Raeto-Romance */
"ro" , TEXTS_ro, /* 6/ 16 Romanian */
"ru" , TEXTS_ru, /* 9/ 32 Russian */
- "si_LK" , TEXTS_si_LK, /* 1/ 6 Sinhalese (Sri Lanka) */
+ "si_LK" , TEXTS_si_LK, /* 2/ 12 Sinhalese (Sri Lanka) */
"sk" , TEXTS_sk, /* 20/ 22 Slovak */
"sl" , TEXTS_sl, /* 8/ 20 Slovenian */
"sr" , TEXTS_sr, /* 11/ 94 Serbian */
"sv" , TEXTS_sv, /* 21/ 54 Swedish */
"sw" , TEXTS_sw, /* 9/ 18 Swahili */
"ta_IN" , TEXTS_ta_IN, /* 2/ 12 Tamil (India) */
+ "ta_LK" , TEXTS_ta_LK, /* 2/ 12 Tamil (Sri Lanka) */
+ "ta_SG" , TEXTS_ta_SG, /* 1/ 4 Tamil (Singapore) */
"te_IN" , TEXTS_te_IN, /* 2/ 12 Telugu (India) */
"th" , TEXTS_th, /* 2/ 12 Thai */
"tl" , TEXTS_tl, /* 7/ 9 Tagalog */
diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
index ad14c06ef..162a209e3 100644
--- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
@@ -231,7 +231,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
// Don't add single letter words, possibly confuses
// capitalization of i.
final int wordLen = StringUtils.codePointCount(word);
- if (wordLen < MAX_WORD_LENGTH && wordLen > 1) {
+ if (wordLen <= MAX_WORD_LENGTH && wordLen > 1) {
if (DEBUG) {
Log.d(TAG, "addName " + name + ", " + word + ", " + prevWordsInfo);
}
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
index d6e6656ab..fd1f51dd6 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
@@ -468,7 +468,9 @@ public class DictionaryFacilitator {
// We don't add words with 0-frequency (assuming they would be profanity etc.).
final boolean isValid = maxFreq > 0;
UserHistoryDictionary.addToDictionary(userHistoryDictionary, prevWordsInfo, secondWord,
- isValid, timeStampInSeconds, mDistracterFilter);
+ isValid, timeStampInSeconds,
+ new DistracterFilterCheckingIsInDictionary(
+ mDistracterFilter, userHistoryDictionary));
}
private void removeWord(final String dictName, final String word) {
@@ -489,8 +491,9 @@ public class DictionaryFacilitator {
final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo,
final SettingsValuesForSuggestion settingsValuesForSuggestion, final int sessionId) {
final Dictionaries dictionaries = mDictionaries;
- final SuggestionResults suggestionResults =
- new SuggestionResults(dictionaries.mLocale, SuggestedWords.MAX_SUGGESTIONS);
+ final SuggestionResults suggestionResults = new SuggestionResults(
+ dictionaries.mLocale, SuggestedWords.MAX_SUGGESTIONS,
+ prevWordsInfo.mPrevWordsInfo[0].mIsBeginningOfSentence);
final float[] languageWeight = new float[] { Dictionary.NOT_A_LANGUAGE_WEIGHT };
for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
final Dictionary dictionary = dictionaries.getDict(dictType);
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index 5808b9e4e..c11a220a4 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -38,6 +38,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
+import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -163,9 +164,31 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
}
private void asyncExecuteTaskWithLock(final Lock lock, final Runnable task) {
+ asyncPreCheckAndExecuteTaskWithLock(lock, null /* preCheckTask */, task);
+ }
+
+ private void asyncPreCheckAndExecuteTaskWithWriteLock(
+ final Callable<Boolean> preCheckTask, final Runnable task) {
+ asyncPreCheckAndExecuteTaskWithLock(mLock.writeLock(), preCheckTask, task);
+
+ }
+
+ // Execute task with lock when the result of preCheckTask is true or preCheckTask is null.
+ private void asyncPreCheckAndExecuteTaskWithLock(final Lock lock,
+ final Callable<Boolean> preCheckTask, final Runnable task) {
ExecutorUtils.getExecutor(mDictName).execute(new Runnable() {
@Override
public void run() {
+ if (preCheckTask != null) {
+ try {
+ if (!preCheckTask.call().booleanValue()) {
+ return;
+ }
+ } catch (final Exception e) {
+ Log.e(TAG, "The pre check task throws an exception.", e);
+ return;
+ }
+ }
lock.lock();
try {
task.run();
@@ -278,22 +301,25 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
final boolean isBlacklisted, final int timestamp,
final DistracterFilter distracterFilter) {
reloadDictionaryIfRequired();
- asyncExecuteTaskWithWriteLock(new Runnable() {
- @Override
- public void run() {
- if (mBinaryDictionary == null) {
- return;
- }
- if (distracterFilter.isDistracterToWordsInDictionaries(
- PrevWordsInfo.EMPTY_PREV_WORDS_INFO, word, mLocale)) {
- // The word is a distracter.
- return;
- }
- runGCIfRequiredLocked(true /* mindsBlockByGC */);
- addUnigramLocked(word, frequency, shortcutTarget, shortcutFreq,
- isNotAWord, isBlacklisted, timestamp);
- }
- });
+ asyncPreCheckAndExecuteTaskWithWriteLock(
+ new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ return !distracterFilter.isDistracterToWordsInDictionaries(
+ PrevWordsInfo.EMPTY_PREV_WORDS_INFO, word, mLocale);
+ }
+ },
+ new Runnable() {
+ @Override
+ public void run() {
+ if (mBinaryDictionary == null) {
+ return;
+ }
+ runGCIfRequiredLocked(true /* mindsBlockByGC */);
+ addUnigramLocked(word, frequency, shortcutTarget, shortcutFreq,
+ isNotAWord, isBlacklisted, timestamp);
+ }
+ });
}
protected void addUnigramLocked(final String word, final int frequency,
diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java
index ebe436128..fecb0ef94 100644
--- a/java/src/com/android/inputmethod/latin/InputAttributes.java
+++ b/java/src/com/android/inputmethod/latin/InputAttributes.java
@@ -42,6 +42,7 @@ public final class InputAttributes {
final public boolean mApplicationSpecifiedCompletionOn;
final public boolean mShouldInsertSpacesAutomatically;
final public boolean mShouldShowVoiceInputKey;
+ final public boolean mIsGeneralTextInput;
final private int mInputType;
final private EditorInfo mEditorInfo;
final private String mPackageNameForPrivateImeOptions;
@@ -76,6 +77,7 @@ public final class InputAttributes {
mApplicationSpecifiedCompletionOn = false;
mShouldInsertSpacesAutomatically = false;
mShouldShowVoiceInputKey = false;
+ mIsGeneralTextInput = false;
return;
}
// inputClass == InputType.TYPE_CLASS_TEXT
@@ -102,7 +104,7 @@ public final class InputAttributes {
mShouldInsertSpacesAutomatically = InputTypeUtils.isAutoSpaceFriendlyType(inputType);
final boolean noMicrophone = mIsPasswordField
- || InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS == variation
+ || InputTypeUtils.isEmailVariation(variation)
|| InputType.TYPE_TEXT_VARIATION_URI == variation
|| hasNoMicrophoneKeyOption();
mShouldShowVoiceInputKey = !noMicrophone;
@@ -117,6 +119,15 @@ public final class InputAttributes {
|| (!flagAutoCorrect && !flagMultiLine);
mApplicationSpecifiedCompletionOn = flagAutoComplete && isFullscreenMode;
+
+ // If we come here, inputClass is always TYPE_CLASS_TEXT
+ mIsGeneralTextInput = InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS != variation
+ && InputType.TYPE_TEXT_VARIATION_PASSWORD != variation
+ && InputType.TYPE_TEXT_VARIATION_PHONETIC != variation
+ && InputType.TYPE_TEXT_VARIATION_URI != variation
+ && InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD != variation
+ && InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS != variation
+ && InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD != variation;
}
public boolean isTypeNull() {
diff --git a/java/src/com/android/inputmethod/latin/InputView.java b/java/src/com/android/inputmethod/latin/InputView.java
index e9e12f09f..7fa935413 100644
--- a/java/src/com/android/inputmethod/latin/InputView.java
+++ b/java/src/com/android/inputmethod/latin/InputView.java
@@ -21,14 +21,14 @@ import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
-import android.widget.LinearLayout;
+import android.widget.FrameLayout;
import com.android.inputmethod.accessibility.AccessibilityUtils;
import com.android.inputmethod.keyboard.MainKeyboardView;
import com.android.inputmethod.latin.suggestions.MoreSuggestionsView;
import com.android.inputmethod.latin.suggestions.SuggestionStripView;
-public final class InputView extends LinearLayout {
+public final class InputView extends FrameLayout {
private final Rect mInputViewRect = new Rect();
private MainKeyboardView mMainKeyboardView;
private KeyboardTopPaddingForwarder mKeyboardTopPaddingForwarder;
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index d2a2fbdd8..d57db8e9a 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -20,7 +20,6 @@ import static com.android.inputmethod.latin.Constants.ImeOption.FORCE_ASCII;
import static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE;
import static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE_COMPAT;
-import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -30,7 +29,6 @@ import android.content.Intent;
import android.content.IntentFilter;
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;
@@ -44,18 +42,22 @@ import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.SparseArray;
+import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
+import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.CursorAnchorInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodSubtype;
+import android.widget.TextView;
import com.android.inputmethod.accessibility.AccessibilityUtils;
import com.android.inputmethod.annotations.UsedForTesting;
-import com.android.inputmethod.compat.InputConnectionCompatUtils;
+import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper;
import com.android.inputmethod.compat.InputMethodServiceCompatUtils;
import com.android.inputmethod.dictionarypack.DictionaryPackConstants;
import com.android.inputmethod.event.Event;
@@ -67,6 +69,7 @@ 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.keyboard.TextDecoratorUi;
import com.android.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.define.DebugFlags;
@@ -84,14 +87,16 @@ import com.android.inputmethod.latin.suggestions.SuggestionStripViewAccessor;
import com.android.inputmethod.latin.utils.ApplicationUtils;
import com.android.inputmethod.latin.utils.CapsModeUtils;
import com.android.inputmethod.latin.utils.CoordinateUtils;
+import com.android.inputmethod.latin.utils.CursorAnchorInfoUtils;
import com.android.inputmethod.latin.utils.DialogUtils;
-import com.android.inputmethod.latin.utils.DistracterFilterCheckingExactMatches;
+import com.android.inputmethod.latin.utils.DistracterFilterCheckingExactMatchesAndSuggestions;
import com.android.inputmethod.latin.utils.ImportantNoticeUtils;
import com.android.inputmethod.latin.utils.IntentUtils;
import com.android.inputmethod.latin.utils.JniUtils;
import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper;
import com.android.inputmethod.latin.utils.StatsUtils;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
+import com.android.inputmethod.latin.utils.ViewLayoutUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -127,7 +132,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private final Settings mSettings;
private final DictionaryFacilitator mDictionaryFacilitator =
- new DictionaryFacilitator(new DistracterFilterCheckingExactMatches(this /* context */));
+ new DictionaryFacilitator(
+ new DistracterFilterCheckingExactMatchesAndSuggestions(this /* context */));
// TODO: Move from LatinIME.
private final PersonalizationDictionaryUpdater mPersonalizationDictionaryUpdater =
new PersonalizationDictionaryUpdater(this /* context */, mDictionaryFacilitator);
@@ -136,7 +142,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
new Runnable() {
@Override
public void run() {
- mHandler.postUpdateSuggestionStrip();
+ mHandler.postUpdateSuggestionStrip(SuggestedWords.INPUT_STYLE_NONE);
}
});
private final InputLogic mInputLogic = new InputLogic(this /* LatinIME */,
@@ -145,14 +151,19 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// If it turns out we need several, it will get grown seamlessly.
final SparseArray<HardwareEventDecoder> mHardwareEventDecoders = new SparseArray<>(1);
- private View mExtractArea;
- private View mKeyPreviewBackingView;
+ // TODO: Move these {@link View}s to {@link KeyboardSwitcher}.
+ private View mInputView;
private SuggestionStripView mSuggestionStripView;
+ private TextView mExtractEditText;
private RichInputMethodManager mRichImm;
@UsedForTesting final KeyboardSwitcher mKeyboardSwitcher;
private final SubtypeSwitcher mSubtypeSwitcher;
private final SubtypeState mSubtypeState = new SubtypeState();
+ private final SpecialKeyDetector mSpecialKeyDetector;
+ // Working variable for {@link #startShowingInputView()} and
+ // {@link #onEvaluateInputViewShown()}.
+ private boolean mIsExecutingStartShowingInputView;
// Object for reacting to adding/removing a dictionary pack.
private final BroadcastReceiver mDictionaryPackInstallReceiver =
@@ -187,8 +198,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private static final int ARG1_FALSE = 0;
private static final int ARG1_TRUE = 1;
- private int mDelayUpdateSuggestions;
- private int mDelayUpdateShiftState;
+ private int mDelayInMillisecondsToUpdateSuggestions;
+ private int mDelayInMillisecondsToUpdateShiftState;
public UIHandler(final LatinIME ownerInstance) {
super(ownerInstance);
@@ -200,8 +211,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return;
}
final Resources res = latinIme.getResources();
- mDelayUpdateSuggestions = res.getInteger(R.integer.config_delay_update_suggestions);
- mDelayUpdateShiftState = res.getInteger(R.integer.config_delay_update_shift_state);
+ mDelayInMillisecondsToUpdateSuggestions = res.getInteger(
+ R.integer.config_delay_in_milliseconds_to_update_suggestions);
+ mDelayInMillisecondsToUpdateShiftState = res.getInteger(
+ R.integer.config_delay_in_milliseconds_to_update_shift_state);
}
@Override
@@ -215,7 +228,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
case MSG_UPDATE_SUGGESTION_STRIP:
cancelUpdateSuggestionStrip();
latinIme.mInputLogic.performUpdateSuggestionStripSync(
- latinIme.mSettings.getCurrent());
+ latinIme.mSettings.getCurrent(), msg.arg1 /* inputStyle */);
break;
case MSG_UPDATE_SHIFT_STATE:
switcher.requestUpdatingShiftState(latinIme.getCurrentAutoCapsState(),
@@ -237,10 +250,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
latinIme.mKeyboardSwitcher.getCurrentKeyboardScriptId());
break;
case MSG_REOPEN_DICTIONARIES:
- latinIme.resetSuggest();
// We need to re-evaluate the currently composing word in case the script has
// changed.
postWaitForDictionaryLoad();
+ latinIme.resetSuggest();
break;
case MSG_UPDATE_TAIL_BATCH_INPUT_COMPLETED:
latinIme.mInputLogic.onUpdateTailBatchInputCompleted(
@@ -249,8 +262,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
break;
case MSG_RESET_CACHES:
final SettingsValues settingsValues = latinIme.mSettings.getCurrent();
- if (latinIme.mInputLogic.retryResetCachesAndReturnSuccess(settingsValues,
- msg.arg1 == 1 /* tryResumeSuggestions */,
+ if (latinIme.mInputLogic.retryResetCachesAndReturnSuccess(
+ msg.arg1 == ARG1_TRUE /* tryResumeSuggestions */,
msg.arg2 /* remainingTries */, this /* handler */)) {
// If we were able to reset the caches, then we can reload the keyboard.
// Otherwise, we'll do it when we can.
@@ -265,8 +278,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
- public void postUpdateSuggestionStrip() {
- sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION_STRIP), mDelayUpdateSuggestions);
+ public void postUpdateSuggestionStrip(final int inputStyle) {
+ sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION_STRIP, inputStyle,
+ 0 /* ignored */), mDelayInMillisecondsToUpdateSuggestions);
}
public void postReopenDictionaries() {
@@ -279,16 +293,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (latinIme == null) {
return;
}
- if (!latinIme.mSettings.getCurrent()
- .isSuggestionsEnabledPerUserSettings()) {
+ if (!latinIme.mSettings.getCurrent().isSuggestionsEnabledPerUserSettings()) {
return;
}
removeMessages(MSG_RESUME_SUGGESTIONS);
if (shouldDelay) {
sendMessageDelayed(obtainMessage(MSG_RESUME_SUGGESTIONS,
- shouldIncludeResumedWordInSuggestions ? ARG1_TRUE : ARG1_FALSE,
- 0 /* ignored */),
- mDelayUpdateSuggestions);
+ shouldIncludeResumedWordInSuggestions ? ARG1_TRUE : ARG1_FALSE,
+ 0 /* ignored */), mDelayInMillisecondsToUpdateSuggestions);
} else {
sendMessage(obtainMessage(MSG_RESUME_SUGGESTIONS,
shouldIncludeResumedWordInSuggestions ? ARG1_TRUE : ARG1_FALSE,
@@ -329,7 +341,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public void postUpdateShiftState() {
removeMessages(MSG_UPDATE_SHIFT_STATE);
- sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), mDelayUpdateShiftState);
+ sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE),
+ mDelayInMillisecondsToUpdateShiftState);
}
@UsedForTesting
@@ -414,15 +427,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (latinIme != null) {
executePendingImsCallback(latinIme, editorInfo, restarting);
latinIme.onStartInputInternal(editorInfo, restarting);
- if (ProductionFlags.ENABLE_CURSOR_RECT_CALLBACK) {
- InputConnectionCompatUtils.requestCursorRect(
- latinIme.getCurrentInputConnection(), true /* enableMonitor */);
- }
- if (ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK) {
- InputConnectionCompatUtils.requestCursorAnchorInfo(
- latinIme.getCurrentInputConnection(), true /* enableMonitor */,
- true /* requestImmediateCallback */);
- }
}
}
}
@@ -514,6 +518,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mSettings = Settings.getInstance();
mSubtypeSwitcher = SubtypeSwitcher.getInstance();
mKeyboardSwitcher = KeyboardSwitcher.getInstance();
+ mSpecialKeyDetector = new SpecialKeyDetector(this);
mIsHardwareAcceleratedDrawingEnabled =
InputMethodServiceCompatUtils.enableHardwareAcceleration(this);
Log.i(TAG, "Hardware accelerated drawing: " + mIsHardwareAcceleratedDrawingEnabled);
@@ -689,11 +694,27 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void onConfigurationChanged(final Configuration conf) {
- final SettingsValues settingsValues = mSettings.getCurrent();
+ SettingsValues settingsValues = mSettings.getCurrent();
if (settingsValues.mDisplayOrientation != conf.orientation) {
mHandler.startOrientationChanging();
mInputLogic.onOrientationChange(mSettings.getCurrent());
}
+ if (settingsValues.mHasHardwareKeyboard != Settings.readHasHardwareKeyboard(conf)) {
+ // If the state of having a hardware keyboard changed, then we want to reload the
+ // settings to adjust for that.
+ // TODO: we should probably do this unconditionally here, rather than only when we
+ // have a change in hardware keyboard configuration.
+ loadSettings();
+ settingsValues = mSettings.getCurrent();
+ if (settingsValues.mHasHardwareKeyboard) {
+ // We call cleanupInternalStateForFinishInput() because it's the right thing to do;
+ // however, it seems at the moment the framework is passing us a seemingly valid
+ // but actually non-functional InputConnection object. So if this bug ever gets
+ // fixed we'll be able to remove the composition, but until it is this code is
+ // actually not doing much.
+ cleanupInternalStateForFinishInput();
+ }
+ }
// TODO: Remove this test.
if (!conf.locale.equals(mPersonalizationDictionaryUpdater.getLocale())) {
refreshPersonalizationDictionarySession(settingsValues);
@@ -709,13 +730,55 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
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);
+ mInputView = view;
mSuggestionStripView = (SuggestionStripView)view.findViewById(R.id.suggestion_strip_view);
if (hasSuggestionStripView()) {
mSuggestionStripView.setListener(this, view);
}
+ mInputLogic.setTextDecoratorUi(new TextDecoratorUi(this, view));
+ }
+
+ @Override
+ public void setExtractView(final View view) {
+ final TextView prevExtractEditText = mExtractEditText;
+ super.setExtractView(view);
+ TextView nextExtractEditText = null;
+ if (view != null) {
+ final View extractEditText = view.findViewById(android.R.id.inputExtractEditText);
+ if (extractEditText instanceof TextView) {
+ nextExtractEditText = (TextView)extractEditText;
+ }
+ }
+ if (prevExtractEditText == nextExtractEditText) {
+ return;
+ }
+ if (ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK && prevExtractEditText != null) {
+ prevExtractEditText.getViewTreeObserver().removeOnPreDrawListener(
+ mExtractTextViewPreDrawListener);
+ }
+ mExtractEditText = nextExtractEditText;
+ if (ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK && mExtractEditText != null) {
+ mExtractEditText.getViewTreeObserver().addOnPreDrawListener(
+ mExtractTextViewPreDrawListener);
+ }
+ }
+
+ private final ViewTreeObserver.OnPreDrawListener mExtractTextViewPreDrawListener =
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ onExtractTextViewPreDraw();
+ return true;
+ }
+ };
+
+ private void onExtractTextViewPreDraw() {
+ if (!ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK || !isFullscreenMode()
+ || mExtractEditText == null) {
+ return;
+ }
+ final CursorAnchorInfo info = CursorAnchorInfoUtils.getCursorAnchorInfo(mExtractEditText);
+ mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.fromObject(info));
}
@Override
@@ -749,7 +812,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged()
// is not guaranteed. It may even be called at the same time on a different thread.
mSubtypeSwitcher.onSubtypeChanged(subtype);
- mInputLogic.onSubtypeChanged(SubtypeLocaleUtils.getCombiningRulesExtraValue(subtype));
+ mInputLogic.onSubtypeChanged(SubtypeLocaleUtils.getCombiningRulesExtraValue(subtype),
+ mSettings.getCurrent());
loadKeyboard();
}
@@ -819,39 +883,52 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Note: This call should be done by InputMethodService?
updateFullscreenMode();
- // The app calling setText() has the effect of clearing the composing
- // span, so we should reset our state unconditionally, even if restarting is true.
- // We also tell the input logic about the combining rules for the current subtype, so
- // it can adjust its combiners if needed.
- mInputLogic.startInput(mSubtypeSwitcher.getCombiningRulesExtraValueOfCurrentSubtype());
+ // ALERT: settings have not been reloaded and there is a chance they may be stale.
+ // In the practice, if it is, we should have gotten onConfigurationChanged so it should
+ // be fine, but this is horribly confusing and must be fixed AS SOON AS POSSIBLE.
- // Note: the following does a round-trip IPC on the main thread: be careful
- final Locale currentLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
+ // In some cases the input connection has not been reset yet and we can't access it. In
+ // this case we will need to call loadKeyboard() later, when it's accessible, so that we
+ // can go into the correct mode, so we need to do some housekeeping here.
+ final boolean needToCallLoadKeyboardLater;
final Suggest suggest = mInputLogic.mSuggest;
- if (null != currentLocale && !currentLocale.equals(suggest.getLocale())) {
- // TODO: Do this automatically.
- resetSuggest();
- }
+ if (!currentSettingsValues.mHasHardwareKeyboard) {
+ // The app calling setText() has the effect of clearing the composing
+ // span, so we should reset our state unconditionally, even if restarting is true.
+ // We also tell the input logic about the combining rules for the current subtype, so
+ // it can adjust its combiners if needed.
+ mInputLogic.startInput(mSubtypeSwitcher.getCombiningRulesExtraValueOfCurrentSubtype(),
+ currentSettingsValues);
+
+ // Note: the following does a round-trip IPC on the main thread: be careful
+ final Locale currentLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
+ if (null != currentLocale && !currentLocale.equals(suggest.getLocale())) {
+ // TODO: Do this automatically.
+ resetSuggest();
+ }
- // TODO[IL]: Can the following be moved to InputLogic#startInput?
- final boolean canReachInputConnection;
- if (!mInputLogic.mConnection.resetCachesUponCursorMoveAndReturnSuccess(
- editorInfo.initialSelStart, editorInfo.initialSelEnd,
- false /* shouldFinishComposition */)) {
- // Sometimes, while rotating, for some reason the framework tells the app we are not
- // connected to it and that means we can't refresh the cache. In this case, schedule a
- // refresh later.
- // We try resetting the caches up to 5 times before giving up.
- mHandler.postResetCaches(isDifferentTextField, 5 /* remainingTries */);
- // mLastSelection{Start,End} are reset later in this method, don't need to do it here
- canReachInputConnection = false;
+ // TODO[IL]: Can the following be moved to InputLogic#startInput?
+ if (!mInputLogic.mConnection.resetCachesUponCursorMoveAndReturnSuccess(
+ editorInfo.initialSelStart, editorInfo.initialSelEnd,
+ false /* shouldFinishComposition */)) {
+ // Sometimes, while rotating, for some reason the framework tells the app we are not
+ // connected to it and that means we can't refresh the cache. In this case, schedule
+ // a refresh later.
+ // We try resetting the caches up to 5 times before giving up.
+ mHandler.postResetCaches(isDifferentTextField, 5 /* remainingTries */);
+ // mLastSelection{Start,End} are reset later in this method, no need to do it here
+ needToCallLoadKeyboardLater = true;
+ } else {
+ // When rotating, initialSelStart and initialSelEnd sometimes are lying. Make a best
+ // effort to work around this bug.
+ mInputLogic.mConnection.tryFixLyingCursorPosition();
+ mHandler.postResumeSuggestions(true /* shouldIncludeResumedWordInSuggestions */,
+ true /* shouldDelay */);
+ needToCallLoadKeyboardLater = false;
+ }
} else {
- // When rotating, initialSelStart and initialSelEnd sometimes are lying. Make a best
- // effort to work around this bug.
- mInputLogic.mConnection.tryFixLyingCursorPosition();
- mHandler.postResumeSuggestions(true /* shouldIncludeResumedWordInSuggestions */,
- true /* shouldDelay */);
- canReachInputConnection = true;
+ // If we have a hardware keyboard we don't need to call loadKeyboard later anyway.
+ needToCallLoadKeyboardLater = false;
}
if (isDifferentTextField ||
@@ -869,9 +946,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
switcher.loadKeyboard(editorInfo, currentSettingsValues, getCurrentAutoCapsState(),
getCurrentRecapitalizeState());
- if (!canReachInputConnection) {
- // If we can't reach the input connection, we will call loadKeyboard again later,
- // so we need to save its state now. The call will be done in #retryResetCaches.
+ if (needToCallLoadKeyboardLater) {
+ // If we need to call loadKeyboard again later, we need to save its state now. The
+ // later call will be done in #retryResetCaches.
switcher.saveKeyboardState();
}
} else if (restarting) {
@@ -928,6 +1005,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private void onFinishInputViewInternal(final boolean finishingInput) {
super.onFinishInputView(finishingInput);
+ cleanupInternalStateForFinishInput();
+ }
+
+ private void cleanupInternalStateForFinishInput() {
mKeyboardSwitcher.deallocateMemory();
// Remove pending messages related to update suggestions
mHandler.cancelUpdateSuggestionStrip();
@@ -947,24 +1028,25 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
+ ", cs=" + composingSpanStart + ", ce=" + composingSpanEnd);
}
- // If the keyboard is not visible, we don't need to do all the housekeeping work, as it
- // will be reset when the keyboard shows up anyway.
- // TODO: revisit this when LatinIME supports hardware keyboards.
- // NOTE: the test harness subclasses LatinIME and overrides isInputViewShown().
- // TODO: find a better way to simulate actual execution.
- if (isInputViewShown() &&
- mInputLogic.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd)) {
+ // This call happens when we have a hardware keyboard as well as when we don't. While we
+ // don't support hardware keyboards yet we should avoid doing the processing associated
+ // with cursor movement when we have a hardware keyboard since we are not in charge.
+ final SettingsValues settingsValues = mSettings.getCurrent();
+ if ((!settingsValues.mHasHardwareKeyboard || ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED)
+ && mInputLogic.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
+ settingsValues)) {
mKeyboardSwitcher.requestUpdatingShiftState(getCurrentAutoCapsState(),
getCurrentRecapitalizeState());
}
}
- @Override
- public void onUpdateCursor(final Rect rect) {
- if (DEBUG) {
- Log.i(TAG, "onUpdateCursor:" + rect.toShortString());
+ // We cannot mark this method as @Override until new SDK becomes publicly available.
+ // @Override
+ public void onUpdateCursorAnchorInfo(final CursorAnchorInfo info) {
+ if (!ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK || isFullscreenMode()) {
+ return;
}
- super.onUpdateCursor(rect);
+ mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.fromObject(info));
}
/**
@@ -1040,78 +1122,76 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
applicationSpecifiedCompletions);
final SuggestedWords suggestedWords = new SuggestedWords(applicationSuggestedWords,
null /* rawSuggestions */, false /* typedWordValid */, false /* willAutoCorrect */,
- false /* isObsoleteSuggestions */, false /* isPrediction */);
+ false /* isObsoleteSuggestions */,
+ SuggestedWords.INPUT_STYLE_APPLICATION_SPECIFIED /* inputStyle */);
// When in fullscreen mode, show completions generated by the application forcibly
setSuggestedWords(suggestedWords);
}
- 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 SettingsValues settingsValues = mSettings.getCurrent();
final View visibleKeyboardView = mKeyboardSwitcher.getVisibleKeyboardView();
if (visibleKeyboardView == null || !hasSuggestionStripView()) {
return;
}
- 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
+ final int inputHeight = mInputView.getHeight();
+ final boolean hasHardwareKeyboard = settingsValues.mHasHardwareKeyboard;
+ if (hasHardwareKeyboard && visibleKeyboardView.getVisibility() == View.GONE) {
+ // If there is a hardware keyboard and a visible software keyboard view has been hidden,
+ // no visual element will be shown on the screen.
+ outInsets.touchableInsets = inputHeight;
+ outInsets.visibleTopInsets = inputHeight;
+ return;
+ }
+ final int suggestionsHeight = (!mKeyboardSwitcher.isShowingEmojiPalettes()
+ && mSuggestionStripView.getVisibility() == View.VISIBLE)
+ ? mSuggestionStripView.getHeight() : 0;
+ final int visibleTopY = inputHeight - visibleKeyboardView.getHeight() - suggestionsHeight;
+ mSuggestionStripView.setMoreSuggestionsHeight(visibleTopY);
+ // Need to set touchable region only if a keyboard view is being shown.
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.isShowingEmojiPalettes()
- || mSuggestionStripView.getVisibility() == View.VISIBLE) {
- visibleTopY -= suggestionsHeight;
- }
- final int touchY = mKeyboardSwitcher.isShowingMoreKeysPanel() ? 0 : visibleTopY;
- final int touchWidth = visibleKeyboardView.getWidth();
- final int touchHeight = visibleKeyboardView.getHeight() + extraHeight
+ final int touchLeft = 0;
+ final int touchTop = mKeyboardSwitcher.isShowingMoreKeysPanel() ? 0 : visibleTopY;
+ final int touchRight = visibleKeyboardView.getWidth();
+ final int touchBottom = inputHeight
// Extend touchable region below the keyboard.
+ EXTENDED_TOUCHABLE_REGION_HEIGHT;
outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION;
- outInsets.touchableRegion.set(0, touchY, touchWidth, touchHeight);
+ outInsets.touchableRegion.set(touchLeft, touchTop, touchRight, touchBottom);
}
outInsets.contentTopInsets = visibleTopY;
outInsets.visibleTopInsets = visibleTopY;
}
+ public void startShowingInputView() {
+ mIsExecutingStartShowingInputView = true;
+ // This {@link #showWindow(boolean)} will eventually call back
+ // {@link #onEvaluateInputViewShown()}.
+ showWindow(true /* showInput */);
+ mIsExecutingStartShowingInputView = false;
+ }
+
+ public void stopShowingInputView() {
+ showWindow(false /* showInput */);
+ }
+
+ @Override
+ public boolean onEvaluateInputViewShown() {
+ if (mIsExecutingStartShowingInputView) {
+ return true;
+ }
+ return super.onEvaluateInputViewShown();
+ }
+
@Override
public boolean onEvaluateFullscreenMode() {
+ final SettingsValues settingsValues = mSettings.getCurrent();
+ if (settingsValues.mHasHardwareKeyboard) {
+ // If there is a hardware keyboard, disable full screen mode.
+ return false;
+ }
// Reread resource value here, because this method is called by the framework as needed.
final boolean isFullscreenModeAllowed = Settings.readUseFullscreenMode(getResources());
if (super.onEvaluateFullscreenMode() && isFullscreenModeAllowed) {
@@ -1121,19 +1201,34 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// hack for now. Let's get rid of this once the framework gets fixed.
final EditorInfo ei = getCurrentInputEditorInfo();
return !(ei != null && ((ei.imeOptions & EditorInfo.IME_FLAG_NO_EXTRACT_UI) != 0));
- } else {
- return false;
}
+ return false;
}
@Override
public void updateFullscreenMode() {
+ // Override layout parameters to expand {@link SoftInputWindow} to the entire screen.
+ // See {@link InputMethodService#setinputView(View) and
+ // {@link SoftInputWindow#updateWidthHeight(WindowManager.LayoutParams)}.
+ final Window window = getWindow().getWindow();
+ ViewLayoutUtils.updateLayoutHeightOf(window, LayoutParams.MATCH_PARENT);
+ // This method may be called before {@link #setInputView(View)}.
+ if (mInputView != null) {
+ // In non-fullscreen mode, {@link InputView} and its parent inputArea should expand to
+ // the entire screen and be placed at the bottom of {@link SoftInputWindow}.
+ // In fullscreen mode, these shouldn't expand to the entire screen and should be
+ // coexistent with {@link #mExtractedArea} above.
+ // See {@link InputMethodService#setInputView(View) and
+ // com.android.internal.R.layout.input_method.xml.
+ final int layoutHeight = isFullscreenMode()
+ ? LayoutParams.WRAP_CONTENT : LayoutParams.MATCH_PARENT;
+ final View inputArea = window.findViewById(android.R.id.inputArea);
+ ViewLayoutUtils.updateLayoutHeightOf(inputArea, layoutHeight);
+ ViewLayoutUtils.updateLayoutGravityOf(inputArea, Gravity.BOTTOM);
+ ViewLayoutUtils.updateLayoutHeightOf(mInputView, layoutHeight);
+ }
super.updateFullscreenMode();
-
- 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);
+ mInputLogic.onUpdateFullscreenMode(isFullscreenMode());
}
private int getCurrentAutoCapsState() {
@@ -1157,9 +1252,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (null == keyboard) {
return CoordinateUtils.newCoordinateArray(codePoints.length,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
- } else {
- return keyboard.getCoordinates(codePoints);
}
+ return keyboard.getCoordinates(codePoints);
}
// Callback for the {@link SuggestionStripView}, to call when the "add to dictionary" hint is
@@ -1177,6 +1271,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
wordToEdit = word;
}
mDictionaryFacilitator.addWordToUserDictionary(this /* context */, wordToEdit);
+ mInputLogic.onAddWordToUserDictionary();
}
// Callback for the {@link SuggestionStripView}, to call when the important notice strip is
@@ -1365,7 +1460,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
private void setSuggestedWords(final SuggestedWords suggestedWords) {
- mInputLogic.setSuggestedWords(suggestedWords);
+ final SettingsValues currentSettingsValues = mSettings.getCurrent();
+ mInputLogic.setSuggestedWords(suggestedWords, currentSettingsValues, mHandler);
// TODO: Modify this when we support suggestions with hard keyboard
if (!hasSuggestionStripView()) {
return;
@@ -1374,7 +1470,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return;
}
- final SettingsValues currentSettingsValues = mSettings.getCurrent();
final boolean shouldShowImportantNotice =
ImportantNoticeUtils.shouldShowImportantNotice(this);
final boolean shouldShowSuggestionCandidates =
@@ -1394,26 +1489,30 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final boolean isEmptyApplicationSpecifiedCompletions =
currentSettingsValues.isApplicationSpecifiedCompletionsOn()
&& suggestedWords.isEmpty();
- final boolean noSuggestionsToShow = (SuggestedWords.EMPTY == suggestedWords)
+ final boolean noSuggestionsFromDictionaries = (SuggestedWords.EMPTY == suggestedWords)
|| suggestedWords.isPunctuationSuggestions()
|| isEmptyApplicationSpecifiedCompletions;
- if (shouldShowImportantNotice && noSuggestionsToShow) {
+ final boolean isBeginningOfSentencePrediction = (suggestedWords.mInputStyle
+ == SuggestedWords.INPUT_STYLE_BEGINNING_OF_SENTENCE_PREDICTION);
+ final boolean noSuggestionsToOverrideImportantNotice = noSuggestionsFromDictionaries
+ || isBeginningOfSentencePrediction;
+ if (shouldShowImportantNotice && noSuggestionsToOverrideImportantNotice) {
if (mSuggestionStripView.maybeShowImportantNoticeTitle()) {
return;
}
}
if (currentSettingsValues.isSuggestionsEnabledPerUserSettings()
- // We should clear suggestions if there is no suggestion to show.
- || noSuggestionsToShow
- || currentSettingsValues.isApplicationSpecifiedCompletionsOn()) {
+ || currentSettingsValues.isApplicationSpecifiedCompletionsOn()
+ // We should clear the contextual strip if there is no suggestion from dictionaries.
+ || noSuggestionsFromDictionaries) {
mSuggestionStripView.setSuggestions(suggestedWords,
SubtypeLocaleUtils.isRtlLanguage(mSubtypeSwitcher.getCurrentSubtype()));
}
}
// TODO[IL]: Move this out of LatinIME.
- public void getSuggestedWords(final int sessionId, final int sequenceNumber,
+ public void getSuggestedWords(final int inputStyle, final int sequenceNumber,
final OnGetSuggestedWordsCallback callback) {
final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
if (keyboard == null) {
@@ -1421,7 +1520,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return;
}
mInputLogic.getSuggestedWords(mSettings.getCurrent(), keyboard.getProximityInfo(),
- mKeyboardSwitcher.getKeyboardShiftMode(), sessionId, sequenceNumber, callback);
+ mKeyboardSwitcher.getKeyboardShiftMode(), inputStyle, sequenceNumber, callback);
}
@Override
@@ -1505,7 +1604,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
default: // SHIFT_NO_UPDATE
}
if (inputTransaction.requiresUpdateSuggestions()) {
- mHandler.postUpdateSuggestionStrip();
+ final int inputStyle;
+ if (inputTransaction.mEvent.isSuggestionStripPress()) {
+ // Suggestion strip press: no input.
+ inputStyle = SuggestedWords.INPUT_STYLE_NONE;
+ } else if (inputTransaction.mEvent.isGesture()) {
+ inputStyle = SuggestedWords.INPUT_STYLE_TAIL_BATCH;
+ } else {
+ inputStyle = SuggestedWords.INPUT_STYLE_TYPING;
+ }
+ mHandler.postUpdateSuggestionStrip(inputStyle);
}
if (inputTransaction.didAffectContents()) {
mSubtypeState.setCurrentSubtypeHasBeenUsed();
@@ -1568,6 +1676,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Hooks for hardware keyboard
@Override
public boolean onKeyDown(final int keyCode, final KeyEvent keyEvent) {
+ mSpecialKeyDetector.onKeyDown(keyEvent);
if (!ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED) {
return super.onKeyDown(keyCode, keyEvent);
}
@@ -1587,12 +1696,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
@Override
- public boolean onKeyUp(final int keyCode, final KeyEvent event) {
- final long keyIdentifier = event.getDeviceId() << 32 + event.getKeyCode();
+ public boolean onKeyUp(final int keyCode, final KeyEvent keyEvent) {
+ mSpecialKeyDetector.onKeyUp(keyEvent);
+ if (!ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED) {
+ return super.onKeyUp(keyCode, keyEvent);
+ }
+ final long keyIdentifier = keyEvent.getDeviceId() << 32 + keyEvent.getKeyCode();
if (mInputLogic.mCurrentlyPressedHardwareKeys.remove(keyIdentifier)) {
return true;
}
- return super.onKeyUp(keyCode, event);
+ return super.onKeyUp(keyCode, keyEvent);
}
// onKeyDown and onKeyUp are the main events we are interested in. There are two more events
@@ -1621,24 +1734,22 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (mainKeyboardView != null) {
mainKeyboardView.closing();
}
- launchSubActivity(SettingsActivity.class);
- }
-
- private void launchSubActivity(final Class<? extends Activity> activityClass) {
- Intent intent = new Intent();
- intent.setClass(LatinIME.this, activityClass);
+ final Intent intent = new Intent();
+ intent.setClass(LatinIME.this, SettingsActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ intent.putExtra(SettingsActivity.EXTRA_SHOW_HOME_AS_UP, false);
startActivity(intent);
}
private void showSubtypeSelectorAndSettings() {
final CharSequence title = getString(R.string.english_ime_input_options);
+ // TODO: Should use new string "Select active input modes".
+ final CharSequence languageSelectionTitle = getString(R.string.language_selection_title);
final CharSequence[] items = new CharSequence[] {
- // TODO: Should use new string "Select active input modes".
- getString(R.string.language_selection_title),
- getString(ApplicationUtils.getActivityTitleResId(this, SettingsActivity.class)),
+ languageSelectionTitle,
+ getString(ApplicationUtils.getActivityTitleResId(this, SettingsActivity.class))
};
final OnClickListener listener = new OnClickListener() {
@Override
@@ -1651,6 +1762,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ intent.putExtra(Intent.EXTRA_TITLE, languageSelectionTitle);
startActivity(intent);
break;
case 1:
diff --git a/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java b/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java
index 0fba37c8a..56014cbad 100644
--- a/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java
@@ -35,7 +35,7 @@ public final class PunctuationSuggestions extends SuggestedWords {
false /* typedWordValid */,
false /* hasAutoCorrectionCandidate */,
false /* isObsoleteSuggestions */,
- false /* isPrediction */);
+ INPUT_STYLE_NONE /* inputStyle */);
}
/**
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index a6b3b710b..744b0321a 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -16,8 +16,13 @@
package com.android.inputmethod.latin;
+import android.graphics.Color;
import android.inputmethodservice.InputMethodService;
+import android.os.Build;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
import android.text.TextUtils;
+import android.text.style.BackgroundColorSpan;
import android.util.Log;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
@@ -25,7 +30,9 @@ import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
+import com.android.inputmethod.compat.InputConnectionCompatUtils;
import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
import com.android.inputmethod.latin.utils.CapsModeUtils;
import com.android.inputmethod.latin.utils.DebugLogUtils;
@@ -80,6 +87,18 @@ public final class RichInputConnection {
*/
private final StringBuilder mComposingText = new StringBuilder();
+ /**
+ * This variable is a temporary object used in
+ * {@link #commitTextWithBackgroundColor(CharSequence, int, int)} to avoid object creation.
+ */
+ private SpannableStringBuilder mTempObjectForCommitText = new SpannableStringBuilder();
+ /**
+ * This variable is used to track whether the last committed text had the background color or
+ * not.
+ * TODO: Omit this flag if possible.
+ */
+ private boolean mLastCommittedTextHasBackgroundColor = false;
+
private final InputMethodService mParent;
InputConnection mIC;
int mNestLevel;
@@ -218,12 +237,39 @@ public final class RichInputConnection {
// it works, but it's wrong and should be fixed.
mCommittedTextBeforeComposingText.append(mComposingText);
mComposingText.setLength(0);
+ // TODO: Clear this flag in setComposingRegion() and setComposingText() as well if needed.
+ mLastCommittedTextHasBackgroundColor = false;
if (null != mIC) {
mIC.finishComposingText();
}
}
- public void commitText(final CharSequence text, final int i) {
+ /**
+ * Synonym of {@code commitTextWithBackgroundColor(text, newCursorPosition, Color.TRANSPARENT}.
+ * @param text The text to commit. This may include styles.
+ * See {@link InputConnection#commitText(CharSequence, int)}.
+ * @param newCursorPosition The new cursor position around the text.
+ * See {@link InputConnection#commitText(CharSequence, int)}.
+ */
+ public void commitText(final CharSequence text, final int newCursorPosition) {
+ commitTextWithBackgroundColor(text, newCursorPosition, Color.TRANSPARENT, text.length());
+ }
+
+ /**
+ * Calls {@link InputConnection#commitText(CharSequence, int)} with the given background color.
+ * @param text The text to commit. This may include styles.
+ * See {@link InputConnection#commitText(CharSequence, int)}.
+ * @param newCursorPosition The new cursor position around the text.
+ * See {@link InputConnection#commitText(CharSequence, int)}.
+ * @param color The background color to be attached. Set {@link Color#TRANSPARENT} to disable
+ * the background color. Note that this method specifies {@link BackgroundColorSpan} with
+ * {@link Spanned#SPAN_COMPOSING} flag, meaning that the background color persists until
+ * {@link #finishComposingText()} is called.
+ * @param coloredTextLength the length of text, in Java chars, which should be rendered with
+ * the given background color.
+ */
+ public void commitTextWithBackgroundColor(final CharSequence text, final int newCursorPosition,
+ final int color, final int coloredTextLength) {
if (DEBUG_BATCH_NESTING) checkBatchEdit();
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
mCommittedTextBeforeComposingText.append(text);
@@ -233,11 +279,44 @@ public final class RichInputConnection {
mExpectedSelStart += text.length() - mComposingText.length();
mExpectedSelEnd = mExpectedSelStart;
mComposingText.setLength(0);
+ mLastCommittedTextHasBackgroundColor = false;
if (null != mIC) {
- mIC.commitText(text, i);
+ if (color == Color.TRANSPARENT) {
+ mIC.commitText(text, newCursorPosition);
+ } else {
+ mTempObjectForCommitText.clear();
+ mTempObjectForCommitText.append(text);
+ final BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(color);
+ final int spanLength = Math.min(coloredTextLength, text.length());
+ mTempObjectForCommitText.setSpan(backgroundColorSpan, 0, spanLength,
+ Spanned.SPAN_COMPOSING | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ mIC.commitText(mTempObjectForCommitText, newCursorPosition);
+ mLastCommittedTextHasBackgroundColor = true;
+ }
}
}
+ /**
+ * Removes the background color from the highlighted text if necessary. Should be called while
+ * there is no on-going composing text.
+ *
+ * <p>CAVEAT: This method internally calls {@link InputConnection#finishComposingText()}.
+ * Be careful of any unexpected side effects.</p>
+ */
+ public void removeBackgroundColorFromHighlightedTextIfNecessary() {
+ // TODO: We haven't yet full tested if we really need to check this flag or not. Omit this
+ // flag if everything works fine without this condition.
+ if (!mLastCommittedTextHasBackgroundColor) {
+ return;
+ }
+ if (mComposingText.length() > 0) {
+ Log.e(TAG, "clearSpansWithComposingFlags should be called when composing text is " +
+ "empty. mComposingText=" + mComposingText);
+ return;
+ }
+ finishComposingText();
+ }
+
public CharSequence getSelectedText(final int flags) {
return (null == mIC) ? null : mIC.getSelectedText(flags);
}
@@ -547,14 +626,24 @@ public final class RichInputConnection {
return Arrays.binarySearch(sortedSeparators, code) >= 0;
}
+ private static boolean isPartOfCompositionForScript(final int codePoint,
+ final SpacingAndPunctuations spacingAndPunctuations, final int scriptId) {
+ // We always consider word connectors part of compositions.
+ return spacingAndPunctuations.isWordConnector(codePoint)
+ // Otherwise, it's part of composition if it's part of script and not a separator.
+ || (!spacingAndPunctuations.isWordSeparator(codePoint)
+ && ScriptUtils.isLetterPartOfScript(codePoint, scriptId));
+ }
+
/**
* Returns the text surrounding the cursor.
*
- * @param sortedSeparators a sorted array of code points that split words.
+ * @param spacingAndPunctuations the rules for spacing and punctuation
* @param scriptId the script we consider to be writing words, as one of ScriptUtils.SCRIPT_*
* @return a range containing the text surrounding the cursor
*/
- public TextRange getWordRangeAtCursor(final int[] sortedSeparators, final int scriptId) {
+ public TextRange getWordRangeAtCursor(final SpacingAndPunctuations spacingAndPunctuations,
+ final int scriptId) {
mIC = mParent.getCurrentInputConnection();
if (mIC == null) {
return null;
@@ -571,8 +660,7 @@ public final class RichInputConnection {
int startIndexInBefore = before.length();
while (startIndexInBefore > 0) {
final int codePoint = Character.codePointBefore(before, startIndexInBefore);
- if (isSeparator(codePoint, sortedSeparators)
- || !ScriptUtils.isLetterPartOfScript(codePoint, scriptId)) {
+ if (!isPartOfCompositionForScript(codePoint, spacingAndPunctuations, scriptId)) {
break;
}
--startIndexInBefore;
@@ -585,8 +673,7 @@ public final class RichInputConnection {
int endIndexInAfter = -1;
while (++endIndexInAfter < after.length()) {
final int codePoint = Character.codePointAt(after, endIndexInAfter);
- if (isSeparator(codePoint, sortedSeparators)
- || !ScriptUtils.isLetterPartOfScript(codePoint, scriptId)) {
+ if (!isPartOfCompositionForScript(codePoint, spacingAndPunctuations, scriptId)) {
break;
}
if (Character.isSupplementaryCodePoint(codePoint)) {
@@ -811,4 +898,60 @@ public final class RichInputConnection {
public boolean isCursorPositionKnown() {
return INVALID_CURSOR_POSITION != mExpectedSelStart;
}
+
+ /**
+ * Work around a bug that was present before Jelly Bean upon rotation.
+ *
+ * Before Jelly Bean, there is a bug where setComposingRegion and other committing
+ * functions on the input connection get ignored until the cursor moves. This method works
+ * around the bug by wiggling the cursor first, which reactivates the connection and has
+ * the subsequent methods work, then restoring it to its original position.
+ *
+ * On platforms on which this method is not present, this is a no-op.
+ */
+ public void maybeMoveTheCursorAroundAndRestoreToWorkaroundABug() {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
+ if (mExpectedSelStart > 0) {
+ mIC.setSelection(mExpectedSelStart - 1, mExpectedSelStart - 1);
+ } else {
+ mIC.setSelection(mExpectedSelStart + 1, mExpectedSelStart + 1);
+ }
+ mIC.setSelection(mExpectedSelStart, mExpectedSelEnd);
+ }
+ }
+
+ private boolean mCursorAnchorInfoMonitorEnabled = false;
+
+ /**
+ * Requests the editor to call back {@link InputMethodManager#updateCursorAnchorInfo}.
+ * @param enableMonitor {@code true} to request the editor to call back the method whenever the
+ * cursor/anchor position is changed.
+ * @param requestImmediateCallback {@code true} to request the editor to call back the method
+ * as soon as possible to notify the current cursor/anchor position to the input method.
+ * @return {@code true} if the request is accepted. Returns {@code false} otherwise, which
+ * includes "not implemented" or "rejected" or "temporarily unavailable" or whatever which
+ * prevents the application from fulfilling the request. (TODO: Improve the API when it turns
+ * out that we actually need more detailed error codes)
+ */
+ public boolean requestCursorUpdates(final boolean enableMonitor,
+ final boolean requestImmediateCallback) {
+ mIC = mParent.getCurrentInputConnection();
+ final boolean scheduled;
+ if (null != mIC) {
+ scheduled = InputConnectionCompatUtils.requestCursorUpdates(mIC, enableMonitor,
+ requestImmediateCallback);
+ } else {
+ scheduled = false;
+ }
+ mCursorAnchorInfoMonitorEnabled = (scheduled && enableMonitor);
+ return scheduled;
+ }
+
+ /**
+ * @return {@code true} if the application reported that the monitor mode of
+ * {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)} is currently enabled.
+ */
+ public boolean isCursorAnchorInfoMonitorEnabled() {
+ return mCursorAnchorInfoMonitorEnabled;
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index b8b6d6471..b03818c1d 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -40,13 +40,8 @@ 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 = 0;
-
- // TODO: rename this to CORRECTION_OFF
- public static final int CORRECTION_NONE = 0;
- // TODO: rename this to CORRECTION_ON
- public static final int CORRECTION_FULL = 1;
+ public static final int SESSION_ID_TYPING = 0;
+ public static final int SESSION_ID_GESTURE = 0;
// Close to -2**31
private static final int SUPPRESS_SUGGEST_THRESHOLD = -2000000000;
@@ -75,14 +70,15 @@ public final class Suggest {
public void getSuggestedWords(final WordComposer wordComposer,
final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo,
final SettingsValuesForSuggestion settingsValuesForSuggestion,
- final boolean isCorrectionEnabled, final int sessionId, final int sequenceNumber,
+ final boolean isCorrectionEnabled, final int inputStyle, final int sequenceNumber,
final OnGetSuggestedWordsCallback callback) {
if (wordComposer.isBatchMode()) {
getSuggestedWordsForBatchInput(wordComposer, prevWordsInfo, proximityInfo,
- settingsValuesForSuggestion, sessionId, sequenceNumber, callback);
+ settingsValuesForSuggestion, inputStyle, sequenceNumber, callback);
} else {
- getSuggestedWordsForTypingInput(wordComposer, prevWordsInfo, proximityInfo,
- settingsValuesForSuggestion, isCorrectionEnabled, sequenceNumber, callback);
+ getSuggestedWordsForNonBatchInput(wordComposer, prevWordsInfo, proximityInfo,
+ settingsValuesForSuggestion, inputStyle, isCorrectionEnabled,
+ sequenceNumber, callback);
}
}
@@ -120,13 +116,13 @@ public final class Suggest {
return firstSuggestedWordInfo.mWord;
}
- // Retrieves suggestions for the typing input
+ // Retrieves suggestions for non-batch input (typing, recorrection, predictions...)
// and calls the callback function with the suggestions.
- private void getSuggestedWordsForTypingInput(final WordComposer wordComposer,
+ private void getSuggestedWordsForNonBatchInput(final WordComposer wordComposer,
final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo,
final SettingsValuesForSuggestion settingsValuesForSuggestion,
- final boolean isCorrectionEnabled, final int sequenceNumber,
- final OnGetSuggestedWordsCallback callback) {
+ final int inputStyleIfNotPrediction, final boolean isCorrectionEnabled,
+ final int sequenceNumber, final OnGetSuggestedWordsCallback callback) {
final String typedWord = wordComposer.getTypedWord();
final int trailingSingleQuotesCount = StringUtils.getTrailingSingleQuotesCount(typedWord);
final String consideredWord = trailingSingleQuotesCount > 0
@@ -135,7 +131,7 @@ public final class Suggest {
final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults(
wordComposer, prevWordsInfo, proximityInfo, settingsValuesForSuggestion,
- SESSION_TYPING);
+ SESSION_ID_TYPING);
final ArrayList<SuggestedWordInfo> suggestionsContainer =
getTransformedSuggestedWordInfoList(wordComposer, suggestionResults,
trailingSingleQuotesCount);
@@ -190,6 +186,14 @@ public final class Suggest {
suggestionsList = suggestionsContainer;
}
+ final int inputStyle;
+ if (resultsArePredictions) {
+ inputStyle = suggestionResults.mIsBeginningOfSentence
+ ? SuggestedWords.INPUT_STYLE_BEGINNING_OF_SENTENCE_PREDICTION
+ : SuggestedWords.INPUT_STYLE_PREDICTION;
+ } else {
+ inputStyle = inputStyleIfNotPrediction;
+ }
callback.onGetSuggestedWords(new SuggestedWords(suggestionsList,
suggestionResults.mRawSuggestions,
// TODO: this first argument is lying. If this is a whitelisted word which is an
@@ -197,7 +201,7 @@ public final class Suggest {
// rename the attribute or change the value.
!resultsArePredictions && !allowsToBeAutoCorrected /* typedWordValid */,
hasAutoCorrection /* willAutoCorrect */,
- false /* isObsoleteSuggestions */, resultsArePredictions, sequenceNumber));
+ false /* isObsoleteSuggestions */, inputStyle, sequenceNumber));
}
// Retrieves suggestions for the batch input
@@ -205,10 +209,11 @@ public final class Suggest {
private void getSuggestedWordsForBatchInput(final WordComposer wordComposer,
final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo,
final SettingsValuesForSuggestion settingsValuesForSuggestion,
- final int sessionId, final int sequenceNumber,
+ final int inputStyle, final int sequenceNumber,
final OnGetSuggestedWordsCallback callback) {
final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults(
- wordComposer, prevWordsInfo, proximityInfo, settingsValuesForSuggestion, sessionId);
+ wordComposer, prevWordsInfo, proximityInfo, settingsValuesForSuggestion,
+ SESSION_ID_GESTURE);
final ArrayList<SuggestedWordInfo> suggestionsContainer =
new ArrayList<>(suggestionResults);
final int suggestionsCount = suggestionsContainer.size();
@@ -241,12 +246,14 @@ 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).
+ // Note that because this method is never used to get predictions, there is no need to
+ // modify inputType such in getSuggestedWordsForNonBatchInput.
callback.onGetSuggestedWords(new SuggestedWords(suggestionsContainer,
suggestionResults.mRawSuggestions,
true /* typedWordValid */,
false /* willAutoCorrect */,
false /* isObsoleteSuggestions */,
- false /* isPrediction */, sequenceNumber));
+ inputStyle, sequenceNumber));
}
private static ArrayList<SuggestedWordInfo> getSuggestionsInfoListWithDebugInfo(
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index 5231cc893..1d221b77f 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -19,6 +19,7 @@ package com.android.inputmethod.latin;
import android.text.TextUtils;
import android.view.inputmethod.CompletionInfo;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.define.DebugFlags;
import com.android.inputmethod.latin.utils.StringUtils;
@@ -31,12 +32,22 @@ public class SuggestedWords {
public static final int INDEX_OF_AUTO_CORRECTION = 1;
public static final int NOT_A_SEQUENCE_NUMBER = -1;
+ public static final int INPUT_STYLE_NONE = 0;
+ public static final int INPUT_STYLE_TYPING = 1;
+ public static final int INPUT_STYLE_UPDATE_BATCH = 2;
+ public static final int INPUT_STYLE_TAIL_BATCH = 3;
+ public static final int INPUT_STYLE_APPLICATION_SPECIFIED = 4;
+ public static final int INPUT_STYLE_RECORRECTION = 5;
+ public static final int INPUT_STYLE_PREDICTION = 6;
+ public static final int INPUT_STYLE_BEGINNING_OF_SENTENCE_PREDICTION = 7;
+
// The maximum number of suggestions available.
public static final int MAX_SUGGESTIONS = 18;
private static final ArrayList<SuggestedWordInfo> EMPTY_WORD_INFO_LIST = new ArrayList<>(0);
public static final SuggestedWords EMPTY = new SuggestedWords(
- EMPTY_WORD_INFO_LIST, null /* rawSuggestions */, false, false, false, false);
+ EMPTY_WORD_INFO_LIST, null /* rawSuggestions */, false /* typedWordValid */,
+ false /* willAutoCorrect */, false /* isObsoleteSuggestions */, INPUT_STYLE_NONE);
public final String mTypedWord;
public final boolean mTypedWordValid;
@@ -45,7 +56,9 @@ public class SuggestedWords {
// whether this exactly matches the user entry or not.
public final boolean mWillAutoCorrect;
public final boolean mIsObsoleteSuggestions;
- public final boolean mIsPrediction;
+ // How the input for these suggested words was done by the user. Must be one of the
+ // INPUT_STYLE_* constants above.
+ public final int mInputStyle;
public final int mSequenceNumber; // Sequence number for auto-commit.
protected final ArrayList<SuggestedWordInfo> mSuggestedWordInfoList;
public final ArrayList<SuggestedWordInfo> mRawSuggestions;
@@ -55,9 +68,9 @@ public class SuggestedWords {
final boolean typedWordValid,
final boolean willAutoCorrect,
final boolean isObsoleteSuggestions,
- final boolean isPrediction) {
+ final int inputStyle) {
this(suggestedWordInfoList, rawSuggestions, typedWordValid, willAutoCorrect,
- isObsoleteSuggestions, isPrediction, NOT_A_SEQUENCE_NUMBER);
+ isObsoleteSuggestions, inputStyle, NOT_A_SEQUENCE_NUMBER);
}
public SuggestedWords(final ArrayList<SuggestedWordInfo> suggestedWordInfoList,
@@ -65,13 +78,12 @@ public class SuggestedWords {
final boolean typedWordValid,
final boolean willAutoCorrect,
final boolean isObsoleteSuggestions,
- final boolean isPrediction,
+ final int inputStyle,
final int sequenceNumber) {
this(suggestedWordInfoList, rawSuggestions,
- (suggestedWordInfoList.isEmpty() || isPrediction) ? null
+ (suggestedWordInfoList.isEmpty() || isPrediction(inputStyle)) ? null
: suggestedWordInfoList.get(INDEX_OF_TYPED_WORD).mWord,
- typedWordValid, willAutoCorrect, isObsoleteSuggestions, isPrediction,
- sequenceNumber);
+ typedWordValid, willAutoCorrect, isObsoleteSuggestions, inputStyle, sequenceNumber);
}
public SuggestedWords(final ArrayList<SuggestedWordInfo> suggestedWordInfoList,
@@ -80,14 +92,14 @@ public class SuggestedWords {
final boolean typedWordValid,
final boolean willAutoCorrect,
final boolean isObsoleteSuggestions,
- final boolean isPrediction,
+ final int inputStyle,
final int sequenceNumber) {
mSuggestedWordInfoList = suggestedWordInfoList;
mRawSuggestions = rawSuggestions;
mTypedWordValid = typedWordValid;
mWillAutoCorrect = willAutoCorrect;
mIsObsoleteSuggestions = isObsoleteSuggestions;
- mIsPrediction = isPrediction;
+ mInputStyle = inputStyle;
mSequenceNumber = sequenceNumber;
mTypedWord = typedWord;
}
@@ -159,6 +171,7 @@ public class SuggestedWords {
return "SuggestedWords:"
+ " mTypedWordValid=" + mTypedWordValid
+ " mWillAutoCorrect=" + mWillAutoCorrect
+ + " mInputStyle=" + mInputStyle
+ " words=" + Arrays.toString(mSuggestedWordInfoList.toArray());
}
@@ -365,9 +378,19 @@ public class SuggestedWords {
}
}
+ private static boolean isPrediction(final int inputStyle) {
+ return INPUT_STYLE_PREDICTION == inputStyle
+ || INPUT_STYLE_BEGINNING_OF_SENTENCE_PREDICTION == inputStyle;
+ }
+
+ public boolean isPrediction() {
+ return isPrediction(mInputStyle);
+ }
+
// SuggestedWords is an immutable object, as much as possible. We must not just remove
// words from the member ArrayList as some other parties may expect the object to never change.
- public SuggestedWords getSuggestedWordsExcludingTypedWord() {
+ // This is only ever called by recorrection at the moment, hence the ForRecorrection moniker.
+ public SuggestedWords getSuggestedWordsExcludingTypedWordForRecorrection() {
final ArrayList<SuggestedWordInfo> newSuggestions = new ArrayList<>();
String typedWord = null;
for (int i = 0; i < mSuggestedWordInfoList.size(); ++i) {
@@ -383,7 +406,7 @@ public class SuggestedWords {
// no auto-correction should take place hence willAutoCorrect = false.
return new SuggestedWords(newSuggestions, null /* rawSuggestions */, typedWord,
true /* typedWordValid */, false /* willAutoCorrect */, mIsObsoleteSuggestions,
- mIsPrediction, NOT_A_SEQUENCE_NUMBER);
+ SuggestedWords.INPUT_STYLE_RECORRECTION, NOT_A_SEQUENCE_NUMBER);
}
// Creates a new SuggestedWordInfo from the currently suggested words that removes all but the
@@ -402,6 +425,20 @@ public class SuggestedWords {
SuggestedWordInfo.NOT_A_CONFIDENCE));
}
return new SuggestedWords(newSuggestions, null /* rawSuggestions */, mTypedWordValid,
- mWillAutoCorrect, mIsObsoleteSuggestions, mIsPrediction);
+ mWillAutoCorrect, mIsObsoleteSuggestions, INPUT_STYLE_TAIL_BATCH);
+ }
+
+ /**
+ * @return the {@link SuggestedWordInfo} which corresponds to the word that is originally
+ * typed by the user. Otherwise returns {@code null}. Note that gesture input is not
+ * considered to be a typed word.
+ */
+ @UsedForTesting
+ public SuggestedWordInfo getTypedWordInfoOrNull() {
+ if (SuggestedWords.INDEX_OF_TYPED_WORD >= size()) {
+ return null;
+ }
+ final SuggestedWordInfo info = getInfo(SuggestedWords.INDEX_OF_TYPED_WORD);
+ return (info.getKind() == SuggestedWordInfo.KIND_TYPED) ? info : null;
}
}
diff --git a/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java b/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java
index e4ee42660..123ab208c 100644
--- a/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java
+++ b/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java
@@ -17,21 +17,16 @@
package com.android.inputmethod.latin;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
import android.os.Process;
-import android.preference.PreferenceManager;
import android.util.Log;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.compat.IntentCompatUtils;
-import com.android.inputmethod.latin.settings.Settings;
+import com.android.inputmethod.keyboard.KeyboardLayoutSet;
import com.android.inputmethod.latin.setup.LauncherIconVisibilityManager;
-import com.android.inputmethod.latin.setup.SetupActivity;
import com.android.inputmethod.latin.utils.UncachedInputMethodManagerUtils;
/**
@@ -58,6 +53,9 @@ import com.android.inputmethod.latin.utils.UncachedInputMethodManagerUtils;
* When a multiuser account has been created, {@link Intent#ACTION_USER_INITIALIZE} is received
* by this receiver and it checks the whether the setup wizard's icon should be appeared or not on
* the launcher depending on which partition this IME is installed.
+ *
+ * When the system locale has been changed, {@link Intent#ACTION_LOCALE_CHANGED} is received by
+ * this receiver and the {@link KeyboardLayoutSet}'s cache is cleared.
*/
public final class SystemBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = SystemBroadcastReceiver.class.getSimpleName();
@@ -67,21 +65,22 @@ public final class SystemBroadcastReceiver extends BroadcastReceiver {
final String intentAction = intent.getAction();
if (Intent.ACTION_MY_PACKAGE_REPLACED.equals(intentAction)) {
Log.i(TAG, "Package has been replaced: " + context.getPackageName());
- } else if (Intent.ACTION_BOOT_COMPLETED.equals(intentAction)) {
- Log.i(TAG, "Boot has been completed");
- } else if (IntentCompatUtils.is_ACTION_USER_INITIALIZE(intentAction)) {
- Log.i(TAG, "User initialize");
- }
-
- LauncherIconVisibilityManager.onReceiveGlobalIntent(intentAction, context);
-
- if (Intent.ACTION_MY_PACKAGE_REPLACED.equals(intentAction)) {
// Need to restore additional subtypes because system always clears additional
// subtypes when the package is replaced.
RichInputMethodManager.init(context);
final RichInputMethodManager richImm = RichInputMethodManager.getInstance();
final InputMethodSubtype[] additionalSubtypes = richImm.getAdditionalSubtypes(context);
richImm.setAdditionalInputMethodSubtypes(additionalSubtypes);
+ LauncherIconVisibilityManager.updateSetupWizardIconVisibility(context);
+ } else if (Intent.ACTION_BOOT_COMPLETED.equals(intentAction)) {
+ Log.i(TAG, "Boot has been completed");
+ LauncherIconVisibilityManager.updateSetupWizardIconVisibility(context);
+ } else if (IntentCompatUtils.is_ACTION_USER_INITIALIZE(intentAction)) {
+ Log.i(TAG, "User initialize");
+ LauncherIconVisibilityManager.updateSetupWizardIconVisibility(context);
+ } else if (Intent.ACTION_LOCALE_CHANGED.equals(intentAction)) {
+ Log.i(TAG, "System locale changed");
+ KeyboardLayoutSet.onSystemLocaleChanged();
}
// The process that hosts this broadcast receiver is invoked and remains alive even after
diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
index debaad13e..21014b378 100644
--- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
@@ -253,12 +253,12 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
final int frequency = cursor.getInt(indexFrequency);
final int adjustedFrequency = scaleFrequencyFromDefaultToLatinIme(frequency);
// Safeguard against adding really long words.
- if (word.length() < MAX_WORD_LENGTH) {
+ if (word.length() <= MAX_WORD_LENGTH) {
runGCIfRequiredLocked(true /* mindsBlockByGC */);
addUnigramLocked(word, adjustedFrequency, null /* shortcutTarget */,
0 /* shortcutFreq */, false /* isNotAWord */,
false /* isBlacklisted */, BinaryDictionary.NOT_A_VALID_TIMESTAMP);
- if (null != shortcut && shortcut.length() < MAX_WORD_LENGTH) {
+ if (null != shortcut && shortcut.length() <= MAX_WORD_LENGTH) {
runGCIfRequiredLocked(true /* mindsBlockByGC */);
addUnigramLocked(shortcut, adjustedFrequency, word,
USER_DICT_SHORTCUT_FREQUENCY, true /* isNotAWord */,
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index cdd782244..32d1fe372 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -25,6 +25,8 @@ import com.android.inputmethod.latin.utils.StringUtils;
import java.util.ArrayList;
import java.util.Collections;
+import javax.annotation.Nonnull;
+
/**
* A place to store the currently composing word with information such as adjacent key codes as well
*/
@@ -175,20 +177,34 @@ public final class WordComposer {
}
/**
- * Process an input event.
+ * Process an event and return an event, and return a processed event to apply.
+ * @param event the unprocessed event.
+ * @return the processed event. Never null, but may be marked as consumed.
+ */
+ @Nonnull
+ public Event processEvent(final Event event) {
+ final Event processedEvent = mCombinerChain.processEvent(mEvents, event);
+ // The retained state of the combiner chain may have changed while processing the event,
+ // so we need to update our cache.
+ refreshTypedWordCache();
+ mEvents.add(event);
+ return processedEvent;
+ }
+
+ /**
+ * Apply a processed input event.
*
* All input events should be supported, including software/hardware events, characters as well
* as deletions, multiple inputs and gestures.
*
- * @param event the event to process.
+ * @param event the event to apply. Must not be null.
*/
- public void processEvent(final Event event) {
+ public void applyProcessedEvent(final Event event) {
+ mCombinerChain.applyProcessedEvent(event);
final int primaryCode = event.mCodePoint;
final int keyX = event.mX;
final int keyY = event.mY;
final int newIndex = size();
- mCombinerChain.processEvent(mEvents, event);
- mEvents.add(event);
refreshTypedWordCache();
mCursorPositionWithinWord = mCodePointSize;
// We may have deleted the last one.
@@ -281,7 +297,9 @@ public final class WordComposer {
final int codePoint = Character.codePointAt(word, i);
// We don't want to override the batch input points that are held in mInputPointers
// (See {@link #add(int,int,int)}).
- processEvent(Event.createEventForCodePointFromUnknownSource(codePoint));
+ final Event processedEvent =
+ processEvent(Event.createEventForCodePointFromUnknownSource(codePoint));
+ applyProcessedEvent(processedEvent);
}
}
@@ -295,9 +313,11 @@ public final class WordComposer {
reset();
final int length = codePoints.length;
for (int i = 0; i < length; ++i) {
- processEvent(Event.createEventForCodePointFromAlreadyTypedText(codePoints[i],
+ final Event processedEvent =
+ processEvent(Event.createEventForCodePointFromAlreadyTypedText(codePoints[i],
CoordinateUtils.xFromArray(coordinates, i),
CoordinateUtils.yFromArray(coordinates, i)));
+ applyProcessedEvent(processedEvent);
}
mIsResumed = true;
}
diff --git a/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java b/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java
index 7071d8689..a87785b1a 100644
--- a/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java
+++ b/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java
@@ -168,7 +168,7 @@ public class ExternalDictionaryGetterForDebug {
} catch (IOException e) {
// There was an error: show a dialog
new AlertDialog.Builder(DialogUtils.getPlatformDialogThemeContext(context))
- .setTitle(R.string.error)
+ .setTitle(R.string.read_external_dictionary_error)
.setMessage(e.toString())
.setPositiveButton(android.R.string.ok, new OnClickListener() {
@Override
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 74d879919..fdab7f25f 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -16,21 +16,29 @@
package com.android.inputmethod.latin.inputlogic;
+import android.graphics.Color;
+import android.inputmethodservice.InputMethodService;
import android.os.SystemClock;
import android.text.SpannableString;
+import android.text.Spanned;
import android.text.TextUtils;
+import android.text.style.BackgroundColorSpan;
import android.text.style.SuggestionSpan;
import android.util.Log;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.CursorAnchorInfo;
import android.view.inputmethod.EditorInfo;
+import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper;
import com.android.inputmethod.compat.SuggestionSpanUtils;
import com.android.inputmethod.event.Event;
import com.android.inputmethod.event.InputTransaction;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.keyboard.ProximityInfo;
+import com.android.inputmethod.keyboard.TextDecorator;
+import com.android.inputmethod.keyboard.TextDecoratorUiOperator;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.Dictionary;
import com.android.inputmethod.latin.DictionaryFacilitator;
@@ -45,6 +53,7 @@ import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.WordComposer;
import com.android.inputmethod.latin.define.DebugFlags;
+import com.android.inputmethod.latin.define.ProductionFlags;
import com.android.inputmethod.latin.settings.SettingsValues;
import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
@@ -80,6 +89,14 @@ public final class InputLogic {
public final Suggest mSuggest;
private final DictionaryFacilitator mDictionaryFacilitator;
+ private final TextDecorator mTextDecorator = new TextDecorator(new TextDecorator.Listener() {
+ @Override
+ public void onClickComposingTextToAddToDictionary(final String word) {
+ mLatinIME.addWordToUserDictionary(word);
+ mLatinIME.dismissAddToDictionaryHint();
+ }
+ });
+
public LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
// This has package visibility so it can be accessed from InputLogicHandler.
/* package */ final WordComposer mWordComposer;
@@ -123,8 +140,9 @@ public final class InputLogic {
* Call this when input starts or restarts in some editor (typically, in onStartInputView).
*
* @param combiningSpec the combining spec string for this subtype
+ * @param settingsValues the current settings values
*/
- public void startInput(final String combiningSpec) {
+ public void startInput(final String combiningSpec, final SettingsValues settingsValues) {
mEnteredText = null;
mWordComposer.restartCombining(combiningSpec);
resetComposingState(true /* alsoResetLastComposedWord */);
@@ -142,15 +160,25 @@ public final class InputLogic {
} else {
mInputLogicHandler.reset();
}
+
+ if (ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK) {
+ // AcceptTypedWord feature relies on CursorAnchorInfo.
+ if (settingsValues.mShouldShowUiToAcceptTypedWord) {
+ mConnection.requestCursorUpdates(true /* enableMonitor */,
+ true /* requestImmediateCallback */);
+ }
+ mTextDecorator.reset();
+ }
}
/**
* Call this when the subtype changes.
* @param combiningSpec the spec string for the combining rules
+ * @param settingsValues the current settings values
*/
- public void onSubtypeChanged(final String combiningSpec) {
+ public void onSubtypeChanged(final String combiningSpec, final SettingsValues settingsValues) {
finishInput();
- startInput(combiningSpec);
+ startInput(combiningSpec, settingsValues);
}
/**
@@ -206,7 +234,7 @@ public final class InputLogic {
final int keyboardShiftMode,
// TODO: remove this argument
final LatinIME.UIHandler handler) {
- final String rawText = event.mText.toString();
+ final String rawText = event.getTextToCommit().toString();
final InputTransaction inputTransaction = new InputTransaction(settingsValues, event,
SystemClock.uptimeMillis(), mSpaceState,
getActualCapsMode(settingsValues, keyboardShiftMode));
@@ -216,7 +244,7 @@ public final class InputLogic {
} else {
resetComposingState(true /* alsoResetLastComposedWord */);
}
- handler.postUpdateSuggestionStrip();
+ handler.postUpdateSuggestionStrip(SuggestedWords.INPUT_STYLE_TYPING);
final String text = performSpecificTldProcessingOnTextInput(rawText);
if (SpaceState.PHANTOM == mSpaceState) {
promotePhantomSpace(settingsValues);
@@ -232,6 +260,20 @@ public final class InputLogic {
}
/**
+ * Determines whether "Touch again to save" should be shown or not.
+ * @param suggestionInfo the suggested word chosen by the user.
+ * @return {@code true} if we should show the "Touch again to save" hint.
+ */
+ private boolean shouldShowAddToDictionaryHint(final SuggestedWordInfo suggestionInfo) {
+ // We should show the "Touch again to save" hint if the user pressed the first entry
+ // AND it's in none of our current dictionaries (main, user or otherwise).
+ return (suggestionInfo.isKindOf(SuggestedWordInfo.KIND_TYPED)
+ || suggestionInfo.isKindOf(SuggestedWordInfo.KIND_OOV_CORRECTION))
+ && !mDictionaryFacilitator.isValidWord(suggestionInfo.mWord, true /* ignoreCase */)
+ && mDictionaryFacilitator.isUserDictionaryEnabled();
+ }
+
+ /**
* A suggestion was picked from the suggestion strip.
* @param settingsValues the current values of the settings.
* @param suggestionInfo the suggestion info.
@@ -288,11 +330,9 @@ public final class InputLogic {
return inputTransaction;
}
- // We need to log before we commit, because the word composer will store away the user
- // typed word.
- final String replacedWord = mWordComposer.getTypedWord();
- commitChosenWord(settingsValues, suggestion,
- LastComposedWord.COMMIT_TYPE_MANUAL_PICK, LastComposedWord.NOT_A_SEPARATOR);
+ final boolean shouldShowAddToDictionaryHint = shouldShowAddToDictionaryHint(suggestionInfo);
+ commitChosenWord(settingsValues, suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK,
+ LastComposedWord.NOT_A_SEPARATOR);
mConnection.endBatchEdit();
// Don't allow cancellation of manual pick
mLastComposedWord.deactivate();
@@ -300,18 +340,12 @@ public final class InputLogic {
mSpaceState = SpaceState.PHANTOM;
inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
- // We should show the "Touch again to save" hint if the user pressed the first entry
- // AND it's in none of our current dictionaries (main, user or otherwise).
- final boolean showingAddToDictionaryHint =
- (suggestionInfo.isKindOf(SuggestedWordInfo.KIND_TYPED)
- || suggestionInfo.isKindOf(SuggestedWordInfo.KIND_OOV_CORRECTION))
- && !mDictionaryFacilitator.isValidWord(suggestion, true /* ignoreCase */);
-
- if (showingAddToDictionaryHint && mDictionaryFacilitator.isUserDictionaryEnabled()) {
+ if (shouldShowAddToDictionaryHint) {
mSuggestionStripViewAccessor.showAddToDictionaryHint(suggestion);
} else {
// If we're not showing the "Touch again to save", then update the suggestion strip.
- handler.postUpdateSuggestionStrip();
+ // That's going to be predictions (or punctuation suggestions), so INPUT_STYLE_NONE.
+ handler.postUpdateSuggestionStrip(SuggestedWords.INPUT_STYLE_NONE);
}
return inputTransaction;
}
@@ -324,10 +358,11 @@ public final class InputLogic {
* @param oldSelEnd old selection end
* @param newSelStart new selection start
* @param newSelEnd new selection end
+ * @param settingsValues the current values of the settings.
* @return whether the cursor has moved as a result of user interaction.
*/
public boolean onUpdateSelection(final int oldSelStart, final int oldSelEnd,
- final int newSelStart, final int newSelEnd) {
+ final int newSelStart, final int newSelEnd, final SettingsValues settingsValues) {
if (mConnection.isBelatedExpectedUpdate(oldSelStart, newSelStart, oldSelEnd, newSelEnd)) {
return false;
}
@@ -352,8 +387,9 @@ public final class InputLogic {
// should be true, but that is if the framework had taken that wrong cursor position
// into account, which means we have to reset the entire composing state whenever there
// is or was a selection regardless of whether it changed or not.
- if (hasOrHadSelection || (selectionChangedOrSafeToReset
- && !mWordComposer.moveCursorByAndReturnIfInsideComposingWord(moveAmount))) {
+ if (hasOrHadSelection || !settingsValues.needsToLookupSuggestions()
+ || (selectionChangedOrSafeToReset
+ && !mWordComposer.moveCursorByAndReturnIfInsideComposingWord(moveAmount))) {
// If we are composing a word and moving the cursor, we would want to set a
// suggestion span for recorrection to work correctly. Unfortunately, that
// would involve the keyboard committing some new text, which would move the
@@ -380,6 +416,11 @@ public final class InputLogic {
// The cursor has been moved : we now accept to perform recapitalization
mRecapitalizeStatus.enable();
+ // We moved the cursor and need to invalidate the indicator right now.
+ mTextDecorator.reset();
+ // Remaining background color that was used for the add-to-dictionary indicator should be
+ // removed.
+ mConnection.removeBackgroundColorFromHighlightedTextIfNecessary();
// We moved the cursor. If we are touching a word, we need to resume suggestion.
mLatinIME.mHandler.postResumeSuggestions(false /* shouldIncludeResumedWordInSuggestions */,
true /* shouldDelay */);
@@ -405,128 +446,44 @@ public final class InputLogic {
final int keyboardShiftMode,
// TODO: remove these arguments
final int currentKeyboardScriptId, final LatinIME.UIHandler handler) {
- final InputTransaction inputTransaction = new InputTransaction(settingsValues, event,
- SystemClock.uptimeMillis(), mSpaceState,
+ final Event processedEvent = mWordComposer.processEvent(event);
+ final InputTransaction inputTransaction = new InputTransaction(settingsValues,
+ processedEvent, SystemClock.uptimeMillis(), mSpaceState,
getActualCapsMode(settingsValues, keyboardShiftMode));
- if (event.mKeyCode != Constants.CODE_DELETE
+ if (processedEvent.mKeyCode != Constants.CODE_DELETE
|| inputTransaction.mTimestamp > mLastKeyTime + Constants.LONG_PRESS_MILLISECONDS) {
mDeleteCount = 0;
}
mLastKeyTime = inputTransaction.mTimestamp;
mConnection.beginBatchEdit();
if (!mWordComposer.isComposingWord()) {
+ // TODO: is this useful? It doesn't look like it should be done here, but rather after
+ // a word is committed.
mIsAutoCorrectionIndicatorOn = false;
}
// TODO: Consolidate the double-space period timer, mLastKeyTime, and the space state.
- if (event.mCodePoint != Constants.CODE_SPACE) {
+ if (processedEvent.mCodePoint != Constants.CODE_SPACE) {
cancelDoubleSpacePeriodCountdown();
}
- boolean didAutoCorrect = false;
- if (event.isFunctionalKeyEvent()) {
- // A special key, like delete, shift, emoji, or the settings key.
- switch (event.mKeyCode) {
- case Constants.CODE_DELETE:
- handleBackspace(inputTransaction, currentKeyboardScriptId);
- // Backspace is a functional key, but it affects the contents of the editor.
- inputTransaction.setDidAffectContents();
- break;
- case Constants.CODE_SHIFT:
- performRecapitalization(inputTransaction.mSettingsValues);
- inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
- if (mSuggestedWords.mIsPrediction) {
- inputTransaction.setRequiresUpdateSuggestions();
- }
- break;
- case Constants.CODE_CAPSLOCK:
- // Note: Changing keyboard to shift lock state is handled in
- // {@link KeyboardSwitcher#onCodeInput(int)}.
- break;
- case Constants.CODE_SYMBOL_SHIFT:
- // Note: Calling back to the keyboard on the symbol Shift key is handled in
- // {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}.
- break;
- case Constants.CODE_SWITCH_ALPHA_SYMBOL:
- // Note: Calling back to the keyboard on symbol key is handled in
- // {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}.
- break;
- case Constants.CODE_SETTINGS:
- onSettingsKeyPressed();
- break;
- case Constants.CODE_SHORTCUT:
- // We need to switch to the shortcut IME. This is handled by LatinIME since the
- // input logic has no business with IME switching.
- break;
- case Constants.CODE_ACTION_NEXT:
- performEditorAction(EditorInfo.IME_ACTION_NEXT);
- break;
- case Constants.CODE_ACTION_PREVIOUS:
- performEditorAction(EditorInfo.IME_ACTION_PREVIOUS);
- break;
- case Constants.CODE_LANGUAGE_SWITCH:
- handleLanguageSwitchKey();
- break;
- case Constants.CODE_EMOJI:
- // Note: Switching emoji keyboard is being handled in
- // {@link KeyboardState#onCodeInput(int,int)}.
- break;
- case Constants.CODE_ALPHA_FROM_EMOJI:
- // Note: Switching back from Emoji keyboard to the main keyboard is being
- // handled in {@link KeyboardState#onCodeInput(int,int)}.
- break;
- case Constants.CODE_SHIFT_ENTER:
- // TODO: remove this object
- final Event tmpEvent = Event.createSoftwareKeypressEvent(Constants.CODE_ENTER,
- event.mKeyCode, event.mX, event.mY, event.isKeyRepeat());
- final InputTransaction tmpTransaction = new InputTransaction(
- inputTransaction.mSettingsValues, tmpEvent,
- inputTransaction.mTimestamp, inputTransaction.mSpaceState,
- inputTransaction.mShiftState);
- didAutoCorrect = handleNonSpecialCharacter(tmpTransaction, handler);
- // Shift + Enter is treated as a functional key but it results in adding a new
- // line, so that does affect the contents of the editor.
- inputTransaction.setDidAffectContents();
- break;
- default:
- throw new RuntimeException("Unknown key code : " + event.mKeyCode);
- }
- } else {
- inputTransaction.setDidAffectContents();
- switch (event.mCodePoint) {
- case Constants.CODE_ENTER:
- final EditorInfo editorInfo = getCurrentInputEditorInfo();
- final int imeOptionsActionId =
- InputTypeUtils.getImeOptionsActionIdFromEditorInfo(editorInfo);
- if (InputTypeUtils.IME_ACTION_CUSTOM_LABEL == imeOptionsActionId) {
- // Either we have an actionLabel and we should performEditorAction with
- // actionId regardless of its value.
- performEditorAction(editorInfo.actionId);
- } else if (EditorInfo.IME_ACTION_NONE != imeOptionsActionId) {
- // We didn't have an actionLabel, but we had another action to execute.
- // EditorInfo.IME_ACTION_NONE explicitly means no action. In contrast,
- // EditorInfo.IME_ACTION_UNSPECIFIED is the default value for an action, so it
- // means there should be an action and the app didn't bother to set a specific
- // code for it - presumably it only handles one. It does not have to be treated
- // in any specific way: anything that is not IME_ACTION_NONE should be sent to
- // performEditorAction.
- performEditorAction(imeOptionsActionId);
- } else {
- // No action label, and the action from imeOptions is NONE: this is a regular
- // enter key that should input a carriage return.
- didAutoCorrect = handleNonSpecialCharacter(inputTransaction, handler);
- }
- break;
- default:
- didAutoCorrect = handleNonSpecialCharacter(inputTransaction, handler);
- break;
+ Event currentEvent = processedEvent;
+ while (null != currentEvent) {
+ if (currentEvent.isConsumed()) {
+ handleConsumedEvent(currentEvent, inputTransaction);
+ } else if (currentEvent.isFunctionalKeyEvent()) {
+ handleFunctionalEvent(currentEvent, inputTransaction, currentKeyboardScriptId,
+ handler);
+ } else {
+ handleNonFunctionalEvent(currentEvent, inputTransaction, handler);
}
+ currentEvent = currentEvent.mNextEvent;
}
- if (!didAutoCorrect && event.mKeyCode != Constants.CODE_SHIFT
- && event.mKeyCode != Constants.CODE_CAPSLOCK
- && event.mKeyCode != Constants.CODE_SWITCH_ALPHA_SYMBOL)
+ if (!inputTransaction.didAutoCorrect() && processedEvent.mKeyCode != Constants.CODE_SHIFT
+ && processedEvent.mKeyCode != Constants.CODE_CAPSLOCK
+ && processedEvent.mKeyCode != Constants.CODE_SWITCH_ALPHA_SYMBOL)
mLastComposedWord.deactivate();
- if (Constants.CODE_DELETE != event.mKeyCode) {
+ if (Constants.CODE_DELETE != processedEvent.mKeyCode) {
mEnteredText = null;
}
mConnection.endBatchEdit();
@@ -542,7 +499,9 @@ public final class InputLogic {
handler.cancelUpdateSuggestionStrip();
++mAutoCommitSequenceNumber;
mConnection.beginBatchEdit();
- if (mWordComposer.isComposingWord()) {
+ if (!mWordComposer.isComposingWord()) {
+ mConnection.removeBackgroundColorFromHighlightedTextIfNecessary();
+ } else {
if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) {
// If we are in the middle of a recorrection, we need to commit the recorrection
// first so that we can insert the batch input at the current cursor position.
@@ -639,7 +598,8 @@ public final class InputLogic {
// TODO: on the long term, this method should become private, but it will be difficult.
// Especially, how do we deal with InputMethodService.onDisplayCompletions?
- public void setSuggestedWords(final SuggestedWords suggestedWords) {
+ public void setSuggestedWords(final SuggestedWords suggestedWords,
+ final SettingsValues settingsValues, final LatinIME.UIHandler handler) {
if (SuggestedWords.EMPTY != suggestedWords) {
final String autoCorrection;
if (suggestedWords.mWillAutoCorrect) {
@@ -653,6 +613,7 @@ public final class InputLogic {
}
mSuggestedWords = suggestedWords;
final boolean newAutoCorrectionIndicator = suggestedWords.mWillAutoCorrect;
+
// Put a blue underline to a word in TextView which will be auto-corrected.
if (mIsAutoCorrectionIndicatorOn != newAutoCorrectionIndicator
&& mWordComposer.isComposingWord()) {
@@ -663,7 +624,154 @@ public final class InputLogic {
// message, this is called outside any batch edit. Potentially, this may result in some
// janky flickering of the screen, although the display speed makes it unlikely in
// the practice.
- mConnection.setComposingText(textWithUnderline, 1);
+ setComposingTextInternal(textWithUnderline, 1);
+ }
+ }
+
+ /**
+ * Handle a consumed event.
+ *
+ * Consumed events represent events that have already been consumed, typically by the
+ * combining chain.
+ *
+ * @param event The event to handle.
+ * @param inputTransaction The transaction in progress.
+ */
+ private void handleConsumedEvent(final Event event, final InputTransaction inputTransaction) {
+ // A consumed event may have text to commit and an update to the composing state, so
+ // we evaluate both. With some combiners, it's possible than an event contains both
+ // and we enter both of the following if clauses.
+ final CharSequence textToCommit = event.getTextToCommit();
+ if (!TextUtils.isEmpty(textToCommit)) {
+ mConnection.commitText(textToCommit, 1);
+ inputTransaction.setDidAffectContents();
+ }
+ if (mWordComposer.isComposingWord()) {
+ setComposingTextInternal(mWordComposer.getTypedWord(), 1);
+ inputTransaction.setDidAffectContents();
+ inputTransaction.setRequiresUpdateSuggestions();
+ }
+ }
+
+ /**
+ * Handle a functional key event.
+ *
+ * A functional event is a special key, like delete, shift, emoji, or the settings key.
+ * Non-special keys are those that generate a single code point.
+ * This includes all letters, digits, punctuation, separators, emoji. It excludes keys that
+ * manage keyboard-related stuff like shift, language switch, settings, layout switch, or
+ * any key that results in multiple code points like the ".com" key.
+ *
+ * @param event The event to handle.
+ * @param inputTransaction The transaction in progress.
+ */
+ private void handleFunctionalEvent(final Event event, final InputTransaction inputTransaction,
+ // TODO: remove these arguments
+ final int currentKeyboardScriptId, final LatinIME.UIHandler handler) {
+ switch (event.mKeyCode) {
+ case Constants.CODE_DELETE:
+ handleBackspaceEvent(event, inputTransaction, currentKeyboardScriptId);
+ // Backspace is a functional key, but it affects the contents of the editor.
+ inputTransaction.setDidAffectContents();
+ break;
+ case Constants.CODE_SHIFT:
+ performRecapitalization(inputTransaction.mSettingsValues);
+ inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
+ if (mSuggestedWords.isPrediction()) {
+ inputTransaction.setRequiresUpdateSuggestions();
+ }
+ break;
+ case Constants.CODE_CAPSLOCK:
+ // Note: Changing keyboard to shift lock state is handled in
+ // {@link KeyboardSwitcher#onCodeInput(int)}.
+ break;
+ case Constants.CODE_SYMBOL_SHIFT:
+ // Note: Calling back to the keyboard on the symbol Shift key is handled in
+ // {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}.
+ break;
+ case Constants.CODE_SWITCH_ALPHA_SYMBOL:
+ // Note: Calling back to the keyboard on symbol key is handled in
+ // {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}.
+ break;
+ case Constants.CODE_SETTINGS:
+ onSettingsKeyPressed();
+ break;
+ case Constants.CODE_SHORTCUT:
+ // We need to switch to the shortcut IME. This is handled by LatinIME since the
+ // input logic has no business with IME switching.
+ break;
+ case Constants.CODE_ACTION_NEXT:
+ performEditorAction(EditorInfo.IME_ACTION_NEXT);
+ break;
+ case Constants.CODE_ACTION_PREVIOUS:
+ performEditorAction(EditorInfo.IME_ACTION_PREVIOUS);
+ break;
+ case Constants.CODE_LANGUAGE_SWITCH:
+ handleLanguageSwitchKey();
+ break;
+ case Constants.CODE_EMOJI:
+ // Note: Switching emoji keyboard is being handled in
+ // {@link KeyboardState#onCodeInput(int,int)}.
+ break;
+ case Constants.CODE_ALPHA_FROM_EMOJI:
+ // Note: Switching back from Emoji keyboard to the main keyboard is being
+ // handled in {@link KeyboardState#onCodeInput(int,int)}.
+ break;
+ case Constants.CODE_SHIFT_ENTER:
+ // TODO: remove this object
+ final Event tmpEvent = Event.createSoftwareKeypressEvent(Constants.CODE_ENTER,
+ event.mKeyCode, event.mX, event.mY, event.isKeyRepeat());
+ handleNonSpecialCharacterEvent(tmpEvent, inputTransaction, handler);
+ // Shift + Enter is treated as a functional key but it results in adding a new
+ // line, so that does affect the contents of the editor.
+ inputTransaction.setDidAffectContents();
+ break;
+ default:
+ throw new RuntimeException("Unknown key code : " + event.mKeyCode);
+ }
+ }
+
+ /**
+ * Handle an event that is not a functional event.
+ *
+ * These events are generally events that cause input, but in some cases they may do other
+ * things like trigger an editor action.
+ *
+ * @param event The event to handle.
+ * @param inputTransaction The transaction in progress.
+ */
+ private void handleNonFunctionalEvent(final Event event,
+ final InputTransaction inputTransaction,
+ // TODO: remove this argument
+ final LatinIME.UIHandler handler) {
+ inputTransaction.setDidAffectContents();
+ switch (event.mCodePoint) {
+ case Constants.CODE_ENTER:
+ final EditorInfo editorInfo = getCurrentInputEditorInfo();
+ final int imeOptionsActionId =
+ InputTypeUtils.getImeOptionsActionIdFromEditorInfo(editorInfo);
+ if (InputTypeUtils.IME_ACTION_CUSTOM_LABEL == imeOptionsActionId) {
+ // Either we have an actionLabel and we should performEditorAction with
+ // actionId regardless of its value.
+ performEditorAction(editorInfo.actionId);
+ } else if (EditorInfo.IME_ACTION_NONE != imeOptionsActionId) {
+ // We didn't have an actionLabel, but we had another action to execute.
+ // EditorInfo.IME_ACTION_NONE explicitly means no action. In contrast,
+ // EditorInfo.IME_ACTION_UNSPECIFIED is the default value for an action, so it
+ // means there should be an action and the app didn't bother to set a specific
+ // code for it - presumably it only handles one. It does not have to be treated
+ // in any specific way: anything that is not IME_ACTION_NONE should be sent to
+ // performEditorAction.
+ performEditorAction(imeOptionsActionId);
+ } else {
+ // No action label, and the action from imeOptions is NONE: this is a regular
+ // enter key that should input a carriage return.
+ handleNonSpecialCharacterEvent(event, inputTransaction, handler);
+ }
+ break;
+ default:
+ handleNonSpecialCharacterEvent(event, inputTransaction, handler);
+ break;
}
}
@@ -675,21 +783,29 @@ public final class InputLogic {
* manage keyboard-related stuff like shift, language switch, settings, layout switch, or
* any key that results in multiple code points like the ".com" key.
*
+ * @param event The event to handle.
* @param inputTransaction The transaction in progress.
- * @return whether this caused an auto-correction to happen.
*/
- private boolean handleNonSpecialCharacter(final InputTransaction inputTransaction,
+ private void handleNonSpecialCharacterEvent(final Event event,
+ final InputTransaction inputTransaction,
// TODO: remove this argument
final LatinIME.UIHandler handler) {
- final int codePoint = inputTransaction.mEvent.mCodePoint;
+ if (!mWordComposer.isComposingWord()) {
+ mConnection.removeBackgroundColorFromHighlightedTextIfNecessary();
+ // In case the "add to dictionary" hint was still displayed.
+ // TODO: Do we really need to check if we have composing text here?
+ if (mSuggestionStripViewAccessor.isShowingAddToDictionaryHint()) {
+ mSuggestionStripViewAccessor.dismissAddToDictionaryHint();
+ mTextDecorator.reset();
+ }
+ }
+
+ final int codePoint = event.mCodePoint;
mSpaceState = SpaceState.NONE;
- final boolean didAutoCorrect;
if (inputTransaction.mSettingsValues.isWordSeparator(codePoint)
|| Character.getType(codePoint) == Character.OTHER_SYMBOL) {
- didAutoCorrect = handleSeparator(inputTransaction,
- inputTransaction.mEvent.isSuggestionStripPress(), handler);
+ handleSeparatorEvent(event, inputTransaction, handler);
} else {
- didAutoCorrect = false;
if (SpaceState.PHANTOM == inputTransaction.mSpaceState) {
if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) {
// If we are in the middle of a recorrection, we need to commit the recorrection
@@ -700,22 +816,23 @@ public final class InputLogic {
commitTyped(inputTransaction.mSettingsValues, LastComposedWord.NOT_A_SEPARATOR);
}
}
- handleNonSeparator(inputTransaction.mSettingsValues, inputTransaction);
+ handleNonSeparatorEvent(event, inputTransaction.mSettingsValues, inputTransaction);
}
- return didAutoCorrect;
}
/**
* Handle a non-separator.
+ * @param event The event to handle.
* @param settingsValues The current settings values.
* @param inputTransaction The transaction in progress.
*/
- private void handleNonSeparator(final SettingsValues settingsValues,
+ private void handleNonSeparatorEvent(final Event event, final SettingsValues settingsValues,
final InputTransaction inputTransaction) {
- final int codePoint = inputTransaction.mEvent.mCodePoint;
+ final int codePoint = event.mCodePoint;
// TODO: refactor this method to stop flipping isComposingWord around all the time, and
- // make it shorter (possibly cut into several pieces). Also factor handleNonSpecialCharacter
- // which has the same name as other handle* methods but is not the same.
+ // make it shorter (possibly cut into several pieces). Also factor
+ // handleNonSpecialCharacterEvent 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.
@@ -762,41 +879,35 @@ public final class InputLogic {
resetComposingState(false /* alsoResetLastComposedWord */);
}
if (isComposingWord) {
- mWordComposer.processEvent(inputTransaction.mEvent);
+ mWordComposer.applyProcessedEvent(event);
// If it's the first letter, make note of auto-caps state
if (mWordComposer.isSingleLetter()) {
mWordComposer.setCapitalizedModeAtStartComposingTime(inputTransaction.mShiftState);
}
- mConnection.setComposingText(getTextWithUnderline(
- mWordComposer.getTypedWord()), 1);
+ setComposingTextInternal(getTextWithUnderline(mWordComposer.getTypedWord()), 1);
} else {
- final boolean swapWeakSpace = tryStripSpaceAndReturnWhetherShouldSwapInstead(
- inputTransaction, inputTransaction.mEvent.isSuggestionStripPress());
+ final boolean swapWeakSpace = tryStripSpaceAndReturnWhetherShouldSwapInstead(event,
+ inputTransaction);
- if (swapWeakSpace && trySwapSwapperAndSpace(inputTransaction)) {
+ if (swapWeakSpace && trySwapSwapperAndSpace(event, inputTransaction)) {
mSpaceState = SpaceState.WEAK;
} else {
sendKeyCodePoint(settingsValues, codePoint);
}
- // In case the "add to dictionary" hint was still displayed.
- mSuggestionStripViewAccessor.dismissAddToDictionaryHint();
}
inputTransaction.setRequiresUpdateSuggestions();
}
/**
* Handle input of a separator code point.
+ * @param event The event to handle.
* @param inputTransaction The transaction in progress.
- * @param isFromSuggestionStrip whether this code point comes from the suggestion strip.
- * @return whether this caused an auto-correction to happen.
*/
- private boolean handleSeparator(final InputTransaction inputTransaction,
- final boolean isFromSuggestionStrip,
+ private void handleSeparatorEvent(final Event event, final InputTransaction inputTransaction,
// TODO: remove this argument
final LatinIME.UIHandler handler) {
- final int codePoint = inputTransaction.mEvent.mCodePoint;
+ final int codePoint = event.mCodePoint;
final SettingsValues settingsValues = inputTransaction.mSettingsValues;
- boolean didAutoCorrect = false;
final boolean wasComposingWord = mWordComposer.isComposingWord();
// We avoid sending spaces in languages without spaces if we were composing.
final boolean shouldAvoidSendingCode = Constants.CODE_SPACE == codePoint
@@ -814,15 +925,15 @@ public final class InputLogic {
final String separator = shouldAvoidSendingCode ? LastComposedWord.NOT_A_SEPARATOR
: StringUtils.newSingleCodePointString(codePoint);
commitCurrentAutoCorrection(settingsValues, separator, handler);
- didAutoCorrect = true;
+ inputTransaction.setDidAutoCorrect();
} else {
commitTyped(settingsValues,
StringUtils.newSingleCodePointString(codePoint));
}
}
- final boolean swapWeakSpace = tryStripSpaceAndReturnWhetherShouldSwapInstead(
- inputTransaction, isFromSuggestionStrip);
+ final boolean swapWeakSpace = tryStripSpaceAndReturnWhetherShouldSwapInstead(event,
+ inputTransaction);
final boolean isInsideDoubleQuoteOrAfterDigit = Constants.CODE_DOUBLE_QUOTE == codePoint
&& mConnection.isInsideDoubleQuoteOrAfterDigit();
@@ -846,10 +957,10 @@ public final class InputLogic {
promotePhantomSpace(settingsValues);
}
- if (tryPerformDoubleSpacePeriod(inputTransaction)) {
+ if (tryPerformDoubleSpacePeriod(event, inputTransaction)) {
mSpaceState = SpaceState.DOUBLE;
inputTransaction.setRequiresUpdateSuggestions();
- } else if (swapWeakSpace && trySwapSwapperAndSpace(inputTransaction)) {
+ } else if (swapWeakSpace && trySwapSwapperAndSpace(event, inputTransaction)) {
mSpaceState = SpaceState.SWAP_PUNCTUATION;
mSuggestionStripViewAccessor.setNeutralSuggestionStrip();
} else if (Constants.CODE_SPACE == codePoint) {
@@ -892,14 +1003,14 @@ public final class InputLogic {
}
inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
- return didAutoCorrect;
}
/**
* Handle a press on the backspace key.
+ * @param event The event to handle.
* @param inputTransaction The transaction in progress.
*/
- private void handleBackspace(final InputTransaction inputTransaction,
+ private void handleBackspaceEvent(final Event event, final InputTransaction inputTransaction,
// TODO: remove this argument, put it into settingsValues
final int currentKeyboardScriptId) {
mSpaceState = SpaceState.NONE;
@@ -913,7 +1024,7 @@ public final class InputLogic {
// Then again, even in the case of a key repeat, if the cursor is at start of text, it
// can't go any further back, so we can update right away even if it's a key repeat.
final int shiftUpdateKind =
- inputTransaction.mEvent.isKeyRepeat() && mConnection.getExpectedSelectionStart() > 0
+ event.isKeyRepeat() && mConnection.getExpectedSelectionStart() > 0
? InputTransaction.SHIFT_UPDATE_LATER : InputTransaction.SHIFT_UPDATE_NOW;
inputTransaction.requireShiftUpdate(shiftUpdateKind);
@@ -933,17 +1044,17 @@ public final class InputLogic {
mDictionaryFacilitator.removeWordFromPersonalizedDicts(rejectedSuggestion);
}
} else {
- mWordComposer.processEvent(inputTransaction.mEvent);
+ mWordComposer.applyProcessedEvent(event);
}
if (mWordComposer.isComposingWord()) {
- mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1);
+ setComposingTextInternal(getTextWithUnderline(mWordComposer.getTypedWord()), 1);
} else {
mConnection.commitText("", 1);
}
inputTransaction.setRequiresUpdateSuggestions();
} else {
if (mLastComposedWord.canRevertCommit()) {
- revertCommit(inputTransaction);
+ revertCommit(inputTransaction, inputTransaction.mSettingsValues);
return;
}
if (mEnteredText != null && mConnection.sameAsTextBeforeCursor(mEnteredText)) {
@@ -1052,16 +1163,18 @@ public final class InputLogic {
*
* This method will check that there are two characters before the cursor and that the first
* one is a space before it does the actual swapping.
+ * @param event The event to handle.
* @param inputTransaction The transaction in progress.
* @return true if the swap has been performed, false if it was prevented by preliminary checks.
*/
- private boolean trySwapSwapperAndSpace(final InputTransaction inputTransaction) {
+ private boolean trySwapSwapperAndSpace(final Event event,
+ final InputTransaction inputTransaction) {
final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor();
if (Constants.CODE_SPACE != codePointBeforeCursor) {
return false;
}
mConnection.deleteSurroundingText(1, 0);
- final String text = inputTransaction.mEvent.getTextToCommit() + " ";
+ final String text = event.getTextToCommit() + " ";
mConnection.commitText(text, 1);
inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
return true;
@@ -1069,13 +1182,14 @@ public final class InputLogic {
/*
* Strip a trailing space if necessary and returns whether it's a swap weak space situation.
+ * @param event The event to handle.
* @param inputTransaction The transaction in progress.
- * @param isFromSuggestionStrip Whether this code point is coming from the suggestion strip.
* @return whether we should swap the space instead of removing it.
*/
- private boolean tryStripSpaceAndReturnWhetherShouldSwapInstead(
- final InputTransaction inputTransaction, final boolean isFromSuggestionStrip) {
- final int codePoint = inputTransaction.mEvent.mCodePoint;
+ private boolean tryStripSpaceAndReturnWhetherShouldSwapInstead(final Event event,
+ final InputTransaction inputTransaction) {
+ final int codePoint = event.mCodePoint;
+ final boolean isFromSuggestionStrip = event.isSuggestionStripPress();
if (Constants.CODE_ENTER == codePoint &&
SpaceState.SWAP_PUNCTUATION == inputTransaction.mSpaceState) {
mConnection.removeTrailingSpace();
@@ -1120,14 +1234,16 @@ public final class InputLogic {
* these conditions are fulfilled, this method applies the transformation and returns true.
* Otherwise, it does nothing and returns false.
*
+ * @param event The event to handle.
* @param inputTransaction The transaction in progress.
* @return true if we applied the double-space-to-period transformation, false otherwise.
*/
- private boolean tryPerformDoubleSpacePeriod(final InputTransaction inputTransaction) {
+ private boolean tryPerformDoubleSpacePeriod(final Event event,
+ final InputTransaction inputTransaction) {
// Check the setting, the typed character and the countdown. If any of the conditions is
// not fulfilled, return false.
if (!inputTransaction.mSettingsValues.mUseDoubleSpacePeriod
- || Constants.CODE_SPACE != inputTransaction.mEvent.mCodePoint
+ || Constants.CODE_SPACE != event.mCodePoint
|| !isDoubleSpacePeriodCountdownActive(inputTransaction)) {
return false;
}
@@ -1235,7 +1351,8 @@ public final class InputLogic {
prevWordsInfo, timeStampInSeconds, settingsValues.mBlockPotentiallyOffensive);
}
- public void performUpdateSuggestionStripSync(final SettingsValues settingsValues) {
+ public void performUpdateSuggestionStripSync(final SettingsValues settingsValues,
+ final int inputStyle) {
// Check if we have a suggestion engine attached.
if (!settingsValues.needsToLookupSuggestions()) {
if (mWordComposer.isComposingWord()) {
@@ -1253,8 +1370,8 @@ public final class InputLogic {
}
final AsyncResultHolder<SuggestedWords> holder = new AsyncResultHolder<>();
- mInputLogicHandler.getSuggestedWords(Suggest.SESSION_TYPING,
- SuggestedWords.NOT_A_SEQUENCE_NUMBER, new OnGetSuggestedWordsCallback() {
+ mInputLogicHandler.getSuggestedWords(inputStyle, SuggestedWords.NOT_A_SEQUENCE_NUMBER,
+ new OnGetSuggestedWordsCallback() {
@Override
public void onGetSuggestedWords(final SuggestedWords suggestedWords) {
final String typedWord = mWordComposer.getTypedWord();
@@ -1315,12 +1432,11 @@ public final class InputLogic {
if (!mConnection.isCursorTouchingWord(settingsValues.mSpacingAndPunctuations)) {
// Show predictions.
mWordComposer.setCapitalizedModeAtStartComposingTime(WordComposer.CAPS_MODE_OFF);
- mLatinIME.mHandler.postUpdateSuggestionStrip();
+ mLatinIME.mHandler.postUpdateSuggestionStrip(SuggestedWords.INPUT_STYLE_RECORRECTION);
return;
}
final TextRange range = mConnection.getWordRangeAtCursor(
- settingsValues.mSpacingAndPunctuations.mSortedWordSeparators,
- currentKeyboardScriptId);
+ settingsValues.mSpacingAndPunctuations, currentKeyboardScriptId);
if (null == range) return; // Happens if we don't have an input connection at all
if (range.length() <= 0) {
// Race condition, or touching a word in a non-supported script.
@@ -1373,13 +1489,14 @@ public final class InputLogic {
mLatinIME.getCoordinatesForCurrentKeyboard(codePoints));
mWordComposer.setCursorPositionWithinWord(
typedWord.codePointCount(0, numberOfCharsInWordBeforeCursor));
+ mConnection.maybeMoveTheCursorAroundAndRestoreToWorkaroundABug();
mConnection.setComposingRegion(expectedCursorPosition - numberOfCharsInWordBeforeCursor,
expectedCursorPosition + range.getNumberOfCharsInWordAfterCursor());
if (suggestions.size() <= (shouldIncludeResumedWordInSuggestions ? 1 : 0)) {
// If there weren't any suggestion spans on this word, suggestions#size() will be 1
// if shouldIncludeResumedWordInSuggestions is true, 0 otherwise. In this case, we
// have no useful suggestions, so we will try to compute some for it instead.
- mInputLogicHandler.getSuggestedWords(Suggest.SESSION_TYPING,
+ mInputLogicHandler.getSuggestedWords(Suggest.SESSION_ID_TYPING,
SuggestedWords.NOT_A_SEQUENCE_NUMBER, new OnGetSuggestedWordsCallback() {
@Override
public void onGetSuggestedWords(
@@ -1389,10 +1506,10 @@ public final class InputLogic {
&& !shouldIncludeResumedWordInSuggestions) {
// 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.
+ // case. The #getSuggestedWordsExcludingTypedWordForRecorrection()
+ // method sets willAutoCorrect to false.
suggestedWords = suggestedWordsIncludingTypedWord
- .getSuggestedWordsExcludingTypedWord();
+ .getSuggestedWordsExcludingTypedWordForRecorrection();
} else {
// No saved suggestions, and we were unable to compute any good one
// either. Rather than displaying an empty suggestion strip, we'll
@@ -1409,10 +1526,9 @@ public final class InputLogic {
// color of the word in the suggestion strip changes according to this parameter,
// and false gives the correct color.
final SuggestedWords suggestedWords = new SuggestedWords(suggestions,
- null /* rawSuggestions */, typedWord,
- false /* typedWordValid */, false /* willAutoCorrect */,
- false /* isObsoleteSuggestions */, false /* isPrediction */,
- SuggestedWords.NOT_A_SEQUENCE_NUMBER);
+ null /* rawSuggestions */, typedWord, false /* typedWordValid */,
+ false /* willAutoCorrect */, false /* isObsoleteSuggestions */,
+ SuggestedWords.INPUT_STYLE_RECORRECTION, SuggestedWords.NOT_A_SEQUENCE_NUMBER);
mIsAutoCorrectionIndicatorOn = false;
mLatinIME.mHandler.showSuggestionStrip(suggestedWords);
}
@@ -1424,14 +1540,19 @@ public final class InputLogic {
* This is triggered upon pressing backspace just after a commit with auto-correction.
*
* @param inputTransaction The transaction in progress.
+ * @param settingsValues the current values of the settings.
*/
- private void revertCommit(final InputTransaction inputTransaction) {
+ private void revertCommit(final InputTransaction inputTransaction,
+ final SettingsValues settingsValues) {
final CharSequence originallyTypedWord = mLastComposedWord.mTypedWord;
+ final String originallyTypedWordString =
+ originallyTypedWord != null ? originallyTypedWord.toString() : "";
final CharSequence committedWord = mLastComposedWord.mCommittedWord;
final String committedWordString = committedWord.toString();
final int cancelLength = committedWord.length();
+ final String separatorString = mLastComposedWord.mSeparatorString;
// We want java chars, not codepoints for the following.
- final int separatorLength = mLastComposedWord.mSeparatorString.length();
+ final int separatorLength = separatorString.length();
// TODO: should we check our saved separator against the actual contents of the text view?
final int deleteLength = cancelLength + separatorLength;
if (DebugFlags.DEBUG_ENABLED) {
@@ -1450,7 +1571,7 @@ public final class InputLogic {
if (!TextUtils.isEmpty(committedWord)) {
mDictionaryFacilitator.removeWordFromPersonalizedDicts(committedWordString);
}
- final String stringToCommit = originallyTypedWord + mLastComposedWord.mSeparatorString;
+ final String stringToCommit = originallyTypedWord + separatorString;
final SpannableString textToCommit = new SpannableString(stringToCommit);
if (committedWord instanceof SpannableString) {
final SpannableString committedWordWithSuggestionSpans = (SpannableString)committedWord;
@@ -1487,23 +1608,53 @@ public final class InputLogic {
suggestions.toArray(new String[suggestions.size()]), 0 /* flags */),
0 /* start */, lastCharIndex /* end */, 0 /* flags */);
}
+
+ final boolean shouldShowAddToDictionaryForTypedWord =
+ shouldShowAddToDictionaryForTypedWord(mLastComposedWord, settingsValues);
+
if (inputTransaction.mSettingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces) {
// For languages with spaces, we revert to the typed string, but the cursor is still
// after the separator so we don't resume suggestions. If the user wants to correct
// the word, they have to press backspace again.
- mConnection.commitText(textToCommit, 1);
+ if (shouldShowAddToDictionaryForTypedWord) {
+ mConnection.commitTextWithBackgroundColor(textToCommit, 1,
+ settingsValues.mTextHighlightColorForAddToDictionaryIndicator,
+ originallyTypedWordString.length());
+ } else {
+ mConnection.commitText(textToCommit, 1);
+ }
} else {
// For languages without spaces, we revert the typed string but the cursor is flush
// with the typed word, so we need to resume suggestions right away.
final int[] codePoints = StringUtils.toCodePointArray(stringToCommit);
mWordComposer.setComposingWord(codePoints,
mLatinIME.getCoordinatesForCurrentKeyboard(codePoints));
- mConnection.setComposingText(textToCommit, 1);
+ if (shouldShowAddToDictionaryForTypedWord) {
+ setComposingTextInternalWithBackgroundColor(textToCommit, 1,
+ settingsValues.mTextHighlightColorForAddToDictionaryIndicator,
+ originallyTypedWordString.length());
+ } else {
+ setComposingTextInternal(textToCommit, 1);
+ }
}
// Don't restart suggestion yet. We'll restart if the user deletes the separator.
mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
- // We have a separator between the word and the cursor: we should show predictions.
- inputTransaction.setRequiresUpdateSuggestions();
+
+ if (shouldShowAddToDictionaryForTypedWord) {
+ // Due to the API limitation as of L, we cannot reliably retrieve the reverted text
+ // when the separator causes line breaking. Until this API limitation is addressed in
+ // the framework, show the indicator only when the separator doesn't contain
+ // line-breaking characters.
+ if (!StringUtils.hasLineBreakCharacter(separatorString)) {
+ mTextDecorator.showAddToDictionaryIndicator(originallyTypedWordString,
+ mConnection.getExpectedSelectionStart(),
+ mConnection.getExpectedSelectionEnd());
+ }
+ mSuggestionStripViewAccessor.showAddToDictionaryHint(originallyTypedWordString);
+ } else {
+ // We have a separator between the word and the cursor: we should show predictions.
+ inputTransaction.setRequiresUpdateSuggestions();
+ }
}
/**
@@ -1708,7 +1859,7 @@ public final class InputLogic {
SuggestedWords.getTypedWordAndPreviousSuggestions(typedWord, oldSuggestedWords);
return new SuggestedWords(typedWordAndPreviousSuggestions, null /* rawSuggestions */,
false /* typedWordValid */, false /* hasAutoCorrectionCandidate */,
- true /* isObsoleteSuggestions */, false /* isPrediction */);
+ true /* isObsoleteSuggestions */, oldSuggestedWords.mInputStyle);
}
/**
@@ -1831,10 +1982,10 @@ public final class InputLogic {
}
final String lastWord = batchInputText.substring(indexOfLastSpace);
mWordComposer.setBatchInputWord(lastWord);
- mConnection.setComposingText(lastWord, 1);
+ setComposingTextInternal(lastWord, 1);
} else {
mWordComposer.setBatchInputWord(batchInputText);
- mConnection.setComposingText(batchInputText, 1);
+ setComposingTextInternal(batchInputText, 1);
}
mConnection.endBatchEdit();
// Space state must be updated before calling updateShiftState
@@ -1891,7 +2042,15 @@ public final class InputLogic {
// Complete any pending suggestions query first
if (handler.hasPendingUpdateSuggestions()) {
handler.cancelUpdateSuggestionStrip();
- performUpdateSuggestionStripSync(settingsValues);
+ // To know the input style here, we should retrieve the in-flight "update suggestions"
+ // message and read its arg1 member here. However, the Handler class does not let
+ // us retrieve this message, so we can't do that. But in fact, we notice that
+ // we only ever come here when the input style was typing. In the case of batch
+ // input, we update the suggestions synchronously when the tail batch comes. Likewise
+ // for application-specified completions. As for recorrections, we never auto-correct,
+ // so we don't come here either. Hence, the input style is necessarily
+ // INPUT_STYLE_TYPING.
+ performUpdateSuggestionStripSync(settingsValues, SuggestedWords.INPUT_STYLE_TYPING);
}
final String typedAutoCorrection = mWordComposer.getAutoCorrectionOrNull();
final String typedWord = mWordComposer.getTypedWord();
@@ -1955,14 +2114,13 @@ public final class InputLogic {
* This method handles the retry, and re-schedules a new retry if we still can't access.
* We only retry up to 5 times before giving up.
*
- * @param settingsValues the current values of the settings.
* @param tryResumeSuggestions Whether we should resume suggestions or not.
* @param remainingTries How many times we may try again before giving up.
* @return whether true if the caches were successfully reset, false otherwise.
*/
// TODO: make this private
- public boolean retryResetCachesAndReturnSuccess(final SettingsValues settingsValues,
- final boolean tryResumeSuggestions, final int remainingTries,
+ public boolean retryResetCachesAndReturnSuccess(final boolean tryResumeSuggestions,
+ final int remainingTries,
// TODO: remove these arguments
final LatinIME.UIHandler handler) {
final boolean shouldFinishComposition = mConnection.hasSelection()
@@ -1988,7 +2146,7 @@ public final class InputLogic {
}
public void getSuggestedWords(final SettingsValues settingsValues,
- final ProximityInfo proximityInfo, final int keyboardShiftMode, final int sessionId,
+ final ProximityInfo proximityInfo, final int keyboardShiftMode, final int inputStyle,
final int sequenceNumber, final OnGetSuggestedWordsCallback callback) {
mWordComposer.adviseCapitalizedModeBeforeFetchingSuggestions(
getActualCapsMode(settingsValues, keyboardShiftMode));
@@ -2004,6 +2162,124 @@ public final class InputLogic {
settingsValues.mPhraseGestureEnabled,
settingsValues.mAdditionalFeaturesSettingValues),
settingsValues.mAutoCorrectionEnabledPerUserSettings,
- sessionId, sequenceNumber, callback);
+ inputStyle, sequenceNumber, callback);
+ }
+
+ /**
+ * Used as an injection point for each call of
+ * {@link RichInputConnection#setComposingText(CharSequence, int)}.
+ *
+ * <p>Currently using this method is optional and you can still directly call
+ * {@link RichInputConnection#setComposingText(CharSequence, int)}, but it is recommended to
+ * use this method whenever possible to optimize the behavior of {@link TextDecorator}.<p>
+ * <p>TODO: Should we move this mechanism to {@link RichInputConnection}?</p>
+ *
+ * @param newComposingText the composing text to be set
+ * @param newCursorPosition the new cursor position
+ */
+ private void setComposingTextInternal(final CharSequence newComposingText,
+ final int newCursorPosition) {
+ setComposingTextInternalWithBackgroundColor(newComposingText, newCursorPosition,
+ Color.TRANSPARENT, newComposingText.length());
+ }
+
+ /**
+ * Equivalent to {@link #setComposingTextInternal(CharSequence, int)} except that this method
+ * allows to set {@link BackgroundColorSpan} to the composing text with the given color.
+ *
+ * <p>TODO: Currently the background color is exclusive with the black underline, which is
+ * automatically added by the framework. We need to change the framework if we need to have both
+ * of them at the same time.</p>
+ * <p>TODO: Should we move this method to {@link RichInputConnection}?</p>
+ *
+ * @param newComposingText the composing text to be set
+ * @param newCursorPosition the new cursor position
+ * @param backgroundColor the background color to be set to the composing text. Set
+ * {@link Color#TRANSPARENT} to disable the background color.
+ * @param coloredTextLength the length of text, in Java chars, which should be rendered with
+ * the given background color.
+ */
+ private void setComposingTextInternalWithBackgroundColor(final CharSequence newComposingText,
+ final int newCursorPosition, final int backgroundColor, final int coloredTextLength) {
+ final CharSequence composingTextToBeSet;
+ if (backgroundColor == Color.TRANSPARENT) {
+ composingTextToBeSet = newComposingText;
+ } else {
+ final SpannableString spannable = new SpannableString(newComposingText);
+ final BackgroundColorSpan backgroundColorSpan =
+ new BackgroundColorSpan(backgroundColor);
+ final int spanLength = Math.min(coloredTextLength, spannable.length());
+ spannable.setSpan(backgroundColorSpan, 0, spanLength,
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
+ composingTextToBeSet = spannable;
+ }
+ mConnection.setComposingText(composingTextToBeSet, newCursorPosition);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // Following methods are tentatively placed in this class for the integration with
+ // TextDecorator.
+ // TODO: Decouple things that are not related to the input logic.
+ //////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Sets the UI operator for {@link TextDecorator}.
+ * @param uiOperator the UI operator which should be associated with {@link TextDecorator}.
+ */
+ public void setTextDecoratorUi(final TextDecoratorUiOperator uiOperator) {
+ mTextDecorator.setUiOperator(uiOperator);
+ }
+
+ /**
+ * Must be called from {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)} is
+ * called.
+ * @param info The wrapper object with which we can access cursor/anchor info.
+ */
+ public void onUpdateCursorAnchorInfo(final CursorAnchorInfoCompatWrapper info) {
+ mTextDecorator.onUpdateCursorAnchorInfo(info);
+ }
+
+ /**
+ * Must be called when {@link InputMethodService#updateFullscreenMode} is called.
+ * @param isFullscreen {@code true} if the input method is in full-screen mode.
+ */
+ public void onUpdateFullscreenMode(final boolean isFullscreen) {
+ mTextDecorator.notifyFullScreenMode(isFullscreen);
+ }
+
+ /**
+ * Must be called from {@link LatinIME#addWordToUserDictionary(String)}.
+ */
+ public void onAddWordToUserDictionary() {
+ mConnection.removeBackgroundColorFromHighlightedTextIfNecessary();
+ mTextDecorator.reset();
+ }
+
+ /**
+ * Returns whether the add to dictionary indicator should be shown or not.
+ * @param lastComposedWord the last composed word information.
+ * @param settingsValues the current settings value.
+ * @return {@code true} if the commit indicator should be shown.
+ */
+ private boolean shouldShowAddToDictionaryForTypedWord(final LastComposedWord lastComposedWord,
+ final SettingsValues settingsValues) {
+ if (!mConnection.isCursorAnchorInfoMonitorEnabled()) {
+ // We cannot help in this case because we are heavily relying on this new API.
+ return false;
+ }
+ if (!settingsValues.mShouldShowUiToAcceptTypedWord) {
+ return false;
+ }
+ if (TextUtils.isEmpty(lastComposedWord.mTypedWord)) {
+ return false;
+ }
+ if (TextUtils.equals(lastComposedWord.mTypedWord, lastComposedWord.mCommittedWord)) {
+ return false;
+ }
+ if (!mDictionaryFacilitator.isUserDictionaryEnabled()) {
+ return false;
+ }
+ return !mDictionaryFacilitator.isValidWord(lastComposedWord.mTypedWord,
+ true /* ignoreCase */);
}
}
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java
index 9dbe2c38b..c6f83d0b9 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java
@@ -96,7 +96,7 @@ class InputLogicHandler implements Handler.Callback {
public boolean handleMessage(final Message msg) {
switch (msg.what) {
case MSG_GET_SUGGESTED_WORDS:
- mLatinIME.getSuggestedWords(msg.arg1 /* sessionId */,
+ mLatinIME.getSuggestedWords(msg.arg1 /* inputStyle */,
msg.arg2 /* sequenceNumber */, (OnGetSuggestedWordsCallback) msg.obj);
break;
}
@@ -134,7 +134,8 @@ class InputLogicHandler implements Handler.Callback {
return;
}
mInputLogic.mWordComposer.setBatchInputPointers(batchPointers);
- getSuggestedWords(Suggest.SESSION_GESTURE, sequenceNumber,
+ getSuggestedWords(isTailBatchInput ? SuggestedWords.INPUT_STYLE_TAIL_BATCH
+ : SuggestedWords.INPUT_STYLE_UPDATE_BATCH, sequenceNumber,
new OnGetSuggestedWordsCallback() {
@Override
public void onGetSuggestedWords(SuggestedWords suggestedWords) {
@@ -205,9 +206,9 @@ class InputLogicHandler implements Handler.Callback {
updateBatchInput(batchPointers, sequenceNumber, true /* isTailBatchInput */);
}
- public void getSuggestedWords(final int sessionId, final int sequenceNumber,
+ public void getSuggestedWords(final int inputStyle, final int sequenceNumber,
final OnGetSuggestedWordsCallback callback) {
mNonUIThreadHandler.obtainMessage(
- MSG_GET_SUGGESTED_WORDS, sessionId, sequenceNumber, callback).sendToTarget();
+ MSG_GET_SUGGESTED_WORDS, inputStyle, sequenceNumber, callback).sendToTarget();
}
}
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
index aac40940b..331f85e0e 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
@@ -138,6 +138,7 @@ public class PersonalizationHelper {
final File filesDir = context.getFilesDir();
if (filesDir == null) {
Log.e(TAG, "context.getFilesDir() returned null.");
+ return;
}
if (!FileUtils.deleteFilteredFiles(filesDir, new DictFilter(dictNamePrefix))) {
Log.e(TAG, "Cannot remove all existing dictionary files. filesDir: "
diff --git a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
index 8e027e4f9..34d4d4ed7 100644
--- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
@@ -62,8 +62,8 @@ public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBas
final PrevWordsInfo prevWordsInfo, final String word, final boolean isValid,
final int timestamp, final DistracterFilter distracterFilter) {
final CharSequence prevWord = prevWordsInfo.mPrevWordsInfo[0].mWord;
- if (word.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH ||
- (prevWord != null && prevWord.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH)) {
+ if (word.length() > Constants.DICTIONARY_MAX_WORD_LENGTH ||
+ (prevWord != null && prevWord.length() > Constants.DICTIONARY_MAX_WORD_LENGTH)) {
return;
}
final int frequency = isValid ?
diff --git a/java/src/com/android/inputmethod/latin/settings/AdvancedSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/AdvancedSettingsFragment.java
new file mode 100644
index 000000000..00f2c73dd
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/settings/AdvancedSettingsFragment.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.settings;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.TwoStatePreference;
+
+import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.define.ProductionFlags;
+import com.android.inputmethod.latin.setup.LauncherIconVisibilityManager;
+
+/**
+ * "Advanced" settings sub screen.
+ *
+ * This settings sub screen handles the following advanced preferences.
+ * - Key popup dismiss delay
+ * - Keypress vibration duration
+ * - Keypress sound volume
+ * - Show app icon
+ * - Improve keyboard
+ * - Debug settings
+ */
+public final class AdvancedSettingsFragment extends SubScreenFragment {
+ @Override
+ public void onCreate(final Bundle icicle) {
+ super.onCreate(icicle);
+ addPreferencesFromResource(R.xml.prefs_screen_advanced);
+
+ final Resources res = getResources();
+ final Context context = getActivity();
+
+ // When we are called from the Settings application but we are not already running, some
+ // singleton and utility classes may not have been initialized. We have to call
+ // initialization method of these classes here. See {@link LatinIME#onCreate()}.
+ AudioAndHapticFeedbackManager.init(context);
+
+ final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
+
+ if (!Settings.isInternal(prefs)) {
+ removePreference(Settings.SCREEN_DEBUG);
+ }
+
+ if (!AudioAndHapticFeedbackManager.getInstance().hasVibrator()) {
+ removePreference(Settings.PREF_VIBRATION_DURATION_SETTINGS);
+ }
+
+ // TODO: consolidate key preview dismiss delay with the key preview animation parameters.
+ if (!Settings.readFromBuildConfigIfToShowKeyPreviewPopupOption(res)) {
+ removePreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
+ } else {
+ // TODO: Cleanup this setup.
+ final ListPreference keyPreviewPopupDismissDelay =
+ (ListPreference) findPreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
+ final String popupDismissDelayDefaultValue = Integer.toString(res.getInteger(
+ R.integer.config_key_preview_linger_timeout));
+ keyPreviewPopupDismissDelay.setEntries(new String[] {
+ res.getString(R.string.key_preview_popup_dismiss_no_delay),
+ res.getString(R.string.key_preview_popup_dismiss_default_delay),
+ });
+ keyPreviewPopupDismissDelay.setEntryValues(new String[] {
+ "0",
+ popupDismissDelayDefaultValue
+ });
+ if (null == keyPreviewPopupDismissDelay.getValue()) {
+ keyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue);
+ }
+ keyPreviewPopupDismissDelay.setEnabled(
+ Settings.readKeyPreviewPopupEnabled(prefs, res));
+ }
+
+ if (!res.getBoolean(R.bool.config_setup_wizard_available)) {
+ removePreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON);
+ }
+
+ if (ProductionFlags.IS_METRICS_LOGGING_SUPPORTED) {
+ final Preference enableMetricsLogging =
+ findPreference(Settings.PREF_ENABLE_METRICS_LOGGING);
+ if (enableMetricsLogging != null) {
+ final int applicationLabelRes = context.getApplicationInfo().labelRes;
+ final String applicationName = res.getString(applicationLabelRes);
+ final String enableMetricsLoggingTitle = res.getString(
+ R.string.enable_metrics_logging, applicationName);
+ enableMetricsLogging.setTitle(enableMetricsLoggingTitle);
+ }
+ } else {
+ removePreference(Settings.PREF_ENABLE_METRICS_LOGGING);
+ }
+
+ setupKeypressVibrationDurationSettings();
+ setupKeypressSoundVolumeSettings();
+ refreshEnablingsOfKeypressSoundAndVibrationSettings();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
+ final TwoStatePreference showSetupWizardIcon =
+ (TwoStatePreference)findPreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON);
+ if (showSetupWizardIcon != null) {
+ showSetupWizardIcon.setChecked(Settings.readShowSetupWizardIcon(prefs, getActivity()));
+ }
+ updateListPreferenceSummaryToCurrentValue(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
+ final Resources res = getResources();
+ if (key.equals(Settings.PREF_POPUP_ON)) {
+ setPreferenceEnabled(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY,
+ Settings.readKeyPreviewPopupEnabled(prefs, res));
+ } else if (key.equals(Settings.PREF_SHOW_SETUP_WIZARD_ICON)) {
+ LauncherIconVisibilityManager.updateSetupWizardIconVisibility(getActivity());
+ }
+ updateListPreferenceSummaryToCurrentValue(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
+ refreshEnablingsOfKeypressSoundAndVibrationSettings();
+ }
+
+ private void refreshEnablingsOfKeypressSoundAndVibrationSettings() {
+ final SharedPreferences prefs = getSharedPreferences();
+ final Resources res = getResources();
+ setPreferenceEnabled(Settings.PREF_VIBRATION_DURATION_SETTINGS,
+ Settings.readVibrationEnabled(prefs, res));
+ setPreferenceEnabled(Settings.PREF_KEYPRESS_SOUND_VOLUME,
+ Settings.readKeypressSoundEnabled(prefs, res));
+ }
+
+ private void setupKeypressVibrationDurationSettings() {
+ final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(
+ Settings.PREF_VIBRATION_DURATION_SETTINGS);
+ if (pref == null) {
+ return;
+ }
+ final SharedPreferences prefs = getSharedPreferences();
+ final Resources res = getResources();
+ pref.setInterface(new SeekBarDialogPreference.ValueProxy() {
+ @Override
+ public void writeValue(final int value, final String key) {
+ prefs.edit().putInt(key, value).apply();
+ }
+
+ @Override
+ public void writeDefaultValue(final String key) {
+ prefs.edit().remove(key).apply();
+ }
+
+ @Override
+ public int readValue(final String key) {
+ return Settings.readKeypressVibrationDuration(prefs, res);
+ }
+
+ @Override
+ public int readDefaultValue(final String key) {
+ return Settings.readDefaultKeypressVibrationDuration(res);
+ }
+
+ @Override
+ public void feedbackValue(final int value) {
+ AudioAndHapticFeedbackManager.getInstance().vibrate(value);
+ }
+
+ @Override
+ public String getValueText(final int value) {
+ if (value < 0) {
+ return res.getString(R.string.settings_system_default);
+ }
+ return res.getString(R.string.abbreviation_unit_milliseconds, value);
+ }
+ });
+ }
+
+ private void setupKeypressSoundVolumeSettings() {
+ final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(
+ Settings.PREF_KEYPRESS_SOUND_VOLUME);
+ if (pref == null) {
+ return;
+ }
+ final SharedPreferences prefs = getSharedPreferences();
+ final Resources res = getResources();
+ final AudioManager am = (AudioManager)getActivity().getSystemService(Context.AUDIO_SERVICE);
+ pref.setInterface(new SeekBarDialogPreference.ValueProxy() {
+ private static final float PERCENTAGE_FLOAT = 100.0f;
+
+ private float getValueFromPercentage(final int percentage) {
+ return percentage / PERCENTAGE_FLOAT;
+ }
+
+ private int getPercentageFromValue(final float floatValue) {
+ return (int)(floatValue * PERCENTAGE_FLOAT);
+ }
+
+ @Override
+ public void writeValue(final int value, final String key) {
+ prefs.edit().putFloat(key, getValueFromPercentage(value)).apply();
+ }
+
+ @Override
+ public void writeDefaultValue(final String key) {
+ prefs.edit().remove(key).apply();
+ }
+
+ @Override
+ public int readValue(final String key) {
+ return getPercentageFromValue(Settings.readKeypressSoundVolume(prefs, res));
+ }
+
+ @Override
+ public int readDefaultValue(final String key) {
+ return getPercentageFromValue(Settings.readDefaultKeypressSoundVolume(res));
+ }
+
+ @Override
+ public String getValueText(final int value) {
+ if (value < 0) {
+ return res.getString(R.string.settings_system_default);
+ }
+ return Integer.toString(value);
+ }
+
+ @Override
+ public void feedbackValue(final int value) {
+ am.playSoundEffect(
+ AudioManager.FX_KEYPRESS_STANDARD, getValueFromPercentage(value));
+ }
+ });
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/settings/AppearanceSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/AppearanceSettingsFragment.java
new file mode 100644
index 000000000..f5e4d33a2
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/settings/AppearanceSettingsFragment.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.settings;
+
+import android.os.Bundle;
+
+import com.android.inputmethod.latin.R;
+
+
+/**
+ * "Appearance" settings sub screen.
+ */
+public final class AppearanceSettingsFragment extends SubScreenFragment {
+ @Override
+ public void onCreate(final Bundle icicle) {
+ super.onCreate(icicle);
+ addPreferencesFromResource(R.xml.prefs_screen_appearance);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ CustomInputStyleSettingsFragment.updateCustomInputStylesSummary(
+ findPreference(Settings.PREF_CUSTOM_INPUT_STYLES));
+ ThemeSettingsFragment.updateKeyboardThemeSummary(findPreference(Settings.SCREEN_THEME));
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/settings/CorrectionSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/CorrectionSettingsFragment.java
new file mode 100644
index 000000000..ec29a7eb2
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/settings/CorrectionSettingsFragment.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.settings;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Build;
+import android.os.Bundle;
+import android.preference.ListPreference;
+import android.preference.Preference;
+
+import com.android.inputmethod.dictionarypack.DictionarySettingsActivity;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.userdictionary.UserDictionaryList;
+import com.android.inputmethod.latin.userdictionary.UserDictionarySettings;
+
+import java.util.TreeSet;
+
+/**
+ * "Text correction" settings sub screen.
+ *
+ * This settings sub screen handles the following text correction preferences.
+ * - Personal dictionary
+ * - Add-on dictionaries
+ * - Block offensive words
+ * - Auto-correction
+ * - Show correction suggestions
+ * - Personalized suggestions
+ * - Suggest Contact names
+ * - Next-word suggestions
+ */
+public final class CorrectionSettingsFragment extends SubScreenFragment {
+ private static final boolean DBG_USE_INTERNAL_PERSONAL_DICTIONARY_SETTINGS = false;
+ private static final boolean USE_INTERNAL_PERSONAL_DICTIONARY_SETTIGS =
+ DBG_USE_INTERNAL_PERSONAL_DICTIONARY_SETTINGS
+ || Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2;
+
+ @Override
+ public void onCreate(final Bundle icicle) {
+ super.onCreate(icicle);
+ addPreferencesFromResource(R.xml.prefs_screen_correction);
+
+ final Context context = getActivity();
+ final PackageManager pm = context.getPackageManager();
+
+ ensureConsistencyOfAutoCorrectionSettings();
+
+ final Preference dictionaryLink = findPreference(Settings.PREF_CONFIGURE_DICTIONARIES_KEY);
+ final Intent intent = dictionaryLink.getIntent();
+ intent.setClassName(context.getPackageName(), DictionarySettingsActivity.class.getName());
+ final int number = pm.queryIntentActivities(intent, 0).size();
+ if (0 >= number) {
+ removePreference(Settings.PREF_CONFIGURE_DICTIONARIES_KEY);
+ }
+
+ final Preference editPersonalDictionary =
+ findPreference(Settings.PREF_EDIT_PERSONAL_DICTIONARY);
+ final Intent editPersonalDictionaryIntent = editPersonalDictionary.getIntent();
+ final ResolveInfo ri = USE_INTERNAL_PERSONAL_DICTIONARY_SETTIGS ? null
+ : pm.resolveActivity(
+ editPersonalDictionaryIntent, PackageManager.MATCH_DEFAULT_ONLY);
+ if (ri == null) {
+ overwriteUserDictionaryPreference(editPersonalDictionary);
+ }
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
+ ensureConsistencyOfAutoCorrectionSettings();
+ }
+
+ private void ensureConsistencyOfAutoCorrectionSettings() {
+ final String autoCorrectionOff = getString(
+ R.string.auto_correction_threshold_mode_index_off);
+ final ListPreference autoCorrectionThresholdPref = (ListPreference)findPreference(
+ Settings.PREF_AUTO_CORRECTION_THRESHOLD);
+ final String currentSetting = autoCorrectionThresholdPref.getValue();
+ setPreferenceEnabled(
+ Settings.PREF_BIGRAM_PREDICTIONS, !currentSetting.equals(autoCorrectionOff));
+ }
+
+ private void overwriteUserDictionaryPreference(final Preference userDictionaryPreference) {
+ final Activity activity = getActivity();
+ final TreeSet<String> localeList = UserDictionaryList.getUserDictionaryLocalesSet(activity);
+ if (null == localeList) {
+ // The locale list is null if and only if the user dictionary service is
+ // not present or disabled. In this case we need to remove the preference.
+ getPreferenceScreen().removePreference(userDictionaryPreference);
+ } else if (localeList.size() <= 1) {
+ userDictionaryPreference.setFragment(UserDictionarySettings.class.getName());
+ // If the size of localeList is 0, we don't set the locale parameter in the
+ // extras. This will be interpreted by the UserDictionarySettings class as
+ // meaning "the current locale".
+ // Note that with the current code for UserDictionaryList#getUserDictionaryLocalesSet()
+ // the locale list always has at least one element, since it always includes the current
+ // locale explicitly. @see UserDictionaryList.getUserDictionaryLocalesSet().
+ if (localeList.size() == 1) {
+ final String locale = (String)localeList.toArray()[0];
+ userDictionaryPreference.getExtras().putString("locale", locale);
+ }
+ } else {
+ userDictionaryPreference.setFragment(UserDictionaryList.class.getName());
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java
index 21f2afd01..9bc398654 100644
--- a/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java
@@ -30,11 +30,15 @@ import android.preference.DialogPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
+import android.support.v4.view.ViewCompat;
+import android.text.TextUtils;
import android.util.Pair;
+import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
+import android.view.ViewGroup;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
import android.widget.ArrayAdapter;
@@ -43,6 +47,7 @@ import android.widget.SpinnerAdapter;
import android.widget.Toast;
import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
+import com.android.inputmethod.compat.ViewCompatUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.RichInputMethodManager;
import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
@@ -63,7 +68,6 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
private AlertDialog mSubtypeEnablerNotificationDialog;
private String mSubtypePreferenceKeyForSubtypeEnabler;
- private static final int MENU_ADD_SUBTYPE = Menu.FIRST;
private static final String KEY_IS_ADDING_NEW_SUBTYPE = "is_adding_new_subtype";
private static final String KEY_IS_SUBTYPE_ENABLER_NOTIFICATION_DIALOG_OPEN =
"is_subtype_enabler_notification_dialog_open";
@@ -234,6 +238,12 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
mSubtypeLocaleSpinner.setAdapter(mProxy.getSubtypeLocaleAdapter());
mKeyboardLayoutSetSpinner = (Spinner) v.findViewById(R.id.keyboard_layout_set_spinner);
mKeyboardLayoutSetSpinner.setAdapter(mProxy.getKeyboardLayoutSetAdapter());
+ // All keyboard layout names are in the Latin script and thus left to right. That means
+ // the view would align them to the left even if the system locale is RTL, but that
+ // would look strange. To fix this, we align them to the view's start, which will be
+ // natural for any direction.
+ ViewCompatUtils.setTextAlignment(
+ mKeyboardLayoutSetSpinner, ViewCompatUtils.TEXT_ALIGNMENT_VIEW_START);
return v;
}
@@ -387,6 +397,25 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
// Empty constructor for fragment generation.
}
+ static void updateCustomInputStylesSummary(final Preference pref) {
+ // When we are called from the Settings application but we are not already running, some
+ // singleton and utility classes may not have been initialized. We have to call
+ // initialization method of these classes here. See {@link LatinIME#onCreate()}.
+ SubtypeLocaleUtils.init(pref.getContext());
+
+ final Resources res = pref.getContext().getResources();
+ final SharedPreferences prefs = pref.getSharedPreferences();
+ final String prefSubtype = Settings.readPrefAdditionalSubtypes(prefs, res);
+ final InputMethodSubtype[] subtypes =
+ AdditionalSubtypeUtils.createAdditionalSubtypesArray(prefSubtype);
+ final ArrayList<String> subtypeNames = new ArrayList<>();
+ for (final InputMethodSubtype subtype : subtypes) {
+ subtypeNames.add(SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype));
+ }
+ // TODO: A delimiter of custom input styles should be localized.
+ pref.setSummary(TextUtils.join(", ", subtypeNames));
+ }
+
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -399,6 +428,16 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
}
@Override
+ public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
+ final Bundle savedInstanceState) {
+ final View view = super.onCreateView(inflater, container, savedInstanceState);
+ // For correct display in RTL locales, we need to set the layout direction of the
+ // fragment's top view.
+ ViewCompat.setLayoutDirection(view, ViewCompat.LAYOUT_DIRECTION_LOCALE);
+ return view;
+ }
+
+ @Override
public void onActivityCreated(final Bundle savedInstanceState) {
final Context context = getActivity();
mSubtypeLocaleAdapter = new SubtypeLocaleAdapter(context);
@@ -423,7 +462,7 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
KEY_SUBTYPE_FOR_SUBTYPE_ENABLER);
final SubtypePreference subtypePref = (SubtypePreference)findPreference(
mSubtypePreferenceKeyForSubtypeEnabler);
- mSubtypeEnablerNotificationDialog = createDialog(subtypePref);
+ mSubtypeEnablerNotificationDialog = createDialog();
mSubtypeEnablerNotificationDialog.show();
}
}
@@ -477,7 +516,7 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
if (findDuplicatedSubtype(subtype) == null) {
mRichImm.setAdditionalInputMethodSubtypes(getSubtypes());
mSubtypePreferenceKeyForSubtypeEnabler = subtypePref.getKey();
- mSubtypeEnablerNotificationDialog = createDialog(subtypePref);
+ mSubtypeEnablerNotificationDialog = createDialog();
mSubtypeEnablerNotificationDialog.show();
return;
}
@@ -514,7 +553,7 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
localeString, keyboardLayoutSetName);
}
- private AlertDialog createDialog(final SubtypePreference subtypePref) {
+ private AlertDialog createDialog() {
final AlertDialog.Builder builder = new AlertDialog.Builder(
DialogUtils.getPlatformDialogThemeContext(getActivity()));
builder.setTitle(R.string.custom_input_styles_title)
@@ -581,14 +620,13 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
@Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
- final MenuItem addSubtypeMenu = menu.add(0, MENU_ADD_SUBTYPE, 0, R.string.add_style);
- addSubtypeMenu.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ inflater.inflate(R.menu.add_style, menu);
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
final int itemId = item.getItemId();
- if (itemId == MENU_ADD_SUBTYPE) {
+ if (itemId == R.id.action_add_style) {
final SubtypePreference newSubtype =
SubtypePreference.newIncompleteSubtypePreference(getActivity(), mSubtypeProxy);
getPreferenceScreen().addPreference(newSubtype);
diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
index e4271adac..48f4c758c 100644
--- a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
+++ b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
@@ -16,283 +16,31 @@
package com.android.inputmethod.latin.settings;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.os.Process;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceClickListener;
-import android.preference.PreferenceFragment;
-import android.preference.PreferenceGroup;
-import android.preference.PreferenceScreen;
-import android.preference.TwoStatePreference;
-
-import com.android.inputmethod.latin.DictionaryDumpBroadcastReceiver;
-import com.android.inputmethod.latin.DictionaryFacilitator;
-import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.debug.ExternalDictionaryGetterForDebug;
-import com.android.inputmethod.latin.utils.ApplicationUtils;
-import com.android.inputmethod.latin.utils.ResourceUtils;
-
-public final class DebugSettings extends PreferenceFragment
- implements SharedPreferences.OnSharedPreferenceChangeListener {
-
+public final class DebugSettings {
public static final String PREF_DEBUG_MODE = "debug_mode";
public static final String PREF_FORCE_NON_DISTINCT_MULTITOUCH = "force_non_distinct_multitouch";
- public static final String PREF_KEY_PREVIEW_SHOW_UP_START_SCALE =
- "pref_key_preview_show_up_start_scale";
- public static final String PREF_KEY_PREVIEW_DISMISS_END_SCALE =
- "pref_key_preview_dismiss_end_scale";
+ public static final String PREF_FORCE_PHYSICAL_KEYBOARD_SPECIAL_KEY =
+ "force_physical_keyboard_special_key";
+ public static final String PREF_SHOW_UI_TO_ACCEPT_TYPED_WORD =
+ "pref_show_ui_to_accept_typed_word";
+ public static final String PREF_HAS_CUSTOM_KEY_PREVIEW_ANIMATION_PARAMS =
+ "pref_has_custom_key_preview_animation_params";
+ public static final String PREF_KEY_PREVIEW_SHOW_UP_START_X_SCALE =
+ "pref_key_preview_show_up_start_x_scale";
+ public static final String PREF_KEY_PREVIEW_SHOW_UP_START_Y_SCALE =
+ "pref_key_preview_show_up_start_y_scale";
+ public static final String PREF_KEY_PREVIEW_DISMISS_END_X_SCALE =
+ "pref_key_preview_dismiss_end_x_scale";
+ public static final String PREF_KEY_PREVIEW_DISMISS_END_Y_SCALE =
+ "pref_key_preview_dismiss_end_y_scale";
public static final String PREF_KEY_PREVIEW_SHOW_UP_DURATION =
"pref_key_preview_show_up_duration";
public static final String PREF_KEY_PREVIEW_DISMISS_DURATION =
"pref_key_preview_dismiss_duration";
- private static final String PREF_READ_EXTERNAL_DICTIONARY = "read_external_dictionary";
- private static final String PREF_KEY_DUMP_DICTS = "pref_key_dump_dictionaries";
- private static final String PREF_KEY_DUMP_DICT_PREFIX = "pref_key_dump_dictionaries";
- private static final String DICT_NAME_KEY_FOR_EXTRAS = "dict_name";
public static final String PREF_SLIDING_KEY_INPUT_PREVIEW = "pref_sliding_key_input_preview";
public static final String PREF_KEY_LONGPRESS_TIMEOUT = "pref_key_longpress_timeout";
- private boolean mServiceNeedsRestart = false;
- private TwoStatePreference mDebugMode;
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- addPreferencesFromResource(R.xml.prefs_screen_debug);
- TwoStatePreferenceHelper.replaceCheckBoxPreferencesBySwitchPreferences(
- getPreferenceScreen());
- SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
- prefs.registerOnSharedPreferenceChangeListener(this);
-
- final PreferenceScreen readExternalDictionary =
- (PreferenceScreen) findPreference(PREF_READ_EXTERNAL_DICTIONARY);
- if (null != readExternalDictionary) {
- readExternalDictionary.setOnPreferenceClickListener(
- new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(final Preference arg0) {
- ExternalDictionaryGetterForDebug.chooseAndInstallDictionary(
- getActivity());
- mServiceNeedsRestart = true;
- return true;
- }
- });
- }
-
- final PreferenceGroup dictDumpPreferenceGroup =
- (PreferenceGroup)findPreference(PREF_KEY_DUMP_DICTS);
- final OnPreferenceClickListener dictDumpPrefClickListener =
- new DictDumpPrefClickListener(this);
- for (final String dictName : DictionaryFacilitator.DICT_TYPE_TO_CLASS.keySet()) {
- final Preference preference = new Preference(getActivity());
- preference.setKey(PREF_KEY_DUMP_DICT_PREFIX + dictName);
- preference.setTitle("Dump " + dictName + " dictionary");
- preference.setOnPreferenceClickListener(dictDumpPrefClickListener);
- preference.getExtras().putString(DICT_NAME_KEY_FOR_EXTRAS, dictName);
- dictDumpPreferenceGroup.addPreference(preference);
- }
- final Resources res = getResources();
- setupKeyLongpressTimeoutSettings(prefs, res);
- setupKeyPreviewAnimationDuration(prefs, res, PREF_KEY_PREVIEW_SHOW_UP_DURATION,
- res.getInteger(R.integer.config_key_preview_show_up_duration));
- setupKeyPreviewAnimationDuration(prefs, res, PREF_KEY_PREVIEW_DISMISS_DURATION,
- res.getInteger(R.integer.config_key_preview_dismiss_duration));
- setupKeyPreviewAnimationScale(prefs, res, PREF_KEY_PREVIEW_SHOW_UP_START_SCALE,
- ResourceUtils.getFloatFromFraction(
- res, R.fraction.config_key_preview_show_up_start_scale));
- setupKeyPreviewAnimationScale(prefs, res, PREF_KEY_PREVIEW_DISMISS_END_SCALE,
- ResourceUtils.getFloatFromFraction(
- res, R.fraction.config_key_preview_dismiss_end_scale));
-
- mServiceNeedsRestart = false;
- mDebugMode = (TwoStatePreference) findPreference(PREF_DEBUG_MODE);
- updateDebugMode();
- }
-
- private static class DictDumpPrefClickListener implements OnPreferenceClickListener {
- final PreferenceFragment mPreferenceFragment;
-
- public DictDumpPrefClickListener(final PreferenceFragment preferenceFragment) {
- mPreferenceFragment = preferenceFragment;
- }
-
- @Override
- public boolean onPreferenceClick(final Preference arg0) {
- final String dictName = arg0.getExtras().getString(DICT_NAME_KEY_FOR_EXTRAS);
- if (dictName != null) {
- final Intent intent =
- new Intent(DictionaryDumpBroadcastReceiver.DICTIONARY_DUMP_INTENT_ACTION);
- intent.putExtra(DictionaryDumpBroadcastReceiver.DICTIONARY_NAME_KEY, dictName);
- mPreferenceFragment.getActivity().sendBroadcast(intent);
- }
- return true;
- }
- }
-
- @Override
- public void onStop() {
- super.onStop();
- if (mServiceNeedsRestart) {
- Process.killProcess(Process.myPid());
- }
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
- if (key.equals(PREF_DEBUG_MODE) && mDebugMode != null) {
- mDebugMode.setChecked(prefs.getBoolean(PREF_DEBUG_MODE, false));
- updateDebugMode();
- mServiceNeedsRestart = true;
- return;
- }
- if (key.equals(PREF_FORCE_NON_DISTINCT_MULTITOUCH)) {
- mServiceNeedsRestart = true;
- return;
- }
- }
-
- private void updateDebugMode() {
- if (mDebugMode == null) {
- return;
- }
- boolean isDebugMode = mDebugMode.isChecked();
- final String version = getResources().getString(
- R.string.version_text, ApplicationUtils.getVersionName(getActivity()));
- if (!isDebugMode) {
- mDebugMode.setTitle(version);
- mDebugMode.setSummary("");
- } else {
- mDebugMode.setTitle(getResources().getString(R.string.prefs_debug_mode));
- mDebugMode.setSummary(version);
- }
- }
-
- private void setupKeyLongpressTimeoutSettings(final SharedPreferences sp,
- final Resources res) {
- final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(
- PREF_KEY_LONGPRESS_TIMEOUT);
- if (pref == null) {
- return;
- }
- pref.setInterface(new SeekBarDialogPreference.ValueProxy() {
- @Override
- public void writeValue(final int value, final String key) {
- sp.edit().putInt(key, value).apply();
- }
-
- @Override
- public void writeDefaultValue(final String key) {
- sp.edit().remove(key).apply();
- }
-
- @Override
- public int readValue(final String key) {
- return Settings.readKeyLongpressTimeout(sp, res);
- }
-
- @Override
- public int readDefaultValue(final String key) {
- return Settings.readDefaultKeyLongpressTimeout(res);
- }
-
- @Override
- public String getValueText(final int value) {
- return res.getString(R.string.abbreviation_unit_milliseconds, value);
- }
-
- @Override
- public void feedbackValue(final int value) {}
- });
- }
-
- private void setupKeyPreviewAnimationScale(final SharedPreferences sp, final Resources res,
- final String prefKey, final float defaultValue) {
- final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(prefKey);
- if (pref == null) {
- return;
- }
- pref.setInterface(new SeekBarDialogPreference.ValueProxy() {
- private static final float PERCENTAGE_FLOAT = 100.0f;
-
- private float getValueFromPercentage(final int percentage) {
- return percentage / PERCENTAGE_FLOAT;
- }
-
- private int getPercentageFromValue(final float floatValue) {
- return (int)(floatValue * PERCENTAGE_FLOAT);
- }
-
- @Override
- public void writeValue(final int value, final String key) {
- sp.edit().putFloat(key, getValueFromPercentage(value)).apply();
- }
-
- @Override
- public void writeDefaultValue(final String key) {
- sp.edit().remove(key).apply();
- }
-
- @Override
- public int readValue(final String key) {
- return getPercentageFromValue(
- Settings.readKeyPreviewAnimationScale(sp, key, defaultValue));
- }
-
- @Override
- public int readDefaultValue(final String key) {
- return getPercentageFromValue(defaultValue);
- }
-
- @Override
- public String getValueText(final int value) {
- if (value < 0) {
- return res.getString(R.string.settings_system_default);
- }
- return String.format("%d%%", value);
- }
-
- @Override
- public void feedbackValue(final int value) {}
- });
- }
-
- private void setupKeyPreviewAnimationDuration(final SharedPreferences sp, final Resources res,
- final String prefKey, final int defaultValue) {
- final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(prefKey);
- if (pref == null) {
- return;
- }
- pref.setInterface(new SeekBarDialogPreference.ValueProxy() {
- @Override
- public void writeValue(final int value, final String key) {
- sp.edit().putInt(key, value).apply();
- }
-
- @Override
- public void writeDefaultValue(final String key) {
- sp.edit().remove(key).apply();
- }
-
- @Override
- public int readValue(final String key) {
- return Settings.readKeyPreviewAnimationDuration(sp, key, defaultValue);
- }
-
- @Override
- public int readDefaultValue(final String key) {
- return defaultValue;
- }
-
- @Override
- public String getValueText(final int value) {
- return res.getString(R.string.abbreviation_unit_milliseconds, value);
- }
-
- @Override
- public void feedbackValue(final int value) {}
- });
+ private DebugSettings() {
+ // This class is not publicly instantiable.
}
}
diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java
new file mode 100644
index 000000000..5640e2039
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.settings;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Process;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceGroup;
+import android.preference.TwoStatePreference;
+
+import com.android.inputmethod.latin.DictionaryDumpBroadcastReceiver;
+import com.android.inputmethod.latin.DictionaryFacilitator;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.debug.ExternalDictionaryGetterForDebug;
+import com.android.inputmethod.latin.utils.ApplicationUtils;
+import com.android.inputmethod.latin.utils.ResourceUtils;
+
+import java.util.Locale;
+
+/**
+ * "Debug mode" settings sub screen.
+ *
+ * This settings sub screen handles a several preference options for debugging.
+ */
+public final class DebugSettingsFragment extends SubScreenFragment
+ implements OnPreferenceClickListener {
+ private static final String PREF_READ_EXTERNAL_DICTIONARY = "read_external_dictionary";
+ private static final String PREF_KEY_DUMP_DICTS = "pref_key_dump_dictionaries";
+ private static final String PREF_KEY_DUMP_DICT_PREFIX = "pref_key_dump_dictionaries";
+
+ private boolean mServiceNeedsRestart = false;
+ private Preference mReadExternalDictionaryPref;
+ private TwoStatePreference mDebugMode;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ addPreferencesFromResource(R.xml.prefs_screen_debug);
+
+ if (!Settings.HAS_UI_TO_ACCEPT_TYPED_WORD) {
+ removePreference(DebugSettings.PREF_SHOW_UI_TO_ACCEPT_TYPED_WORD);
+ }
+
+ mReadExternalDictionaryPref = findPreference(PREF_READ_EXTERNAL_DICTIONARY);
+ if (mReadExternalDictionaryPref != null) {
+ mReadExternalDictionaryPref.setOnPreferenceClickListener(this);
+ }
+
+ final PreferenceGroup dictDumpPreferenceGroup =
+ (PreferenceGroup)findPreference(PREF_KEY_DUMP_DICTS);
+ for (final String dictName : DictionaryFacilitator.DICT_TYPE_TO_CLASS.keySet()) {
+ final Preference pref = new DictDumpPreference(getActivity(), dictName);
+ pref.setOnPreferenceClickListener(this);
+ dictDumpPreferenceGroup.addPreference(pref);
+ }
+ final Resources res = getResources();
+ setupKeyLongpressTimeoutSettings();
+ setupKeyPreviewAnimationDuration(DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_DURATION,
+ res.getInteger(R.integer.config_key_preview_show_up_duration));
+ setupKeyPreviewAnimationDuration(DebugSettings.PREF_KEY_PREVIEW_DISMISS_DURATION,
+ res.getInteger(R.integer.config_key_preview_dismiss_duration));
+ final float defaultKeyPreviewShowUpStartScale = ResourceUtils.getFloatFromFraction(
+ res, R.fraction.config_key_preview_show_up_start_scale);
+ final float defaultKeyPreviewDismissEndScale = ResourceUtils.getFloatFromFraction(
+ res, R.fraction.config_key_preview_dismiss_end_scale);
+ setupKeyPreviewAnimationScale(DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_X_SCALE,
+ defaultKeyPreviewShowUpStartScale);
+ setupKeyPreviewAnimationScale(DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_Y_SCALE,
+ defaultKeyPreviewShowUpStartScale);
+ setupKeyPreviewAnimationScale(DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_X_SCALE,
+ defaultKeyPreviewDismissEndScale);
+ setupKeyPreviewAnimationScale(DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_Y_SCALE,
+ defaultKeyPreviewDismissEndScale);
+
+ mServiceNeedsRestart = false;
+ mDebugMode = (TwoStatePreference) findPreference(DebugSettings.PREF_DEBUG_MODE);
+ updateDebugMode();
+ }
+
+ private static class DictDumpPreference extends Preference {
+ public final String mDictName;
+
+ public DictDumpPreference(final Context context, final String dictName) {
+ super(context);
+ setKey(PREF_KEY_DUMP_DICT_PREFIX + dictName);
+ setTitle("Dump " + dictName + " dictionary");
+ mDictName = dictName;
+ }
+ }
+
+ @Override
+ public boolean onPreferenceClick(final Preference pref) {
+ final Context context = getActivity();
+ if (pref == mReadExternalDictionaryPref) {
+ ExternalDictionaryGetterForDebug.chooseAndInstallDictionary(context);
+ mServiceNeedsRestart = true;
+ return true;
+ }
+ if (pref instanceof DictDumpPreference) {
+ final DictDumpPreference dictDumpPref = (DictDumpPreference)pref;
+ final String dictName = dictDumpPref.mDictName;
+ final Intent intent = new Intent(
+ DictionaryDumpBroadcastReceiver.DICTIONARY_DUMP_INTENT_ACTION);
+ intent.putExtra(DictionaryDumpBroadcastReceiver.DICTIONARY_NAME_KEY, dictName);
+ context.sendBroadcast(intent);
+ return true;
+ }
+ return true;
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ if (mServiceNeedsRestart) {
+ Process.killProcess(Process.myPid());
+ }
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
+ if (key.equals(DebugSettings.PREF_DEBUG_MODE) && mDebugMode != null) {
+ mDebugMode.setChecked(prefs.getBoolean(DebugSettings.PREF_DEBUG_MODE, false));
+ updateDebugMode();
+ mServiceNeedsRestart = true;
+ return;
+ }
+ if (key.equals(DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH)
+ || key.equals(DebugSettings.PREF_FORCE_PHYSICAL_KEYBOARD_SPECIAL_KEY)) {
+ mServiceNeedsRestart = true;
+ return;
+ }
+ }
+
+ private void updateDebugMode() {
+ boolean isDebugMode = mDebugMode.isChecked();
+ final String version = getString(
+ R.string.version_text, ApplicationUtils.getVersionName(getActivity()));
+ if (!isDebugMode) {
+ mDebugMode.setTitle(version);
+ mDebugMode.setSummary(null);
+ } else {
+ mDebugMode.setTitle(getString(R.string.prefs_debug_mode));
+ mDebugMode.setSummary(version);
+ }
+ }
+
+ private void setupKeyLongpressTimeoutSettings() {
+ final SharedPreferences prefs = getSharedPreferences();
+ final Resources res = getResources();
+ final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(
+ DebugSettings.PREF_KEY_LONGPRESS_TIMEOUT);
+ if (pref == null) {
+ return;
+ }
+ pref.setInterface(new SeekBarDialogPreference.ValueProxy() {
+ @Override
+ public void writeValue(final int value, final String key) {
+ prefs.edit().putInt(key, value).apply();
+ }
+
+ @Override
+ public void writeDefaultValue(final String key) {
+ prefs.edit().remove(key).apply();
+ }
+
+ @Override
+ public int readValue(final String key) {
+ return Settings.readKeyLongpressTimeout(prefs, res);
+ }
+
+ @Override
+ public int readDefaultValue(final String key) {
+ return Settings.readDefaultKeyLongpressTimeout(res);
+ }
+
+ @Override
+ public String getValueText(final int value) {
+ return res.getString(R.string.abbreviation_unit_milliseconds, value);
+ }
+
+ @Override
+ public void feedbackValue(final int value) {}
+ });
+ }
+
+ private void setupKeyPreviewAnimationScale(final String prefKey, final float defaultValue) {
+ final SharedPreferences prefs = getSharedPreferences();
+ final Resources res = getResources();
+ final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(prefKey);
+ if (pref == null) {
+ return;
+ }
+ pref.setInterface(new SeekBarDialogPreference.ValueProxy() {
+ private static final float PERCENTAGE_FLOAT = 100.0f;
+
+ private float getValueFromPercentage(final int percentage) {
+ return percentage / PERCENTAGE_FLOAT;
+ }
+
+ private int getPercentageFromValue(final float floatValue) {
+ return (int)(floatValue * PERCENTAGE_FLOAT);
+ }
+
+ @Override
+ public void writeValue(final int value, final String key) {
+ prefs.edit().putFloat(key, getValueFromPercentage(value)).apply();
+ }
+
+ @Override
+ public void writeDefaultValue(final String key) {
+ prefs.edit().remove(key).apply();
+ }
+
+ @Override
+ public int readValue(final String key) {
+ return getPercentageFromValue(
+ Settings.readKeyPreviewAnimationScale(prefs, key, defaultValue));
+ }
+
+ @Override
+ public int readDefaultValue(final String key) {
+ return getPercentageFromValue(defaultValue);
+ }
+
+ @Override
+ public String getValueText(final int value) {
+ if (value < 0) {
+ return res.getString(R.string.settings_system_default);
+ }
+ return String.format(Locale.ROOT, "%d%%", value);
+ }
+
+ @Override
+ public void feedbackValue(final int value) {}
+ });
+ }
+
+ private void setupKeyPreviewAnimationDuration(final String prefKey, final int defaultValue) {
+ final SharedPreferences prefs = getSharedPreferences();
+ final Resources res = getResources();
+ final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(prefKey);
+ if (pref == null) {
+ return;
+ }
+ pref.setInterface(new SeekBarDialogPreference.ValueProxy() {
+ @Override
+ public void writeValue(final int value, final String key) {
+ prefs.edit().putInt(key, value).apply();
+ }
+
+ @Override
+ public void writeDefaultValue(final String key) {
+ prefs.edit().remove(key).apply();
+ }
+
+ @Override
+ public int readValue(final String key) {
+ return Settings.readKeyPreviewAnimationDuration(prefs, key, defaultValue);
+ }
+
+ @Override
+ public int readDefaultValue(final String key) {
+ return defaultValue;
+ }
+
+ @Override
+ public String getValueText(final int value) {
+ return res.getString(R.string.abbreviation_unit_milliseconds, value);
+ }
+
+ @Override
+ public void feedbackValue(final int value) {}
+ });
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/settings/GestureSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/GestureSettingsFragment.java
new file mode 100644
index 000000000..832fbf65a
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/settings/GestureSettingsFragment.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.settings;
+
+import android.content.SharedPreferences;
+import android.os.Bundle;
+
+import com.android.inputmethod.latin.R;
+
+/**
+ * "Gesture typing preferences" settings sub screen.
+ *
+ * This settings sub screen handles the following gesture typing preferences.
+ * - Enable gesture typing
+ * - Dynamic floating preview
+ * - Show gesture trail
+ * - Phrase gesture
+ */
+public final class GestureSettingsFragment extends SubScreenFragment {
+ @Override
+ public void onCreate(final Bundle icicle) {
+ super.onCreate(icicle);
+ addPreferencesFromResource(R.xml.prefs_screen_gesture);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/settings/MultiLingualSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/MultiLingualSettingsFragment.java
index f40106ba9..b073c50a4 100644
--- a/java/src/com/android/inputmethod/latin/settings/MultiLingualSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/MultiLingualSettingsFragment.java
@@ -16,71 +16,27 @@
package com.android.inputmethod.latin.settings;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.res.Resources;
import android.os.Bundle;
-import android.preference.PreferenceScreen;
-import android.text.TextUtils;
-import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
-import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
import java.util.ArrayList;
/**
- * "Multi lingual options" settings sub screen.
+ * "Multilingual options" settings sub screen.
*
* This settings sub screen handles the following input preferences.
* - Language switch key
* - Switch to other input methods
- * - Custom input styles
*/
public final class MultiLingualSettingsFragment extends SubScreenFragment {
@Override
public void onCreate(final Bundle icicle) {
super.onCreate(icicle);
- addPreferencesFromResource(R.xml.prefs_screen_multi_lingual);
-
- final Context context = getActivity();
-
- // When we are called from the Settings application but we are not already running, some
- // singleton and utility classes may not have been initialized. We have to call
- // initialization method of these classes here. See {@link LatinIME#onCreate()}.
- SubtypeLocaleUtils.init(context);
-
+ addPreferencesFromResource(R.xml.prefs_screen_multilingual);
if (!Settings.ENABLE_SHOW_LANGUAGE_SWITCH_KEY_SETTINGS) {
removePreference(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY);
removePreference(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST);
}
}
-
- @Override
- public void onResume() {
- super.onResume();
- updateCustomInputStylesSummary();
- }
-
- @Override
- public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
- // Nothing to do here.
- }
-
- private void updateCustomInputStylesSummary() {
- final SharedPreferences prefs = getSharedPreferences();
- final Resources res = getResources();
- final PreferenceScreen customInputStyles =
- (PreferenceScreen)findPreference(Settings.PREF_CUSTOM_INPUT_STYLES);
- final String prefSubtype = Settings.readPrefAdditionalSubtypes(prefs, res);
- final InputMethodSubtype[] subtypes =
- AdditionalSubtypeUtils.createAdditionalSubtypesArray(prefSubtype);
- final ArrayList<String> subtypeNames = new ArrayList<>();
- for (final InputMethodSubtype subtype : subtypes) {
- subtypeNames.add(SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype));
- }
- // TODO: A delimiter of custom input styles should be localized.
- customInputStyles.setSummary(TextUtils.join(", ", subtypeNames));
- }
}
diff --git a/java/src/com/android/inputmethod/latin/settings/InputSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/PreferencesSettingsFragment.java
index f459d68dd..49db2bdc0 100644
--- a/java/src/com/android/inputmethod/latin/settings/InputSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/PreferencesSettingsFragment.java
@@ -27,7 +27,7 @@ import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SubtypeSwitcher;
/**
- * "Input preferences" settings sub screen.
+ * "Preferences" settings sub screen.
*
* This settings sub screen handles the following input preferences.
* - Auto-capitalization
@@ -37,11 +37,11 @@ import com.android.inputmethod.latin.SubtypeSwitcher;
* - Popup on keypress
* - Voice input key
*/
-public final class InputSettingsFragment extends SubScreenFragment {
+public final class PreferencesSettingsFragment extends SubScreenFragment {
@Override
public void onCreate(final Bundle icicle) {
super.onCreate(icicle);
- addPreferencesFromResource(R.xml.prefs_screen_input);
+ addPreferencesFromResource(R.xml.prefs_screen_preferences);
final Resources res = getResources();
final Context context = getActivity();
diff --git a/java/src/com/android/inputmethod/latin/settings/RadioButtonPreference.java b/java/src/com/android/inputmethod/latin/settings/RadioButtonPreference.java
new file mode 100644
index 000000000..c173d4706
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/settings/RadioButtonPreference.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.settings;
+
+import android.content.Context;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.RadioButton;
+
+import com.android.inputmethod.latin.R;
+
+/**
+ * Radio Button preference
+ */
+public class RadioButtonPreference extends Preference {
+ interface OnRadioButtonClickedListener {
+ /**
+ * Called when this preference needs to be saved its state.
+ *
+ * @param preference This preference.
+ */
+ public void onRadioButtonClicked(RadioButtonPreference preference);
+ }
+
+ private boolean mIsSelected;
+ private RadioButton mRadioButton;
+ private OnRadioButtonClickedListener mListener;
+ private final View.OnClickListener mClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ if (mListener != null) {
+ mListener.onRadioButtonClicked(RadioButtonPreference.this);
+ }
+ }
+ };
+
+ public RadioButtonPreference(final Context context) {
+ this(context, null);
+ }
+
+ public RadioButtonPreference(final Context context, final AttributeSet attrs) {
+ this(context, attrs, android.R.attr.preferenceStyle);
+ }
+
+ public RadioButtonPreference(final Context context, final AttributeSet attrs,
+ final int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ setWidgetLayoutResource(R.layout.radio_button_preference_widget);
+ }
+
+ public void setOnRadioButtonClickedListener(final OnRadioButtonClickedListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ protected void onBindView(final View view) {
+ super.onBindView(view);
+ mRadioButton = (RadioButton)view.findViewById(R.id.radio_button);
+ mRadioButton.setChecked(mIsSelected);
+ mRadioButton.setOnClickListener(mClickListener);
+ view.setOnClickListener(mClickListener);
+ }
+
+ public boolean isSelected() {
+ return mIsSelected;
+ }
+
+ public void setSelected(final boolean selected) {
+ if (selected == mIsSelected) {
+ return;
+ }
+ mIsSelected = selected;
+ if (mRadioButton != null) {
+ mRadioButton.setChecked(selected);
+ }
+ notifyChanged();
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java
index 0e6a15a7e..0de2d8831 100644
--- a/java/src/com/android/inputmethod/latin/settings/Settings.java
+++ b/java/src/com/android/inputmethod/latin/settings/Settings.java
@@ -19,11 +19,13 @@ package com.android.inputmethod.latin.settings;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.preference.PreferenceManager;
import android.util.Log;
+import com.android.inputmethod.compat.BuildCompatUtils;
import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
import com.android.inputmethod.latin.InputAttributes;
import com.android.inputmethod.latin.R;
@@ -40,8 +42,10 @@ import java.util.concurrent.locks.ReentrantLock;
public final class Settings implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = Settings.class.getSimpleName();
// Settings screens
- public static final String SCREEN_INPUT = "screen_input";
- public static final String SCREEN_MULTI_LINGUAL = "screen_multi_lingual";
+ public static final String SCREEN_PREFERENCES = "screen_preferences";
+ public static final String SCREEN_APPEARANCE = "screen_appearance";
+ public static final String SCREEN_THEME = "screen_theme";
+ public static final String SCREEN_MULTILINGUAL = "screen_multilingual";
public static final String SCREEN_GESTURE = "screen_gesture";
public static final String SCREEN_CORRECTION = "screen_correction";
public static final String SCREEN_ADVANCED = "screen_advanced";
@@ -66,10 +70,13 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
"pref_key_use_double_space_period";
public static final String PREF_BLOCK_POTENTIALLY_OFFENSIVE =
"pref_key_block_potentially_offensive";
+ // No multilingual options in Android L and above for now.
+ public static final boolean SHOW_MULTILINGUAL_SETTINGS =
+ BuildCompatUtils.EFFECTIVE_SDK_INT <= Build.VERSION_CODES.KITKAT;
public static final boolean ENABLE_SHOW_LANGUAGE_SWITCH_KEY_SETTINGS =
- (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
- || (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT
- && Build.VERSION.CODENAME.equals("REL"));
+ BuildCompatUtils.EFFECTIVE_SDK_INT <= Build.VERSION_CODES.KITKAT;
+ public static final boolean HAS_UI_TO_ACCEPT_TYPED_WORD =
+ BuildCompatUtils.EFFECTIVE_SDK_INT >= BuildCompatUtils.VERSION_CODES_LXX;
public static final String PREF_SHOW_LANGUAGE_SWITCH_KEY =
"pref_show_language_switch_key";
public static final String PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST =
@@ -366,6 +373,15 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
return prefs.getBoolean(PREF_SHOW_SETUP_WIZARD_ICON, false);
}
+ public static boolean readHasHardwareKeyboard(final Configuration conf) {
+ // The standard way of finding out whether we have a hardware keyboard. This code is taken
+ // from InputMethodService#onEvaluateInputShown, which canonically determines this.
+ // In a nutshell, we have a keyboard if the configuration says the type of hardware keyboard
+ // is NOKEYS and if it's not hidden (e.g. folded inside the device).
+ return conf.keyboard != Configuration.KEYBOARD_NOKEYS
+ && conf.hardKeyboardHidden != Configuration.HARDKEYBOARDHIDDEN_YES;
+ }
+
public static boolean isInternal(final SharedPreferences prefs) {
return prefs.getBoolean(PREF_KEY_IS_INTERNAL, false);
}
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsActivity.java b/java/src/com/android/inputmethod/latin/settings/SettingsActivity.java
index c7b9dcdd9..b0c494098 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsActivity.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsActivity.java
@@ -18,11 +18,36 @@ package com.android.inputmethod.latin.settings;
import com.android.inputmethod.latin.utils.FragmentUtils;
+import android.app.ActionBar;
import android.content.Intent;
+import android.os.Bundle;
import android.preference.PreferenceActivity;
+import android.view.MenuItem;
public final class SettingsActivity extends PreferenceActivity {
+ public static final String EXTRA_SHOW_HOME_AS_UP = "show_home_as_up";
private static final String DEFAULT_FRAGMENT = SettingsFragment.class.getName();
+ private boolean mShowHomeAsUp;
+
+ @Override
+ protected void onCreate(final Bundle savedState) {
+ super.onCreate(savedState);
+ final ActionBar actionBar = getActionBar();
+ if (actionBar != null) {
+ mShowHomeAsUp = getIntent().getBooleanExtra(EXTRA_SHOW_HOME_AS_UP, true);
+ actionBar.setDisplayHomeAsUpEnabled(mShowHomeAsUp);
+ actionBar.setHomeButtonEnabled(mShowHomeAsUp);
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(final MenuItem item) {
+ if (mShowHomeAsUp && item.getItemId() == android.R.id.home) {
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
@Override
public Intent getIntent() {
@@ -36,7 +61,7 @@ public final class SettingsActivity extends PreferenceActivity {
}
@Override
- public boolean isValidFragment(String fragmentName) {
+ public boolean isValidFragment(final String fragmentName) {
return FragmentUtils.isValidFragment(fragmentName);
}
}
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
index f0bc27972..4fc17387f 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
@@ -16,81 +16,26 @@
package com.android.inputmethod.latin.settings;
-import android.app.Activity;
-import android.app.backup.BackupManager;
-import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.media.AudioManager;
-import android.os.Build;
import android.os.Bundle;
-import android.preference.ListPreference;
import android.preference.Preference;
-import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
-import android.preference.TwoStatePreference;
-import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
-import com.android.inputmethod.dictionarypack.DictionarySettingsActivity;
-import com.android.inputmethod.keyboard.KeyboardTheme;
-import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.define.ProductionFlags;
-import com.android.inputmethod.latin.setup.LauncherIconVisibilityManager;
-import com.android.inputmethod.latin.userdictionary.UserDictionaryList;
-import com.android.inputmethod.latin.userdictionary.UserDictionarySettings;
import com.android.inputmethod.latin.utils.ApplicationUtils;
import com.android.inputmethod.latin.utils.FeedbackUtils;
import com.android.inputmethodcommon.InputMethodSettingsFragment;
-import java.util.TreeSet;
-
-public final class SettingsFragment extends InputMethodSettingsFragment
- implements SharedPreferences.OnSharedPreferenceChangeListener {
- private static final String TAG = SettingsFragment.class.getSimpleName();
- private static final boolean DBG_USE_INTERNAL_PERSONAL_DICTIONARY_SETTINGS = false;
- private static final boolean USE_INTERNAL_PERSONAL_DICTIONARY_SETTIGS =
- DBG_USE_INTERNAL_PERSONAL_DICTIONARY_SETTINGS
- || Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2;
-
- private static final int NO_MENU_GROUP = Menu.NONE; // We don't care about menu grouping.
- private static final int MENU_FEEDBACK = Menu.FIRST; // The first menu item id and order.
- private static final int MENU_ABOUT = Menu.FIRST + 1; // The second menu item id and order.
-
- private void setPreferenceEnabled(final String preferenceKey, final boolean enabled) {
- final Preference preference = findPreference(preferenceKey);
- if (preference != null) {
- preference.setEnabled(enabled);
- }
- }
-
- private void updateListPreferenceSummaryToCurrentValue(final String prefKey) {
- // Because the "%s" summary trick of {@link ListPreference} doesn't work properly before
- // KitKat, we need to update the summary programmatically.
- final ListPreference listPreference = (ListPreference)findPreference(prefKey);
- if (listPreference == null) {
- return;
- }
- final CharSequence entries[] = listPreference.getEntries();
- final int entryIndex = listPreference.findIndexOfValue(listPreference.getValue());
- listPreference.setSummary(entryIndex < 0 ? null : entries[entryIndex]);
- }
-
- private static void removePreference(final String preferenceKey, final PreferenceGroup parent) {
- if (parent == null) {
- return;
- }
- final Preference preference = parent.findPreference(preferenceKey);
- if (preference != null) {
- parent.removePreference(preference);
- }
- }
+public final class SettingsFragment extends InputMethodSettingsFragment {
+ // We don't care about menu grouping.
+ private static final int NO_MENU_GROUP = Menu.NONE;
+ // The first menu item id and order.
+ private static final int MENU_ABOUT = Menu.FIRST;
+ // The second menu item id and order.
+ private static final int MENU_HELP_AND_FEEDBACK = Menu.FIRST + 1;
@Override
public void onCreate(final Bundle icicle) {
@@ -100,320 +45,19 @@ public final class SettingsFragment extends InputMethodSettingsFragment
setSubtypeEnablerTitle(R.string.select_language);
addPreferencesFromResource(R.xml.prefs);
final PreferenceScreen preferenceScreen = getPreferenceScreen();
- TwoStatePreferenceHelper.replaceCheckBoxPreferencesBySwitchPreferences(preferenceScreen);
preferenceScreen.setTitle(
ApplicationUtils.getActivityTitleResId(getActivity(), SettingsActivity.class));
-
- final Resources res = getResources();
- final Context context = getActivity();
-
- // When we are called from the Settings application but we are not already running, some
- // singleton and utility classes may not have been initialized. We have to call
- // initialization method of these classes here. See {@link LatinIME#onCreate()}.
- AudioAndHapticFeedbackManager.init(context);
-
- final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
- prefs.registerOnSharedPreferenceChangeListener(this);
-
- ensureConsistencyOfAutoCorrectionSettings();
-
- final PreferenceScreen gestureScreen =
- (PreferenceScreen) findPreference(Settings.SCREEN_GESTURE);
- final PreferenceScreen correctionScreen =
- (PreferenceScreen) findPreference(Settings.SCREEN_CORRECTION);
- final PreferenceScreen advancedScreen =
- (PreferenceScreen) findPreference(Settings.SCREEN_ADVANCED);
- final PreferenceScreen debugScreen =
- (PreferenceScreen) findPreference(Settings.SCREEN_DEBUG);
-
- if (!Settings.isInternal(prefs)) {
- advancedScreen.removePreference(debugScreen);
- }
-
- if (!AudioAndHapticFeedbackManager.getInstance().hasVibrator()) {
- removePreference(Settings.PREF_VIBRATION_DURATION_SETTINGS, advancedScreen);
- }
-
- // TODO: consolidate key preview dismiss delay with the key preview animation parameters.
- if (!Settings.readFromBuildConfigIfToShowKeyPreviewPopupOption(res)) {
- removePreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, advancedScreen);
- } else {
- // TODO: Cleanup this setup.
- final ListPreference keyPreviewPopupDismissDelay =
- (ListPreference) findPreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
- final String popupDismissDelayDefaultValue = Integer.toString(res.getInteger(
- R.integer.config_key_preview_linger_timeout));
- keyPreviewPopupDismissDelay.setEntries(new String[] {
- res.getString(R.string.key_preview_popup_dismiss_no_delay),
- res.getString(R.string.key_preview_popup_dismiss_default_delay),
- });
- keyPreviewPopupDismissDelay.setEntryValues(new String[] {
- "0",
- popupDismissDelayDefaultValue
- });
- if (null == keyPreviewPopupDismissDelay.getValue()) {
- keyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue);
- }
- keyPreviewPopupDismissDelay.setEnabled(
- Settings.readKeyPreviewPopupEnabled(prefs, res));
- }
-
- if (!res.getBoolean(R.bool.config_setup_wizard_available)) {
- removePreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON, advancedScreen);
- }
-
- final PreferenceScreen dictionaryLink =
- (PreferenceScreen) findPreference(Settings.PREF_CONFIGURE_DICTIONARIES_KEY);
- final Intent intent = dictionaryLink.getIntent();
- intent.setClassName(context.getPackageName(), DictionarySettingsActivity.class.getName());
- final int number = context.getPackageManager().queryIntentActivities(intent, 0).size();
- if (0 >= number) {
- correctionScreen.removePreference(dictionaryLink);
- }
-
- if (ProductionFlags.IS_METRICS_LOGGING_SUPPORTED) {
- final Preference enableMetricsLogging =
- findPreference(Settings.PREF_ENABLE_METRICS_LOGGING);
- if (enableMetricsLogging != null) {
- final int applicationLabelRes = context.getApplicationInfo().labelRes;
- final String applicationName = res.getString(applicationLabelRes);
- final String enableMetricsLoggingTitle = res.getString(
- R.string.enable_metrics_logging, applicationName);
- enableMetricsLogging.setTitle(enableMetricsLoggingTitle);
- }
- } else {
- removePreference(Settings.PREF_ENABLE_METRICS_LOGGING, advancedScreen);
- }
-
- final Preference editPersonalDictionary =
- findPreference(Settings.PREF_EDIT_PERSONAL_DICTIONARY);
- final Intent editPersonalDictionaryIntent = editPersonalDictionary.getIntent();
- final ResolveInfo ri = USE_INTERNAL_PERSONAL_DICTIONARY_SETTIGS ? null
- : context.getPackageManager().resolveActivity(
- editPersonalDictionaryIntent, PackageManager.MATCH_DEFAULT_ONLY);
- if (ri == null) {
- overwriteUserDictionaryPreference(editPersonalDictionary);
- }
-
- if (!Settings.readFromBuildConfigIfGestureInputEnabled(res)) {
- getPreferenceScreen().removePreference(gestureScreen);
- }
-
- AdditionalFeaturesSettingUtils.addAdditionalFeaturesPreferences(context, this);
-
- setupKeypressVibrationDurationSettings(prefs, res);
- setupKeypressSoundVolumeSettings(prefs, res);
- refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, res);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
- final Resources res = getResources();
- final TwoStatePreference showSetupWizardIcon =
- (TwoStatePreference)findPreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON);
- if (showSetupWizardIcon != null) {
- showSetupWizardIcon.setChecked(Settings.readShowSetupWizardIcon(prefs, getActivity()));
- }
- updateListPreferenceSummaryToCurrentValue(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
- final ListPreference keyboardThemePref = (ListPreference)findPreference(
- Settings.PREF_KEYBOARD_THEME);
- if (keyboardThemePref != null) {
- final KeyboardTheme keyboardTheme = KeyboardTheme.getKeyboardTheme(prefs);
- final String value = Integer.toString(keyboardTheme.mThemeId);
- final CharSequence entries[] = keyboardThemePref.getEntries();
- final int entryIndex = keyboardThemePref.findIndexOfValue(value);
- keyboardThemePref.setSummary(entryIndex < 0 ? null : entries[entryIndex]);
- keyboardThemePref.setValue(value);
- }
- }
-
- @Override
- public void onPause() {
- super.onPause();
- final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
- final ListPreference keyboardThemePref = (ListPreference)findPreference(
- Settings.PREF_KEYBOARD_THEME);
- if (keyboardThemePref != null) {
- KeyboardTheme.saveKeyboardThemeId(keyboardThemePref.getValue(), prefs);
- }
- }
-
- @Override
- public void onDestroy() {
- getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(
- this);
- super.onDestroy();
- }
-
- @Override
- public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
- final Activity activity = getActivity();
- if (activity == null) {
- // TODO: Introduce a static function to register this class and ensure that
- // onCreate must be called before "onSharedPreferenceChanged" is called.
- Log.w(TAG, "onSharedPreferenceChanged called before activity starts.");
- return;
- }
- (new BackupManager(activity)).dataChanged();
- final Resources res = getResources();
- if (key.equals(Settings.PREF_POPUP_ON)) {
- setPreferenceEnabled(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY,
- Settings.readKeyPreviewPopupEnabled(prefs, res));
- } else if (key.equals(Settings.PREF_SHOW_SETUP_WIZARD_ICON)) {
- LauncherIconVisibilityManager.updateSetupWizardIconVisibility(getActivity());
- }
- ensureConsistencyOfAutoCorrectionSettings();
- updateListPreferenceSummaryToCurrentValue(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
- updateListPreferenceSummaryToCurrentValue(Settings.PREF_KEYBOARD_THEME);
- refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, getResources());
- }
-
- private void ensureConsistencyOfAutoCorrectionSettings() {
- final String autoCorrectionOff = getResources().getString(
- R.string.auto_correction_threshold_mode_index_off);
- final ListPreference autoCorrectionThresholdPref = (ListPreference)findPreference(
- Settings.PREF_AUTO_CORRECTION_THRESHOLD);
- final String currentSetting = autoCorrectionThresholdPref.getValue();
- setPreferenceEnabled(
- Settings.PREF_BIGRAM_PREDICTIONS, !currentSetting.equals(autoCorrectionOff));
- }
-
- private void refreshEnablingsOfKeypressSoundAndVibrationSettings(
- final SharedPreferences sp, final Resources res) {
- setPreferenceEnabled(Settings.PREF_VIBRATION_DURATION_SETTINGS,
- Settings.readVibrationEnabled(sp, res));
- setPreferenceEnabled(Settings.PREF_KEYPRESS_SOUND_VOLUME,
- Settings.readKeypressSoundEnabled(sp, res));
- }
-
- private void setupKeypressVibrationDurationSettings(final SharedPreferences sp,
- final Resources res) {
- final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(
- Settings.PREF_VIBRATION_DURATION_SETTINGS);
- if (pref == null) {
- return;
- }
- pref.setInterface(new SeekBarDialogPreference.ValueProxy() {
- @Override
- public void writeValue(final int value, final String key) {
- sp.edit().putInt(key, value).apply();
- }
-
- @Override
- public void writeDefaultValue(final String key) {
- sp.edit().remove(key).apply();
- }
-
- @Override
- public int readValue(final String key) {
- return Settings.readKeypressVibrationDuration(sp, res);
- }
-
- @Override
- public int readDefaultValue(final String key) {
- return Settings.readDefaultKeypressVibrationDuration(res);
- }
-
- @Override
- public void feedbackValue(final int value) {
- AudioAndHapticFeedbackManager.getInstance().vibrate(value);
- }
-
- @Override
- public String getValueText(final int value) {
- if (value < 0) {
- return res.getString(R.string.settings_system_default);
- }
- return res.getString(R.string.abbreviation_unit_milliseconds, value);
- }
- });
- }
-
- private void setupKeypressSoundVolumeSettings(final SharedPreferences sp, final Resources res) {
- final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(
- Settings.PREF_KEYPRESS_SOUND_VOLUME);
- if (pref == null) {
- return;
- }
- final AudioManager am = (AudioManager)getActivity().getSystemService(Context.AUDIO_SERVICE);
- pref.setInterface(new SeekBarDialogPreference.ValueProxy() {
- private static final float PERCENTAGE_FLOAT = 100.0f;
-
- private float getValueFromPercentage(final int percentage) {
- return percentage / PERCENTAGE_FLOAT;
- }
-
- private int getPercentageFromValue(final float floatValue) {
- return (int)(floatValue * PERCENTAGE_FLOAT);
- }
-
- @Override
- public void writeValue(final int value, final String key) {
- sp.edit().putFloat(key, getValueFromPercentage(value)).apply();
- }
-
- @Override
- public void writeDefaultValue(final String key) {
- sp.edit().remove(key).apply();
- }
-
- @Override
- public int readValue(final String key) {
- return getPercentageFromValue(Settings.readKeypressSoundVolume(sp, res));
- }
-
- @Override
- public int readDefaultValue(final String key) {
- return getPercentageFromValue(Settings.readDefaultKeypressSoundVolume(res));
- }
-
- @Override
- public String getValueText(final int value) {
- if (value < 0) {
- return res.getString(R.string.settings_system_default);
- }
- return Integer.toString(value);
- }
-
- @Override
- public void feedbackValue(final int value) {
- am.playSoundEffect(
- AudioManager.FX_KEYPRESS_STANDARD, getValueFromPercentage(value));
- }
- });
- }
-
- private void overwriteUserDictionaryPreference(Preference userDictionaryPreference) {
- final Activity activity = getActivity();
- final TreeSet<String> localeList = UserDictionaryList.getUserDictionaryLocalesSet(activity);
- if (null == localeList) {
- // The locale list is null if and only if the user dictionary service is
- // not present or disabled. In this case we need to remove the preference.
- getPreferenceScreen().removePreference(userDictionaryPreference);
- } else if (localeList.size() <= 1) {
- userDictionaryPreference.setFragment(UserDictionarySettings.class.getName());
- // If the size of localeList is 0, we don't set the locale parameter in the
- // extras. This will be interpreted by the UserDictionarySettings class as
- // meaning "the current locale".
- // Note that with the current code for UserDictionaryList#getUserDictionaryLocalesSet()
- // the locale list always has at least one element, since it always includes the current
- // locale explicitly. @see UserDictionaryList.getUserDictionaryLocalesSet().
- if (localeList.size() == 1) {
- final String locale = (String)localeList.toArray()[0];
- userDictionaryPreference.getExtras().putString("locale", locale);
- }
- } else {
- userDictionaryPreference.setFragment(UserDictionaryList.class.getName());
+ if (!Settings.SHOW_MULTILINGUAL_SETTINGS) {
+ final Preference multilingualOptions = findPreference(Settings.SCREEN_MULTILINGUAL);
+ preferenceScreen.removePreference(multilingualOptions);
}
}
@Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
- if (FeedbackUtils.isFeedbackFormSupported()) {
- menu.add(NO_MENU_GROUP, MENU_FEEDBACK /* itemId */, MENU_FEEDBACK /* order */,
- R.string.send_feedback);
+ if (FeedbackUtils.isHelpAndFeedbackFormSupported()) {
+ menu.add(NO_MENU_GROUP, MENU_HELP_AND_FEEDBACK /* itemId */,
+ MENU_HELP_AND_FEEDBACK /* order */, R.string.help_and_feedback);
}
final int aboutResId = FeedbackUtils.getAboutKeyboardTitleResId();
if (aboutResId != 0) {
@@ -424,8 +68,8 @@ public final class SettingsFragment extends InputMethodSettingsFragment
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
final int itemId = item.getItemId();
- if (itemId == MENU_FEEDBACK) {
- FeedbackUtils.showFeedbackForm(getActivity());
+ if (itemId == MENU_HELP_AND_FEEDBACK) {
+ FeedbackUtils.showHelpAndFeedbackForm(getActivity());
return true;
}
if (itemId == MENU_ABOUT) {
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index 39e834f84..d8c548d8b 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -50,9 +50,12 @@ public final class SettingsValues {
// From resources:
public final SpacingAndPunctuations mSpacingAndPunctuations;
- public final int mDelayUpdateOldSuggestions;
+ public final int mDelayInMillisecondsToUpdateOldSuggestions;
public final long mDoubleSpacePeriodTimeout;
-
+ // From configuration:
+ public final Locale mLocale;
+ public final boolean mHasHardwareKeyboard;
+ public final int mDisplayOrientation;
// From preferences, in the same order as xml/prefs.xml:
public final boolean mAutoCap;
public final boolean mVibrateOn;
@@ -73,8 +76,8 @@ public final class SettingsValues {
public final boolean mSlidingKeyInputPreviewEnabled;
public final boolean mPhraseGestureEnabled;
public final int mKeyLongpressTimeout;
- public final Locale mLocale;
public final boolean mEnableMetricsLogging;
+ public final boolean mShouldShowUiToAcceptTypedWord;
// From the input box
public final InputAttributes mInputAttributes;
@@ -87,25 +90,31 @@ public final class SettingsValues {
public final float mAutoCorrectionThreshold;
public final boolean mAutoCorrectionEnabledPerUserSettings;
private final boolean mSuggestionsEnabledPerUserSettings;
- public final int mDisplayOrientation;
private final AsyncResultHolder<AppWorkaroundsUtils> mAppWorkarounds;
// Setting values for additional features
public final int[] mAdditionalFeaturesSettingValues =
new int[AdditionalFeaturesSettingUtils.ADDITIONAL_FEATURES_SETTINGS_SIZE];
+ // TextDecorator
+ public final int mTextHighlightColorForAddToDictionaryIndicator;
+
// Debug settings
public final boolean mIsInternal;
+ public final boolean mHasCustomKeyPreviewAnimationParams;
public final int mKeyPreviewShowUpDuration;
public final int mKeyPreviewDismissDuration;
- public final float mKeyPreviewShowUpStartScale;
- public final float mKeyPreviewDismissEndScale;
+ public final float mKeyPreviewShowUpStartXScale;
+ public final float mKeyPreviewShowUpStartYScale;
+ public final float mKeyPreviewDismissEndXScale;
+ public final float mKeyPreviewDismissEndYScale;
public SettingsValues(final Context context, final SharedPreferences prefs, final Resources res,
final InputAttributes inputAttributes) {
mLocale = res.getConfiguration().locale;
// Get the resources
- mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions);
+ mDelayInMillisecondsToUpdateOldSuggestions =
+ res.getInteger(R.integer.config_delay_in_milliseconds_to_update_old_suggestions);
mSpacingAndPunctuations = new SpacingAndPunctuations(res);
// Store the input attributes
@@ -136,12 +145,16 @@ public final class SettingsValues {
? Settings.readShowsLanguageSwitchKey(prefs) : true /* forcibly */;
mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true);
mUsePersonalizedDicts = prefs.getBoolean(Settings.PREF_KEY_USE_PERSONALIZED_DICTS, true);
- mUseDoubleSpacePeriod = prefs.getBoolean(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true);
+ mUseDoubleSpacePeriod = prefs.getBoolean(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true)
+ && inputAttributes.mIsGeneralTextInput;
mBlockPotentiallyOffensive = Settings.readBlockPotentiallyOffensive(prefs, res);
mAutoCorrectEnabled = Settings.readAutoCorrectEnabled(autoCorrectionThresholdRawValue, res);
mBigramPredictionEnabled = readBigramPredictionEnabled(prefs, res);
mDoubleSpacePeriodTimeout = res.getInteger(R.integer.config_double_space_period_timeout);
+ mHasHardwareKeyboard = Settings.readHasHardwareKeyboard(res.getConfiguration());
mEnableMetricsLogging = prefs.getBoolean(Settings.PREF_ENABLE_METRICS_LOGGING, true);
+ mShouldShowUiToAcceptTypedWord = Settings.HAS_UI_TO_ACCEPT_TYPED_WORD
+ && prefs.getBoolean(DebugSettings.PREF_SHOW_UI_TO_ACCEPT_TYPED_WORD, true);
// Compute other readable settings
mKeyLongpressTimeout = Settings.readKeyLongpressTimeout(prefs, res);
mKeypressVibrationDuration = Settings.readKeypressVibrationDuration(prefs, res);
@@ -159,21 +172,33 @@ public final class SettingsValues {
mSuggestionsEnabledPerUserSettings = readSuggestionsEnabled(prefs);
AdditionalFeaturesSettingUtils.readAdditionalFeaturesPreferencesIntoArray(
prefs, mAdditionalFeaturesSettingValues);
+ mTextHighlightColorForAddToDictionaryIndicator = res.getColor(
+ R.color.text_decorator_add_to_dictionary_indicator_text_highlight_color);
mIsInternal = Settings.isInternal(prefs);
+ mHasCustomKeyPreviewAnimationParams = prefs.getBoolean(
+ DebugSettings.PREF_HAS_CUSTOM_KEY_PREVIEW_ANIMATION_PARAMS, false);
mKeyPreviewShowUpDuration = Settings.readKeyPreviewAnimationDuration(
prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_DURATION,
res.getInteger(R.integer.config_key_preview_show_up_duration));
mKeyPreviewDismissDuration = Settings.readKeyPreviewAnimationDuration(
prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_DURATION,
res.getInteger(R.integer.config_key_preview_dismiss_duration));
- mKeyPreviewShowUpStartScale = Settings.readKeyPreviewAnimationScale(
- prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_SCALE,
- ResourceUtils.getFloatFromFraction(
- res, R.fraction.config_key_preview_show_up_start_scale));
- mKeyPreviewDismissEndScale = Settings.readKeyPreviewAnimationScale(
- prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_SCALE,
- ResourceUtils.getFloatFromFraction(
- res, R.fraction.config_key_preview_dismiss_end_scale));
+ final float defaultKeyPreviewShowUpStartScale = ResourceUtils.getFloatFromFraction(
+ res, R.fraction.config_key_preview_show_up_start_scale);
+ final float defaultKeyPreviewDismissEndScale = ResourceUtils.getFloatFromFraction(
+ res, R.fraction.config_key_preview_dismiss_end_scale);
+ mKeyPreviewShowUpStartXScale = Settings.readKeyPreviewAnimationScale(
+ prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_X_SCALE,
+ defaultKeyPreviewShowUpStartScale);
+ mKeyPreviewShowUpStartYScale = Settings.readKeyPreviewAnimationScale(
+ prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_Y_SCALE,
+ defaultKeyPreviewShowUpStartScale);
+ mKeyPreviewDismissEndXScale = Settings.readKeyPreviewAnimationScale(
+ prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_X_SCALE,
+ defaultKeyPreviewDismissEndScale);
+ mKeyPreviewDismissEndYScale = Settings.readKeyPreviewAnimationScale(
+ prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_Y_SCALE,
+ defaultKeyPreviewDismissEndScale);
mDisplayOrientation = res.getConfiguration().orientation;
mAppWorkarounds = new AsyncResultHolder<>();
final PackageInfo packageInfo = TargetPackageInfoGetterTask.getCachedPackageInfo(
@@ -329,8 +354,8 @@ public final class SettingsValues {
final StringBuilder sb = new StringBuilder("Current settings :");
sb.append("\n mSpacingAndPunctuations = ");
sb.append("" + mSpacingAndPunctuations.dump());
- sb.append("\n mDelayUpdateOldSuggestions = ");
- sb.append("" + mDelayUpdateOldSuggestions);
+ sb.append("\n mDelayInMillisecondsToUpdateOldSuggestions = ");
+ sb.append("" + mDelayInMillisecondsToUpdateOldSuggestions);
sb.append("\n mAutoCap = ");
sb.append("" + mAutoCap);
sb.append("\n mVibrateOn = ");
@@ -392,16 +417,22 @@ public final class SettingsValues {
sb.append("" + (null == awu ? "null" : awu.toString()));
sb.append("\n mAdditionalFeaturesSettingValues = ");
sb.append("" + Arrays.toString(mAdditionalFeaturesSettingValues));
+ sb.append("\n mTextHighlightColorForAddToDictionaryIndicator = ");
+ sb.append("" + mTextHighlightColorForAddToDictionaryIndicator);
sb.append("\n mIsInternal = ");
sb.append("" + mIsInternal);
sb.append("\n mKeyPreviewShowUpDuration = ");
sb.append("" + mKeyPreviewShowUpDuration);
sb.append("\n mKeyPreviewDismissDuration = ");
sb.append("" + mKeyPreviewDismissDuration);
- sb.append("\n mKeyPreviewShowUpStartScale = ");
- sb.append("" + mKeyPreviewShowUpStartScale);
- sb.append("\n mKeyPreviewDismissEndScale = ");
- sb.append("" + mKeyPreviewDismissEndScale);
+ sb.append("\n mKeyPreviewShowUpStartScaleX = ");
+ sb.append("" + mKeyPreviewShowUpStartXScale);
+ sb.append("\n mKeyPreviewShowUpStartScaleY = ");
+ sb.append("" + mKeyPreviewShowUpStartYScale);
+ sb.append("\n mKeyPreviewDismissEndScaleX = ");
+ sb.append("" + mKeyPreviewDismissEndXScale);
+ sb.append("\n mKeyPreviewDismissEndScaleY = ");
+ sb.append("" + mKeyPreviewDismissEndYScale);
return sb.toString();
}
}
diff --git a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
index b8d2a2248..49d81104d 100644
--- a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
+++ b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
@@ -18,6 +18,7 @@ package com.android.inputmethod.latin.settings;
import android.content.res.Resources;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.internal.MoreKeySpec;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.PunctuationSuggestions;
@@ -68,6 +69,22 @@ public final class SpacingAndPunctuations {
mSuggestPuncList = PunctuationSuggestions.newPunctuationSuggestions(suggestPuncsSpec);
}
+ @UsedForTesting
+ public SpacingAndPunctuations(final SpacingAndPunctuations model,
+ final int[] overrideSortedWordSeparators) {
+ mSortedSymbolsPrecededBySpace = model.mSortedSymbolsPrecededBySpace;
+ mSortedSymbolsFollowedBySpace = model.mSortedSymbolsFollowedBySpace;
+ mSortedSymbolsClusteringTogether = model.mSortedSymbolsClusteringTogether;
+ mSortedWordConnectors = model.mSortedWordConnectors;
+ mSortedWordSeparators = overrideSortedWordSeparators;
+ mSuggestPuncList = model.mSuggestPuncList;
+ mSentenceSeparator = model.mSentenceSeparator;
+ mSentenceSeparatorAndSpace = model.mSentenceSeparatorAndSpace;
+ mCurrentLanguageHasSpaces = model.mCurrentLanguageHasSpaces;
+ mUsesAmericanTypography = model.mUsesAmericanTypography;
+ mUsesGermanRules = model.mUsesGermanRules;
+ }
+
public boolean isWordSeparator(final int code) {
return Arrays.binarySearch(mSortedWordSeparators, code) >= 0;
}
diff --git a/java/src/com/android/inputmethod/latin/settings/SubScreenFragment.java b/java/src/com/android/inputmethod/latin/settings/SubScreenFragment.java
index c70bf2997..ca5b395ce 100644
--- a/java/src/com/android/inputmethod/latin/settings/SubScreenFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/SubScreenFragment.java
@@ -115,4 +115,9 @@ abstract class SubScreenFragment extends PreferenceFragment
mSharedPreferenceChangeListener);
super.onDestroy();
}
+
+ @Override
+ public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
+ // This method may be overridden by an extended class.
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/settings/ThemeSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/ThemeSettingsFragment.java
new file mode 100644
index 000000000..5a3fc3600
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/settings/ThemeSettingsFragment.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.settings;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceScreen;
+
+import com.android.inputmethod.keyboard.KeyboardTheme;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.settings.RadioButtonPreference.OnRadioButtonClickedListener;
+
+/**
+ * "Keyboard theme" settings sub screen.
+ */
+public final class ThemeSettingsFragment extends SubScreenFragment
+ implements OnRadioButtonClickedListener {
+ private String mSelectedThemeId;
+
+ static class KeyboardThemePreference extends RadioButtonPreference {
+ final String mThemeId;
+
+ KeyboardThemePreference(final Context context, final String name, final String id) {
+ super(context);
+ setTitle(name);
+ mThemeId = id;
+ }
+ }
+
+ static void updateKeyboardThemeSummary(final Preference pref) {
+ final Resources res = pref.getContext().getResources();
+ final SharedPreferences prefs = pref.getSharedPreferences();
+ final KeyboardTheme keyboardTheme = KeyboardTheme.getKeyboardTheme(prefs);
+ final String keyboardThemeId = String.valueOf(keyboardTheme.mThemeId);
+ final String[] keyboardThemeNames = res.getStringArray(R.array.keyboard_theme_names);
+ final String[] keyboardThemeIds = res.getStringArray(R.array.keyboard_theme_ids);
+ for (int index = 0; index < keyboardThemeNames.length; index++) {
+ if (keyboardThemeId.equals(keyboardThemeIds[index])) {
+ pref.setSummary(keyboardThemeNames[index]);
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void onCreate(final Bundle icicle) {
+ super.onCreate(icicle);
+ addPreferencesFromResource(R.xml.prefs_screen_theme);
+ final PreferenceScreen screen = getPreferenceScreen();
+ final Resources res = getResources();
+ final String[] keyboardThemeNames = res.getStringArray(R.array.keyboard_theme_names);
+ final String[] keyboardThemeIds = res.getStringArray(R.array.keyboard_theme_ids);
+ for (int index = 0; index < keyboardThemeNames.length; index++) {
+ final KeyboardThemePreference pref = new KeyboardThemePreference(
+ getActivity(), keyboardThemeNames[index], keyboardThemeIds[index]);
+ screen.addPreference(pref);
+ pref.setOnRadioButtonClickedListener(this);
+ }
+ final SharedPreferences prefs = getSharedPreferences();
+ final KeyboardTheme keyboardTheme = KeyboardTheme.getKeyboardTheme(prefs);
+ mSelectedThemeId = String.valueOf(keyboardTheme.mThemeId);
+ }
+
+ @Override
+ public void onRadioButtonClicked(final RadioButtonPreference preference) {
+ if (preference instanceof KeyboardThemePreference) {
+ final KeyboardThemePreference pref = (KeyboardThemePreference)preference;
+ mSelectedThemeId = pref.mThemeId;
+ updateSelected();
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ updateSelected();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ KeyboardTheme.saveKeyboardThemeId(mSelectedThemeId, getSharedPreferences());
+ }
+
+ private void updateSelected() {
+ final PreferenceScreen screen = getPreferenceScreen();
+ final int count = screen.getPreferenceCount();
+ for (int index = 0; index < count; index++) {
+ final Preference preference = screen.getPreference(index);
+ if (preference instanceof KeyboardThemePreference) {
+ final KeyboardThemePreference pref = (KeyboardThemePreference)preference;
+ final boolean selected = mSelectedThemeId.equals(pref.mThemeId);
+ pref.setSelected(selected);
+ }
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java b/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java
index 9585736e7..3f0b10225 100644
--- a/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java
+++ b/java/src/com/android/inputmethod/latin/setup/LauncherIconVisibilityManager.java
@@ -24,7 +24,6 @@ import android.content.pm.PackageManager;
import android.preference.PreferenceManager;
import android.util.Log;
-import com.android.inputmethod.compat.IntentCompatUtils;
import com.android.inputmethod.latin.settings.Settings;
/**
@@ -55,14 +54,6 @@ import com.android.inputmethod.latin.settings.Settings;
public final class LauncherIconVisibilityManager {
private static final String TAG = LauncherIconVisibilityManager.class.getSimpleName();
- public static void onReceiveGlobalIntent(final String action, final Context context) {
- if (Intent.ACTION_MY_PACKAGE_REPLACED.equals(action) ||
- Intent.ACTION_BOOT_COMPLETED.equals(action) ||
- IntentCompatUtils.is_ACTION_USER_INITIALIZE(action)) {
- updateSetupWizardIconVisibility(context);
- }
- }
-
public static void updateSetupWizardIconVisibility(final Context context) {
final ComponentName setupWizardActivity = new ComponentName(context, SetupActivity.class);
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
index 346aea34a..9d186d44d 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
@@ -125,9 +125,9 @@ public final class MoreSuggestions extends Keyboard {
}
private static final int[][] COLUMN_ORDER_TO_NUMBER = {
- { 0, },
- { 1, 0, },
- { 2, 0, 1},
+ { 0 }, // center
+ { 1, 0 }, // right-left
+ { 1, 0, 2 }, // center-left-right
};
public int getNumColumnInRow(final int index) {
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
index c5f062d5b..1e8df8986 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
@@ -45,11 +45,14 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.inputmethod.accessibility.AccessibilityUtils;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.PunctuationSuggestions;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.define.DebugFlags;
+import com.android.inputmethod.latin.settings.Settings;
+import com.android.inputmethod.latin.settings.SettingsValues;
import com.android.inputmethod.latin.utils.AutoCorrectionUtils;
import com.android.inputmethod.latin.utils.ResourceUtils;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
@@ -72,7 +75,7 @@ final class SuggestionStripLayoutHelper {
private int mMaxMoreSuggestionsRow;
public final float mMinMoreSuggestionsWidth;
public final int mMoreSuggestionsBottomGap;
- public boolean mMoreSuggestionsAvailable;
+ private boolean mMoreSuggestionsAvailable;
// The index of these {@link ArrayList} is the position in the suggestion strip. The indices
// increase towards the right for LTR scripts and the left for RTL scripts, starting with 0.
@@ -167,16 +170,14 @@ final class SuggestionStripLayoutHelper {
return mMaxMoreSuggestionsRow * mMoreSuggestionsRowHeight + mMoreSuggestionsBottomGap;
}
- public int setMoreSuggestionsHeight(final int remainingHeight) {
+ public void setMoreSuggestionsHeight(final int remainingHeight) {
final int currentHeight = getMoreSuggestionsHeight();
if (currentHeight <= remainingHeight) {
- return currentHeight;
+ return;
}
mMaxMoreSuggestionsRow = (remainingHeight - mMoreSuggestionsBottomGap)
/ mMoreSuggestionsRowHeight;
- final int newHeight = getMoreSuggestionsHeight();
- return newHeight;
}
private static Drawable getMoreSuggestionsHint(final Resources res, final float textSize,
@@ -225,11 +226,59 @@ final class SuggestionStripLayoutHelper {
return spannedWord;
}
+ /**
+ * Convert an index of {@link SuggestedWords} to position in the suggestion strip.
+ * @param indexInSuggestedWords the index of {@link SuggestedWords}.
+ * @param suggestedWords the suggested words list
+ * @return Non-negative integer of the position in the suggestion strip.
+ * Negative integer if the word of the index shouldn't be shown on the suggestion strip.
+ */
private int getPositionInSuggestionStrip(final int indexInSuggestedWords,
final SuggestedWords suggestedWords) {
+ final SettingsValues settingsValues = Settings.getInstance().getCurrent();
+ final boolean shouldOmitTypedWord = shouldOmitTypedWord(suggestedWords.mInputStyle,
+ settingsValues.mGestureFloatingPreviewTextEnabled,
+ settingsValues.mShouldShowUiToAcceptTypedWord);
+ return getPositionInSuggestionStrip(indexInSuggestedWords, suggestedWords.mWillAutoCorrect,
+ settingsValues.mShouldShowUiToAcceptTypedWord && shouldOmitTypedWord,
+ mCenterPositionInStrip, mTypedWordPositionWhenAutocorrect);
+ }
+
+ @UsedForTesting
+ static boolean shouldOmitTypedWord(final int inputStyle,
+ final boolean gestureFloatingPreviewTextEnabled,
+ final boolean shouldShowUiToAcceptTypedWord) {
+ final boolean omitTypedWord = (inputStyle == SuggestedWords.INPUT_STYLE_TYPING)
+ || (inputStyle == SuggestedWords.INPUT_STYLE_TAIL_BATCH)
+ || (inputStyle == SuggestedWords.INPUT_STYLE_UPDATE_BATCH
+ && gestureFloatingPreviewTextEnabled);
+ return shouldShowUiToAcceptTypedWord && omitTypedWord;
+ }
+
+ @UsedForTesting
+ static int getPositionInSuggestionStrip(final int indexInSuggestedWords,
+ final boolean willAutoCorrect, final boolean omitTypedWord,
+ final int centerPositionInStrip, final int typedWordPositionWhenAutoCorrect) {
+ if (omitTypedWord) {
+ if (indexInSuggestedWords == SuggestedWords.INDEX_OF_TYPED_WORD) {
+ // Ignore.
+ return -1;
+ }
+ if (indexInSuggestedWords == SuggestedWords.INDEX_OF_AUTO_CORRECTION) {
+ // Center in the suggestion strip.
+ return centerPositionInStrip;
+ }
+ // If neither of those, the order in the suggestion strip is left of the center first
+ // then right of the center, to both edges of the suggestion strip.
+ // For example, center-1, center+1, center-2, center+2, and so on.
+ final int n = indexInSuggestedWords;
+ final int offsetFromCenter = (n % 2) == 0 ? -(n / 2) : (n / 2);
+ final int positionInSuggestionStrip = centerPositionInStrip + offsetFromCenter;
+ return positionInSuggestionStrip;
+ }
final int indexToDisplayMostImportantSuggestion;
final int indexToDisplaySecondMostImportantSuggestion;
- if (suggestedWords.mWillAutoCorrect) {
+ if (willAutoCorrect) {
indexToDisplayMostImportantSuggestion = SuggestedWords.INDEX_OF_AUTO_CORRECTION;
indexToDisplaySecondMostImportantSuggestion = SuggestedWords.INDEX_OF_TYPED_WORD;
} else {
@@ -237,25 +286,31 @@ final class SuggestionStripLayoutHelper {
indexToDisplaySecondMostImportantSuggestion = SuggestedWords.INDEX_OF_AUTO_CORRECTION;
}
if (indexInSuggestedWords == indexToDisplayMostImportantSuggestion) {
- return mCenterPositionInStrip;
+ // Center in the suggestion strip.
+ return centerPositionInStrip;
}
if (indexInSuggestedWords == indexToDisplaySecondMostImportantSuggestion) {
- return mTypedWordPositionWhenAutocorrect;
+ // Center-1.
+ return typedWordPositionWhenAutoCorrect;
}
- // If neither of those, the order in the suggestion strip is the same as in SuggestedWords.
- return indexInSuggestedWords;
+ // If neither of those, the order in the suggestion strip is right of the center first
+ // then left of the center, to both edges of the suggestion strip.
+ // For example, Center+1, center-2, center+2, center-3, and so on.
+ final int n = indexInSuggestedWords + 1;
+ final int offsetFromCenter = (n % 2) == 0 ? -(n / 2) : (n / 2);
+ final int positionInSuggestionStrip = centerPositionInStrip + offsetFromCenter;
+ return positionInSuggestionStrip;
}
private int getSuggestionTextColor(final SuggestedWords suggestedWords,
final int indexInSuggestedWords) {
- final int positionInStrip =
- getPositionInSuggestionStrip(indexInSuggestedWords, suggestedWords);
// Use identity for strings, not #equals : it's the typed word if it's the same object
final boolean isTypedWord = suggestedWords.getInfo(indexInSuggestedWords).isKindOf(
SuggestedWordInfo.KIND_TYPED);
final int color;
- if (positionInStrip == mCenterPositionInStrip && suggestedWords.mWillAutoCorrect) {
+ if (indexInSuggestedWords == SuggestedWords.INDEX_OF_AUTO_CORRECTION
+ && suggestedWords.mWillAutoCorrect) {
color = mColorAutoCorrect;
} else if (isTypedWord && suggestedWords.mTypedWordValid) {
color = mColorValidTypedWord;
@@ -267,7 +322,8 @@ final class SuggestionStripLayoutHelper {
if (DebugFlags.DEBUG_ENABLED && suggestedWords.size() > 1) {
// If we auto-correct, then the autocorrection is in slot 0 and the typed word
// is in slot 1.
- if (positionInStrip == mCenterPositionInStrip
+ if (indexInSuggestedWords == SuggestedWords.INDEX_OF_AUTO_CORRECTION
+ && suggestedWords.mWillAutoCorrect
&& AutoCorrectionUtils.shouldBlockAutoCorrectionBySafetyNet(
suggestedWords.getLabel(SuggestedWords.INDEX_OF_AUTO_CORRECTION),
suggestedWords.getLabel(SuggestedWords.INDEX_OF_TYPED_WORD))) {
@@ -294,31 +350,31 @@ final class SuggestionStripLayoutHelper {
}
/**
- * Layout suggestions to the suggestions strip. And returns the number of suggestions displayed
- * in the suggestions strip.
+ * Layout suggestions to the suggestions strip. And returns the start index of more
+ * suggestions.
*
* @param suggestedWords suggestions to be shown in the suggestions strip.
* @param stripView the suggestions strip view.
* @param placerView the view where the debug info will be placed.
- * @return the number of suggestions displayed in the suggestions strip
+ * @return the start index of more suggestions.
*/
- public int layoutAndReturnSuggestionCountInStrip(final SuggestedWords suggestedWords,
+ public int layoutAndReturnStartIndexOfMoreSuggestions(final SuggestedWords suggestedWords,
final ViewGroup stripView, final ViewGroup placerView) {
if (suggestedWords.isPunctuationSuggestions()) {
- return layoutPunctuationSuggestionsAndReturnSuggestionCountInStrip(
+ return layoutPunctuationsAndReturnStartIndexOfMoreSuggestions(
(PunctuationSuggestions)suggestedWords, stripView);
}
- setupWordViewsTextAndColor(suggestedWords, mSuggestionsCountInStrip);
+ final int startIndexOfMoreSuggestions = setupWordViewsAndReturnStartIndexOfMoreSuggestions(
+ suggestedWords, mSuggestionsCountInStrip);
final TextView centerWordView = mWordViews.get(mCenterPositionInStrip);
final int stripWidth = stripView.getWidth();
final int centerWidth = getSuggestionWidth(mCenterPositionInStrip, stripWidth);
- final int countInStrip;
if (suggestedWords.size() == 1 || getTextScaleX(centerWordView.getText(), centerWidth,
centerWordView.getPaint()) < MIN_TEXT_XSCALE) {
// Layout only the most relevant suggested word at the center of the suggestion strip
// by consolidating all slots in the strip.
- countInStrip = 1;
+ final int countInStrip = 1;
mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip);
layoutWord(mCenterPositionInStrip, stripWidth - mPadding);
stripView.addView(centerWordView);
@@ -326,31 +382,33 @@ final class SuggestionStripLayoutHelper {
if (SuggestionStripView.DBG) {
layoutDebugInfo(mCenterPositionInStrip, placerView, stripWidth);
}
- } else {
- countInStrip = mSuggestionsCountInStrip;
- mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip);
- int x = 0;
- for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) {
- if (positionInStrip != 0) {
- final View divider = mDividerViews.get(positionInStrip);
- // Add divider if this isn't the left most suggestion in suggestions strip.
- addDivider(stripView, divider);
- x += divider.getMeasuredWidth();
- }
-
- final int width = getSuggestionWidth(positionInStrip, stripWidth);
- final TextView wordView = layoutWord(positionInStrip, width);
- stripView.addView(wordView);
- setLayoutWeight(wordView, getSuggestionWeight(positionInStrip),
- ViewGroup.LayoutParams.MATCH_PARENT);
- x += wordView.getMeasuredWidth();
-
- if (SuggestionStripView.DBG) {
- layoutDebugInfo(positionInStrip, placerView, x);
- }
+ final Integer lastIndex = (Integer)centerWordView.getTag();
+ return (lastIndex == null ? 0 : lastIndex) + 1;
+ }
+
+ final int countInStrip = mSuggestionsCountInStrip;
+ mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip);
+ int x = 0;
+ for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) {
+ if (positionInStrip != 0) {
+ final View divider = mDividerViews.get(positionInStrip);
+ // Add divider if this isn't the left most suggestion in suggestions strip.
+ addDivider(stripView, divider);
+ x += divider.getMeasuredWidth();
+ }
+
+ final int width = getSuggestionWidth(positionInStrip, stripWidth);
+ final TextView wordView = layoutWord(positionInStrip, width);
+ stripView.addView(wordView);
+ setLayoutWeight(wordView, getSuggestionWeight(positionInStrip),
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ x += wordView.getMeasuredWidth();
+
+ if (SuggestionStripView.DBG) {
+ layoutDebugInfo(positionInStrip, placerView, x);
}
}
- return countInStrip;
+ return startIndexOfMoreSuggestions;
}
/**
@@ -428,10 +486,10 @@ final class SuggestionStripLayoutHelper {
return (1.0f - mCenterSuggestionWeight) / (mSuggestionsCountInStrip - 1);
}
- private void setupWordViewsTextAndColor(final SuggestedWords suggestedWords,
- final int countInStrip) {
+ private int setupWordViewsAndReturnStartIndexOfMoreSuggestions(
+ final SuggestedWords suggestedWords, final int maxSuggestionInStrip) {
// Clear all suggestions first
- for (int positionInStrip = 0; positionInStrip < countInStrip; ++positionInStrip) {
+ for (int positionInStrip = 0; positionInStrip < maxSuggestionInStrip; ++positionInStrip) {
final TextView wordView = mWordViews.get(positionInStrip);
wordView.setText(null);
wordView.setTag(null);
@@ -440,11 +498,15 @@ final class SuggestionStripLayoutHelper {
mDebugInfoViews.get(positionInStrip).setText(null);
}
}
- final int count = Math.min(suggestedWords.size(), countInStrip);
- for (int indexInSuggestedWords = 0; indexInSuggestedWords < count;
- indexInSuggestedWords++) {
+ int count = 0;
+ int indexInSuggestedWords;
+ for (indexInSuggestedWords = 0; indexInSuggestedWords < suggestedWords.size()
+ && count < maxSuggestionInStrip; indexInSuggestedWords++) {
final int positionInStrip =
getPositionInSuggestionStrip(indexInSuggestedWords, suggestedWords);
+ if (positionInStrip < 0) {
+ continue;
+ }
final TextView wordView = mWordViews.get(positionInStrip);
// {@link TextView#getTag()} is used to get the index in suggestedWords at
// {@link SuggestionStripView#onClick(View)}.
@@ -455,10 +517,12 @@ final class SuggestionStripLayoutHelper {
mDebugInfoViews.get(positionInStrip).setText(
suggestedWords.getDebugString(indexInSuggestedWords));
}
+ count++;
}
+ return indexInSuggestedWords;
}
- private int layoutPunctuationSuggestionsAndReturnSuggestionCountInStrip(
+ private int layoutPunctuationsAndReturnStartIndexOfMoreSuggestions(
final PunctuationSuggestions punctuationSuggestions, final ViewGroup stripView) {
final int countInStrip = Math.min(punctuationSuggestions.size(), PUNCTUATIONS_IN_STRIP);
for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) {
@@ -485,8 +549,11 @@ final class SuggestionStripLayoutHelper {
}
public void layoutAddToDictionaryHint(final String word, final ViewGroup addToDictionaryStrip) {
+ final boolean shouldShowUiToAcceptTypedWord = Settings.getInstance().getCurrent()
+ .mShouldShowUiToAcceptTypedWord;
final int stripWidth = addToDictionaryStrip.getWidth();
- final int width = stripWidth - mDividerWidth - mPadding * 2;
+ final int width = shouldShowUiToAcceptTypedWord ? stripWidth
+ : stripWidth - mDividerWidth - mPadding * 2;
final TextView wordView = (TextView)addToDictionaryStrip.findViewById(R.id.word_to_save);
wordView.setTextColor(mColorTypedWord);
@@ -496,25 +563,38 @@ final class SuggestionStripLayoutHelper {
wordView.setText(wordToSave);
wordView.setTextScaleX(wordScaleX);
setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT);
+ final int wordVisibility = shouldShowUiToAcceptTypedWord ? View.GONE : View.VISIBLE;
+ wordView.setVisibility(wordVisibility);
+ addToDictionaryStrip.findViewById(R.id.word_to_save_divider).setVisibility(wordVisibility);
+ final Resources res = addToDictionaryStrip.getResources();
+ final CharSequence hintText;
+ final int hintWidth;
+ final float hintWeight;
final TextView hintView = (TextView)addToDictionaryStrip.findViewById(
R.id.hint_add_to_dictionary);
+ if (shouldShowUiToAcceptTypedWord) {
+ hintText = res.getText(R.string.hint_add_to_dictionary_without_word);
+ hintWidth = width;
+ hintWeight = 1.0f;
+ hintView.setGravity(Gravity.CENTER);
+ } else {
+ final boolean isRtlLanguage = (ViewCompat.getLayoutDirection(addToDictionaryStrip)
+ == ViewCompat.LAYOUT_DIRECTION_RTL);
+ final String arrow = isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW;
+ final boolean isRtlSystem = SubtypeLocaleUtils.isRtlLanguage(
+ res.getConfiguration().locale);
+ final CharSequence hint = res.getText(R.string.hint_add_to_dictionary);
+ hintText = (isRtlLanguage == isRtlSystem) ? (arrow + hint) : (hint + arrow);
+ hintWidth = width - wordWidth;
+ hintWeight = 1.0f - mCenterSuggestionWeight;
+ hintView.setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
+ }
hintView.setTextColor(mColorAutoCorrect);
- final boolean isRtlLanguage = (ViewCompat.getLayoutDirection(addToDictionaryStrip)
- == ViewCompat.LAYOUT_DIRECTION_RTL);
- final String arrow = isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW;
- final Resources res = addToDictionaryStrip.getResources();
- final boolean isRtlSystem = SubtypeLocaleUtils.isRtlLanguage(res.getConfiguration().locale);
- final CharSequence hintText = res.getText(R.string.hint_add_to_dictionary);
- final String hintWithArrow = (isRtlLanguage == isRtlSystem)
- ? (arrow + hintText) : (hintText + arrow);
- final int hintWidth = width - wordWidth;
- hintView.setTextScaleX(1.0f); // Reset textScaleX.
- final float hintScaleX = getTextScaleX(hintWithArrow, hintWidth, hintView.getPaint());
- hintView.setText(hintWithArrow);
+ final float hintScaleX = getTextScaleX(hintText, hintWidth, hintView.getPaint());
+ hintView.setText(hintText);
hintView.setTextScaleX(hintScaleX);
- setLayoutWeight(
- hintView, 1.0f - mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT);
+ setLayoutWeight(hintView, hintWeight, ViewGroup.LayoutParams.MATCH_PARENT);
}
public void layoutImportantNotice(final View importantNoticeStrip,
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index d151e4037..0fd5e139e 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -38,6 +38,7 @@ import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.TextView;
+import com.android.inputmethod.accessibility.AccessibilityUtils;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.MainKeyboardView;
import com.android.inputmethod.keyboard.MoreKeysPanel;
@@ -82,7 +83,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
Listener mListener;
private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
- private int mSuggestionsCountInStrip;
+ private int mStartIndexOfMoreSuggestions;
private final SuggestionStripLayoutHelper mLayoutHelper;
private final StripVisibilityGroup mStripVisibilityGroup;
@@ -213,13 +214,13 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
clear();
mStripVisibilityGroup.setLayoutDirection(isRtlLanguage);
mSuggestedWords = suggestedWords;
- mSuggestionsCountInStrip = mLayoutHelper.layoutAndReturnSuggestionCountInStrip(
+ mStartIndexOfMoreSuggestions = mLayoutHelper.layoutAndReturnStartIndexOfMoreSuggestions(
mSuggestedWords, mSuggestionsStrip, this);
mStripVisibilityGroup.showSuggestionsStrip();
}
- public int setMoreSuggestionsHeight(final int remainingHeight) {
- return mLayoutHelper.setMoreSuggestionsHeight(remainingHeight);
+ public void setMoreSuggestionsHeight(final int remainingHeight) {
+ mLayoutHelper.setMoreSuggestionsHeight(remainingHeight);
}
public boolean isShowingAddToDictionaryHint() {
@@ -336,7 +337,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
return false;
}
final SuggestionStripLayoutHelper layoutHelper = mLayoutHelper;
- if (!layoutHelper.mMoreSuggestionsAvailable) {
+ if (mSuggestedWords.size() <= mStartIndexOfMoreSuggestions) {
return false;
}
// Dismiss another {@link MoreKeysPanel} that may be being showed, for example
@@ -349,7 +350,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
final View container = mMoreSuggestionsContainer;
final int maxWidth = stripWidth - container.getPaddingLeft() - container.getPaddingRight();
final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder;
- builder.layout(mSuggestedWords, mSuggestionsCountInStrip, maxWidth,
+ builder.layout(mSuggestedWords, mStartIndexOfMoreSuggestions, maxWidth,
(int)(maxWidth * layoutHelper.mMinMoreSuggestionsWidth),
layoutHelper.getMaxMoreSuggestionsRow(), parentKeyboard);
mMoreSuggestionsView.setKeyboard(builder.build());
@@ -362,19 +363,21 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
mMoreSuggestionsListener);
mOriginX = mLastX;
mOriginY = mLastY;
- for (int i = 0; i < mSuggestionsCountInStrip; i++) {
+ for (int i = 0; i < mStartIndexOfMoreSuggestions; i++) {
mWordViews.get(i).setPressed(false);
}
return true;
}
- // Working variables for {@link #onLongClick(View)} and
- // {@link onInterceptTouchEvent(MotionEvent)}.
+ // Working variables for {@link onInterceptTouchEvent(MotionEvent)} and
+ // {@link onTouchEvent(MotionEvent)}.
private int mLastX;
private int mLastY;
private int mOriginX;
private int mOriginY;
private final int mMoreSuggestionsModalTolerance;
+ private boolean mNeedsToTransformTouchEventToHoverEvent;
+ private boolean mIsDispatchingHoverEventToMoreSuggestions;
private final GestureDetector mMoreSuggestionsSlidingDetector;
private final GestureDetector.OnGestureListener mMoreSuggestionsSlidingListener =
new GestureDetector.SimpleOnGestureListener() {
@@ -402,9 +405,12 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
final int y = (int)me.getY(index);
if (Math.abs(x - mOriginX) >= mMoreSuggestionsModalTolerance
|| mOriginY - y >= mMoreSuggestionsModalTolerance) {
- // Decided to be in the sliding input mode only when the touch point has been moved
+ // Decided to be in the sliding suggestion mode only when the touch point has been moved
// upward. Further {@link MotionEvent}s will be delivered to
// {@link #onTouchEvent(MotionEvent)}.
+ mNeedsToTransformTouchEventToHoverEvent =
+ AccessibilityUtils.getInstance().isTouchExplorationEnabled();
+ mIsDispatchingHoverEventToMoreSuggestions = false;
return true;
}
@@ -426,10 +432,41 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
// In the sliding input mode. {@link MotionEvent} should be forwarded to
// {@link MoreSuggestionsView}.
final int index = me.getActionIndex();
- final int x = (int)me.getX(index);
- final int y = (int)me.getY(index);
- me.setLocation(mMoreSuggestionsView.translateX(x), mMoreSuggestionsView.translateY(y));
- mMoreSuggestionsView.onTouchEvent(me);
+ final int x = mMoreSuggestionsView.translateX((int)me.getX(index));
+ final int y = mMoreSuggestionsView.translateY((int)me.getY(index));
+ me.setLocation(x, y);
+ if (!mNeedsToTransformTouchEventToHoverEvent) {
+ mMoreSuggestionsView.onTouchEvent(me);
+ return true;
+ }
+ // In sliding suggestion mode with accessibility mode on, a touch event should be
+ // transformed to a hover event.
+ final int width = mMoreSuggestionsView.getWidth();
+ final int height = mMoreSuggestionsView.getHeight();
+ final boolean onMoreSuggestions = (x >= 0 && x < width && y >= 0 && y < height);
+ if (!onMoreSuggestions && !mIsDispatchingHoverEventToMoreSuggestions) {
+ // Just drop this touch event because dispatching hover event isn't started yet and
+ // the touch event isn't on {@link MoreSuggestionsView}.
+ return true;
+ }
+ final int hoverAction;
+ if (onMoreSuggestions && !mIsDispatchingHoverEventToMoreSuggestions) {
+ // Transform this touch event to a hover enter event and start dispatching a hover
+ // event to {@link MoreSuggestionsView}.
+ mIsDispatchingHoverEventToMoreSuggestions = true;
+ hoverAction = MotionEvent.ACTION_HOVER_ENTER;
+ } else if (me.getActionMasked() == MotionEvent.ACTION_UP) {
+ // Transform this touch event to a hover exit event and stop dispatching a hover event
+ // after this.
+ mIsDispatchingHoverEventToMoreSuggestions = false;
+ mNeedsToTransformTouchEventToHoverEvent = false;
+ hoverAction = MotionEvent.ACTION_HOVER_EXIT;
+ } else {
+ // Transform this touch event to a hover move event.
+ hoverAction = MotionEvent.ACTION_HOVER_MOVE;
+ }
+ me.setAction(hoverAction);
+ mMoreSuggestionsView.onHoverEvent(me);
return true;
}
diff --git a/java/src/com/android/inputmethod/latin/utils/CursorAnchorInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/CursorAnchorInfoUtils.java
new file mode 100644
index 000000000..9dc0524a2
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/CursorAnchorInfoUtils.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.utils;
+
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.inputmethodservice.ExtractEditText;
+import android.inputmethodservice.InputMethodService;
+import android.text.Layout;
+import android.text.Spannable;
+import android.view.View;
+import android.view.ViewParent;
+import android.view.inputmethod.CursorAnchorInfo;
+import android.widget.TextView;
+
+/**
+ * This class allows input methods to extract {@link CursorAnchorInfo} directly from the given
+ * {@link TextView}. This is useful and even necessary to support full-screen mode where the default
+ * {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)} event callback must be
+ * ignored because it reports the character locations of the target application rather than
+ * characters on {@link ExtractEditText}.
+ */
+public final class CursorAnchorInfoUtils {
+ private CursorAnchorInfoUtils() {
+ // This helper class is not instantiable.
+ }
+
+ private static boolean isPositionVisible(final View view, final float positionX,
+ final float positionY) {
+ final float[] position = new float[] { positionX, positionY };
+ View currentView = view;
+
+ while (currentView != null) {
+ if (currentView != view) {
+ // Local scroll is already taken into account in positionX/Y
+ position[0] -= currentView.getScrollX();
+ position[1] -= currentView.getScrollY();
+ }
+
+ if (position[0] < 0 || position[1] < 0 ||
+ position[0] > currentView.getWidth() || position[1] > currentView.getHeight()) {
+ return false;
+ }
+
+ if (!currentView.getMatrix().isIdentity()) {
+ currentView.getMatrix().mapPoints(position);
+ }
+
+ position[0] += currentView.getLeft();
+ position[1] += currentView.getTop();
+
+ final ViewParent parent = currentView.getParent();
+ if (parent instanceof View) {
+ currentView = (View) parent;
+ } else {
+ // We've reached the ViewRoot, stop iterating
+ currentView = null;
+ }
+ }
+
+ // We've been able to walk up the view hierarchy and the position was never clipped
+ return true;
+ }
+
+ /**
+ * Returns {@link CursorAnchorInfo} from the given {@link TextView}.
+ * @param textView the target text view from which {@link CursorAnchorInfo} is to be extracted.
+ * @return the {@link CursorAnchorInfo} object based on the current layout. {@code null} if it
+ * is not feasible.
+ */
+ public static CursorAnchorInfo getCursorAnchorInfo(final TextView textView) {
+ Layout layout = textView.getLayout();
+ if (layout == null) {
+ return null;
+ }
+
+ final CursorAnchorInfo.Builder builder = new CursorAnchorInfo.Builder();
+
+ final int selectionStart = textView.getSelectionStart();
+ builder.setSelectionRange(selectionStart, textView.getSelectionEnd());
+
+ // Construct transformation matrix from view local coordinates to screen coordinates.
+ final Matrix viewToScreenMatrix = new Matrix(textView.getMatrix());
+ final int[] viewOriginInScreen = new int[2];
+ textView.getLocationOnScreen(viewOriginInScreen);
+ viewToScreenMatrix.postTranslate(viewOriginInScreen[0], viewOriginInScreen[1]);
+ builder.setMatrix(viewToScreenMatrix);
+
+ if (layout.getLineCount() == 0) {
+ return null;
+ }
+ final Rect lineBoundsWithoutOffset = new Rect();
+ final Rect lineBoundsWithOffset = new Rect();
+ layout.getLineBounds(0, lineBoundsWithoutOffset);
+ textView.getLineBounds(0, lineBoundsWithOffset);
+ final float viewportToContentHorizontalOffset = lineBoundsWithOffset.left
+ - lineBoundsWithoutOffset.left - textView.getScrollX();
+ final float viewportToContentVerticalOffset = lineBoundsWithOffset.top
+ - lineBoundsWithoutOffset.top - textView.getScrollY();
+
+ final CharSequence text = textView.getText();
+ if (text instanceof Spannable) {
+ // Here we assume that the composing text is marked as SPAN_COMPOSING flag. This is not
+ // necessarily true, but basically works.
+ int composingTextStart = text.length();
+ int composingTextEnd = 0;
+ final Spannable spannable = (Spannable) text;
+ final Object[] spans = spannable.getSpans(0, text.length(), Object.class);
+ for (Object span : spans) {
+ final int spanFlag = spannable.getSpanFlags(span);
+ if ((spanFlag & Spannable.SPAN_COMPOSING) != 0) {
+ composingTextStart = Math.min(composingTextStart,
+ spannable.getSpanStart(span));
+ composingTextEnd = Math.max(composingTextEnd, spannable.getSpanEnd(span));
+ }
+ }
+
+ final boolean hasComposingText =
+ (0 <= composingTextStart) && (composingTextStart < composingTextEnd);
+ if (hasComposingText) {
+ final CharSequence composingText = text.subSequence(composingTextStart,
+ composingTextEnd);
+ builder.setComposingText(composingTextStart, composingText);
+
+ final int minLine = layout.getLineForOffset(composingTextStart);
+ final int maxLine = layout.getLineForOffset(composingTextEnd - 1);
+ for (int line = minLine; line <= maxLine; ++line) {
+ final int lineStart = layout.getLineStart(line);
+ final int lineEnd = layout.getLineEnd(line);
+ final int offsetStart = Math.max(lineStart, composingTextStart);
+ final int offsetEnd = Math.min(lineEnd, composingTextEnd);
+ final boolean ltrLine =
+ layout.getParagraphDirection(line) == Layout.DIR_LEFT_TO_RIGHT;
+ final float[] widths = new float[offsetEnd - offsetStart];
+ layout.getPaint().getTextWidths(text, offsetStart, offsetEnd, widths);
+ final float top = layout.getLineTop(line);
+ final float bottom = layout.getLineBottom(line);
+ for (int offset = offsetStart; offset < offsetEnd; ++offset) {
+ final float charWidth = widths[offset - offsetStart];
+ final boolean isRtl = layout.isRtlCharAt(offset);
+ final float primary = layout.getPrimaryHorizontal(offset);
+ final float secondary = layout.getSecondaryHorizontal(offset);
+ // TODO: This doesn't work perfectly for text with custom styles and TAB
+ // chars.
+ final float left;
+ final float right;
+ if (ltrLine) {
+ if (isRtl) {
+ left = secondary - charWidth;
+ right = secondary;
+ } else {
+ left = primary;
+ right = primary + charWidth;
+ }
+ } else {
+ if (!isRtl) {
+ left = secondary;
+ right = secondary + charWidth;
+ } else {
+ left = primary - charWidth;
+ right = primary;
+ }
+ }
+ // TODO: Check top-right and bottom-left as well.
+ final float localLeft = left + viewportToContentHorizontalOffset;
+ final float localRight = right + viewportToContentHorizontalOffset;
+ final float localTop = top + viewportToContentVerticalOffset;
+ final float localBottom = bottom + viewportToContentVerticalOffset;
+ final boolean isTopLeftVisible = isPositionVisible(textView,
+ localLeft, localTop);
+ final boolean isBottomRightVisible =
+ isPositionVisible(textView, localRight, localBottom);
+ int characterBoundsFlags = 0;
+ if (isTopLeftVisible || isBottomRightVisible) {
+ characterBoundsFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
+ }
+ if (!isTopLeftVisible || !isTopLeftVisible) {
+ characterBoundsFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
+ }
+ if (isRtl) {
+ characterBoundsFlags |= CursorAnchorInfo.FLAG_IS_RTL;
+ }
+ // Here offset is the index in Java chars.
+ builder.addCharacterBounds(offset, localLeft, localTop, localRight,
+ localBottom, characterBoundsFlags);
+ }
+ }
+ }
+ }
+
+ // Treat selectionStart as the insertion point.
+ if (0 <= selectionStart) {
+ final int offset = selectionStart;
+ final int line = layout.getLineForOffset(offset);
+ final float insertionMarkerX = layout.getPrimaryHorizontal(offset)
+ + viewportToContentHorizontalOffset;
+ final float insertionMarkerTop = layout.getLineTop(line)
+ + viewportToContentVerticalOffset;
+ final float insertionMarkerBaseline = layout.getLineBaseline(line)
+ + viewportToContentVerticalOffset;
+ final float insertionMarkerBottom = layout.getLineBottom(line)
+ + viewportToContentVerticalOffset;
+ final boolean isTopVisible =
+ isPositionVisible(textView, insertionMarkerX, insertionMarkerTop);
+ final boolean isBottomVisible =
+ isPositionVisible(textView, insertionMarkerX, insertionMarkerBottom);
+ int insertionMarkerFlags = 0;
+ if (isTopVisible || isBottomVisible) {
+ insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
+ }
+ if (!isTopVisible || !isBottomVisible) {
+ insertionMarkerFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION;
+ }
+ if (layout.isRtlCharAt(offset)) {
+ insertionMarkerFlags |= CursorAnchorInfo.FLAG_IS_RTL;
+ }
+ builder.setInsertionMarkerLocation(insertionMarkerX, insertionMarkerTop,
+ insertionMarkerBaseline, insertionMarkerBottom, insertionMarkerFlags);
+ }
+ return builder.build();
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
index d76ea10c0..197908032 100644
--- a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
@@ -386,8 +386,7 @@ public class DictionaryInfoUtils {
final SpacingAndPunctuations spacingAndPunctuations) {
if (TextUtils.isEmpty(text)) return false;
final int length = text.length();
- // TODO: Make this test "length > Constants.DICTIONARY_MAX_WORD_LENGTH".
- if (length >= Constants.DICTIONARY_MAX_WORD_LENGTH) {
+ if (length > Constants.DICTIONARY_MAX_WORD_LENGTH) {
return false;
}
int i = 0;
diff --git a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatches.java b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatches.java
deleted file mode 100644
index 0ee6236b1..000000000
--- a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatches.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.inputmethod.latin.utils;
-
-import java.util.List;
-import java.util.Locale;
-import java.util.concurrent.TimeUnit;
-
-import android.content.Context;
-import android.util.Log;
-import android.util.LruCache;
-import android.view.inputmethod.InputMethodSubtype;
-
-import com.android.inputmethod.latin.DictionaryFacilitator;
-import com.android.inputmethod.latin.PrevWordsInfo;
-
-/**
- * This class is used to prevent distracters being added to personalization
- * or user history dictionaries
- */
-public class DistracterFilterCheckingExactMatches implements DistracterFilter {
- private static final String TAG = DistracterFilterCheckingExactMatches.class.getSimpleName();
- private static final boolean DEBUG = false;
-
- private static final long TIMEOUT_TO_WAIT_LOADING_DICTIONARIES_IN_SECONDS = 120;
- private static final int MAX_DISTRACTERS_CACHE_SIZE = 512;
-
- private final Context mContext;
- private final DictionaryFacilitator mDictionaryFacilitator;
- private final LruCache<String, Boolean> mDistractersCache;
- private final Object mLock = new Object();
-
- /**
- * Create a DistracterFilter instance.
- *
- * @param context the context.
- */
- public DistracterFilterCheckingExactMatches(final Context context) {
- mContext = context;
- mDictionaryFacilitator = new DictionaryFacilitator();
- mDistractersCache = new LruCache<>(MAX_DISTRACTERS_CACHE_SIZE);
- }
-
- @Override
- public void close() {
- mDictionaryFacilitator.closeDictionaries();
- }
-
- @Override
- public void updateEnabledSubtypes(final List<InputMethodSubtype> enabledSubtypes) {
- }
-
- private void loadDictionariesForLocale(final Locale newlocale) throws InterruptedException {
- mDictionaryFacilitator.resetDictionaries(mContext, newlocale,
- false /* useContactsDict */, false /* usePersonalizedDicts */,
- false /* forceReloadMainDictionary */, null /* listener */);
- mDictionaryFacilitator.waitForLoadingMainDictionary(
- TIMEOUT_TO_WAIT_LOADING_DICTIONARIES_IN_SECONDS, TimeUnit.SECONDS);
- }
-
- /**
- * Determine whether a word is a distracter to words in dictionaries.
- *
- * @param prevWordsInfo the information of previous words. Not used for now.
- * @param testedWord the word that will be tested to see whether it is a distracter to words
- * in dictionaries.
- * @param locale the locale of word.
- * @return true if testedWord is a distracter, otherwise false.
- */
- @Override
- public boolean isDistracterToWordsInDictionaries(final PrevWordsInfo prevWordsInfo,
- final String testedWord, final Locale locale) {
- if (locale == null) {
- return false;
- }
- if (!locale.equals(mDictionaryFacilitator.getLocale())) {
- synchronized (mLock) {
- // Reset dictionaries for the locale.
- try {
- mDistractersCache.evictAll();
- loadDictionariesForLocale(locale);
- } catch (final InterruptedException e) {
- Log.e(TAG, "Interrupted while waiting for loading dicts in DistracterFilter",
- e);
- return false;
- }
- }
- }
-
- final Boolean isCachedDistracter = mDistractersCache.get(testedWord);
- if (isCachedDistracter != null && isCachedDistracter) {
- if (DEBUG) {
- Log.d(TAG, "testedWord: " + testedWord);
- Log.d(TAG, "isDistracter: true (cache hit)");
- }
- return true;
- }
- // The tested word is a distracter when there is a word that is exact matched to the tested
- // word and its probability is higher than the tested word's probability.
- final int perfectMatchFreq = mDictionaryFacilitator.getFrequency(testedWord);
- final int exactMatchFreq = mDictionaryFacilitator.getMaxFrequencyOfExactMatches(testedWord);
- final boolean isDistracter = perfectMatchFreq < exactMatchFreq;
- if (DEBUG) {
- Log.d(TAG, "testedWord: " + testedWord);
- Log.d(TAG, "perfectMatchFreq: " + perfectMatchFreq);
- Log.d(TAG, "exactMatchFreq: " + exactMatchFreq);
- Log.d(TAG, "isDistracter: " + isDistracter);
- }
- if (isDistracter) {
- // Add the word to the cache.
- mDistractersCache.put(testedWord, Boolean.TRUE);
- }
- return isDistracter;
- }
-}
diff --git a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
new file mode 100644
index 000000000..27973287d
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.utils;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.text.InputType;
+import android.util.Log;
+import android.util.LruCache;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.keyboard.KeyboardLayoutSet;
+import com.android.inputmethod.latin.DictionaryFacilitator;
+import com.android.inputmethod.latin.PrevWordsInfo;
+import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.WordComposer;
+import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
+
+/**
+ * This class is used to prevent distracters being added to personalization
+ * or user history dictionaries
+ */
+public class DistracterFilterCheckingExactMatchesAndSuggestions implements DistracterFilter {
+ private static final String TAG =
+ DistracterFilterCheckingExactMatchesAndSuggestions.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
+ private static final long TIMEOUT_TO_WAIT_LOADING_DICTIONARIES_IN_SECONDS = 120;
+ private static final int MAX_DISTRACTERS_CACHE_SIZE = 512;
+
+ private final Context mContext;
+ private final Map<Locale, InputMethodSubtype> mLocaleToSubtypeMap;
+ private final Map<Locale, Keyboard> mLocaleToKeyboardMap;
+ private final DictionaryFacilitator mDictionaryFacilitator;
+ private final LruCache<String, Boolean> mDistractersCache;
+ private Keyboard mKeyboard;
+ private final Object mLock = new Object();
+
+ // If the score of the top suggestion exceeds this value, the tested word (e.g.,
+ // an OOV, a misspelling, or an in-vocabulary word) would be considered as a distractor to
+ // words in dictionary. The greater the threshold is, the less likely the tested word would
+ // become a distractor, which means the tested word will be more likely to be added to
+ // the dictionary.
+ private static final float DISTRACTER_WORD_SCORE_THRESHOLD = 0.4f;
+
+ /**
+ * Create a DistracterFilter instance.
+ *
+ * @param context the context.
+ */
+ public DistracterFilterCheckingExactMatchesAndSuggestions(final Context context) {
+ mContext = context;
+ mLocaleToSubtypeMap = new HashMap<>();
+ mLocaleToKeyboardMap = new HashMap<>();
+ mDictionaryFacilitator = new DictionaryFacilitator();
+ mDistractersCache = new LruCache<>(MAX_DISTRACTERS_CACHE_SIZE);
+ mKeyboard = null;
+ }
+
+ @Override
+ public void close() {
+ mDictionaryFacilitator.closeDictionaries();
+ }
+
+ @Override
+ public void updateEnabledSubtypes(final List<InputMethodSubtype> enabledSubtypes) {
+ final Map<Locale, InputMethodSubtype> newLocaleToSubtypeMap = new HashMap<>();
+ if (enabledSubtypes != null) {
+ for (final InputMethodSubtype subtype : enabledSubtypes) {
+ final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype);
+ if (newLocaleToSubtypeMap.containsKey(locale)) {
+ // Multiple subtypes are enabled for one locale.
+ // TODO: Investigate what we should do for this case.
+ continue;
+ }
+ newLocaleToSubtypeMap.put(locale, subtype);
+ }
+ }
+ if (mLocaleToSubtypeMap.equals(newLocaleToSubtypeMap)) {
+ // Enabled subtypes have not been changed.
+ return;
+ }
+ synchronized (mLock) {
+ mLocaleToSubtypeMap.clear();
+ mLocaleToSubtypeMap.putAll(newLocaleToSubtypeMap);
+ mLocaleToKeyboardMap.clear();
+ }
+ }
+
+ private void loadKeyboardForLocale(final Locale newLocale) {
+ final Keyboard cachedKeyboard = mLocaleToKeyboardMap.get(newLocale);
+ if (cachedKeyboard != null) {
+ mKeyboard = cachedKeyboard;
+ return;
+ }
+ final InputMethodSubtype subtype;
+ synchronized (mLock) {
+ subtype = mLocaleToSubtypeMap.get(newLocale);
+ }
+ if (subtype == null) {
+ return;
+ }
+ final EditorInfo editorInfo = new EditorInfo();
+ editorInfo.inputType = InputType.TYPE_CLASS_TEXT;
+ final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(
+ mContext, editorInfo);
+ final Resources res = mContext.getResources();
+ final int keyboardWidth = ResourceUtils.getDefaultKeyboardWidth(res);
+ final int keyboardHeight = ResourceUtils.getDefaultKeyboardHeight(res);
+ builder.setKeyboardGeometry(keyboardWidth, keyboardHeight);
+ builder.setSubtype(subtype);
+ builder.setIsSpellChecker(false /* isSpellChecker */);
+ final KeyboardLayoutSet layoutSet = builder.build();
+ mKeyboard = layoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET);
+ }
+
+ private void loadDictionariesForLocale(final Locale newlocale) throws InterruptedException {
+ mDictionaryFacilitator.resetDictionaries(mContext, newlocale,
+ false /* useContactsDict */, false /* usePersonalizedDicts */,
+ false /* forceReloadMainDictionary */, null /* listener */);
+ mDictionaryFacilitator.waitForLoadingMainDictionary(
+ TIMEOUT_TO_WAIT_LOADING_DICTIONARIES_IN_SECONDS, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Determine whether a word is a distracter to words in dictionaries.
+ *
+ * @param prevWordsInfo the information of previous words. Not used for now.
+ * @param testedWord the word that will be tested to see whether it is a distracter to words
+ * in dictionaries.
+ * @param locale the locale of word.
+ * @return true if testedWord is a distracter, otherwise false.
+ */
+ @Override
+ public boolean isDistracterToWordsInDictionaries(final PrevWordsInfo prevWordsInfo,
+ final String testedWord, final Locale locale) {
+ if (locale == null) {
+ return false;
+ }
+ if (!locale.equals(mDictionaryFacilitator.getLocale())) {
+ synchronized (mLock) {
+ if (!mLocaleToSubtypeMap.containsKey(locale)) {
+ Log.e(TAG, "Locale " + locale + " is not enabled.");
+ // TODO: Investigate what we should do for disabled locales.
+ return false;
+ }
+ loadKeyboardForLocale(locale);
+ // Reset dictionaries for the locale.
+ try {
+ mDistractersCache.evictAll();
+ loadDictionariesForLocale(locale);
+ } catch (final InterruptedException e) {
+ Log.e(TAG, "Interrupted while waiting for loading dicts in DistracterFilter",
+ e);
+ return false;
+ }
+ }
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "testedWord: " + testedWord);
+ }
+ final Boolean isCachedDistracter = mDistractersCache.get(testedWord);
+ if (isCachedDistracter != null && isCachedDistracter) {
+ if (DEBUG) {
+ Log.d(TAG, "isDistracter: true (cache hit)");
+ }
+ return true;
+ }
+
+ final boolean isDistracterCheckedByGetMaxFreqencyOfExactMatches =
+ checkDistracterUsingMaxFreqencyOfExactMatches(testedWord);
+ if (isDistracterCheckedByGetMaxFreqencyOfExactMatches) {
+ // Add the word to the cache.
+ mDistractersCache.put(testedWord, Boolean.TRUE);
+ return true;
+ }
+ final boolean isValidWord = mDictionaryFacilitator.isValidWord(testedWord,
+ false /* ignoreCase */);
+ if (isValidWord) {
+ // Valid word is not a distractor.
+ if (DEBUG) {
+ Log.d(TAG, "isDistracter: false (valid word)");
+ }
+ return false;
+ }
+
+ final boolean isDistracterCheckedByGetSuggestion =
+ checkDistracterUsingGetSuggestions(testedWord);
+ if (isDistracterCheckedByGetSuggestion) {
+ // Add the word to the cache.
+ mDistractersCache.put(testedWord, Boolean.TRUE);
+ return true;
+ }
+ return false;
+ }
+
+ private boolean checkDistracterUsingMaxFreqencyOfExactMatches(final String testedWord) {
+ // The tested word is a distracter when there is a word that is exact matched to the tested
+ // word and its probability is higher than the tested word's probability.
+ final int perfectMatchFreq = mDictionaryFacilitator.getFrequency(testedWord);
+ final int exactMatchFreq = mDictionaryFacilitator.getMaxFrequencyOfExactMatches(testedWord);
+ final boolean isDistracter = perfectMatchFreq < exactMatchFreq;
+ if (DEBUG) {
+ Log.d(TAG, "perfectMatchFreq: " + perfectMatchFreq);
+ Log.d(TAG, "exactMatchFreq: " + exactMatchFreq);
+ Log.d(TAG, "isDistracter: " + isDistracter);
+ }
+ return isDistracter;
+ }
+
+ private boolean checkDistracterUsingGetSuggestions(final String testedWord) {
+ if (mKeyboard == null) {
+ return false;
+ }
+ final SettingsValuesForSuggestion settingsValuesForSuggestion =
+ new SettingsValuesForSuggestion(false /* blockPotentiallyOffensive */,
+ false /* spaceAwareGestureEnabled */,
+ null /* additionalFeaturesSettingValues */);
+ final int trailingSingleQuotesCount = StringUtils.getTrailingSingleQuotesCount(testedWord);
+ final String consideredWord = trailingSingleQuotesCount > 0 ?
+ testedWord.substring(0, testedWord.length() - trailingSingleQuotesCount) :
+ testedWord;
+ final WordComposer composer = new WordComposer();
+ final int[] codePoints = StringUtils.toCodePointArray(testedWord);
+
+ synchronized (mLock) {
+ final int[] coordinates = mKeyboard.getCoordinates(codePoints);
+ composer.setComposingWord(codePoints, coordinates);
+ final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults(
+ composer, PrevWordsInfo.EMPTY_PREV_WORDS_INFO, mKeyboard.getProximityInfo(),
+ settingsValuesForSuggestion, 0 /* sessionId */);
+ if (suggestionResults.isEmpty()) {
+ return false;
+ }
+ final SuggestedWordInfo firstSuggestion = suggestionResults.first();
+ final boolean isDistractor = suggestionExceedsDistracterThreshold(
+ firstSuggestion, consideredWord, DISTRACTER_WORD_SCORE_THRESHOLD);
+ if (DEBUG) {
+ Log.d(TAG, "isDistracter: " + isDistractor);
+ }
+ return isDistractor;
+ }
+ }
+
+ private static boolean suggestionExceedsDistracterThreshold(final SuggestedWordInfo suggestion,
+ final String consideredWord, final float distracterThreshold) {
+ if (suggestion == null) {
+ return false;
+ }
+ final int suggestionScore = suggestion.mScore;
+ final float normalizedScore = BinaryDictionaryUtils.calcNormalizedScore(
+ consideredWord, suggestion.mWord, suggestionScore);
+ if (DEBUG) {
+ Log.d(TAG, "normalizedScore: " + normalizedScore);
+ Log.d(TAG, "distracterThreshold: " + distracterThreshold);
+ }
+ if (normalizedScore > distracterThreshold) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java b/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java
index a44c5764a..c2167a76b 100644
--- a/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java
@@ -18,11 +18,16 @@ package com.android.inputmethod.latin.utils;
import com.android.inputmethod.dictionarypack.DictionarySettingsFragment;
import com.android.inputmethod.latin.about.AboutPreferences;
+import com.android.inputmethod.latin.settings.AdvancedSettingsFragment;
+import com.android.inputmethod.latin.settings.AppearanceSettingsFragment;
+import com.android.inputmethod.latin.settings.CorrectionSettingsFragment;
import com.android.inputmethod.latin.settings.CustomInputStyleSettingsFragment;
-import com.android.inputmethod.latin.settings.DebugSettings;
-import com.android.inputmethod.latin.settings.InputSettingsFragment;
+import com.android.inputmethod.latin.settings.DebugSettingsFragment;
+import com.android.inputmethod.latin.settings.GestureSettingsFragment;
import com.android.inputmethod.latin.settings.MultiLingualSettingsFragment;
+import com.android.inputmethod.latin.settings.PreferencesSettingsFragment;
import com.android.inputmethod.latin.settings.SettingsFragment;
+import com.android.inputmethod.latin.settings.ThemeSettingsFragment;
import com.android.inputmethod.latin.spellcheck.SpellCheckerSettingsFragment;
import com.android.inputmethod.latin.userdictionary.UserDictionaryAddWordFragment;
import com.android.inputmethod.latin.userdictionary.UserDictionaryList;
@@ -36,10 +41,15 @@ public class FragmentUtils {
static {
sLatinImeFragments.add(DictionarySettingsFragment.class.getName());
sLatinImeFragments.add(AboutPreferences.class.getName());
- sLatinImeFragments.add(InputSettingsFragment.class.getName());
+ sLatinImeFragments.add(PreferencesSettingsFragment.class.getName());
+ sLatinImeFragments.add(AppearanceSettingsFragment.class.getName());
+ sLatinImeFragments.add(ThemeSettingsFragment.class.getName());
sLatinImeFragments.add(MultiLingualSettingsFragment.class.getName());
sLatinImeFragments.add(CustomInputStyleSettingsFragment.class.getName());
- sLatinImeFragments.add(DebugSettings.class.getName());
+ sLatinImeFragments.add(GestureSettingsFragment.class.getName());
+ sLatinImeFragments.add(CorrectionSettingsFragment.class.getName());
+ sLatinImeFragments.add(AdvancedSettingsFragment.class.getName());
+ sLatinImeFragments.add(DebugSettingsFragment.class.getName());
sLatinImeFragments.add(SettingsFragment.class.getName());
sLatinImeFragments.add(SpellCheckerSettingsFragment.class.getName());
sLatinImeFragments.add(UserDictionaryAddWordFragment.class.getName());
diff --git a/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java
index 8b7077879..ea406fa75 100644
--- a/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java
@@ -23,15 +23,24 @@ import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
import android.util.Log;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.R;
+import java.util.concurrent.TimeUnit;
+
public final class ImportantNoticeUtils {
private static final String TAG = ImportantNoticeUtils.class.getSimpleName();
// {@link SharedPreferences} name to save the last important notice version that has been
// displayed to users.
private static final String PREFERENCE_NAME = "important_notice_pref";
- private static final String KEY_IMPORTANT_NOTICE_VERSION = "important_notice_version";
+ @UsedForTesting
+ static final String KEY_IMPORTANT_NOTICE_VERSION = "important_notice_version";
+ @UsedForTesting
+ static final String KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE =
+ "timestamp_of_first_important_notice";
+ @UsedForTesting
+ static final long TIMEOUT_OF_IMPORTANT_NOTICE = TimeUnit.HOURS.toMillis(23);
public static final int VERSION_TO_ENABLE_PERSONALIZED_SUGGESTIONS = 1;
// Copy of the hidden {@link Settings.Secure#USER_SETUP_COMPLETE} settings key.
@@ -56,15 +65,18 @@ public final class ImportantNoticeUtils {
}
}
- private static SharedPreferences getImportantNoticePreferences(final Context context) {
+ @UsedForTesting
+ static SharedPreferences getImportantNoticePreferences(final Context context) {
return context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
}
- private static int getCurrentImportantNoticeVersion(final Context context) {
+ @UsedForTesting
+ static int getCurrentImportantNoticeVersion(final Context context) {
return context.getResources().getInteger(R.integer.config_important_notice_version);
}
- private static int getLastImportantNoticeVersion(final Context context) {
+ @UsedForTesting
+ static int getLastImportantNoticeVersion(final Context context) {
return getImportantNoticePreferences(context).getInt(KEY_IMPORTANT_NOTICE_VERSION, 0);
}
@@ -77,6 +89,20 @@ public final class ImportantNoticeUtils {
return getCurrentImportantNoticeVersion(context) > lastVersion;
}
+ @UsedForTesting
+ static boolean hasTimeoutPassed(final Context context, final long currentTimeInMillis) {
+ final SharedPreferences prefs = getImportantNoticePreferences(context);
+ if (!prefs.contains(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE)) {
+ prefs.edit()
+ .putLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE, currentTimeInMillis)
+ .apply();
+ }
+ final long firstDisplayTimeInMillis = prefs.getLong(
+ KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE, currentTimeInMillis);
+ final long elapsedTime = currentTimeInMillis - firstDisplayTimeInMillis;
+ return elapsedTime >= TIMEOUT_OF_IMPORTANT_NOTICE;
+ }
+
public static boolean shouldShowImportantNotice(final Context context) {
if (!hasNewImportantNotice(context)) {
return false;
@@ -88,6 +114,10 @@ public final class ImportantNoticeUtils {
if (isInSystemSetupWizard(context)) {
return false;
}
+ if (hasTimeoutPassed(context, System.currentTimeMillis())) {
+ updateLastImportantNoticeVersion(context);
+ return false;
+ }
return true;
}
@@ -95,11 +125,12 @@ public final class ImportantNoticeUtils {
getImportantNoticePreferences(context)
.edit()
.putInt(KEY_IMPORTANT_NOTICE_VERSION, getNextImportantNoticeVersion(context))
+ .remove(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE)
.apply();
}
public static String getNextImportantNoticeTitle(final Context context) {
- final int nextVersion = getCurrentImportantNoticeVersion(context);
+ final int nextVersion = getNextImportantNoticeVersion(context);
final String[] importantNoticeTitleArray = context.getResources().getStringArray(
R.array.important_notice_title_array);
if (nextVersion > 0 && nextVersion < importantNoticeTitleArray.length) {
diff --git a/java/src/com/android/inputmethod/latin/utils/ScriptUtils.java b/java/src/com/android/inputmethod/latin/utils/ScriptUtils.java
index a76a6dfd7..0e244666d 100644
--- a/java/src/com/android/inputmethod/latin/utils/ScriptUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/ScriptUtils.java
@@ -26,13 +26,24 @@ public class ScriptUtils {
// Used for hardware keyboards
public static final int SCRIPT_UNKNOWN = -1;
// TODO: should we use ISO 15924 identifiers instead?
- public static final int SCRIPT_LATIN = 0;
- public static final int SCRIPT_CYRILLIC = 1;
- public static final int SCRIPT_GREEK = 2;
- public static final int SCRIPT_ARABIC = 3;
- public static final int SCRIPT_HEBREW = 4;
- public static final int SCRIPT_ARMENIAN = 5;
- public static final int SCRIPT_GEORGIAN = 6;
+ public static final int SCRIPT_ARABIC = 0;
+ public static final int SCRIPT_ARMENIAN = 1;
+ public static final int SCRIPT_BENGALI = 2;
+ public static final int SCRIPT_CYRILLIC = 3;
+ public static final int SCRIPT_DEVANAGARI = 4;
+ public static final int SCRIPT_GEORGIAN = 5;
+ public static final int SCRIPT_GREEK = 6;
+ public static final int SCRIPT_HEBREW = 7;
+ public static final int SCRIPT_KANNADA = 8;
+ public static final int SCRIPT_KHMER = 9;
+ public static final int SCRIPT_LAO = 10;
+ public static final int SCRIPT_LATIN = 11;
+ public static final int SCRIPT_MALAYALAM = 12;
+ public static final int SCRIPT_MYANMAR = 13;
+ public static final int SCRIPT_SINHALA = 14;
+ public static final int SCRIPT_TAMIL = 15;
+ public static final int SCRIPT_TELUGU = 16;
+ public static final int SCRIPT_THAI = 17;
public static final TreeMap<String, Integer> mSpellCheckerLanguageToScript;
static {
// List of the supported languages and their associated script. We won't check
@@ -72,56 +83,96 @@ public class ScriptUtils {
*/
public static boolean isLetterPartOfScript(final int codePoint, final int scriptId) {
switch (scriptId) {
- case SCRIPT_LATIN:
- // Our supported latin script dictionaries (EFIGS) at the moment only include
- // characters in the C0, C1, Latin Extended A and B, IPA extensions unicode
- // blocks. As it happens, those are back-to-back in the code range 0x40 to 0x2AF,
- // so the below is a very efficient way to test for it. As for the 0-0x3F, it's
- // excluded from isLetter anyway.
- return codePoint <= 0x2AF && Character.isLetter(codePoint);
- case SCRIPT_CYRILLIC:
- // All Cyrillic characters are in the 400~52F block. There are some in the upper
- // Unicode range, but they are archaic characters that are not used in modern
- // Russian and are not used by our dictionary.
- return codePoint >= 0x400 && codePoint <= 0x52F && Character.isLetter(codePoint);
- case SCRIPT_GREEK:
- // Greek letters are either in the 370~3FF range (Greek & Coptic), or in the
- // 1F00~1FFF range (Greek extended). Our dictionary contains both sort of characters.
- // Our dictionary also contains a few words with 0xF2; it would be best to check
- // if that's correct, but a web search does return results for these words so
- // they are probably okay.
- return (codePoint >= 0x370 && codePoint <= 0x3FF)
- || (codePoint >= 0x1F00 && codePoint <= 0x1FFF)
- || codePoint == 0xF2;
case SCRIPT_ARABIC:
// Arabic letters can be in any of the following blocks:
// Arabic U+0600..U+06FF
- // Arabic Supplement U+0750..U+077F
+ // Arabic Supplement, Thaana U+0750..U+077F, U+0780..U+07BF
// Arabic Extended-A U+08A0..U+08FF
// Arabic Presentation Forms-A U+FB50..U+FDFF
// Arabic Presentation Forms-B U+FE70..U+FEFF
return (codePoint >= 0x600 && codePoint <= 0x6FF)
- || (codePoint >= 0x750 && codePoint <= 0x77F)
+ || (codePoint >= 0x750 && codePoint <= 0x7BF)
|| (codePoint >= 0x8A0 && codePoint <= 0x8FF)
|| (codePoint >= 0xFB50 && codePoint <= 0xFDFF)
|| (codePoint >= 0xFE70 && codePoint <= 0xFEFF);
- case SCRIPT_HEBREW:
- // Hebrew letters are in the Hebrew unicode block, which spans from U+0590 to U+05FF,
- // or in the Alphabetic Presentation Forms block, U+FB00..U+FB4F, but only in the
- // Hebrew part of that block, which is U+FB1D..U+FB4F.
- return (codePoint >= 0x590 && codePoint <= 0x5FF
- || codePoint >= 0xFB1D && codePoint <= 0xFB4F);
case SCRIPT_ARMENIAN:
// Armenian letters are in the Armenian unicode block, U+0530..U+058F and
// Alphabetic Presentation Forms block, U+FB00..U+FB4F, but only in the Armenian part
// of that block, which is U+FB13..U+FB17.
return (codePoint >= 0x530 && codePoint <= 0x58F
|| codePoint >= 0xFB13 && codePoint <= 0xFB17);
+ case SCRIPT_BENGALI:
+ // Bengali unicode block is U+0980..U+09FF
+ return (codePoint >= 0x980 && codePoint <= 0x9FF);
+ case SCRIPT_CYRILLIC:
+ // All Cyrillic characters are in the 400~52F block. There are some in the upper
+ // Unicode range, but they are archaic characters that are not used in modern
+ // Russian and are not used by our dictionary.
+ return codePoint >= 0x400 && codePoint <= 0x52F && Character.isLetter(codePoint);
+ case SCRIPT_DEVANAGARI:
+ // Devanagari unicode block is +0900..U+097F
+ return (codePoint >= 0x900 && codePoint <= 0x97F);
case SCRIPT_GEORGIAN:
// Georgian letters are in the Georgian unicode block, U+10A0..U+10FF,
// or Georgian supplement block, U+2D00..U+2D2F
return (codePoint >= 0x10A0 && codePoint <= 0x10FF
|| codePoint >= 0x2D00 && codePoint <= 0x2D2F);
+ case SCRIPT_GREEK:
+ // Greek letters are either in the 370~3FF range (Greek & Coptic), or in the
+ // 1F00~1FFF range (Greek extended). Our dictionary contains both sort of characters.
+ // Our dictionary also contains a few words with 0xF2; it would be best to check
+ // if that's correct, but a web search does return results for these words so
+ // they are probably okay.
+ return (codePoint >= 0x370 && codePoint <= 0x3FF)
+ || (codePoint >= 0x1F00 && codePoint <= 0x1FFF)
+ || codePoint == 0xF2;
+ case SCRIPT_HEBREW:
+ // Hebrew letters are in the Hebrew unicode block, which spans from U+0590 to U+05FF,
+ // or in the Alphabetic Presentation Forms block, U+FB00..U+FB4F, but only in the
+ // Hebrew part of that block, which is U+FB1D..U+FB4F.
+ return (codePoint >= 0x590 && codePoint <= 0x5FF
+ || codePoint >= 0xFB1D && codePoint <= 0xFB4F);
+ case SCRIPT_KANNADA:
+ // Kannada unicode block is U+0C80..U+0CFF
+ return (codePoint >= 0xC80 && codePoint <= 0xCFF);
+ case SCRIPT_KHMER:
+ // Khmer letters are in unicode block U+1780..U+17FF, and the Khmer symbols block
+ // is U+19E0..U+19FF
+ return (codePoint >= 0x1780 && codePoint <= 0x17FF
+ || codePoint >= 0x19E0 && codePoint <= 0x19FF);
+ case SCRIPT_LAO:
+ // The Lao block is U+0E80..U+0EFF
+ return (codePoint >= 0xE80 && codePoint <= 0xEFF);
+ case SCRIPT_LATIN:
+ // Our supported latin script dictionaries (EFIGS) at the moment only include
+ // characters in the C0, C1, Latin Extended A and B, IPA extensions unicode
+ // blocks. As it happens, those are back-to-back in the code range 0x40 to 0x2AF,
+ // so the below is a very efficient way to test for it. As for the 0-0x3F, it's
+ // excluded from isLetter anyway.
+ return codePoint <= 0x2AF && Character.isLetter(codePoint);
+ case SCRIPT_MALAYALAM:
+ // Malayalam unicode block is U+0D00..U+0D7F
+ return (codePoint >= 0xD00 && codePoint <= 0xD7F);
+ case SCRIPT_MYANMAR:
+ // Myanmar has three unicode blocks :
+ // Myanmar U+1000..U+109F
+ // Myanmar extended-A U+AA60..U+AA7F
+ // Myanmar extended-B U+A9E0..U+A9FF
+ return (codePoint >= 0x1000 && codePoint <= 0x109F
+ || codePoint >= 0xAA60 && codePoint <= 0xAA7F
+ || codePoint >= 0xA9E0 && codePoint <= 0xA9FF);
+ case SCRIPT_SINHALA:
+ // Sinhala unicode block is U+0D80..U+0DFF
+ return (codePoint >= 0xD80 && codePoint <= 0xDFF);
+ case SCRIPT_TAMIL:
+ // Tamil unicode block is U+0B80..U+0BFF
+ return (codePoint >= 0xB80 && codePoint <= 0xBFF);
+ case SCRIPT_TELUGU:
+ // Telugu unicode block is U+0C00..U+0C7F
+ return (codePoint >= 0xC00 && codePoint <= 0xC7F);
+ case SCRIPT_THAI:
+ // Thai unicode block is U+0E00..U+0E7F
+ return (codePoint >= 0xE00 && codePoint <= 0xE7F);
case SCRIPT_UNKNOWN:
return true;
default:
diff --git a/java/src/com/android/inputmethod/latin/utils/StringUtils.java b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
index 38f0b3fee..79128dbd2 100644
--- a/java/src/com/android/inputmethod/latin/utils/StringUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
@@ -37,6 +37,14 @@ public final class StringUtils {
private static final String EMPTY_STRING = "";
+ private static final char CHAR_LINE_FEED = 0X000A;
+ private static final char CHAR_VERTICAL_TAB = 0X000B;
+ private static final char CHAR_FORM_FEED = 0X000C;
+ private static final char CHAR_CARRIAGE_RETURN = 0X000D;
+ private static final char CHAR_NEXT_LINE = 0X0085;
+ private static final char CHAR_LINE_SEPARATOR = 0X2028;
+ private static final char CHAR_PARAGRAPH_SEPARATOR = 0X2029;
+
private StringUtils() {
// This utility class is not publicly instantiable.
}
@@ -123,20 +131,20 @@ public final class StringUtils {
public static String capitalizeFirstCodePoint(final String s, final Locale locale) {
if (s.length() <= 1) {
- return s.toUpperCase(locale);
+ return toUpperCaseOfStringForLocale(s, true /* needsToUpperCase */, locale);
}
// Please refer to the comment below in
// {@link #capitalizeFirstAndDowncaseRest(String,Locale)} as this has the same shortcomings
final int cutoff = s.offsetByCodePoints(0, 1);
- return s.substring(0, cutoff).toUpperCase(locale) + s.substring(cutoff);
+ return toUpperCaseOfStringForLocale(
+ s.substring(0, cutoff), true /* needsToUpperCase */, locale) + s.substring(cutoff);
}
public static String capitalizeFirstAndDowncaseRest(final String s, final Locale locale) {
if (s.length() <= 1) {
- return s.toUpperCase(locale);
+ return toUpperCaseOfStringForLocale(s, true /* needsToUpperCase */, locale);
}
// TODO: fix the bugs below
- // - This does not work for Greek, because it returns upper case instead of title case.
// - It does not work for Serbian, because it fails to account for the "lj" character,
// which should be "Lj" in title case and "LJ" in upper case.
// - It does not work for Dutch, because it fails to account for the "ij" digraph when it's
@@ -144,7 +152,9 @@ public final class StringUtils {
// be capitalized as "IJ" as if they were a single letter in most words (not all). If the
// unicode char for the ligature is used however, it works.
final int cutoff = s.offsetByCodePoints(0, 1);
- return s.substring(0, cutoff).toUpperCase(locale) + s.substring(cutoff).toLowerCase(locale);
+ final String titleCaseFirstLetter = toUpperCaseOfStringForLocale(
+ s.substring(0, cutoff), true /* needsToUpperCase */, locale);
+ return titleCaseFirstLetter + s.substring(cutoff).toLowerCase(locale);
}
private static final int[] EMPTY_CODEPOINTS = {};
@@ -481,10 +491,23 @@ public final class StringUtils {
return bytes;
}
+ private static final String LANGUAGE_GREEK = "el";
+
+ private static Locale getLocaleUsedForToTitleCase(final Locale locale) {
+ // In Greek locale {@link String#toUpperCase(Locale)} eliminates accents from its result.
+ // In order to get accented upper case letter, {@link Locale#ROOT} should be used.
+ if (LANGUAGE_GREEK.equals(locale.getLanguage())) {
+ return Locale.ROOT;
+ }
+ return locale;
+ }
+
public static String toUpperCaseOfStringForLocale(final String text,
final boolean needsToUpperCase, final Locale locale) {
- if (text == null || !needsToUpperCase) return text;
- return text.toUpperCase(locale);
+ if (text == null || !needsToUpperCase) {
+ return text;
+ }
+ return text.toUpperCase(getLocaleUsedForToTitleCase(locale));
}
public static int toUpperCaseOfCodeForLocale(final int code, final boolean needsToUpperCase,
@@ -594,4 +617,30 @@ public final class StringUtils {
return sb + "]";
}
}
+
+ /**
+ * Returns whether the last composed word contains line-breaking character (e.g. CR or LF).
+ * @param text the text to be examined.
+ * @return {@code true} if the last composed word contains line-breaking separator.
+ */
+ @UsedForTesting
+ public static boolean hasLineBreakCharacter(final String text) {
+ if (TextUtils.isEmpty(text)) {
+ return false;
+ }
+ for (int i = text.length() - 1; i >= 0; --i) {
+ final char c = text.charAt(i);
+ switch (c) {
+ case CHAR_LINE_FEED:
+ case CHAR_VERTICAL_TAB:
+ case CHAR_FORM_FEED:
+ case CHAR_CARRIAGE_RETURN:
+ case CHAR_NEXT_LINE:
+ case CHAR_LINE_SEPARATOR:
+ case CHAR_PARAGRAPH_SEPARATOR:
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java
index 7170bd789..8cd49509f 100644
--- a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java
+++ b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java
@@ -32,14 +32,18 @@ import java.util.TreeSet;
public final class SuggestionResults extends TreeSet<SuggestedWordInfo> {
public final Locale mLocale;
public final ArrayList<SuggestedWordInfo> mRawSuggestions;
+ // TODO: Instead of a boolean , we may want to include the context of this suggestion results,
+ // such as {@link PrevWordsInfo}.
+ public final boolean mIsBeginningOfSentence;
private final int mCapacity;
- public SuggestionResults(final Locale locale, final int capacity) {
- this(locale, sSuggestedWordInfoComparator, capacity);
+ public SuggestionResults(final Locale locale, final int capacity,
+ final boolean isBeginningOfSentence) {
+ this(locale, sSuggestedWordInfoComparator, capacity, isBeginningOfSentence);
}
- public SuggestionResults(final Locale locale, final Comparator<SuggestedWordInfo> comparator,
- final int capacity) {
+ private SuggestionResults(final Locale locale, final Comparator<SuggestedWordInfo> comparator,
+ final int capacity, final boolean isBeginningOfSentence) {
super(comparator);
mLocale = locale;
mCapacity = capacity;
@@ -48,6 +52,7 @@ public final class SuggestionResults extends TreeSet<SuggestedWordInfo> {
} else {
mRawSuggestions = null;
}
+ mIsBeginningOfSentence = isBeginningOfSentence;
}
@Override
diff --git a/java/src/com/android/inputmethod/latin/utils/ViewLayoutUtils.java b/java/src/com/android/inputmethod/latin/utils/ViewLayoutUtils.java
index f9d853493..dd122b634 100644
--- a/java/src/com/android/inputmethod/latin/utils/ViewLayoutUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/ViewLayoutUtils.java
@@ -19,7 +19,10 @@ package com.android.inputmethod.latin.utils;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.MarginLayoutParams;
+import android.view.Window;
+import android.view.WindowManager;
import android.widget.FrameLayout;
+import android.widget.LinearLayout;
import android.widget.RelativeLayout;
public final class ViewLayoutUtils {
@@ -51,4 +54,40 @@ public final class ViewLayoutUtils {
marginLayoutParams.setMargins(x, y, 0, 0);
}
}
+
+ public static void updateLayoutHeightOf(final Window window, final int layoutHeight) {
+ final WindowManager.LayoutParams params = window.getAttributes();
+ if (params.height != layoutHeight) {
+ params.height = layoutHeight;
+ window.setAttributes(params);
+ }
+ }
+
+ public static void updateLayoutHeightOf(final View view, final int layoutHeight) {
+ final ViewGroup.LayoutParams params = view.getLayoutParams();
+ if (params.height != layoutHeight) {
+ params.height = layoutHeight;
+ view.setLayoutParams(params);
+ }
+ }
+
+ public static void updateLayoutGravityOf(final View view, final int layoutGravity) {
+ final ViewGroup.LayoutParams lp = view.getLayoutParams();
+ if (lp instanceof LinearLayout.LayoutParams) {
+ final LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)lp;
+ if (params.gravity != layoutGravity) {
+ params.gravity = layoutGravity;
+ view.setLayoutParams(params);
+ }
+ } else if (lp instanceof FrameLayout.LayoutParams) {
+ final FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)lp;
+ if (params.gravity != layoutGravity) {
+ params.gravity = layoutGravity;
+ view.setLayoutParams(params);
+ }
+ } else {
+ throw new IllegalArgumentException("Layout parameter doesn't have gravity: "
+ + lp.getClass().getName());
+ }
+ }
}
diff --git a/native/jni/NativeFileList.mk b/native/jni/NativeFileList.mk
index 1cb61c45f..7a732a588 100644
--- a/native/jni/NativeFileList.mk
+++ b/native/jni/NativeFileList.mk
@@ -72,7 +72,7 @@ LATIN_IME_CORE_SRC_FILES := \
ver4_pt_node_array_reader.cpp) \
$(addprefix suggest/policyimpl/dictionary/structure/v4/content/, \
bigram_dict_content.cpp \
- probability_dict_content.cpp \
+ language_model_dict_content.cpp \
shortcut_dict_content.cpp \
sparse_table_dict_content.cpp \
terminal_position_lookup_table.cpp) \
@@ -84,7 +84,8 @@ LATIN_IME_CORE_SRC_FILES := \
forgetting_curve_utils.cpp \
format_utils.cpp \
mmapped_buffer.cpp \
- sparse_table.cpp) \
+ sparse_table.cpp \
+ trie_map.cpp ) \
suggest/policyimpl/gesture/gesture_suggest_policy_factory.cpp \
$(addprefix suggest/policyimpl/typing/, \
scoring_params.cpp \
@@ -124,5 +125,9 @@ LATIN_IME_CORE_TEST_FILES := \
defines_test.cpp \
suggest/core/layout/normal_distribution_2d_test.cpp \
suggest/core/dictionary/bloom_filter_test.cpp \
+ suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content_test.cpp \
+ suggest/policyimpl/dictionary/structure/v4/content/probability_entry_test.cpp \
suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer_test.cpp \
- utils/autocorrection_threshold_utils_test.cpp
+ suggest/policyimpl/dictionary/utils/trie_map_test.cpp \
+ utils/autocorrection_threshold_utils_test.cpp \
+ utils/int_array_view_test.cpp
diff --git a/native/jni/src/suggest/core/dicnode/dic_node.h b/native/jni/src/suggest/core/dicnode/dic_node.h
index 92f39ea25..d1b2c87be 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node.h
@@ -117,7 +117,7 @@ class DicNode {
int newPrevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
newPrevWordsPtNodePos[0] = dicNode->mDicNodeProperties.getPtNodePos();
for (size_t i = 1; i < NELEMS(newPrevWordsPtNodePos); ++i) {
- newPrevWordsPtNodePos[i] = dicNode->getNthPrevWordTerminalPtNodePos(i);
+ newPrevWordsPtNodePos[i] = dicNode->getPrevWordsTerminalPtNodePos()[i - 1];
}
mDicNodeProperties.init(rootPtNodeArrayPos, newPrevWordsPtNodePos);
mDicNodeState.initAsRootWithPreviousWord(&dicNode->mDicNodeState,
@@ -208,12 +208,9 @@ class DicNode {
return mDicNodeProperties.getPtNodePos();
}
- // Used to get n-gram probability in DicNodeUtils. n is 1-indexed.
- int getNthPrevWordTerminalPtNodePos(const int n) const {
- if (n <= 0 || n > MAX_PREV_WORD_COUNT_FOR_N_GRAM) {
- return NOT_A_DICT_POS;
- }
- return mDicNodeProperties.getPrevWordsTerminalPtNodePos()[n - 1];
+ // TODO: Use view class to return PtNodePos array.
+ const int *getPrevWordsTerminalPtNodePos() const {
+ return mDicNodeProperties.getPrevWordsTerminalPtNodePos();
}
// Used in DicNodeUtils
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 4445f4aaf..69ea67418 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp
+++ b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp
@@ -85,17 +85,10 @@ namespace latinime {
const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy,
const DicNode *const dicNode, MultiBigramMap *const multiBigramMap) {
const int unigramProbability = dicNode->getProbability();
- const int ptNodePos = dicNode->getPtNodePos();
- const int prevWordTerminalPtNodePos = dicNode->getNthPrevWordTerminalPtNodePos(1 /* n */);
- if (NOT_A_DICT_POS == ptNodePos || NOT_A_DICT_POS == prevWordTerminalPtNodePos) {
- // Note: Normally wordPos comes from the dictionary and should never equal
- // NOT_A_VALID_WORD_POS.
- return dictionaryStructurePolicy->getProbability(unigramProbability,
- NOT_A_PROBABILITY);
- }
if (multiBigramMap) {
+ const int *const prevWordsPtNodePos = dicNode->getPrevWordsTerminalPtNodePos();
return multiBigramMap->getBigramProbability(dictionaryStructurePolicy,
- prevWordTerminalPtNodePos, ptNodePos, unigramProbability);
+ prevWordsPtNodePos, dicNode->getPtNodePos(), unigramProbability);
}
return dictionaryStructurePolicy->getProbability(unigramProbability,
NOT_A_PROBABILITY);
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp
index fb25f757c..d62573970 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp
@@ -59,42 +59,48 @@ void Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession
}
}
+Dictionary::NgramListenerForPrediction::NgramListenerForPrediction(
+ const PrevWordsInfo *const prevWordsInfo, SuggestionResults *const suggestionResults,
+ const DictionaryStructureWithBufferPolicy *const dictStructurePolicy)
+ : mPrevWordsInfo(prevWordsInfo), mSuggestionResults(suggestionResults),
+ mDictStructurePolicy(dictStructurePolicy) {}
+
+void Dictionary::NgramListenerForPrediction::onVisitEntry(const int ngramProbability,
+ const int targetPtNodePos) {
+ if (targetPtNodePos == NOT_A_DICT_POS) {
+ return;
+ }
+ if (mPrevWordsInfo->isNthPrevWordBeginningOfSentence(1 /* n */)
+ && ngramProbability == NOT_A_PROBABILITY) {
+ return;
+ }
+ int targetWordCodePoints[MAX_WORD_LENGTH];
+ int unigramProbability = 0;
+ const int codePointCount = mDictStructurePolicy->
+ getCodePointsAndProbabilityAndReturnCodePointCount(targetPtNodePos,
+ MAX_WORD_LENGTH, targetWordCodePoints, &unigramProbability);
+ if (codePointCount <= 0) {
+ return;
+ }
+ const int probability = mDictStructurePolicy->getProbability(
+ unigramProbability, ngramProbability);
+ mSuggestionResults->addPrediction(targetWordCodePoints, codePointCount, probability);
+}
+
void Dictionary::getPredictions(const PrevWordsInfo *const prevWordsInfo,
SuggestionResults *const outSuggestionResults) const {
TimeKeeper::setCurrentTime();
- int unigramProbability = 0;
- int bigramCodePoints[MAX_WORD_LENGTH];
- BinaryDictionaryBigramsIterator bigramsIt = prevWordsInfo->getBigramsIteratorForPrediction(
+ NgramListenerForPrediction listener(prevWordsInfo, outSuggestionResults,
mDictionaryStructureWithBufferPolicy.get());
- while (bigramsIt.hasNext()) {
- bigramsIt.next();
- if (bigramsIt.getBigramPos() == NOT_A_DICT_POS) {
- continue;
- }
- if (prevWordsInfo->isNthPrevWordBeginningOfSentence(1 /* n */)
- && bigramsIt.getProbability() == NOT_A_PROBABILITY) {
- continue;
- }
- const int codePointCount = mDictionaryStructureWithBufferPolicy->
- getCodePointsAndProbabilityAndReturnCodePointCount(bigramsIt.getBigramPos(),
- MAX_WORD_LENGTH, bigramCodePoints, &unigramProbability);
- if (codePointCount <= 0) {
- continue;
- }
- const int probability = mDictionaryStructureWithBufferPolicy->getProbability(
- unigramProbability, bigramsIt.getProbability());
- outSuggestionResults->addPrediction(bigramCodePoints, codePointCount, probability);
- }
+ int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
+ prevWordsInfo->getPrevWordsTerminalPtNodePos(
+ mDictionaryStructureWithBufferPolicy.get(), prevWordsPtNodePos,
+ true /* tryLowerCaseSearch */);
+ mDictionaryStructureWithBufferPolicy->iterateNgramEntries(prevWordsPtNodePos, &listener);
}
int Dictionary::getProbability(const int *word, int length) const {
- TimeKeeper::setCurrentTime();
- int pos = getDictionaryStructurePolicy()->getTerminalPtNodePositionOfWord(word, length,
- false /* forceLowerCaseSearch */);
- if (NOT_A_DICT_POS == pos) {
- return NOT_A_PROBABILITY;
- }
- return getDictionaryStructurePolicy()->getUnigramProbabilityOfPtNode(pos);
+ return getNgramProbability(nullptr /* prevWordsInfo */, word, length);
}
int Dictionary::getMaxProbabilityOfExactMatches(const int *word, int length) const {
@@ -109,18 +115,15 @@ int Dictionary::getNgramProbability(const PrevWordsInfo *const prevWordsInfo, co
int nextWordPos = mDictionaryStructureWithBufferPolicy->getTerminalPtNodePositionOfWord(word,
length, false /* forceLowerCaseSearch */);
if (NOT_A_DICT_POS == nextWordPos) return NOT_A_PROBABILITY;
- BinaryDictionaryBigramsIterator bigramsIt = prevWordsInfo->getBigramsIteratorForPrediction(
- mDictionaryStructureWithBufferPolicy.get());
- while (bigramsIt.hasNext()) {
- bigramsIt.next();
- if (bigramsIt.getBigramPos() == nextWordPos
- && bigramsIt.getProbability() != NOT_A_PROBABILITY) {
- return mDictionaryStructureWithBufferPolicy->getProbability(
- mDictionaryStructureWithBufferPolicy->getUnigramProbabilityOfPtNode(
- nextWordPos), bigramsIt.getProbability());
- }
+ if (!prevWordsInfo) {
+ return getDictionaryStructurePolicy()->getProbabilityOfPtNode(
+ nullptr /* prevWordsPtNodePos */, nextWordPos);
}
- return NOT_A_PROBABILITY;
+ int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
+ prevWordsInfo->getPrevWordsTerminalPtNodePos(
+ mDictionaryStructureWithBufferPolicy.get(), prevWordsPtNodePos,
+ true /* tryLowerCaseSearch */);
+ return getDictionaryStructurePolicy()->getProbabilityOfPtNode(prevWordsPtNodePos, nextWordPos);
}
bool Dictionary::addUnigramEntry(const int *const word, const int length,
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.h b/native/jni/src/suggest/core/dictionary/dictionary.h
index 3b41088fe..732d3b199 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.h
+++ b/native/jni/src/suggest/core/dictionary/dictionary.h
@@ -21,6 +21,7 @@
#include "defines.h"
#include "jni.h"
+#include "suggest/core/dictionary/ngram_listener.h"
#include "suggest/core/dictionary/property/word_property.h"
#include "suggest/core/policy/dictionary_header_structure_policy.h"
#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
@@ -114,6 +115,21 @@ class Dictionary {
typedef std::unique_ptr<SuggestInterface> SuggestInterfacePtr;
+ class NgramListenerForPrediction : public NgramListener {
+ public:
+ NgramListenerForPrediction(const PrevWordsInfo *const prevWordsInfo,
+ SuggestionResults *const suggestionResults,
+ const DictionaryStructureWithBufferPolicy *const dictStructurePolicy);
+ virtual void onVisitEntry(const int ngramProbability, const int targetPtNodePos);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(NgramListenerForPrediction);
+
+ const PrevWordsInfo *const mPrevWordsInfo;
+ SuggestionResults *const mSuggestionResults;
+ const DictionaryStructureWithBufferPolicy *const mDictStructurePolicy;
+ };
+
static const int HEADER_ATTRIBUTE_BUFFER_SIZE;
const DictionaryStructureWithBufferPolicy::StructurePolicyPtr
diff --git a/native/jni/src/suggest/core/dictionary/multi_bigram_map.cpp b/native/jni/src/suggest/core/dictionary/multi_bigram_map.cpp
index 012e4dc9c..91f33a8dd 100644
--- a/native/jni/src/suggest/core/dictionary/multi_bigram_map.cpp
+++ b/native/jni/src/suggest/core/dictionary/multi_bigram_map.cpp
@@ -35,34 +35,30 @@ const int MultiBigramMap::BigramMap::DEFAULT_HASH_MAP_SIZE_FOR_EACH_BIGRAM_MAP =
// Also caches the bigrams if there is space remaining and they have not been cached already.
int MultiBigramMap::getBigramProbability(
const DictionaryStructureWithBufferPolicy *const structurePolicy,
- const int wordPosition, const int nextWordPosition, const int unigramProbability) {
+ const int *const prevWordsPtNodePos, const int nextWordPosition,
+ const int unigramProbability) {
+ if (!prevWordsPtNodePos || prevWordsPtNodePos[0] == NOT_A_DICT_POS) {
+ return structurePolicy->getProbability(unigramProbability, NOT_A_PROBABILITY);
+ }
std::unordered_map<int, BigramMap>::const_iterator mapPosition =
- mBigramMaps.find(wordPosition);
+ mBigramMaps.find(prevWordsPtNodePos[0]);
if (mapPosition != mBigramMaps.end()) {
return mapPosition->second.getBigramProbability(structurePolicy, nextWordPosition,
unigramProbability);
}
if (mBigramMaps.size() < MAX_CACHED_PREV_WORDS_IN_BIGRAM_MAP) {
- addBigramsForWordPosition(structurePolicy, wordPosition);
- return mBigramMaps[wordPosition].getBigramProbability(structurePolicy,
+ addBigramsForWordPosition(structurePolicy, prevWordsPtNodePos);
+ return mBigramMaps[prevWordsPtNodePos[0]].getBigramProbability(structurePolicy,
nextWordPosition, unigramProbability);
}
- return readBigramProbabilityFromBinaryDictionary(structurePolicy, wordPosition,
+ return readBigramProbabilityFromBinaryDictionary(structurePolicy, prevWordsPtNodePos,
nextWordPosition, unigramProbability);
}
void MultiBigramMap::BigramMap::init(
- const DictionaryStructureWithBufferPolicy *const structurePolicy, const int nodePos) {
- BinaryDictionaryBigramsIterator bigramsIt =
- structurePolicy->getBigramsIteratorOfPtNode(nodePos);
- while (bigramsIt.hasNext()) {
- bigramsIt.next();
- if (bigramsIt.getBigramPos() == NOT_A_DICT_POS) {
- continue;
- }
- mBigramMap[bigramsIt.getBigramPos()] = bigramsIt.getProbability();
- mBloomFilter.setInFilter(bigramsIt.getBigramPos());
- }
+ const DictionaryStructureWithBufferPolicy *const structurePolicy,
+ const int *const prevWordsPtNodePos) {
+ structurePolicy->iterateNgramEntries(prevWordsPtNodePos, this /* listener */);
}
int MultiBigramMap::BigramMap::getBigramProbability(
@@ -79,25 +75,33 @@ int MultiBigramMap::BigramMap::getBigramProbability(
return structurePolicy->getProbability(unigramProbability, bigramProbability);
}
+void MultiBigramMap::BigramMap::onVisitEntry(const int ngramProbability,
+ const int targetPtNodePos) {
+ if (targetPtNodePos == NOT_A_DICT_POS) {
+ return;
+ }
+ mBigramMap[targetPtNodePos] = ngramProbability;
+ mBloomFilter.setInFilter(targetPtNodePos);
+}
+
void MultiBigramMap::addBigramsForWordPosition(
- const DictionaryStructureWithBufferPolicy *const structurePolicy, const int position) {
- mBigramMaps[position].init(structurePolicy, position);
+ const DictionaryStructureWithBufferPolicy *const structurePolicy,
+ const int *const prevWordsPtNodePos) {
+ if (prevWordsPtNodePos) {
+ mBigramMaps[prevWordsPtNodePos[0]].init(structurePolicy, prevWordsPtNodePos);
+ }
}
int MultiBigramMap::readBigramProbabilityFromBinaryDictionary(
- const DictionaryStructureWithBufferPolicy *const structurePolicy, const int nodePos,
- const int nextWordPosition, const int unigramProbability) {
- int bigramProbability = NOT_A_PROBABILITY;
- BinaryDictionaryBigramsIterator bigramsIt =
- structurePolicy->getBigramsIteratorOfPtNode(nodePos);
- while (bigramsIt.hasNext()) {
- bigramsIt.next();
- if (bigramsIt.getBigramPos() == nextWordPosition) {
- bigramProbability = bigramsIt.getProbability();
- break;
- }
+ const DictionaryStructureWithBufferPolicy *const structurePolicy,
+ const int *const prevWordsPtNodePos, const int nextWordPosition,
+ const int unigramProbability) {
+ const int bigramProbability = structurePolicy->getProbabilityOfPtNode(prevWordsPtNodePos,
+ nextWordPosition);
+ if (bigramProbability != NOT_A_PROBABILITY) {
+ return bigramProbability;
}
- return structurePolicy->getProbability(unigramProbability, bigramProbability);
+ return structurePolicy->getProbability(unigramProbability, NOT_A_PROBABILITY);
}
} // namespace latinime
diff --git a/native/jni/src/suggest/core/dictionary/multi_bigram_map.h b/native/jni/src/suggest/core/dictionary/multi_bigram_map.h
index 195b5e22f..ad36dde83 100644
--- a/native/jni/src/suggest/core/dictionary/multi_bigram_map.h
+++ b/native/jni/src/suggest/core/dictionary/multi_bigram_map.h
@@ -23,6 +23,7 @@
#include "defines.h"
#include "suggest/core/dictionary/binary_dictionary_bigrams_iterator.h"
#include "suggest/core/dictionary/bloom_filter.h"
+#include "suggest/core/dictionary/ngram_listener.h"
#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
namespace latinime {
@@ -38,7 +39,8 @@ class MultiBigramMap {
// Look up the bigram probability for the given word pair from the cached bigram maps.
// Also caches the bigrams if there is space remaining and they have not been cached already.
int getBigramProbability(const DictionaryStructureWithBufferPolicy *const structurePolicy,
- const int wordPosition, const int nextWordPosition, const int unigramProbability);
+ const int *const prevWordsPtNodePos, const int nextWordPosition,
+ const int unigramProbability);
void clear() {
mBigramMaps.clear();
@@ -47,32 +49,35 @@ class MultiBigramMap {
private:
DISALLOW_COPY_AND_ASSIGN(MultiBigramMap);
- class BigramMap {
+ class BigramMap : public NgramListener {
public:
BigramMap() : mBigramMap(DEFAULT_HASH_MAP_SIZE_FOR_EACH_BIGRAM_MAP), mBloomFilter() {}
- ~BigramMap() {}
+ // Copy constructor needed for std::unordered_map.
+ BigramMap(const BigramMap &bigramMap)
+ : mBigramMap(bigramMap.mBigramMap), mBloomFilter(bigramMap.mBloomFilter) {}
+ virtual ~BigramMap() {}
void init(const DictionaryStructureWithBufferPolicy *const structurePolicy,
- const int nodePos);
-
+ const int *const prevWordsPtNodePos);
int getBigramProbability(
const DictionaryStructureWithBufferPolicy *const structurePolicy,
const int nextWordPosition, const int unigramProbability) const;
+ virtual void onVisitEntry(const int ngramProbability, const int targetPtNodePos);
private:
- // NOTE: The BigramMap class doesn't use DISALLOW_COPY_AND_ASSIGN() because its default
- // copy constructor is needed for use in hash_map.
static const int DEFAULT_HASH_MAP_SIZE_FOR_EACH_BIGRAM_MAP;
std::unordered_map<int, int> mBigramMap;
BloomFilter mBloomFilter;
};
void addBigramsForWordPosition(
- const DictionaryStructureWithBufferPolicy *const structurePolicy, const int position);
+ const DictionaryStructureWithBufferPolicy *const structurePolicy,
+ const int *const prevWordsPtNodePos);
int readBigramProbabilityFromBinaryDictionary(
- const DictionaryStructureWithBufferPolicy *const structurePolicy, const int nodePos,
- const int nextWordPosition, const int unigramProbability);
+ const DictionaryStructureWithBufferPolicy *const structurePolicy,
+ const int *const prevWordsPtNodePos, const int nextWordPosition,
+ const int unigramProbability);
static const size_t MAX_CACHED_PREV_WORDS_IN_BIGRAM_MAP;
std::unordered_map<int, BigramMap> mBigramMaps;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/dict_content.h b/native/jni/src/suggest/core/dictionary/ngram_listener.h
index c264aeac4..88b88bafb 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/dict_content.h
+++ b/native/jni/src/suggest/core/dictionary/ngram_listener.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013, The Android Open Source Project
+ * Copyright (C) 2014, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,22 +14,27 @@
* limitations under the License.
*/
-#ifndef LATINIME_DICT_CONTENT_H
-#define LATINIME_DICT_CONTENT_H
+#ifndef LATINIME_NGRAM_LISTENER_H
+#define LATINIME_NGRAM_LISTENER_H
#include "defines.h"
namespace latinime {
-class DictContent {
+/**
+ * Interface to iterate ngram entries.
+ */
+class NgramListener {
public:
- virtual ~DictContent() {}
+ virtual void onVisitEntry(const int ngramProbability, const int targetPtNodePos) = 0;
+ virtual ~NgramListener() {};
protected:
- DictContent() {}
+ NgramListener() {}
private:
- DISALLOW_COPY_AND_ASSIGN(DictContent);
+ DISALLOW_COPY_AND_ASSIGN(NgramListener);
+
};
} // namespace latinime
-#endif /* LATINIME_DICT_CONTENT_H */
+#endif /* LATINIME_NGRAM_LISTENER_H */
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 6b1a319aa..e6180fe17 100644
--- a/native/jni/src/suggest/core/layout/proximity_info_state.h
+++ b/native/jni/src/suggest/core/layout/proximity_info_state.h
@@ -215,13 +215,13 @@ class ProximityInfoState {
std::vector<float> mSpeedRates;
std::vector<float> mDirections;
// probabilities of skipping or mapping to a key for each point.
- std::vector<std::unordered_map<int, float> > mCharProbabilities;
+ std::vector<std::unordered_map<int, float>> mCharProbabilities;
// The vector for the key code set which holds nearby keys of some trailing sampled input points
// for each sampled input point. These nearby keys contain the next characters which can be in
// the dictionary. Specifically, currently we are looking for keys nearby trailing sampled
// inputs including the current input point.
std::vector<ProximityInfoStateUtils::NearKeycodesSet> mSampledSearchKeySets;
- std::vector<std::vector<int> > mSampledSearchKeyVectors;
+ std::vector<std::vector<int>> mSampledSearchKeyVectors;
bool mTouchPositionCorrectionEnabled;
int mInputProximities[MAX_PROXIMITY_CHARS_SIZE * MAX_WORD_LENGTH];
int mSampledInputSize;
diff --git a/native/jni/src/suggest/core/layout/proximity_info_state_utils.cpp b/native/jni/src/suggest/core/layout/proximity_info_state_utils.cpp
index ea3b02216..0aeb36aad 100644
--- a/native/jni/src/suggest/core/layout/proximity_info_state_utils.cpp
+++ b/native/jni/src/suggest/core/layout/proximity_info_state_utils.cpp
@@ -621,7 +621,7 @@ namespace latinime {
const std::vector<int> *const sampledLengthCache,
const std::vector<float> *const sampledNormalizedSquaredLengthCache,
const ProximityInfo *const proximityInfo,
- std::vector<std::unordered_map<int, float> > *charProbabilities) {
+ std::vector<std::unordered_map<int, float>> *charProbabilities) {
charProbabilities->resize(sampledInputSize);
// Calculates probabilities of using a point as a correlated point with the character
// for each point.
@@ -822,9 +822,9 @@ namespace latinime {
/* static */ void ProximityInfoStateUtils::updateSampledSearchKeySets(
const ProximityInfo *const proximityInfo, const int sampledInputSize,
const int lastSavedInputSize, const std::vector<int> *const sampledLengthCache,
- const std::vector<std::unordered_map<int, float> > *const charProbabilities,
+ const std::vector<std::unordered_map<int, float>> *const charProbabilities,
std::vector<NearKeycodesSet> *sampledSearchKeySets,
- std::vector<std::vector<int> > *sampledSearchKeyVectors) {
+ std::vector<std::vector<int>> *sampledSearchKeyVectors) {
sampledSearchKeySets->resize(sampledInputSize);
sampledSearchKeyVectors->resize(sampledInputSize);
const int readForwordLength = static_cast<int>(
@@ -868,7 +868,7 @@ namespace latinime {
/* static */ bool ProximityInfoStateUtils::suppressCharProbabilities(const int mostCommonKeyWidth,
const int sampledInputSize, const std::vector<int> *const lengthCache,
const int index0, const int index1,
- std::vector<std::unordered_map<int, float> > *charProbabilities) {
+ std::vector<std::unordered_map<int, float>> *charProbabilities) {
ASSERT(0 <= index0 && index0 < sampledInputSize);
ASSERT(0 <= index1 && index1 < sampledInputSize);
const float keyWidthFloat = static_cast<float>(mostCommonKeyWidth);
@@ -933,7 +933,7 @@ namespace latinime {
// returns probability of generating the word.
/* static */ float ProximityInfoStateUtils::getMostProbableString(
const ProximityInfo *const proximityInfo, const int sampledInputSize,
- const std::vector<std::unordered_map<int, float> > *const charProbabilities,
+ const std::vector<std::unordered_map<int, float>> *const charProbabilities,
int *const codePointBuf) {
ASSERT(sampledInputSize >= 0);
memset(codePointBuf, 0, sizeof(codePointBuf[0]) * MAX_WORD_LENGTH);
diff --git a/native/jni/src/suggest/core/layout/proximity_info_state_utils.h b/native/jni/src/suggest/core/layout/proximity_info_state_utils.h
index 211a79737..4043334e6 100644
--- a/native/jni/src/suggest/core/layout/proximity_info_state_utils.h
+++ b/native/jni/src/suggest/core/layout/proximity_info_state_utils.h
@@ -72,13 +72,13 @@ class ProximityInfoStateUtils {
const std::vector<int> *const sampledLengthCache,
const std::vector<float> *const sampledNormalizedSquaredLengthCache,
const ProximityInfo *const proximityInfo,
- std::vector<std::unordered_map<int, float> > *charProbabilities);
+ std::vector<std::unordered_map<int, float>> *charProbabilities);
static void updateSampledSearchKeySets(const ProximityInfo *const proximityInfo,
const int sampledInputSize, const int lastSavedInputSize,
const std::vector<int> *const sampledLengthCache,
- const std::vector<std::unordered_map<int, float> > *const charProbabilities,
+ const std::vector<std::unordered_map<int, float>> *const charProbabilities,
std::vector<NearKeycodesSet> *sampledSearchKeySets,
- std::vector<std::vector<int> > *sampledSearchKeyVectors);
+ std::vector<std::vector<int>> *sampledSearchKeyVectors);
static float getPointToKeyByIdLength(const float maxPointToKeyLength,
const std::vector<float> *const sampledNormalizedSquaredLengthCache, const int keyCount,
const int inputIndex, const int keyId);
@@ -105,7 +105,7 @@ class ProximityInfoStateUtils {
// TODO: Move to most_probable_string_utils.h
static float getMostProbableString(const ProximityInfo *const proximityInfo,
const int sampledInputSize,
- const std::vector<std::unordered_map<int, float> > *const charProbabilities,
+ const std::vector<std::unordered_map<int, float>> *const charProbabilities,
int *const codePointBuf);
private:
@@ -147,7 +147,7 @@ class ProximityInfoStateUtils {
const int index2);
static bool suppressCharProbabilities(const int mostCommonKeyWidth,
const int sampledInputSize, const std::vector<int> *const lengthCache, const int index0,
- const int index1, std::vector<std::unordered_map<int, float> > *charProbabilities);
+ const int index1, std::vector<std::unordered_map<int, float>> *charProbabilities);
static float calculateSquaredDistanceFromSweetSpotCenter(
const ProximityInfo *const proximityInfo, const std::vector<int> *const sampledInputXs,
const std::vector<int> *const sampledInputYs, const int keyIndex,
diff --git a/native/jni/src/suggest/core/policy/dictionary_bigrams_structure_policy.h b/native/jni/src/suggest/core/policy/dictionary_bigrams_structure_policy.h
index 661ef1b1a..aa0d068aa 100644
--- a/native/jni/src/suggest/core/policy/dictionary_bigrams_structure_policy.h
+++ b/native/jni/src/suggest/core/policy/dictionary_bigrams_structure_policy.h
@@ -30,7 +30,7 @@ class DictionaryBigramsStructurePolicy {
virtual void getNextBigram(int *const outBigramPos, int *const outProbability,
bool *const outHasNext, int *const pos) const = 0;
- virtual void skipAllBigrams(int *const pos) const = 0;
+ virtual bool skipAllBigrams(int *const pos) const = 0;
protected:
DictionaryBigramsStructurePolicy() {}
diff --git a/native/jni/src/suggest/core/policy/dictionary_header_structure_policy.h b/native/jni/src/suggest/core/policy/dictionary_header_structure_policy.h
index a61227626..6da390e55 100644
--- a/native/jni/src/suggest/core/policy/dictionary_header_structure_policy.h
+++ b/native/jni/src/suggest/core/policy/dictionary_header_structure_policy.h
@@ -30,7 +30,7 @@ namespace latinime {
*/
class DictionaryHeaderStructurePolicy {
public:
- typedef std::map<std::vector<int>, std::vector<int> > AttributeMap;
+ typedef std::map<std::vector<int>, std::vector<int>> AttributeMap;
virtual ~DictionaryHeaderStructurePolicy() {}
diff --git a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
index a48d64473..e91f07682 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
@@ -20,16 +20,15 @@
#include <memory>
#include "defines.h"
-#include "suggest/core/dictionary/binary_dictionary_bigrams_iterator.h"
#include "suggest/core/dictionary/property/word_property.h"
namespace latinime {
class DicNode;
class DicNodeVector;
-class DictionaryBigramsStructurePolicy;
class DictionaryHeaderStructurePolicy;
class DictionaryShortcutsStructurePolicy;
+class NgramListener;
class PrevWordsInfo;
class UnigramProperty;
@@ -58,11 +57,13 @@ class DictionaryStructureWithBufferPolicy {
virtual int getProbability(const int unigramProbability,
const int bigramProbability) const = 0;
- virtual int getUnigramProbabilityOfPtNode(const int nodePos) const = 0;
+ virtual int getProbabilityOfPtNode(const int *const prevWordsPtNodePos,
+ const int nodePos) const = 0;
- virtual int getShortcutPositionOfPtNode(const int nodePos) const = 0;
+ virtual void iterateNgramEntries(const int *const prevWordsPtNodePos,
+ NgramListener *const listener) const = 0;
- virtual BinaryDictionaryBigramsIterator getBigramsIteratorOfPtNode(const int nodePos) const = 0;
+ virtual int getShortcutPositionOfPtNode(const int nodePos) const = 0;
virtual const DictionaryHeaderStructurePolicy *getHeaderStructurePolicy() const = 0;
diff --git a/native/jni/src/suggest/core/policy/scoring.h b/native/jni/src/suggest/core/policy/scoring.h
index 292194bf2..9e75cace4 100644
--- a/native/jni/src/suggest/core/policy/scoring.h
+++ b/native/jni/src/suggest/core/policy/scoring.h
@@ -37,7 +37,6 @@ class Scoring {
DicNode *const terminals, const int size) const = 0;
virtual float getDoubleLetterDemotionDistanceCost(
const DicNode *const terminalDicNode) const = 0;
- virtual bool doesAutoCorrectValidWord() const = 0;
virtual bool autoCorrectsToMultiWordSuggestionIfTop() const = 0;
virtual bool sameAsTyped(const DicTraverseSession *const traverseSession,
const DicNode *const dicNode) const = 0;
diff --git a/native/jni/src/suggest/core/result/suggestions_output_utils.cpp b/native/jni/src/suggest/core/result/suggestions_output_utils.cpp
index 7b0e7e1b4..0b99b75ec 100644
--- a/native/jni/src/suggest/core/result/suggestions_output_utils.cpp
+++ b/native/jni/src/suggest/core/result/suggestions_output_utils.cpp
@@ -117,8 +117,7 @@ const int SuggestionsOutputUtils::MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT = 16;
const int finalScore = scoringPolicy->calculateFinalScore(
compoundDistance, traverseSession->getInputSize(),
terminalDicNode->getContainedErrorTypes(),
- (forceCommitMultiWords && terminalDicNode->hasMultipleWords())
- || (isValidWord && scoringPolicy->doesAutoCorrectValidWord()),
+ (forceCommitMultiWords && terminalDicNode->hasMultipleWords()),
boostExactMatches);
// Don't output invalid or blocked offensive words. However, we still need to submit their
@@ -145,12 +144,7 @@ const int SuggestionsOutputUtils::MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT = 16;
traverseSession->getDictionaryStructurePolicy()
->getShortcutPositionOfPtNode(terminalDicNode->getPtNodePos()));
const bool sameAsTyped = scoringPolicy->sameAsTyped(traverseSession, terminalDicNode);
- const int shortcutBaseScore = scoringPolicy->doesAutoCorrectValidWord() ?
- scoringPolicy->calculateFinalScore(compoundDistance,
- traverseSession->getInputSize(),
- terminalDicNode->getContainedErrorTypes(),
- true /* forceCommit */, boostExactMatches) : finalScore;
- outputShortcuts(&shortcutIt, shortcutBaseScore, sameAsTyped, outSuggestionResults);
+ outputShortcuts(&shortcutIt, finalScore, sameAsTyped, outSuggestionResults);
}
}
diff --git a/native/jni/src/suggest/core/session/prev_words_info.h b/native/jni/src/suggest/core/session/prev_words_info.h
index 76276f528..e44e876e9 100644
--- a/native/jni/src/suggest/core/session/prev_words_info.h
+++ b/native/jni/src/suggest/core/session/prev_words_info.h
@@ -90,13 +90,6 @@ class PrevWordsInfo {
}
}
- BinaryDictionaryBigramsIterator getBigramsIteratorForPrediction(
- const DictionaryStructureWithBufferPolicy *const dictStructurePolicy) const {
- return getBigramsIteratorForWordWithTryingLowerCaseSearch(
- dictStructurePolicy, mPrevWordCodePoints[0], mPrevWordCodePointCount[0],
- mIsBeginningOfSentence[0]);
- }
-
// n is 1-indexed.
const int *getNthPrevWordCodePoints(const int n) const {
if (n <= 0 || n > MAX_PREV_WORD_COUNT_FOR_N_GRAM) {
@@ -154,46 +147,6 @@ class PrevWordsInfo {
codePoints, codePointCount, true /* forceLowerCaseSearch */);
}
- static BinaryDictionaryBigramsIterator getBigramsIteratorForWordWithTryingLowerCaseSearch(
- const DictionaryStructureWithBufferPolicy *const dictStructurePolicy,
- const int *const wordCodePoints, const int wordCodePointCount,
- const bool isBeginningOfSentence) {
- if (!dictStructurePolicy || !wordCodePoints || wordCodePointCount > MAX_WORD_LENGTH) {
- return BinaryDictionaryBigramsIterator();
- }
- int codePoints[MAX_WORD_LENGTH];
- int codePointCount = wordCodePointCount;
- memmove(codePoints, wordCodePoints, sizeof(int) * codePointCount);
- if (isBeginningOfSentence) {
- codePointCount = CharUtils::attachBeginningOfSentenceMarker(codePoints,
- codePointCount, MAX_WORD_LENGTH);
- if (codePointCount <= 0) {
- return BinaryDictionaryBigramsIterator();
- }
- }
- BinaryDictionaryBigramsIterator bigramsIt = getBigramsIteratorForWord(dictStructurePolicy,
- codePoints, codePointCount, false /* forceLowerCaseSearch */);
- // getBigramsIteratorForWord returns an empty iterator if this word isn't in the dictionary
- // or has no bigrams.
- if (bigramsIt.hasNext()) {
- return bigramsIt;
- }
- // If no bigrams for this exact word, search again in lower case.
- return getBigramsIteratorForWord(dictStructurePolicy, codePoints,
- codePointCount, true /* forceLowerCaseSearch */);
- }
-
- static BinaryDictionaryBigramsIterator getBigramsIteratorForWord(
- const DictionaryStructureWithBufferPolicy *const dictStructurePolicy,
- const int *wordCodePoints, const int wordCodePointCount,
- const bool forceLowerCaseSearch) {
- if (!wordCodePoints || wordCodePointCount <= 0) return BinaryDictionaryBigramsIterator();
- const int terminalPtNodePos = dictStructurePolicy->getTerminalPtNodePositionOfWord(
- wordCodePoints, wordCodePointCount, forceLowerCaseSearch);
- if (NOT_A_DICT_POS == terminalPtNodePos) return BinaryDictionaryBigramsIterator();
- return dictStructurePolicy->getBigramsIteratorOfPtNode(terminalPtNodePos);
- }
-
void clear() {
for (size_t i = 0; i < NELEMS(mPrevWordCodePoints); ++i) {
mPrevWordCodePointCount[i] = 0;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/bigram/ver4_bigram_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/bigram/ver4_bigram_list_policy.h
index 61623468e..50a4c9743 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/bigram/ver4_bigram_list_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/bigram/ver4_bigram_list_policy.h
@@ -58,8 +58,9 @@ class Ver4BigramListPolicy : public DictionaryBigramsStructurePolicy {
void getNextBigram(int *const outBigramPos, int *const outProbability,
bool *const outHasNext, int *const bigramEntryPos) const;
- void skipAllBigrams(int *const pos) const {
+ bool skipAllBigrams(int *const pos) const {
// Do nothing because we don't need to skip bigram lists in ver4 dictionaries.
+ return true;
}
bool addNewEntry(const int terminalId, const int newTargetTerminalId,
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/single_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/single_dict_content.h
index 6433650b0..49f446814 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/single_dict_content.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/single_dict_content.h
@@ -30,6 +30,7 @@
#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h"
#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h"
+#include "utils/byte_array_view.h"
namespace latinime {
namespace backward {
@@ -40,8 +41,9 @@ class SingleDictContent : public DictContent {
SingleDictContent(const char *const dictPath, const char *const contentFileName,
const bool isUpdatable)
: mMmappedBuffer(MmappedBuffer::openBuffer(dictPath, contentFileName, isUpdatable)),
- mExpandableContentBuffer(mMmappedBuffer ? mMmappedBuffer->getBuffer() : nullptr,
- mMmappedBuffer ? mMmappedBuffer->getBufferSize() : 0,
+ mExpandableContentBuffer(
+ mMmappedBuffer ? mMmappedBuffer->getReadWriteByteArrayView() :
+ ReadWriteByteArrayView(),
BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE),
mIsValid(mMmappedBuffer) {}
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/sparse_table_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/sparse_table_dict_content.h
index c7233edd3..3c626df11 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/sparse_table_dict_content.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/sparse_table_dict_content.h
@@ -31,6 +31,7 @@
#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h"
#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h"
#include "suggest/policyimpl/dictionary/utils/sparse_table.h"
+#include "utils/byte_array_view.h"
namespace latinime {
namespace backward {
@@ -50,15 +51,16 @@ class SparseTableDictContent : public DictContent {
mContentBuffer(
MmappedBuffer::openBuffer(dictPath, contentFileName, isUpdatable)),
mExpandableLookupTableBuffer(
- mLookupTableBuffer ? mLookupTableBuffer->getBuffer() : nullptr,
- mLookupTableBuffer ? mLookupTableBuffer->getBufferSize() : 0,
+ mLookupTableBuffer ? mLookupTableBuffer->getReadWriteByteArrayView() :
+ ReadWriteByteArrayView(),
BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE),
mExpandableAddressTableBuffer(
- mAddressTableBuffer ? mAddressTableBuffer->getBuffer() : nullptr,
- mAddressTableBuffer ? mAddressTableBuffer->getBufferSize() : 0,
+ mAddressTableBuffer ? mAddressTableBuffer->getReadWriteByteArrayView() :
+ ReadWriteByteArrayView(),
BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE),
- mExpandableContentBuffer(mContentBuffer ? mContentBuffer->getBuffer() : nullptr,
- mContentBuffer ? mContentBuffer->getBufferSize() : 0,
+ mExpandableContentBuffer(
+ mContentBuffer ? mContentBuffer->getReadWriteByteArrayView() :
+ ReadWriteByteArrayView(),
BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE),
mAddressLookupTable(&mExpandableLookupTableBuffer, &mExpandableAddressTableBuffer,
sparseTableBlockSize, sparseTableDataSize),
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.cpp
index 93f192976..3dfbd1c94 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.cpp
@@ -30,6 +30,7 @@
#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h"
#include "suggest/policyimpl/dictionary/utils/file_utils.h"
+#include "utils/byte_array_view.h"
namespace latinime {
namespace backward {
@@ -130,12 +131,12 @@ Ver4DictBuffers::Ver4DictBuffers(const char *const dictPath,
: mHeaderBuffer(std::move(headerBuffer)),
mDictBuffer(MmappedBuffer::openBuffer(dictPath,
Ver4DictConstants::TRIE_FILE_EXTENSION, isUpdatable)),
- mHeaderPolicy(mHeaderBuffer->getBuffer(), formatVersion),
- mExpandableHeaderBuffer(mHeaderBuffer ? mHeaderBuffer->getBuffer() : nullptr,
- mHeaderPolicy.getSize(),
+ mHeaderPolicy(mHeaderBuffer->getReadOnlyByteArrayView().data(), formatVersion),
+ mExpandableHeaderBuffer(mHeaderBuffer->getReadWriteByteArrayView(),
BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE),
- mExpandableTrieBuffer(mDictBuffer ? mDictBuffer->getBuffer() : nullptr,
- mDictBuffer ? mDictBuffer->getBufferSize() : 0,
+ mExpandableTrieBuffer(
+ mDictBuffer ? mDictBuffer->getReadWriteByteArrayView() :
+ ReadWriteByteArrayView(),
BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE),
mTerminalPositionLookupTable(dictPath, isUpdatable),
mProbabilityDictContent(dictPath, mHeaderPolicy.hasHistoricalInfoOfWords(), isUpdatable),
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp
index 4220a9561..278f2b199 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp
@@ -231,30 +231,31 @@ bool Ver4PatriciaTrieNodeWriter::writeNewTerminalPtNodeAndAdvancePosition(
&probabilityEntryToWrite);
}
-bool Ver4PatriciaTrieNodeWriter::addNewBigramEntry(
- const PtNodeParams *const sourcePtNodeParams, const PtNodeParams *const targetPtNodeParam,
- const BigramProperty *const bigramProperty, bool *const outAddedNewBigram) {
- if (!mBigramPolicy->addNewEntry(sourcePtNodeParams->getTerminalId(),
- targetPtNodeParam->getTerminalId(), bigramProperty, outAddedNewBigram)) {
+bool Ver4PatriciaTrieNodeWriter::addNgramEntry(const WordIdArrayView prevWordIds, const int wordId,
+ const BigramProperty *const bigramProperty, bool *const outAddedNewEntry) {
+ if (!mBigramPolicy->addNewEntry(prevWordIds[0], wordId, bigramProperty, outAddedNewEntry)) {
AKLOGE("Cannot add new bigram entry. terminalId: %d, targetTerminalId: %d",
sourcePtNodeParams->getTerminalId(), targetPtNodeParam->getTerminalId());
return false;
}
- if (!sourcePtNodeParams->hasBigrams()) {
+ const int ptNodePos =
+ mBuffers->getTerminalPositionLookupTable()->getTerminalPtNodePosition(prevWordIds[0]);
+ const PtNodeParams sourcePtNodeParams =
+ mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos);
+ if (!sourcePtNodeParams.hasBigrams()) {
// Update has bigrams flag.
- return updatePtNodeFlags(sourcePtNodeParams->getHeadPos(),
- sourcePtNodeParams->isBlacklisted(), sourcePtNodeParams->isNotAWord(),
- sourcePtNodeParams->isTerminal(), sourcePtNodeParams->hasShortcutTargets(),
+ return updatePtNodeFlags(sourcePtNodeParams.getHeadPos(),
+ sourcePtNodeParams.isBlacklisted(), sourcePtNodeParams.isNotAWord(),
+ sourcePtNodeParams.isTerminal(), sourcePtNodeParams.hasShortcutTargets(),
true /* hasBigrams */,
- sourcePtNodeParams->getCodePointCount() > 1 /* hasMultipleChars */);
+ sourcePtNodeParams.getCodePointCount() > 1 /* hasMultipleChars */);
}
return true;
}
-bool Ver4PatriciaTrieNodeWriter::removeBigramEntry(
- const PtNodeParams *const sourcePtNodeParams, const PtNodeParams *const targetPtNodeParam) {
- return mBigramPolicy->removeEntry(sourcePtNodeParams->getTerminalId(),
- targetPtNodeParam->getTerminalId());
+bool Ver4PatriciaTrieNodeWriter::removeNgramEntry(const WordIdArrayView prevWordIds,
+ const int wordId) {
+ return mBigramPolicy->removeEntry(prevWordIds[0], wordId);
}
bool Ver4PatriciaTrieNodeWriter::updateAllBigramEntriesAndDeleteUselessEntries(
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.h
index 08226ea26..d49d9a666 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.h
@@ -29,6 +29,7 @@
#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h"
#include "suggest/policyimpl/dictionary/structure/backward/v402/content/probability_entry.h"
+#include "utils/int_array_view.h"
namespace latinime {
namespace backward {
@@ -61,8 +62,8 @@ class Ver4PatriciaTrieNodeWriter : public PtNodeWriter {
const PtNodeArrayReader *const ptNodeArrayReader,
Ver4BigramListPolicy *const bigramPolicy, Ver4ShortcutListPolicy *const shortcutPolicy)
: mTrieBuffer(trieBuffer), mBuffers(buffers), mHeaderPolicy(headerPolicy),
- mReadingHelper(ptNodeReader, ptNodeArrayReader), mBigramPolicy(bigramPolicy),
- mShortcutPolicy(shortcutPolicy) {}
+ mPtNodeReader(ptNodeReader), mReadingHelper(ptNodeReader, ptNodeArrayReader),
+ mBigramPolicy(bigramPolicy), mShortcutPolicy(shortcutPolicy) {}
virtual ~Ver4PatriciaTrieNodeWriter() {}
@@ -92,12 +93,10 @@ class Ver4PatriciaTrieNodeWriter : public PtNodeWriter {
virtual bool writeNewTerminalPtNodeAndAdvancePosition(const PtNodeParams *const ptNodeParams,
const UnigramProperty *const unigramProperty, int *const ptNodeWritingPos);
- virtual bool addNewBigramEntry(const PtNodeParams *const sourcePtNodeParams,
- const PtNodeParams *const targetPtNodeParam, const BigramProperty *const bigramProperty,
- bool *const outAddedNewBigram);
+ virtual bool addNgramEntry(const WordIdArrayView prevWordIds, const int wordId,
+ const BigramProperty *const bigramProperty, bool *const outAddedNewEntry);
- virtual bool removeBigramEntry(const PtNodeParams *const sourcePtNodeParams,
- const PtNodeParams *const targetPtNodeParam);
+ virtual bool removeNgramEntry(const WordIdArrayView prevWordIds, const int wordId);
virtual bool updateAllBigramEntriesAndDeleteUselessEntries(
const PtNodeParams *const sourcePtNodeParams, int *const outBigramEntryCount);
@@ -135,6 +134,7 @@ class Ver4PatriciaTrieNodeWriter : public PtNodeWriter {
BufferWithExtendableBuffer *const mTrieBuffer;
Ver4DictBuffers *const mBuffers;
const HeaderPolicy *const mHeaderPolicy;
+ const PtNodeReader *const mPtNodeReader;
DynamicPtReadingHelper mReadingHelper;
Ver4BigramListPolicy *const mBigramPolicy;
Ver4ShortcutListPolicy *const mShortcutPolicy;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp
index f478d9b91..1296b8acd 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp
@@ -28,6 +28,7 @@
#include "suggest/core/dicnode/dic_node.h"
#include "suggest/core/dicnode/dic_node_vector.h"
+#include "suggest/core/dictionary/ngram_listener.h"
#include "suggest/core/dictionary/property/bigram_property.h"
#include "suggest/core/dictionary/property/unigram_property.h"
#include "suggest/core/dictionary/property/word_property.h"
@@ -131,7 +132,8 @@ int Ver4PatriciaTriePolicy::getProbability(const int unigramProbability,
}
}
-int Ver4PatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int ptNodePos) const {
+int Ver4PatriciaTriePolicy::getProbabilityOfPtNode(const int *const prevWordsPtNodePos,
+ const int ptNodePos) const {
if (ptNodePos == NOT_A_DICT_POS) {
return NOT_A_PROBABILITY;
}
@@ -139,9 +141,34 @@ int Ver4PatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int ptNodePos) c
if (ptNodeParams.isDeleted() || ptNodeParams.isBlacklisted() || ptNodeParams.isNotAWord()) {
return NOT_A_PROBABILITY;
}
+ if (prevWordsPtNodePos) {
+ const int bigramsPosition = getBigramsPositionOfPtNode(prevWordsPtNodePos[0]);
+ BinaryDictionaryBigramsIterator bigramsIt(&mBigramPolicy, bigramsPosition);
+ while (bigramsIt.hasNext()) {
+ bigramsIt.next();
+ if (bigramsIt.getBigramPos() == ptNodePos
+ && bigramsIt.getProbability() != NOT_A_PROBABILITY) {
+ return getProbability(ptNodeParams.getProbability(), bigramsIt.getProbability());
+ }
+ }
+ return NOT_A_PROBABILITY;
+ }
return getProbability(ptNodeParams.getProbability(), NOT_A_PROBABILITY);
}
+void Ver4PatriciaTriePolicy::iterateNgramEntries(const int *const prevWordsPtNodePos,
+ NgramListener *const listener) const {
+ if (!prevWordsPtNodePos) {
+ return;
+ }
+ const int bigramsPosition = getBigramsPositionOfPtNode(prevWordsPtNodePos[0]);
+ BinaryDictionaryBigramsIterator bigramsIt(&mBigramPolicy, bigramsPosition);
+ while (bigramsIt.hasNext()) {
+ bigramsIt.next();
+ listener->onVisitEntry(bigramsIt.getProbability(), bigramsIt.getBigramPos());
+ }
+}
+
int Ver4PatriciaTriePolicy::getShortcutPositionOfPtNode(const int ptNodePos) const {
if (ptNodePos == NOT_A_DICT_POS) {
return NOT_A_DICT_POS;
@@ -154,12 +181,6 @@ int Ver4PatriciaTriePolicy::getShortcutPositionOfPtNode(const int ptNodePos) con
ptNodeParams.getTerminalId());
}
-BinaryDictionaryBigramsIterator Ver4PatriciaTriePolicy::getBigramsIteratorOfPtNode(
- const int ptNodePos) const {
- const int bigramsPosition = getBigramsPositionOfPtNode(ptNodePos);
- return BinaryDictionaryBigramsIterator(&mBigramPolicy, bigramsPosition);
-}
-
int Ver4PatriciaTriePolicy::getBigramsPositionOfPtNode(const int ptNodePos) const {
if (ptNodePos == NOT_A_DICT_POS) {
return NOT_A_DICT_POS;
@@ -288,8 +309,8 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI
return false;
}
bool addedNewBigram = false;
- if (mUpdatingHelper.addBigramWords(prevWordsPtNodePos[0], word1Pos, bigramProperty,
- &addedNewBigram)) {
+ if (mUpdatingHelper.addNgramEntry(PtNodePosArrayView::fromObject(prevWordsPtNodePos),
+ word1Pos, bigramProperty, &addedNewBigram)) {
if (addedNewBigram) {
mBigramCount++;
}
@@ -329,7 +350,8 @@ bool Ver4PatriciaTriePolicy::removeNgramEntry(const PrevWordsInfo *const prevWor
if (wordPos == NOT_A_DICT_POS) {
return false;
}
- if (mUpdatingHelper.removeBigramWords(prevWordsPtNodePos[0], wordPos)) {
+ if (mUpdatingHelper.removeNgramEntry(
+ PtNodePosArrayView::fromObject(prevWordsPtNodePos), wordPos)) {
mBigramCount--;
return true;
} else {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h
index 6d97c7cc8..9e989b268 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h
@@ -90,11 +90,12 @@ class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
int getProbability(const int unigramProbability, const int bigramProbability) const;
- int getUnigramProbabilityOfPtNode(const int ptNodePos) const;
+ int getProbabilityOfPtNode(const int *const prevWordsPtNodePos, const int ptNodePos) const;
- int getShortcutPositionOfPtNode(const int ptNodePos) const;
+ void iterateNgramEntries(const int *const prevWordsPtNodePos,
+ NgramListener *const listener) const;
- BinaryDictionaryBigramsIterator getBigramsIteratorOfPtNode(const int ptNodePos) const;
+ int getShortcutPositionOfPtNode(const int ptNodePos) const;
const DictionaryHeaderStructurePolicy *getHeaderStructurePolicy() const {
return mHeaderPolicy;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp
index e4b5fa267..e4ea3da16 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp
@@ -31,6 +31,7 @@
#include "suggest/policyimpl/dictionary/utils/file_utils.h"
#include "suggest/policyimpl/dictionary/utils/format_utils.h"
#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h"
+#include "utils/byte_array_view.h"
namespace latinime {
@@ -110,7 +111,8 @@ template<class DictConstants, class DictBuffers, class DictBuffersPtr, class Str
return nullptr;
}
const FormatUtils::FORMAT_VERSION formatVersion = FormatUtils::detectFormatVersion(
- mmappedBuffer->getBuffer(), mmappedBuffer->getBufferSize());
+ mmappedBuffer->getReadOnlyByteArrayView().data(),
+ mmappedBuffer->getReadOnlyByteArrayView().size());
switch (formatVersion) {
case FormatUtils::VERSION_2:
AKLOGE("Given path is a directory but the format is version 2. path: %s", path);
@@ -172,8 +174,8 @@ template<class DictConstants, class DictBuffers, class DictBuffersPtr, class Str
if (!mmappedBuffer) {
return nullptr;
}
- switch (FormatUtils::detectFormatVersion(mmappedBuffer->getBuffer(),
- mmappedBuffer->getBufferSize())) {
+ switch (FormatUtils::detectFormatVersion(mmappedBuffer->getReadOnlyByteArrayView().data(),
+ mmappedBuffer->getReadOnlyByteArrayView().size())) {
case FormatUtils::VERSION_2:
return DictionaryStructureWithBufferPolicy::StructurePolicyPtr(
new PatriciaTriePolicy(std::move(mmappedBuffer)));
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.cpp
index 08b4e0b5e..f7fd5c071 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.cpp
@@ -38,9 +38,14 @@ const BigramListReadWriteUtils::BigramFlags BigramListReadWriteUtils::FLAG_ATTRI
const BigramListReadWriteUtils::BigramFlags
BigramListReadWriteUtils::MASK_ATTRIBUTE_PROBABILITY = 0x0F;
-/* static */ void BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(
- const uint8_t *const bigramsBuf, BigramFlags *const outBigramFlags,
+/* static */ bool BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(
+ const uint8_t *const bigramsBuf, const int bufSize, BigramFlags *const outBigramFlags,
int *const outTargetPtNodePos, int *const bigramEntryPos) {
+ if (bufSize <= *bigramEntryPos) {
+ AKLOGE("Read invalid pos in getBigramEntryPropertiesAndAdvancePosition(). bufSize: %d, "
+ "bigramEntryPos: %d.", bufSize, *bigramEntryPos);
+ return false;
+ }
const BigramFlags bigramFlags = ByteArrayUtils::readUint8AndAdvancePosition(bigramsBuf,
bigramEntryPos);
if (outBigramFlags) {
@@ -51,15 +56,19 @@ const BigramListReadWriteUtils::BigramFlags
if (outTargetPtNodePos) {
*outTargetPtNodePos = targetPos;
}
+ return true;
}
-/* static */ void BigramListReadWriteUtils::skipExistingBigrams(const uint8_t *const bigramsBuf,
- int *const bigramListPos) {
+/* static */ bool BigramListReadWriteUtils::skipExistingBigrams(const uint8_t *const bigramsBuf,
+ const int bufSize, int *const bigramListPos) {
BigramFlags flags;
do {
- getBigramEntryPropertiesAndAdvancePosition(bigramsBuf, &flags, 0 /* outTargetPtNodePos */,
- bigramListPos);
+ if (!getBigramEntryPropertiesAndAdvancePosition(bigramsBuf, bufSize, &flags,
+ 0 /* outTargetPtNodePos */, bigramListPos)) {
+ return false;
+ }
} while(hasNext(flags));
+ return true;
}
/* static */ int BigramListReadWriteUtils::getBigramAddressAndAdvancePosition(
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h
index 15f924a6a..10f93fb7a 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h
@@ -30,8 +30,8 @@ class BigramListReadWriteUtils {
public:
typedef uint8_t BigramFlags;
- static void getBigramEntryPropertiesAndAdvancePosition(const uint8_t *const bigramsBuf,
- BigramFlags *const outBigramFlags, int *const outTargetPtNodePos,
+ static bool getBigramEntryPropertiesAndAdvancePosition(const uint8_t *const bigramsBuf,
+ const int bufSize, BigramFlags *const outBigramFlags, int *const outTargetPtNodePos,
int *const bigramEntryPos);
static AK_FORCE_INLINE int getProbabilityFromFlags(const BigramFlags flags) {
@@ -43,7 +43,8 @@ public:
}
// Bigrams reading methods
- static void skipExistingBigrams(const uint8_t *const bigramsBuf, int *const bigramListPos);
+ static bool skipExistingBigrams(const uint8_t *const bigramsBuf, const int bufSize,
+ int *const bigramListPos);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BigramListReadWriteUtils);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h
index 2e05bf397..b7262581a 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h
@@ -26,7 +26,6 @@
namespace latinime {
-class DictionaryBigramsStructurePolicy;
class DictionaryShortcutsStructurePolicy;
class PtNodeArrayReader;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp
index f31c914d2..3c62e2e56 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp
@@ -84,23 +84,39 @@ bool DynamicPtUpdatingHelper::addUnigramWord(
unigramProperty, &pos);
}
-bool DynamicPtUpdatingHelper::addBigramWords(const int word0Pos, const int word1Pos,
- const BigramProperty *const bigramProperty, bool *const outAddedNewBigram) {
- const PtNodeParams sourcePtNodeParams(
- mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(word0Pos));
- const PtNodeParams targetPtNodeParams(
- mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(word1Pos));
- return mPtNodeWriter->addNewBigramEntry(&sourcePtNodeParams, &targetPtNodeParams,
- bigramProperty, outAddedNewBigram);
+bool DynamicPtUpdatingHelper::addNgramEntry(const PtNodePosArrayView prevWordsPtNodePos,
+ const int wordPos, const BigramProperty *const bigramProperty,
+ bool *const outAddedNewEntry) {
+ if (prevWordsPtNodePos.empty()) {
+ return false;
+ }
+ ASSERT(prevWordsPtNodePos.size() <= MAX_PREV_WORD_COUNT_FOR_N_GRAM);
+ int prevWordTerminalIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
+ for (size_t i = 0; i < prevWordsPtNodePos.size(); ++i) {
+ prevWordTerminalIds[i] = mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(
+ prevWordsPtNodePos[i]).getTerminalId();
+ }
+ const WordIdArrayView prevWordIds(prevWordTerminalIds, prevWordsPtNodePos.size());
+ const int wordId =
+ mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(wordPos).getTerminalId();
+ return mPtNodeWriter->addNgramEntry(prevWordIds, wordId, bigramProperty, outAddedNewEntry);
}
-// Remove a bigram relation from word0Pos to word1Pos.
-bool DynamicPtUpdatingHelper::removeBigramWords(const int word0Pos, const int word1Pos) {
- const PtNodeParams sourcePtNodeParams(
- mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(word0Pos));
- const PtNodeParams targetPtNodeParams(
- mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(word1Pos));
- return mPtNodeWriter->removeBigramEntry(&sourcePtNodeParams, &targetPtNodeParams);
+bool DynamicPtUpdatingHelper::removeNgramEntry(const PtNodePosArrayView prevWordsPtNodePos,
+ const int wordPos) {
+ if (prevWordsPtNodePos.empty()) {
+ return false;
+ }
+ ASSERT(prevWordsPtNodePos.size() <= MAX_PREV_WORD_COUNT_FOR_N_GRAM);
+ int prevWordTerminalIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
+ for (size_t i = 0; i < prevWordsPtNodePos.size(); ++i) {
+ prevWordTerminalIds[i] = mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(
+ prevWordsPtNodePos[i]).getTerminalId();
+ }
+ const WordIdArrayView prevWordIds(prevWordTerminalIds, prevWordsPtNodePos.size());
+ const int wordId =
+ mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(wordPos).getTerminalId();
+ return mPtNodeWriter->removeNgramEntry(prevWordIds, wordId);
}
bool DynamicPtUpdatingHelper::addShortcutTarget(const int wordPos,
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h
index f10d15a9b..97c05c1ea 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h
@@ -19,6 +19,7 @@
#include "defines.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h"
+#include "utils/int_array_view.h"
namespace latinime {
@@ -42,12 +43,12 @@ class DynamicPtUpdatingHelper {
const int *const wordCodePoints, const int codePointCount,
const UnigramProperty *const unigramProperty, bool *const outAddedNewUnigram);
- // Add a bigram relation from word0Pos to word1Pos.
- bool addBigramWords(const int word0Pos, const int word1Pos,
- const BigramProperty *const bigramProperty, bool *const outAddedNewBigram);
+ // Add an n-gram entry.
+ bool addNgramEntry(const PtNodePosArrayView prevWordsPtNodePos, const int wordPos,
+ const BigramProperty *const bigramProperty, bool *const outAddedNewEntry);
- // Remove a bigram relation from word0Pos to word1Pos.
- bool removeBigramWords(const int word0Pos, const int word1Pos);
+ // Remove an n-gram entry.
+ bool removeNgramEntry(const PtNodePosArrayView prevWordsPtNodePos, const int wordPos);
// Add a shortcut target.
bool addShortcutTarget(const int wordPos, const int *const targetCodePoints,
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h
index a8029f73f..955d779ac 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h
@@ -21,6 +21,7 @@
#include "defines.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h"
+#include "utils/int_array_view.h"
namespace latinime {
@@ -70,12 +71,10 @@ class PtNodeWriter {
virtual bool writeNewTerminalPtNodeAndAdvancePosition(const PtNodeParams *const ptNodeParams,
const UnigramProperty *const unigramProperty, int *const ptNodeWritingPos) = 0;
- virtual bool addNewBigramEntry(const PtNodeParams *const sourcePtNodeParams,
- const PtNodeParams *const targetPtNodeParam, const BigramProperty *const bigramProperty,
- bool *const outAddedNewBigram) = 0;
+ virtual bool addNgramEntry(const WordIdArrayView prevWordIds, const int wordId,
+ const BigramProperty *const bigramProperty, bool *const outAddedNewEntry) = 0;
- virtual bool removeBigramEntry(const PtNodeParams *const sourcePtNodeParams,
- const PtNodeParams *const targetPtNodeParam) = 0;
+ virtual bool removeNgramEntry(const WordIdArrayView prevWordIds, const int wordId) = 0;
virtual bool updateAllBigramEntriesAndDeleteUselessEntries(
const PtNodeParams *const sourcePtNodeParams, int *const outBigramEntryCount) = 0;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/bigram/bigram_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/bigram/bigram_list_policy.h
index 00bb502dc..73e291ec2 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/bigram/bigram_list_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/bigram/bigram_list_policy.h
@@ -27,27 +27,34 @@ namespace latinime {
class BigramListPolicy : public DictionaryBigramsStructurePolicy {
public:
- explicit BigramListPolicy(const uint8_t *const bigramsBuf) : mBigramsBuf(bigramsBuf) {}
+ BigramListPolicy(const uint8_t *const bigramsBuf, const int bufSize)
+ : mBigramsBuf(bigramsBuf), mBufSize(bufSize) {}
~BigramListPolicy() {}
void getNextBigram(int *const outBigramPos, int *const outProbability, bool *const outHasNext,
int *const pos) const {
BigramListReadWriteUtils::BigramFlags flags;
- BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(mBigramsBuf, &flags,
- outBigramPos, pos);
+ if (!BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(mBigramsBuf,
+ mBufSize, &flags, outBigramPos, pos)) {
+ AKLOGE("Cannot read bigram entry. mBufSize: %d, pos: %d. ", mBufSize, *pos);
+ *outProbability = NOT_A_PROBABILITY;
+ *outHasNext = false;
+ return;
+ }
*outProbability = BigramListReadWriteUtils::getProbabilityFromFlags(flags);
*outHasNext = BigramListReadWriteUtils::hasNext(flags);
}
- void skipAllBigrams(int *const pos) const {
- BigramListReadWriteUtils::skipExistingBigrams(mBigramsBuf, pos);
+ bool skipAllBigrams(int *const pos) const {
+ return BigramListReadWriteUtils::skipExistingBigrams(mBigramsBuf, mBufSize, pos);
}
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BigramListPolicy);
const uint8_t *const mBigramsBuf;
+ const int mBufSize;
};
} // namespace latinime
#endif // LATINIME_BIGRAM_LIST_POLICY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp
index 91d76040f..ea32eb2a9 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp
@@ -21,6 +21,8 @@
#include "suggest/core/dicnode/dic_node.h"
#include "suggest/core/dicnode/dic_node_vector.h"
#include "suggest/core/dictionary/binary_dictionary_bigrams_iterator.h"
+#include "suggest/core/dictionary/ngram_listener.h"
+#include "suggest/core/session/prev_words_info.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h"
#include "suggest/policyimpl/dictionary/utils/probability_utils.h"
@@ -223,7 +225,14 @@ int PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount(
mShortcutListPolicy.skipAllShortcuts(&pos);
}
if (PatriciaTrieReadingUtils::hasBigrams(flags)) {
- mBigramListPolicy.skipAllBigrams(&pos);
+ if (!mBigramListPolicy.skipAllBigrams(&pos)) {
+ AKLOGE("Cannot skip bigrams. BufSize: %d, pos: %d.", mDictBufferSize,
+ pos);
+ mIsCorrupted = true;
+ ASSERT(false);
+ *outUnigramProbability = NOT_A_PROBABILITY;
+ return 0;
+ }
}
}
} else {
@@ -240,7 +249,13 @@ int PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount(
mShortcutListPolicy.skipAllShortcuts(&pos);
}
if (PatriciaTrieReadingUtils::hasBigrams(flags)) {
- mBigramListPolicy.skipAllBigrams(&pos);
+ if (!mBigramListPolicy.skipAllBigrams(&pos)) {
+ AKLOGE("Cannot skip bigrams. BufSize: %d, pos: %d.", mDictBufferSize, pos);
+ mIsCorrupted = true;
+ ASSERT(false);
+ *outUnigramProbability = NOT_A_PROBABILITY;
+ return 0;
+ }
}
}
@@ -282,7 +297,8 @@ int PatriciaTriePolicy::getProbability(const int unigramProbability,
}
}
-int PatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int ptNodePos) const {
+int PatriciaTriePolicy::getProbabilityOfPtNode(const int *const prevWordsPtNodePos,
+ const int ptNodePos) const {
if (ptNodePos == NOT_A_DICT_POS) {
return NOT_A_PROBABILITY;
}
@@ -294,9 +310,34 @@ int PatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int ptNodePos) const
// for shortcuts).
return NOT_A_PROBABILITY;
}
+ if (prevWordsPtNodePos) {
+ const int bigramsPosition = getBigramsPositionOfPtNode(prevWordsPtNodePos[0]);
+ BinaryDictionaryBigramsIterator bigramsIt(&mBigramListPolicy, bigramsPosition);
+ while (bigramsIt.hasNext()) {
+ bigramsIt.next();
+ if (bigramsIt.getBigramPos() == ptNodePos
+ && bigramsIt.getProbability() != NOT_A_PROBABILITY) {
+ return getProbability(ptNodeParams.getProbability(), bigramsIt.getProbability());
+ }
+ }
+ return NOT_A_PROBABILITY;
+ }
return getProbability(ptNodeParams.getProbability(), NOT_A_PROBABILITY);
}
+void PatriciaTriePolicy::iterateNgramEntries(const int *const prevWordsPtNodePos,
+ NgramListener *const listener) const {
+ if (!prevWordsPtNodePos) {
+ return;
+ }
+ const int bigramsPosition = getBigramsPositionOfPtNode(prevWordsPtNodePos[0]);
+ BinaryDictionaryBigramsIterator bigramsIt(&mBigramListPolicy, bigramsPosition);
+ while (bigramsIt.hasNext()) {
+ bigramsIt.next();
+ listener->onVisitEntry(bigramsIt.getProbability(), bigramsIt.getBigramPos());
+ }
+}
+
int PatriciaTriePolicy::getShortcutPositionOfPtNode(const int ptNodePos) const {
if (ptNodePos == NOT_A_DICT_POS) {
return NOT_A_DICT_POS;
@@ -304,12 +345,6 @@ int PatriciaTriePolicy::getShortcutPositionOfPtNode(const int ptNodePos) const {
return mPtNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos).getShortcutPos();
}
-BinaryDictionaryBigramsIterator PatriciaTriePolicy::getBigramsIteratorOfPtNode(
- const int ptNodePos) const {
- const int bigramsPosition = getBigramsPositionOfPtNode(ptNodePos);
- return BinaryDictionaryBigramsIterator(&mBigramListPolicy, bigramsPosition);
-}
-
int PatriciaTriePolicy::getBigramsPositionOfPtNode(const int ptNodePos) const {
if (ptNodePos == NOT_A_DICT_POS) {
return NOT_A_DICT_POS;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
index 7c0b9d3c5..70351d147 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
@@ -29,6 +29,7 @@
#include "suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.h"
#include "suggest/policyimpl/dictionary/utils/format_utils.h"
#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h"
+#include "utils/byte_array_view.h"
namespace latinime {
@@ -39,10 +40,13 @@ class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
public:
PatriciaTriePolicy(MmappedBuffer::MmappedBufferPtr mmappedBuffer)
: mMmappedBuffer(std::move(mmappedBuffer)),
- mHeaderPolicy(mMmappedBuffer->getBuffer(), FormatUtils::VERSION_2),
- mDictRoot(mMmappedBuffer->getBuffer() + mHeaderPolicy.getSize()),
- mDictBufferSize(mMmappedBuffer->getBufferSize() - mHeaderPolicy.getSize()),
- mBigramListPolicy(mDictRoot), mShortcutListPolicy(mDictRoot),
+ mHeaderPolicy(mMmappedBuffer->getReadOnlyByteArrayView().data(),
+ FormatUtils::VERSION_2),
+ mDictRoot(mMmappedBuffer->getReadOnlyByteArrayView().data()
+ + mHeaderPolicy.getSize()),
+ mDictBufferSize(mMmappedBuffer->getReadOnlyByteArrayView().size()
+ - mHeaderPolicy.getSize()),
+ mBigramListPolicy(mDictRoot, mDictBufferSize), mShortcutListPolicy(mDictRoot),
mPtNodeReader(mDictRoot, mDictBufferSize, &mBigramListPolicy, &mShortcutListPolicy),
mPtNodeArrayReader(mDictRoot, mDictBufferSize),
mTerminalPtNodePositionsForIteratingWords(), mIsCorrupted(false) {}
@@ -63,11 +67,12 @@ class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
int getProbability(const int unigramProbability, const int bigramProbability) const;
- int getUnigramProbabilityOfPtNode(const int ptNodePos) const;
+ int getProbabilityOfPtNode(const int *const prevWordsPtNodePos, const int ptNodePos) const;
- int getShortcutPositionOfPtNode(const int ptNodePos) const;
+ void iterateNgramEntries(const int *const prevWordsPtNodePos,
+ NgramListener *const listener) const;
- BinaryDictionaryBigramsIterator getBigramsIteratorOfPtNode(const int ptNodePos) const;
+ int getShortcutPositionOfPtNode(const int ptNodePos) const;
const DictionaryHeaderStructurePolicy *getHeaderStructurePolicy() const {
return &mHeaderPolicy;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/bigram/ver4_bigram_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/bigram/ver4_bigram_list_policy.h
index 55ba613a5..4b3bb3725 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/bigram/ver4_bigram_list_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/bigram/ver4_bigram_list_policy.h
@@ -40,8 +40,9 @@ class Ver4BigramListPolicy : public DictionaryBigramsStructurePolicy {
void getNextBigram(int *const outBigramPos, int *const outProbability,
bool *const outHasNext, int *const bigramEntryPos) const;
- void skipAllBigrams(int *const pos) const {
+ bool skipAllBigrams(int *const pos) const {
// Do nothing because we don't need to skip bigram lists in ver4 dictionaries.
+ return true;
}
bool addNewEntry(const int terminalId, const int newTargetTerminalId,
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp
new file mode 100644
index 000000000..5dc91ba10
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h"
+
+namespace latinime {
+
+bool LanguageModelDictContent::save(FILE *const file) const {
+ return mTrieMap.save(file);
+}
+
+bool LanguageModelDictContent::runGC(
+ const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap,
+ const LanguageModelDictContent *const originalContent,
+ int *const outNgramCount) {
+ return runGCInner(terminalIdMap, originalContent->mTrieMap.getEntriesInRootLevel(),
+ 0 /* nextLevelBitmapEntryIndex */, outNgramCount);
+}
+
+ProbabilityEntry LanguageModelDictContent::getNgramProbabilityEntry(
+ const WordIdArrayView prevWordIds, const int wordId) const {
+ const int bitmapEntryIndex = getBitmapEntryIndex(prevWordIds);
+ if (bitmapEntryIndex == TrieMap::INVALID_INDEX) {
+ return ProbabilityEntry();
+ }
+ const TrieMap::Result result = mTrieMap.get(wordId, bitmapEntryIndex);
+ if (!result.mIsValid) {
+ // Not found.
+ return ProbabilityEntry();
+ }
+ return ProbabilityEntry::decode(result.mValue, mHasHistoricalInfo);
+}
+
+bool LanguageModelDictContent::setNgramProbabilityEntry(const WordIdArrayView prevWordIds,
+ const int terminalId, const ProbabilityEntry *const probabilityEntry) {
+ const int bitmapEntryIndex = getBitmapEntryIndex(prevWordIds);
+ if (bitmapEntryIndex == TrieMap::INVALID_INDEX) {
+ return false;
+ }
+ return mTrieMap.put(terminalId, probabilityEntry->encode(mHasHistoricalInfo), bitmapEntryIndex);
+}
+
+bool LanguageModelDictContent::runGCInner(
+ const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap,
+ const TrieMap::TrieMapRange trieMapRange,
+ const int nextLevelBitmapEntryIndex, int *const outNgramCount) {
+ for (auto &entry : trieMapRange) {
+ const auto it = terminalIdMap->find(entry.key());
+ if (it == terminalIdMap->end() || it->second == Ver4DictConstants::NOT_A_TERMINAL_ID) {
+ // The word has been removed.
+ continue;
+ }
+ if (!mTrieMap.put(it->second, entry.value(), nextLevelBitmapEntryIndex)) {
+ return false;
+ }
+ if (outNgramCount) {
+ *outNgramCount += 1;
+ }
+ if (entry.hasNextLevelMap()) {
+ if (!runGCInner(terminalIdMap, entry.getEntriesInNextLevel(),
+ mTrieMap.getNextLevelBitmapEntryIndex(it->second, nextLevelBitmapEntryIndex),
+ outNgramCount)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+int LanguageModelDictContent::getBitmapEntryIndex(const WordIdArrayView prevWordIds) const {
+ int bitmapEntryIndex = mTrieMap.getRootBitmapEntryIndex();
+ for (const int wordId : prevWordIds) {
+ const TrieMap::Result result = mTrieMap.get(wordId, bitmapEntryIndex);
+ if (!result.mIsValid) {
+ return TrieMap::INVALID_INDEX;
+ }
+ bitmapEntryIndex = result.mNextLevelBitmapEntryIndex;
+ }
+ return bitmapEntryIndex;
+}
+
+} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h
new file mode 100644
index 000000000..18f2e0170
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LATINIME_LANGUAGE_MODEL_DICT_CONTENT_H
+#define LATINIME_LANGUAGE_MODEL_DICT_CONTENT_H
+
+#include <cstdio>
+
+#include "defines.h"
+#include "suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h"
+#include "suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h"
+#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h"
+#include "suggest/policyimpl/dictionary/utils/trie_map.h"
+#include "utils/byte_array_view.h"
+#include "utils/int_array_view.h"
+
+namespace latinime {
+
+/**
+ * Class representing language model.
+ *
+ * This class provides methods to get and store unigram/n-gram probability information and flags.
+ */
+class LanguageModelDictContent {
+ public:
+ LanguageModelDictContent(const ReadWriteByteArrayView trieMapBuffer,
+ const bool hasHistoricalInfo)
+ : mTrieMap(trieMapBuffer), mHasHistoricalInfo(hasHistoricalInfo) {}
+
+ explicit LanguageModelDictContent(const bool hasHistoricalInfo)
+ : mTrieMap(), mHasHistoricalInfo(hasHistoricalInfo) {}
+
+ bool isNearSizeLimit() const {
+ return mTrieMap.isNearSizeLimit();
+ }
+
+ bool save(FILE *const file) const;
+
+ bool runGC(const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap,
+ const LanguageModelDictContent *const originalContent,
+ int *const outNgramCount);
+
+ ProbabilityEntry getProbabilityEntry(const int wordId) const {
+ return getNgramProbabilityEntry(WordIdArrayView(), wordId);
+ }
+
+ bool setProbabilityEntry(const int wordId, const ProbabilityEntry *const probabilityEntry) {
+ return setNgramProbabilityEntry(WordIdArrayView(), wordId, probabilityEntry);
+ }
+
+ ProbabilityEntry getNgramProbabilityEntry(const WordIdArrayView prevWordIds,
+ const int wordId) const;
+
+ bool setNgramProbabilityEntry(const WordIdArrayView prevWordIds, const int wordId,
+ const ProbabilityEntry *const probabilityEntry);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LanguageModelDictContent);
+
+ TrieMap mTrieMap;
+ const bool mHasHistoricalInfo;
+
+ bool runGCInner(const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap,
+ const TrieMap::TrieMapRange trieMapRange, const int nextLevelBitmapEntryIndex,
+ int *const outNgramCount);
+
+ int getBitmapEntryIndex(const WordIdArrayView prevWordIds) const;
+};
+} // namespace latinime
+#endif /* LATINIME_LANGUAGE_MODEL_DICT_CONTENT_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.cpp
deleted file mode 100644
index 2425b3b2f..000000000
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.cpp
+++ /dev/null
@@ -1,159 +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/structure/v4/content/probability_dict_content.h"
-
-#include "suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h"
-#include "suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h"
-#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h"
-#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
-
-namespace latinime {
-
-const ProbabilityEntry ProbabilityDictContent::getProbabilityEntry(const int terminalId) const {
- if (terminalId < 0 || terminalId >= mSize) {
- // This method can be called with invalid terminal id during GC.
- return ProbabilityEntry(0 /* flags */, NOT_A_PROBABILITY);
- }
- const BufferWithExtendableBuffer *const buffer = getBuffer();
- int entryPos = getEntryPos(terminalId);
- const int flags = buffer->readUintAndAdvancePosition(
- Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE, &entryPos);
- const int probability = buffer->readUintAndAdvancePosition(
- Ver4DictConstants::PROBABILITY_SIZE, &entryPos);
- if (mHasHistoricalInfo) {
- const int timestamp = buffer->readUintAndAdvancePosition(
- Ver4DictConstants::TIME_STAMP_FIELD_SIZE, &entryPos);
- const int level = buffer->readUintAndAdvancePosition(
- Ver4DictConstants::WORD_LEVEL_FIELD_SIZE, &entryPos);
- const int count = buffer->readUintAndAdvancePosition(
- Ver4DictConstants::WORD_COUNT_FIELD_SIZE, &entryPos);
- const HistoricalInfo historicalInfo(timestamp, level, count);
- return ProbabilityEntry(flags, probability, &historicalInfo);
- } else {
- return ProbabilityEntry(flags, probability);
- }
-}
-
-bool ProbabilityDictContent::setProbabilityEntry(const int terminalId,
- const ProbabilityEntry *const probabilityEntry) {
- if (terminalId < 0) {
- return false;
- }
- const int entryPos = getEntryPos(terminalId);
- if (terminalId >= mSize) {
- ProbabilityEntry dummyEntry;
- // Write new entry.
- int writingPos = getBuffer()->getTailPosition();
- while (writingPos <= entryPos) {
- // Fulfilling with dummy entries until writingPos.
- if (!writeEntry(&dummyEntry, writingPos)) {
- AKLOGE("Cannot write dummy entry. pos: %d, mSize: %d", writingPos, mSize);
- return false;
- }
- writingPos += getEntrySize();
- mSize++;
- }
- }
- return writeEntry(probabilityEntry, entryPos);
-}
-
-bool ProbabilityDictContent::flushToFile(FILE *const file) const {
- if (getEntryPos(mSize) < getBuffer()->getTailPosition()) {
- ProbabilityDictContent probabilityDictContentToWrite(mHasHistoricalInfo);
- for (int i = 0; i < mSize; ++i) {
- const ProbabilityEntry probabilityEntry = getProbabilityEntry(i);
- if (!probabilityDictContentToWrite.setProbabilityEntry(i, &probabilityEntry)) {
- AKLOGE("Cannot set probability entry in flushToFile. terminalId: %d", i);
- return false;
- }
- }
- return probabilityDictContentToWrite.flush(file);
- } else {
- return flush(file);
- }
-}
-
-bool ProbabilityDictContent::runGC(
- const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap,
- const ProbabilityDictContent *const originalProbabilityDictContent) {
- mSize = 0;
- for (TerminalPositionLookupTable::TerminalIdMap::const_iterator it = terminalIdMap->begin();
- it != terminalIdMap->end(); ++it) {
- const ProbabilityEntry probabilityEntry =
- originalProbabilityDictContent->getProbabilityEntry(it->first);
- if (!setProbabilityEntry(it->second, &probabilityEntry)) {
- AKLOGE("Cannot set probability entry in runGC. terminalId: %d", it->second);
- return false;
- }
- mSize++;
- }
- return true;
-}
-
-int ProbabilityDictContent::getEntrySize() const {
- if (mHasHistoricalInfo) {
- return Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE
- + Ver4DictConstants::PROBABILITY_SIZE
- + Ver4DictConstants::TIME_STAMP_FIELD_SIZE
- + Ver4DictConstants::WORD_LEVEL_FIELD_SIZE
- + Ver4DictConstants::WORD_COUNT_FIELD_SIZE;
- } else {
- return Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE
- + Ver4DictConstants::PROBABILITY_SIZE;
- }
-}
-
-int ProbabilityDictContent::getEntryPos(const int terminalId) const {
- return terminalId * getEntrySize();
-}
-
-bool ProbabilityDictContent::writeEntry(const ProbabilityEntry *const probabilityEntry,
- const int entryPos) {
- BufferWithExtendableBuffer *const bufferToWrite = getWritableBuffer();
- int writingPos = entryPos;
- if (!bufferToWrite->writeUintAndAdvancePosition(probabilityEntry->getFlags(),
- Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE, &writingPos)) {
- AKLOGE("Cannot write flags in probability dict content. pos: %d", writingPos);
- return false;
- }
- if (!bufferToWrite->writeUintAndAdvancePosition(probabilityEntry->getProbability(),
- Ver4DictConstants::PROBABILITY_SIZE, &writingPos)) {
- AKLOGE("Cannot write probability in probability dict content. pos: %d", writingPos);
- return false;
- }
- if (mHasHistoricalInfo) {
- const HistoricalInfo *const historicalInfo = probabilityEntry->getHistoricalInfo();
- if (!bufferToWrite->writeUintAndAdvancePosition(historicalInfo->getTimeStamp(),
- Ver4DictConstants::TIME_STAMP_FIELD_SIZE, &writingPos)) {
- AKLOGE("Cannot write timestamp in probability dict content. pos: %d", writingPos);
- return false;
- }
- if (!bufferToWrite->writeUintAndAdvancePosition(historicalInfo->getLevel(),
- Ver4DictConstants::WORD_LEVEL_FIELD_SIZE, &writingPos)) {
- AKLOGE("Cannot write level in probability dict content. pos: %d", writingPos);
- return false;
- }
- if (!bufferToWrite->writeUintAndAdvancePosition(historicalInfo->getCount(),
- Ver4DictConstants::WORD_COUNT_FIELD_SIZE, &writingPos)) {
- AKLOGE("Cannot write count in probability dict content. pos: %d", writingPos);
- return false;
- }
- }
- return true;
-}
-
-} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h
deleted file mode 100644
index 80e992c1c..000000000
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2013, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef LATINIME_PROBABILITY_DICT_CONTENT_H
-#define LATINIME_PROBABILITY_DICT_CONTENT_H
-
-#include <cstdint>
-#include <cstdio>
-
-#include "defines.h"
-#include "suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h"
-#include "suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h"
-#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h"
-#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
-
-namespace latinime {
-
-class ProbabilityEntry;
-
-class ProbabilityDictContent : public SingleDictContent {
- public:
- ProbabilityDictContent(uint8_t *const buffer, const int bufferSize,
- const bool hasHistoricalInfo)
- : SingleDictContent(buffer, bufferSize),
- mHasHistoricalInfo(hasHistoricalInfo),
- mSize(getBuffer()->getTailPosition() / getEntrySize()) {}
-
- ProbabilityDictContent(const bool hasHistoricalInfo)
- : mHasHistoricalInfo(hasHistoricalInfo), mSize(0) {}
-
- const ProbabilityEntry getProbabilityEntry(const int terminalId) const;
-
- bool setProbabilityEntry(const int terminalId, const ProbabilityEntry *const probabilityEntry);
-
- bool flushToFile(FILE *const file) const;
-
- bool runGC(const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap,
- const ProbabilityDictContent *const originalProbabilityDictContent);
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ProbabilityDictContent);
-
- int getEntrySize() const;
-
- int getEntryPos(const int terminalId) const;
-
- bool writeEntry(const ProbabilityEntry *const probabilityEntry, const int entryPos);
-
- bool mHasHistoricalInfo;
- int mSize;
-};
-} // namespace latinime
-#endif /* LATINIME_PROBABILITY_DICT_CONTENT_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h
index 36ba82be1..feff6b57f 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h
@@ -17,6 +17,9 @@
#ifndef LATINIME_PROBABILITY_ENTRY_H
#define LATINIME_PROBABILITY_ENTRY_H
+#include <climits>
+#include <cstdint>
+
#include "defines.h"
#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h"
#include "suggest/policyimpl/dictionary/utils/historical_info.h"
@@ -67,6 +70,50 @@ class ProbabilityEntry {
return &mHistoricalInfo;
}
+ uint64_t encode(const bool hasHistoricalInfo) const {
+ uint64_t encodedEntry = static_cast<uint64_t>(mFlags);
+ if (hasHistoricalInfo) {
+ encodedEntry = (encodedEntry << (Ver4DictConstants::TIME_STAMP_FIELD_SIZE * CHAR_BIT))
+ ^ static_cast<uint64_t>(mHistoricalInfo.getTimeStamp());
+ encodedEntry = (encodedEntry << (Ver4DictConstants::WORD_LEVEL_FIELD_SIZE * CHAR_BIT))
+ ^ static_cast<uint64_t>(mHistoricalInfo.getLevel());
+ encodedEntry = (encodedEntry << (Ver4DictConstants::WORD_COUNT_FIELD_SIZE * CHAR_BIT))
+ ^ static_cast<uint64_t>(mHistoricalInfo.getCount());
+ } else {
+ encodedEntry = (encodedEntry << (Ver4DictConstants::PROBABILITY_SIZE * CHAR_BIT))
+ ^ static_cast<uint64_t>(mProbability);
+ }
+ return encodedEntry;
+ }
+
+ static ProbabilityEntry decode(const uint64_t encodedEntry, const bool hasHistoricalInfo) {
+ if (hasHistoricalInfo) {
+ const int flags = readFromEncodedEntry(encodedEntry,
+ Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE,
+ Ver4DictConstants::TIME_STAMP_FIELD_SIZE
+ + Ver4DictConstants::WORD_LEVEL_FIELD_SIZE
+ + Ver4DictConstants::WORD_COUNT_FIELD_SIZE);
+ const int timestamp = readFromEncodedEntry(encodedEntry,
+ Ver4DictConstants::TIME_STAMP_FIELD_SIZE,
+ Ver4DictConstants::WORD_LEVEL_FIELD_SIZE
+ + Ver4DictConstants::WORD_COUNT_FIELD_SIZE);
+ const int level = readFromEncodedEntry(encodedEntry,
+ Ver4DictConstants::WORD_LEVEL_FIELD_SIZE,
+ Ver4DictConstants::WORD_COUNT_FIELD_SIZE);
+ const int count = readFromEncodedEntry(encodedEntry,
+ Ver4DictConstants::WORD_COUNT_FIELD_SIZE, 0 /* pos */);
+ const HistoricalInfo historicalInfo(timestamp, level, count);
+ return ProbabilityEntry(flags, NOT_A_PROBABILITY, &historicalInfo);
+ } else {
+ const int flags = readFromEncodedEntry(encodedEntry,
+ Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE,
+ Ver4DictConstants::PROBABILITY_SIZE);
+ const int probability = readFromEncodedEntry(encodedEntry,
+ Ver4DictConstants::PROBABILITY_SIZE, 0 /* pos */);
+ return ProbabilityEntry(flags, probability);
+ }
+ }
+
private:
// Copy constructor is public to use this class as a type of return value.
DISALLOW_ASSIGNMENT_OPERATOR(ProbabilityEntry);
@@ -74,6 +121,11 @@ class ProbabilityEntry {
const int mFlags;
const int mProbability;
const HistoricalInfo mHistoricalInfo;
+
+ static int readFromEncodedEntry(const uint64_t encodedEntry, const int size, const int pos) {
+ return static_cast<int>(
+ (encodedEntry >> (pos * CHAR_BIT)) & ((1ull << (size * CHAR_BIT)) - 1));
+ }
};
} // namespace latinime
#endif /* LATINIME_PROBABILITY_ENTRY_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h
index 69a11425f..921774181 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h
@@ -21,17 +21,17 @@
#include <cstdio>
#include "defines.h"
-#include "suggest/policyimpl/dictionary/structure/v4/content/dict_content.h"
#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h"
#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h"
+#include "utils/byte_array_view.h"
namespace latinime {
-class SingleDictContent : public DictContent {
+class SingleDictContent {
public:
SingleDictContent(uint8_t *const buffer, const int bufferSize)
- : mExpandableContentBuffer(buffer, bufferSize,
+ : mExpandableContentBuffer(ReadWriteByteArrayView(buffer, bufferSize),
BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE) {}
SingleDictContent()
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.h
index cdf870bd2..c98dd11fd 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.h
@@ -21,26 +21,29 @@
#include <cstdio>
#include "defines.h"
-#include "suggest/policyimpl/dictionary/structure/v4/content/dict_content.h"
#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h"
#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
#include "suggest/policyimpl/dictionary/utils/sparse_table.h"
+#include "utils/byte_array_view.h"
namespace latinime {
// TODO: Support multiple contents.
-class SparseTableDictContent : public DictContent {
+class SparseTableDictContent {
public:
AK_FORCE_INLINE SparseTableDictContent(uint8_t *const *buffers, const int *bufferSizes,
const int sparseTableBlockSize, const int sparseTableDataSize)
- : mExpandableLookupTableBuffer(buffers[LOOKUP_TABLE_BUFFER_INDEX],
- bufferSizes[LOOKUP_TABLE_BUFFER_INDEX],
+ : mExpandableLookupTableBuffer(
+ ReadWriteByteArrayView(buffers[LOOKUP_TABLE_BUFFER_INDEX],
+ bufferSizes[LOOKUP_TABLE_BUFFER_INDEX]),
BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE),
- mExpandableAddressTableBuffer(buffers[ADDRESS_TABLE_BUFFER_INDEX],
- bufferSizes[ADDRESS_TABLE_BUFFER_INDEX],
+ mExpandableAddressTableBuffer(
+ ReadWriteByteArrayView(buffers[ADDRESS_TABLE_BUFFER_INDEX],
+ bufferSizes[ADDRESS_TABLE_BUFFER_INDEX]),
BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE),
- mExpandableContentBuffer(buffers[CONTENT_BUFFER_INDEX],
- bufferSizes[CONTENT_BUFFER_INDEX],
+ mExpandableContentBuffer(
+ ReadWriteByteArrayView(buffers[CONTENT_BUFFER_INDEX],
+ bufferSizes[CONTENT_BUFFER_INDEX]),
BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE),
mAddressLookupTable(&mExpandableLookupTableBuffer, &mExpandableAddressTableBuffer,
sparseTableBlockSize, sparseTableDataSize) {}
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp
index 36ab9963a..3c8008dc4 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp
@@ -26,6 +26,7 @@
#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h"
#include "suggest/policyimpl/dictionary/utils/file_utils.h"
+#include "utils/byte_array_view.h"
namespace latinime {
@@ -46,14 +47,16 @@ namespace latinime {
}
std::vector<uint8_t *> buffers;
std::vector<int> bufferSizes;
- uint8_t *const buffer = bodyBuffer->getBuffer();
+ const ReadWriteByteArrayView buffer = bodyBuffer->getReadWriteByteArrayView();
int position = 0;
- while (position < bodyBuffer->getBufferSize()) {
- const int bufferSize = ByteArrayUtils::readUint32AndAdvancePosition(buffer, &position);
- buffers.push_back(buffer + position);
- bufferSizes.push_back(bufferSize);
+ while (position < static_cast<int>(buffer.size())) {
+ const int bufferSize = ByteArrayUtils::readUint32AndAdvancePosition(
+ buffer.data(), &position);
+ const ReadWriteByteArrayView subBuffer = buffer.subView(position, bufferSize);
+ buffers.push_back(subBuffer.data());
+ bufferSizes.push_back(subBuffer.size());
position += bufferSize;
- if (bufferSize < 0 || position < 0 || position > bodyBuffer->getBufferSize()) {
+ if (bufferSize < 0 || position < 0 || position > static_cast<int>(buffer.size())) {
AKLOGE("The dict body file is corrupted.");
return Ver4DictBuffersPtr(nullptr);
}
@@ -118,7 +121,7 @@ bool Ver4DictBuffers::flushHeaderAndDictBuffers(const char *const dictDirPath,
}
FILE *const file = fdopen(fd, "wb");
if (!file) {
- AKLOGE("fdopen failed for the file %s. errno: %d", filePath, errno);
+ AKLOGE("fdopen failed for the file %s. errno: %d", bodyFilePath, errno);
ASSERT(false);
return false;
}
@@ -146,27 +149,27 @@ bool Ver4DictBuffers::flushHeaderAndDictBuffers(const char *const dictDirPath,
bool Ver4DictBuffers::flushDictBuffers(FILE *const file) const {
// Write trie.
if (!DictFileWritingUtils::writeBufferToFileTail(file, &mExpandableTrieBuffer)) {
- AKLOGE("Trie cannot be written. %s", tmpDirPath);
+ AKLOGE("Trie cannot be written.");
return false;
}
// Write terminal position lookup table.
if (!mTerminalPositionLookupTable.flushToFile(file)) {
- AKLOGE("Terminal position lookup table cannot be written. %s", tmpDirPath);
+ AKLOGE("Terminal position lookup table cannot be written.");
return false;
}
- // Write probability dict content.
- if (!mProbabilityDictContent.flushToFile(file)) {
- AKLOGE("Probability dict content cannot be written. %s", tmpDirPath);
+ // Write language model content.
+ if (!mLanguageModelDictContent.save(file)) {
+ AKLOGE("Language model dict content cannot be written.");
return false;
}
// Write bigram dict content.
if (!mBigramDictContent.flushToFile(file)) {
- AKLOGE("Bigram dict content cannot be written. %s", tmpDirPath);
+ AKLOGE("Bigram dict content cannot be written.");
return false;
}
// Write shortcut dict content.
if (!mShortcutDictContent.flushToFile(file)) {
- AKLOGE("Shortcut dict content cannot be written. %s", tmpDirPath);
+ AKLOGE("Shortcut dict content cannot be written.");
return false;
}
return true;
@@ -177,20 +180,21 @@ Ver4DictBuffers::Ver4DictBuffers(MmappedBuffer::MmappedBufferPtr &&headerBuffer,
const FormatUtils::FORMAT_VERSION formatVersion,
const std::vector<uint8_t *> &contentBuffers, const std::vector<int> &contentBufferSizes)
: mHeaderBuffer(std::move(headerBuffer)), mDictBuffer(std::move(bodyBuffer)),
- mHeaderPolicy(mHeaderBuffer->getBuffer(), formatVersion),
- mExpandableHeaderBuffer(mHeaderBuffer ? mHeaderBuffer->getBuffer() : nullptr,
- mHeaderPolicy.getSize(),
+ mHeaderPolicy(mHeaderBuffer->getReadOnlyByteArrayView().data(), formatVersion),
+ mExpandableHeaderBuffer(mHeaderBuffer->getReadWriteByteArrayView(),
BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE),
- mExpandableTrieBuffer(contentBuffers[Ver4DictConstants::TRIE_BUFFER_INDEX],
- contentBufferSizes[Ver4DictConstants::TRIE_BUFFER_INDEX],
+ mExpandableTrieBuffer(
+ ReadWriteByteArrayView(contentBuffers[Ver4DictConstants::TRIE_BUFFER_INDEX],
+ contentBufferSizes[Ver4DictConstants::TRIE_BUFFER_INDEX]),
BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE),
mTerminalPositionLookupTable(
contentBuffers[Ver4DictConstants::TERMINAL_ADDRESS_LOOKUP_TABLE_BUFFER_INDEX],
contentBufferSizes[
Ver4DictConstants::TERMINAL_ADDRESS_LOOKUP_TABLE_BUFFER_INDEX]),
- mProbabilityDictContent(
- contentBuffers[Ver4DictConstants::PROBABILITY_BUFFER_INDEX],
- contentBufferSizes[Ver4DictConstants::PROBABILITY_BUFFER_INDEX],
+ mLanguageModelDictContent(
+ ReadWriteByteArrayView(
+ contentBuffers[Ver4DictConstants::LANGUAGE_MODEL_BUFFER_INDEX],
+ contentBufferSizes[Ver4DictConstants::LANGUAGE_MODEL_BUFFER_INDEX]),
mHeaderPolicy.hasHistoricalInfoOfWords()),
mBigramDictContent(&contentBuffers[Ver4DictConstants::BIGRAM_BUFFERS_INDEX],
&contentBufferSizes[Ver4DictConstants::BIGRAM_BUFFERS_INDEX],
@@ -203,7 +207,7 @@ Ver4DictBuffers::Ver4DictBuffers(const HeaderPolicy *const headerPolicy, const i
: mHeaderBuffer(nullptr), mDictBuffer(nullptr), mHeaderPolicy(headerPolicy),
mExpandableHeaderBuffer(Ver4DictConstants::MAX_DICTIONARY_SIZE),
mExpandableTrieBuffer(maxTrieSize), mTerminalPositionLookupTable(),
- mProbabilityDictContent(headerPolicy->hasHistoricalInfoOfWords()),
+ mLanguageModelDictContent(headerPolicy->hasHistoricalInfoOfWords()),
mBigramDictContent(headerPolicy->hasHistoricalInfoOfWords()), mShortcutDictContent(),
mIsUpdatable(true) {}
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h
index 433411cb8..68027dcb8 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h
@@ -23,7 +23,7 @@
#include "defines.h"
#include "suggest/policyimpl/dictionary/header/header_policy.h"
#include "suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.h"
-#include "suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h"
#include "suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.h"
#include "suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h"
#include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h"
@@ -52,7 +52,7 @@ class Ver4DictBuffers {
AK_FORCE_INLINE bool isNearSizeLimit() const {
return mExpandableTrieBuffer.isNearSizeLimit()
|| mTerminalPositionLookupTable.isNearSizeLimit()
- || mProbabilityDictContent.isNearSizeLimit()
+ || mLanguageModelDictContent.isNearSizeLimit()
|| mBigramDictContent.isNearSizeLimit()
|| mShortcutDictContent.isNearSizeLimit();
}
@@ -81,12 +81,12 @@ class Ver4DictBuffers {
return &mTerminalPositionLookupTable;
}
- AK_FORCE_INLINE ProbabilityDictContent *getMutableProbabilityDictContent() {
- return &mProbabilityDictContent;
+ AK_FORCE_INLINE LanguageModelDictContent *getMutableLanguageModelDictContent() {
+ return &mLanguageModelDictContent;
}
- AK_FORCE_INLINE const ProbabilityDictContent *getProbabilityDictContent() const {
- return &mProbabilityDictContent;
+ AK_FORCE_INLINE const LanguageModelDictContent *getLanguageModelDictContent() const {
+ return &mLanguageModelDictContent;
}
AK_FORCE_INLINE BigramDictContent *getMutableBigramDictContent() {
@@ -135,7 +135,7 @@ class Ver4DictBuffers {
BufferWithExtendableBuffer mExpandableHeaderBuffer;
BufferWithExtendableBuffer mExpandableTrieBuffer;
TerminalPositionLookupTable mTerminalPositionLookupTable;
- ProbabilityDictContent mProbabilityDictContent;
+ LanguageModelDictContent mLanguageModelDictContent;
BigramDictContent mBigramDictContent;
ShortcutDictContent mShortcutDictContent;
const int mIsUpdatable;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp
index d45dfe377..93d4e562d 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp
@@ -27,18 +27,20 @@ const int Ver4DictConstants::MAX_DICTIONARY_SIZE = 8 * 1024 * 1024;
// limited to 1MB to prevent from inefficient traversing.
const int Ver4DictConstants::MAX_DICT_EXTENDED_REGION_SIZE = 1 * 1024 * 1024;
-// NUM_OF_BUFFERS_FOR_SINGLE_DICT_CONTENT for Trie, TerminalAddressLookupTable and Probability.
+// NUM_OF_BUFFERS_FOR_SINGLE_DICT_CONTENT for Trie and TerminalAddressLookupTable.
+// NUM_OF_BUFFERS_FOR_LANGUAGE_MODEL_DICT_CONTENT for language model.
// NUM_OF_BUFFERS_FOR_SPARSE_TABLE_DICT_CONTENT for bigram and shortcut.
const size_t Ver4DictConstants::NUM_OF_CONTENT_BUFFERS_IN_BODY_FILE =
- NUM_OF_BUFFERS_FOR_SINGLE_DICT_CONTENT * 3
+ NUM_OF_BUFFERS_FOR_SINGLE_DICT_CONTENT * 2
+ + NUM_OF_BUFFERS_FOR_LANGUAGE_MODEL_DICT_CONTENT
+ NUM_OF_BUFFERS_FOR_SPARSE_TABLE_DICT_CONTENT * 2;
const int Ver4DictConstants::TRIE_BUFFER_INDEX = 0;
const int Ver4DictConstants::TERMINAL_ADDRESS_LOOKUP_TABLE_BUFFER_INDEX =
TRIE_BUFFER_INDEX + NUM_OF_BUFFERS_FOR_SINGLE_DICT_CONTENT;
-const int Ver4DictConstants::PROBABILITY_BUFFER_INDEX =
+const int Ver4DictConstants::LANGUAGE_MODEL_BUFFER_INDEX =
TERMINAL_ADDRESS_LOOKUP_TABLE_BUFFER_INDEX + NUM_OF_BUFFERS_FOR_SINGLE_DICT_CONTENT;
const int Ver4DictConstants::BIGRAM_BUFFERS_INDEX =
- PROBABILITY_BUFFER_INDEX + NUM_OF_BUFFERS_FOR_SINGLE_DICT_CONTENT;
+ LANGUAGE_MODEL_BUFFER_INDEX + NUM_OF_BUFFERS_FOR_LANGUAGE_MODEL_DICT_CONTENT;
const int Ver4DictConstants::SHORTCUT_BUFFERS_INDEX =
BIGRAM_BUFFERS_INDEX + NUM_OF_BUFFERS_FOR_SPARSE_TABLE_DICT_CONTENT;
@@ -73,5 +75,6 @@ const int Ver4DictConstants::SHORTCUT_HAS_NEXT_MASK = 0x80;
const size_t Ver4DictConstants::NUM_OF_BUFFERS_FOR_SINGLE_DICT_CONTENT = 1;
const size_t Ver4DictConstants::NUM_OF_BUFFERS_FOR_SPARSE_TABLE_DICT_CONTENT = 3;
+const size_t Ver4DictConstants::NUM_OF_BUFFERS_FOR_LANGUAGE_MODEL_DICT_CONTENT = 1;
} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h
index e8f6739ba..6950ca70f 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h
@@ -35,7 +35,7 @@ class Ver4DictConstants {
static const size_t NUM_OF_CONTENT_BUFFERS_IN_BODY_FILE;
static const int TRIE_BUFFER_INDEX;
static const int TERMINAL_ADDRESS_LOOKUP_TABLE_BUFFER_INDEX;
- static const int PROBABILITY_BUFFER_INDEX;
+ static const int LANGUAGE_MODEL_BUFFER_INDEX;
static const int BIGRAM_BUFFERS_INDEX;
static const int SHORTCUT_BUFFERS_INDEX;
@@ -71,6 +71,7 @@ class Ver4DictConstants {
static const size_t NUM_OF_BUFFERS_FOR_SINGLE_DICT_CONTENT;
static const size_t NUM_OF_BUFFERS_FOR_SPARSE_TABLE_DICT_CONTENT;
+ static const size_t NUM_OF_BUFFERS_FOR_LANGUAGE_MODEL_DICT_CONTENT;
};
} // namespace latinime
#endif /* LATINIME_VER4_DICT_CONSTANTS_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.cpp
index 0a435e91c..731092efd 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.cpp
@@ -18,7 +18,7 @@
#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h"
-#include "suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h"
#include "suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h"
#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.h"
#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
@@ -61,8 +61,9 @@ const PtNodeParams Ver4PatriciaTrieNodeReader::fetchPtNodeInfoFromBufferAndProce
terminalIdFieldPos += mBuffer->getOriginalBufferSize();
}
terminalId = Ver4PatriciaTrieReadingUtils::getTerminalIdAndAdvancePosition(dictBuf, &pos);
+ // TODO: Quit reading probability here.
const ProbabilityEntry probabilityEntry =
- mProbabilityDictContent->getProbabilityEntry(terminalId);
+ mLanguageModelDictContent->getProbabilityEntry(terminalId);
if (probabilityEntry.hasHistoricalInfo()) {
probability = ForgettingCurveUtils::decodeProbability(
probabilityEntry.getHistoricalInfo(), mHeaderPolicy);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h
index 22ed4a6c0..a91ad5728 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h
@@ -25,18 +25,18 @@ namespace latinime {
class BufferWithExtendableBuffer;
class HeaderPolicy;
-class ProbabilityDictContent;
+class LanguageModelDictContent;
/*
* This class is used for helping to read nodes of ver4 patricia trie. This class handles moved
- * node and reads node attributes including probability form probabilityBuffer.
+ * node and reads node attributes including probability form language model.
*/
class Ver4PatriciaTrieNodeReader : public PtNodeReader {
public:
Ver4PatriciaTrieNodeReader(const BufferWithExtendableBuffer *const buffer,
- const ProbabilityDictContent *const probabilityDictContent,
+ const LanguageModelDictContent *const languageModelDictContent,
const HeaderPolicy *const headerPolicy)
- : mBuffer(buffer), mProbabilityDictContent(probabilityDictContent),
+ : mBuffer(buffer), mLanguageModelDictContent(languageModelDictContent),
mHeaderPolicy(headerPolicy) {}
~Ver4PatriciaTrieNodeReader() {}
@@ -50,7 +50,7 @@ class Ver4PatriciaTrieNodeReader : public PtNodeReader {
DISALLOW_COPY_AND_ASSIGN(Ver4PatriciaTrieNodeReader);
const BufferWithExtendableBuffer *const mBuffer;
- const ProbabilityDictContent *const mProbabilityDictContent;
+ const LanguageModelDictContent *const mLanguageModelDictContent;
const HeaderPolicy *const mHeaderPolicy;
const PtNodeParams fetchPtNodeInfoFromBufferAndProcessMovedPtNode(const int ptNodePos,
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp
index 3d8da9173..857222f5d 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp
@@ -143,11 +143,11 @@ bool Ver4PatriciaTrieNodeWriter::updatePtNodeUnigramProperty(
return false;
}
const ProbabilityEntry originalProbabilityEntry =
- mBuffers->getProbabilityDictContent()->getProbabilityEntry(
+ mBuffers->getLanguageModelDictContent()->getProbabilityEntry(
toBeUpdatedPtNodeParams->getTerminalId());
const ProbabilityEntry probabilityEntry = createUpdatedEntryFrom(&originalProbabilityEntry,
unigramProperty);
- return mBuffers->getMutableProbabilityDictContent()->setProbabilityEntry(
+ return mBuffers->getMutableLanguageModelDictContent()->setProbabilityEntry(
toBeUpdatedPtNodeParams->getTerminalId(), &probabilityEntry);
}
@@ -158,14 +158,14 @@ bool Ver4PatriciaTrieNodeWriter::updatePtNodeProbabilityAndGetNeedsToKeepPtNodeA
return false;
}
const ProbabilityEntry originalProbabilityEntry =
- mBuffers->getProbabilityDictContent()->getProbabilityEntry(
+ mBuffers->getLanguageModelDictContent()->getProbabilityEntry(
toBeUpdatedPtNodeParams->getTerminalId());
if (originalProbabilityEntry.hasHistoricalInfo()) {
const HistoricalInfo historicalInfo = ForgettingCurveUtils::createHistoricalInfoToSave(
originalProbabilityEntry.getHistoricalInfo(), mHeaderPolicy);
const ProbabilityEntry probabilityEntry =
originalProbabilityEntry.createEntryWithUpdatedHistoricalInfo(&historicalInfo);
- if (!mBuffers->getMutableProbabilityDictContent()->setProbabilityEntry(
+ if (!mBuffers->getMutableLanguageModelDictContent()->setProbabilityEntry(
toBeUpdatedPtNodeParams->getTerminalId(), &probabilityEntry)) {
AKLOGE("Cannot write updated probability entry. terminalId: %d",
toBeUpdatedPtNodeParams->getTerminalId());
@@ -218,26 +218,23 @@ bool Ver4PatriciaTrieNodeWriter::writeNewTerminalPtNodeAndAdvancePosition(
ProbabilityEntry newProbabilityEntry;
const ProbabilityEntry probabilityEntryToWrite = createUpdatedEntryFrom(
&newProbabilityEntry, unigramProperty);
- return mBuffers->getMutableProbabilityDictContent()->setProbabilityEntry(terminalId,
- &probabilityEntryToWrite);
+ return mBuffers->getMutableLanguageModelDictContent()->setProbabilityEntry(
+ terminalId, &probabilityEntryToWrite);
}
-bool Ver4PatriciaTrieNodeWriter::addNewBigramEntry(
- const PtNodeParams *const sourcePtNodeParams, const PtNodeParams *const targetPtNodeParam,
+bool Ver4PatriciaTrieNodeWriter::addNgramEntry(const WordIdArrayView prevWordIds, const int wordId,
const BigramProperty *const bigramProperty, bool *const outAddedNewBigram) {
- if (!mBigramPolicy->addNewEntry(sourcePtNodeParams->getTerminalId(),
- targetPtNodeParam->getTerminalId(), bigramProperty, outAddedNewBigram)) {
+ if (!mBigramPolicy->addNewEntry(prevWordIds[0], wordId, bigramProperty, outAddedNewBigram)) {
AKLOGE("Cannot add new bigram entry. terminalId: %d, targetTerminalId: %d",
- sourcePtNodeParams->getTerminalId(), targetPtNodeParam->getTerminalId());
+ prevWordIds[0], wordId);
return false;
}
return true;
}
-bool Ver4PatriciaTrieNodeWriter::removeBigramEntry(
- const PtNodeParams *const sourcePtNodeParams, const PtNodeParams *const targetPtNodeParam) {
- return mBigramPolicy->removeEntry(sourcePtNodeParams->getTerminalId(),
- targetPtNodeParam->getTerminalId());
+bool Ver4PatriciaTrieNodeWriter::removeNgramEntry(const WordIdArrayView prevWordIds,
+ const int wordId) {
+ return mBigramPolicy->removeEntry(prevWordIds[0], wordId);
}
bool Ver4PatriciaTrieNodeWriter::updateAllBigramEntriesAndDeleteUselessEntries(
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h
index 162dc9b1d..6703dba04 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h
@@ -75,12 +75,10 @@ class Ver4PatriciaTrieNodeWriter : public PtNodeWriter {
virtual bool writeNewTerminalPtNodeAndAdvancePosition(const PtNodeParams *const ptNodeParams,
const UnigramProperty *const unigramProperty, int *const ptNodeWritingPos);
- virtual bool addNewBigramEntry(const PtNodeParams *const sourcePtNodeParams,
- const PtNodeParams *const targetPtNodeParam, const BigramProperty *const bigramProperty,
- bool *const outAddedNewBigram);
+ virtual bool addNgramEntry(const WordIdArrayView prevWordIds, const int wordId,
+ const BigramProperty *const bigramProperty, bool *const outAddedNewEntry);
- virtual bool removeBigramEntry(const PtNodeParams *const sourcePtNodeParams,
- const PtNodeParams *const targetPtNodeParam);
+ virtual bool removeNgramEntry(const WordIdArrayView prevWordIds, const int wordId);
virtual bool updateAllBigramEntriesAndDeleteUselessEntries(
const PtNodeParams *const sourcePtNodeParams, int *const outBigramEntryCount);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
index 0b5764aba..723808399 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
@@ -20,6 +20,7 @@
#include "suggest/core/dicnode/dic_node.h"
#include "suggest/core/dicnode/dic_node_vector.h"
+#include "suggest/core/dictionary/ngram_listener.h"
#include "suggest/core/dictionary/property/bigram_property.h"
#include "suggest/core/dictionary/property/unigram_property.h"
#include "suggest/core/dictionary/property/word_property.h"
@@ -121,7 +122,8 @@ int Ver4PatriciaTriePolicy::getProbability(const int unigramProbability,
}
}
-int Ver4PatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int ptNodePos) const {
+int Ver4PatriciaTriePolicy::getProbabilityOfPtNode(const int *const prevWordsPtNodePos,
+ const int ptNodePos) const {
if (ptNodePos == NOT_A_DICT_POS) {
return NOT_A_PROBABILITY;
}
@@ -129,9 +131,34 @@ int Ver4PatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int ptNodePos) c
if (ptNodeParams.isDeleted() || ptNodeParams.isBlacklisted() || ptNodeParams.isNotAWord()) {
return NOT_A_PROBABILITY;
}
+ if (prevWordsPtNodePos) {
+ const int bigramsPosition = getBigramsPositionOfPtNode(prevWordsPtNodePos[0]);
+ BinaryDictionaryBigramsIterator bigramsIt(&mBigramPolicy, bigramsPosition);
+ while (bigramsIt.hasNext()) {
+ bigramsIt.next();
+ if (bigramsIt.getBigramPos() == ptNodePos
+ && bigramsIt.getProbability() != NOT_A_PROBABILITY) {
+ return getProbability(ptNodeParams.getProbability(), bigramsIt.getProbability());
+ }
+ }
+ return NOT_A_PROBABILITY;
+ }
return getProbability(ptNodeParams.getProbability(), NOT_A_PROBABILITY);
}
+void Ver4PatriciaTriePolicy::iterateNgramEntries(const int *const prevWordsPtNodePos,
+ NgramListener *const listener) const {
+ if (!prevWordsPtNodePos) {
+ return;
+ }
+ const int bigramsPosition = getBigramsPositionOfPtNode(prevWordsPtNodePos[0]);
+ BinaryDictionaryBigramsIterator bigramsIt(&mBigramPolicy, bigramsPosition);
+ while (bigramsIt.hasNext()) {
+ bigramsIt.next();
+ listener->onVisitEntry(bigramsIt.getProbability(), bigramsIt.getBigramPos());
+ }
+}
+
int Ver4PatriciaTriePolicy::getShortcutPositionOfPtNode(const int ptNodePos) const {
if (ptNodePos == NOT_A_DICT_POS) {
return NOT_A_DICT_POS;
@@ -144,12 +171,6 @@ int Ver4PatriciaTriePolicy::getShortcutPositionOfPtNode(const int ptNodePos) con
ptNodeParams.getTerminalId());
}
-BinaryDictionaryBigramsIterator Ver4PatriciaTriePolicy::getBigramsIteratorOfPtNode(
- const int ptNodePos) const {
- const int bigramsPosition = getBigramsPositionOfPtNode(ptNodePos);
- return BinaryDictionaryBigramsIterator(&mBigramPolicy, bigramsPosition);
-}
-
int Ver4PatriciaTriePolicy::getBigramsPositionOfPtNode(const int ptNodePos) const {
if (ptNodePos == NOT_A_DICT_POS) {
return NOT_A_DICT_POS;
@@ -271,6 +292,7 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI
int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
prevWordsInfo->getPrevWordsTerminalPtNodePos(this, prevWordsPtNodePos,
false /* tryLowerCaseSearch */);
+ const auto prevWordsPtNodePosView = PtNodePosArrayView::fromFixedSizeArray(prevWordsPtNodePos);
// TODO: Support N-gram.
if (prevWordsPtNodePos[0] == NOT_A_DICT_POS) {
if (prevWordsInfo->isNthPrevWordBeginningOfSentence(1 /* n */)) {
@@ -298,10 +320,10 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI
if (word1Pos == NOT_A_DICT_POS) {
return false;
}
- bool addedNewBigram = false;
- if (mUpdatingHelper.addBigramWords(prevWordsPtNodePos[0], word1Pos, bigramProperty,
- &addedNewBigram)) {
- if (addedNewBigram) {
+ bool addedNewEntry = false;
+ if (mUpdatingHelper.addNgramEntry(prevWordsPtNodePosView, word1Pos, bigramProperty,
+ &addedNewEntry)) {
+ if (addedNewEntry) {
mBigramCount++;
}
return true;
@@ -331,6 +353,7 @@ bool Ver4PatriciaTriePolicy::removeNgramEntry(const PrevWordsInfo *const prevWor
int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
prevWordsInfo->getPrevWordsTerminalPtNodePos(this, prevWordsPtNodePos,
false /* tryLowerCaseSerch */);
+ const auto prevWordsPtNodePosView = PtNodePosArrayView::fromFixedSizeArray(prevWordsPtNodePos);
// TODO: Support N-gram.
if (prevWordsPtNodePos[0] == NOT_A_DICT_POS) {
return false;
@@ -340,7 +363,7 @@ bool Ver4PatriciaTriePolicy::removeNgramEntry(const PrevWordsInfo *const prevWor
if (wordPos == NOT_A_DICT_POS) {
return false;
}
- if (mUpdatingHelper.removeBigramWords(prevWordsPtNodePos[0], wordPos)) {
+ if (mUpdatingHelper.removeNgramEntry(prevWordsPtNodePosView, wordPos)) {
mBigramCount--;
return true;
} else {
@@ -431,7 +454,7 @@ const WordProperty Ver4PatriciaTriePolicy::getWordProperty(const int *const code
std::vector<int> codePointVector(ptNodeParams.getCodePoints(),
ptNodeParams.getCodePoints() + ptNodeParams.getCodePointCount());
const ProbabilityEntry probabilityEntry =
- mBuffers->getProbabilityDictContent()->getProbabilityEntry(
+ mBuffers->getLanguageModelDictContent()->getProbabilityEntry(
ptNodeParams.getTerminalId());
const HistoricalInfo *const historicalInfo = probabilityEntry.getHistoricalInfo();
// Fetch bigram information.
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h
index 85929b785..faad4290d 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h
@@ -46,7 +46,7 @@ class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
mBuffers->getTerminalPositionLookupTable(), mHeaderPolicy),
mShortcutPolicy(mBuffers->getMutableShortcutDictContent(),
mBuffers->getTerminalPositionLookupTable()),
- mNodeReader(mDictBuffer, mBuffers->getProbabilityDictContent(), mHeaderPolicy),
+ mNodeReader(mDictBuffer, mBuffers->getLanguageModelDictContent(), mHeaderPolicy),
mPtNodeArrayReader(mDictBuffer),
mNodeWriter(mDictBuffer, mBuffers.get(), mHeaderPolicy, &mNodeReader,
&mPtNodeArrayReader, &mBigramPolicy, &mShortcutPolicy),
@@ -72,11 +72,12 @@ class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
int getProbability(const int unigramProbability, const int bigramProbability) const;
- int getUnigramProbabilityOfPtNode(const int ptNodePos) const;
+ int getProbabilityOfPtNode(const int *const prevWordsPtNodePos, const int ptNodePos) const;
- int getShortcutPositionOfPtNode(const int ptNodePos) const;
+ void iterateNgramEntries(const int *const prevWordsPtNodePos,
+ NgramListener *const listener) const;
- BinaryDictionaryBigramsIterator getBigramsIteratorOfPtNode(const int ptNodePos) const;
+ int getShortcutPositionOfPtNode(const int ptNodePos) const;
const DictionaryHeaderStructurePolicy *getHeaderStructurePolicy() const {
return mHeaderPolicy;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp
index 0e658f8e3..4220312e0 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp
@@ -75,7 +75,7 @@ bool Ver4PatriciaTrieWritingHelper::runGC(const int rootPtNodeArrayPos,
const HeaderPolicy *const headerPolicy, Ver4DictBuffers *const buffersToWrite,
int *const outUnigramCount, int *const outBigramCount) {
Ver4PatriciaTrieNodeReader ptNodeReader(mBuffers->getTrieBuffer(),
- mBuffers->getProbabilityDictContent(), headerPolicy);
+ mBuffers->getLanguageModelDictContent(), headerPolicy);
Ver4PtNodeArrayReader ptNodeArrayReader(mBuffers->getTrieBuffer());
Ver4BigramListPolicy bigramPolicy(mBuffers->getMutableBigramDictContent(),
mBuffers->getTerminalPositionLookupTable(), headerPolicy);
@@ -138,7 +138,7 @@ bool Ver4PatriciaTrieWritingHelper::runGC(const int rootPtNodeArrayPos,
// Create policy instances for the GCed dictionary.
Ver4PatriciaTrieNodeReader newPtNodeReader(buffersToWrite->getTrieBuffer(),
- buffersToWrite->getProbabilityDictContent(), headerPolicy);
+ buffersToWrite->getLanguageModelDictContent(), headerPolicy);
Ver4PtNodeArrayReader newPtNodeArrayreader(buffersToWrite->getTrieBuffer());
Ver4BigramListPolicy newBigramPolicy(buffersToWrite->getMutableBigramDictContent(),
buffersToWrite->getTerminalPositionLookupTable(), headerPolicy);
@@ -154,8 +154,8 @@ bool Ver4PatriciaTrieWritingHelper::runGC(const int rootPtNodeArrayPos,
return false;
}
// Run GC for probability dict content.
- if (!buffersToWrite->getMutableProbabilityDictContent()->runGC(&terminalIdMap,
- mBuffers->getProbabilityDictContent())) {
+ if (!buffersToWrite->getMutableLanguageModelDictContent()->runGC(&terminalIdMap,
+ mBuffers->getLanguageModelDictContent(), nullptr /* outNgramCount */)) {
return false;
}
// Run GC for bigram dict content.
@@ -201,7 +201,7 @@ bool Ver4PatriciaTrieWritingHelper::truncateUnigrams(
continue;
}
const ProbabilityEntry probabilityEntry =
- mBuffers->getProbabilityDictContent()->getProbabilityEntry(i);
+ mBuffers->getLanguageModelDictContent()->getProbabilityEntry(i);
const int probability = probabilityEntry.hasHistoricalInfo() ?
ForgettingCurveUtils::decodeProbability(
probabilityEntry.getHistoricalInfo(), mBuffers->getHeaderPolicy()) :
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp
index 825b72c6a..833063c17 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp
@@ -25,7 +25,7 @@ const size_t BufferWithExtendableBuffer::EXTEND_ADDITIONAL_BUFFER_SIZE_STEP = 12
uint32_t BufferWithExtendableBuffer::readUint(const int size, const int pos) const {
const bool readingPosIsInAdditionalBuffer = isInAdditionalBuffer(pos);
- const int posInBuffer = readingPosIsInAdditionalBuffer ? pos - mOriginalBufferSize : pos;
+ const int posInBuffer = readingPosIsInAdditionalBuffer ? pos - mOriginalBuffer.size() : pos;
return ByteArrayUtils::readUint(getBuffer(readingPosIsInAdditionalBuffer), size, posInBuffer);
}
@@ -40,12 +40,12 @@ void BufferWithExtendableBuffer::readCodePointsAndAdvancePosition(const int maxC
int *const outCodePoints, int *outCodePointCount, int *const pos) const {
const bool readingPosIsInAdditionalBuffer = isInAdditionalBuffer(*pos);
if (readingPosIsInAdditionalBuffer) {
- *pos -= mOriginalBufferSize;
+ *pos -= mOriginalBuffer.size();
}
*outCodePointCount = ByteArrayUtils::readStringAndAdvancePosition(
getBuffer(readingPosIsInAdditionalBuffer), maxCodePointCount, outCodePoints, pos);
if (readingPosIsInAdditionalBuffer) {
- *pos += mOriginalBufferSize;
+ *pos += mOriginalBuffer.size();
}
}
@@ -69,13 +69,14 @@ bool BufferWithExtendableBuffer::writeUintAndAdvancePosition(const uint32_t data
return false;
}
const bool usesAdditionalBuffer = isInAdditionalBuffer(*pos);
- uint8_t *const buffer = usesAdditionalBuffer ? &mAdditionalBuffer[0] : mOriginalBuffer;
+ uint8_t *const buffer =
+ usesAdditionalBuffer ? mAdditionalBuffer.data() : mOriginalBuffer.data();
if (usesAdditionalBuffer) {
- *pos -= mOriginalBufferSize;
+ *pos -= mOriginalBuffer.size();
}
ByteArrayUtils::writeUintAndAdvancePosition(buffer, data, size, pos);
if (usesAdditionalBuffer) {
- *pos += mOriginalBufferSize;
+ *pos += mOriginalBuffer.size();
}
return true;
}
@@ -88,14 +89,15 @@ bool BufferWithExtendableBuffer::writeCodePointsAndAdvancePosition(const int *co
return false;
}
const bool usesAdditionalBuffer = isInAdditionalBuffer(*pos);
- uint8_t *const buffer = usesAdditionalBuffer ? &mAdditionalBuffer[0] : mOriginalBuffer;
+ uint8_t *const buffer =
+ usesAdditionalBuffer ? mAdditionalBuffer.data() : mOriginalBuffer.data();
if (usesAdditionalBuffer) {
- *pos -= mOriginalBufferSize;
+ *pos -= mOriginalBuffer.size();
}
ByteArrayUtils::writeCodePointsAndAdvancePosition(buffer, codePoints, codePointCount,
writesTerminator, pos);
if (usesAdditionalBuffer) {
- *pos += mOriginalBufferSize;
+ *pos += mOriginalBuffer.size();
}
return true;
}
@@ -119,7 +121,7 @@ bool BufferWithExtendableBuffer::checkAndPrepareWriting(const int pos, const int
const size_t totalRequiredSize = static_cast<size_t>(pos + size);
if (!isInAdditionalBuffer(pos)) {
// Here don't need to care about the additional buffer.
- if (static_cast<size_t>(mOriginalBufferSize) < totalRequiredSize) {
+ if (mOriginalBuffer.size() < totalRequiredSize) {
// Violate the boundary.
return false;
}
@@ -137,7 +139,7 @@ bool BufferWithExtendableBuffer::checkAndPrepareWriting(const int pos, const int
return false;
}
const size_t extendSize = totalRequiredSize -
- std::min(mAdditionalBuffer.size() + mOriginalBufferSize, totalRequiredSize);
+ std::min(mAdditionalBuffer.size() + mOriginalBuffer.size(), totalRequiredSize);
if (extendSize > 0 && !extendBuffer(extendSize)) {
// Failed to extend the buffer.
return false;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h
index 5e1362eee..fad83aa25 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h
@@ -23,6 +23,7 @@
#include "defines.h"
#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
+#include "utils/byte_array_view.h"
namespace latinime {
@@ -34,20 +35,18 @@ class BufferWithExtendableBuffer {
public:
static const size_t DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE;
- BufferWithExtendableBuffer(uint8_t *const originalBuffer, const int originalBufferSize,
+ BufferWithExtendableBuffer(const ReadWriteByteArrayView originalBuffer,
const int maxAdditionalBufferSize)
- : mOriginalBuffer(originalBuffer), mOriginalBufferSize(originalBufferSize),
- mAdditionalBuffer(0), mUsedAdditionalBufferSize(0),
+ : mOriginalBuffer(originalBuffer), mAdditionalBuffer(), mUsedAdditionalBufferSize(0),
mMaxAdditionalBufferSize(maxAdditionalBufferSize) {}
// Without original buffer.
BufferWithExtendableBuffer(const int maxAdditionalBufferSize)
- : mOriginalBuffer(0), mOriginalBufferSize(0),
- mAdditionalBuffer(0), mUsedAdditionalBufferSize(0),
+ : mOriginalBuffer(), mAdditionalBuffer(), mUsedAdditionalBufferSize(0),
mMaxAdditionalBufferSize(maxAdditionalBufferSize) {}
AK_FORCE_INLINE int getTailPosition() const {
- return mOriginalBufferSize + mUsedAdditionalBufferSize;
+ return mOriginalBuffer.size() + mUsedAdditionalBufferSize;
}
AK_FORCE_INLINE int getUsedAdditionalBufferSize() const {
@@ -58,16 +57,16 @@ class BufferWithExtendableBuffer {
* For reading.
*/
AK_FORCE_INLINE bool isInAdditionalBuffer(const int position) const {
- return position >= mOriginalBufferSize;
+ return position >= static_cast<int>(mOriginalBuffer.size());
}
// 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];
+ return mAdditionalBuffer.data();
} else {
- return mOriginalBuffer;
+ return mOriginalBuffer.data();
}
}
@@ -79,7 +78,7 @@ class BufferWithExtendableBuffer {
int *const outCodePoints, int *outCodePointCount, int *const pos) const;
AK_FORCE_INLINE int getOriginalBufferSize() const {
- return mOriginalBufferSize;
+ return mOriginalBuffer.size();
}
AK_FORCE_INLINE bool isNearSizeLimit() const {
@@ -110,8 +109,7 @@ class BufferWithExtendableBuffer {
static const int NEAR_BUFFER_LIMIT_THRESHOLD_PERCENTILE;
static const size_t EXTEND_ADDITIONAL_BUFFER_SIZE_STEP;
- uint8_t *const mOriginalBuffer;
- const int mOriginalBufferSize;
+ const ReadWriteByteArrayView mOriginalBuffer;
std::vector<uint8_t> mAdditionalBuffer;
int mUsedAdditionalBufferSize;
const size_t mMaxAdditionalBufferSize;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h
index 3ff80aeec..9910777b8 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h
@@ -84,7 +84,7 @@ class ForgettingCurveUtils {
static const int STRONG_BASE_PROBABILITY;
static const int AGGRESSIVE_BASE_PROBABILITY;
- std::vector<std::vector<std::vector<int> > > mTables;
+ std::vector<std::vector<std::vector<int>>> mTables;
static int getBaseProbabilityForLevel(const int tableId, const int level);
};
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h b/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h
index 8460087ab..e25310373 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/mmapped_buffer.h
@@ -21,6 +21,7 @@
#include <memory>
#include "defines.h"
+#include "utils/byte_array_view.h"
namespace latinime {
@@ -39,12 +40,12 @@ class MmappedBuffer {
~MmappedBuffer();
- AK_FORCE_INLINE uint8_t *getBuffer() const {
- return mBuffer;
+ ReadWriteByteArrayView getReadWriteByteArrayView() const {
+ return mByteArrayView;
}
- AK_FORCE_INLINE int getBufferSize() const {
- return mBufferSize;
+ ReadOnlyByteArrayView getReadOnlyByteArrayView() const {
+ return mByteArrayView.getReadOnlyView();
}
AK_FORCE_INLINE bool isUpdatable() const {
@@ -55,18 +56,17 @@ class MmappedBuffer {
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),
+ : mByteArrayView(buffer, bufferSize), mMmappedBuffer(mmappedBuffer),
mAlignedSize(alignedSize), mMmapFd(mmapFd), mIsUpdatable(isUpdatable) {}
// Empty file. We have to handle an empty file as a valid part of a dictionary.
AK_FORCE_INLINE MmappedBuffer(const bool isUpdatable)
- : mBuffer(nullptr), mBufferSize(0), mMmappedBuffer(nullptr), mAlignedSize(0),
+ : mByteArrayView(), mMmappedBuffer(nullptr), mAlignedSize(0),
mMmapFd(0), mIsUpdatable(isUpdatable) {}
DISALLOW_IMPLICIT_CONSTRUCTORS(MmappedBuffer);
- uint8_t *const mBuffer;
- const int mBufferSize;
+ const ReadWriteByteArrayView mByteArrayView;
void *const mMmappedBuffer;
const int mAlignedSize;
const int mMmapFd;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.cpp
new file mode 100644
index 000000000..407b8efd0
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.cpp
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "suggest/policyimpl/dictionary/utils/trie_map.h"
+
+#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h"
+
+namespace latinime {
+
+const int TrieMap::INVALID_INDEX = -1;
+const int TrieMap::FIELD0_SIZE = 4;
+const int TrieMap::FIELD1_SIZE = 3;
+const int TrieMap::ENTRY_SIZE = FIELD0_SIZE + FIELD1_SIZE;
+const uint32_t TrieMap::VALUE_FLAG = 0x400000;
+const uint32_t TrieMap::VALUE_MASK = 0x3FFFFF;
+const uint32_t TrieMap::TERMINAL_LINK_FLAG = 0x800000;
+const uint32_t TrieMap::TERMINAL_LINK_MASK = 0x7FFFFF;
+const int TrieMap::NUM_OF_BITS_USED_FOR_ONE_LEVEL = 5;
+const uint32_t TrieMap::LABEL_MASK = 0x1F;
+const int TrieMap::MAX_NUM_OF_ENTRIES_IN_ONE_LEVEL = 1 << NUM_OF_BITS_USED_FOR_ONE_LEVEL;
+const int TrieMap::ROOT_BITMAP_ENTRY_INDEX = 0;
+const int TrieMap::ROOT_BITMAP_ENTRY_POS = MAX_NUM_OF_ENTRIES_IN_ONE_LEVEL * FIELD0_SIZE;
+const TrieMap::Entry TrieMap::EMPTY_BITMAP_ENTRY = TrieMap::Entry(0, 0);
+const uint64_t TrieMap::MAX_VALUE =
+ (static_cast<uint64_t>(1) << ((FIELD0_SIZE + FIELD1_SIZE) * CHAR_BIT)) - 1;
+const int TrieMap::MAX_BUFFER_SIZE = TERMINAL_LINK_MASK * ENTRY_SIZE;
+
+TrieMap::TrieMap() : mBuffer(MAX_BUFFER_SIZE) {
+ mBuffer.extend(ROOT_BITMAP_ENTRY_POS);
+ writeEntry(EMPTY_BITMAP_ENTRY, ROOT_BITMAP_ENTRY_INDEX);
+}
+
+TrieMap::TrieMap(const ReadWriteByteArrayView buffer)
+ : mBuffer(buffer, BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE) {}
+
+void TrieMap::dump(const int from, const int to) const {
+ AKLOGI("BufSize: %d", mBuffer.getTailPosition());
+ for (int i = from; i < to; ++i) {
+ AKLOGI("Entry[%d]: %x, %x", i, readField0(i), readField1(i));
+ }
+ int unusedRegionSize = 0;
+ for (int i = 1; i <= MAX_NUM_OF_ENTRIES_IN_ONE_LEVEL; ++i) {
+ int index = readEmptyTableLink(i);
+ while (index != ROOT_BITMAP_ENTRY_INDEX) {
+ index = readField0(index);
+ unusedRegionSize += i;
+ }
+ }
+ AKLOGI("Unused Size: %d", unusedRegionSize);
+}
+
+int TrieMap::getNextLevelBitmapEntryIndex(const int key, const int bitmapEntryIndex) {
+ const Entry bitmapEntry = readEntry(bitmapEntryIndex);
+ const uint32_t unsignedKey = static_cast<uint32_t>(key);
+ const int terminalEntryIndex = getTerminalEntryIndex(
+ unsignedKey, getBitShuffledKey(unsignedKey), bitmapEntry, 0 /* level */);
+ if (terminalEntryIndex == INVALID_INDEX) {
+ // Not found.
+ return INVALID_INDEX;
+ }
+ const Entry terminalEntry = readEntry(terminalEntryIndex);
+ if (terminalEntry.hasTerminalLink()) {
+ return terminalEntry.getValueEntryIndex() + 1;
+ }
+ // Create a value entry and a bitmap entry.
+ const int valueEntryIndex = allocateTable(2 /* entryCount */);
+ if (!writeEntry(Entry(0, terminalEntry.getValue()), valueEntryIndex)) {
+ return INVALID_INDEX;
+ }
+ if (!writeEntry(EMPTY_BITMAP_ENTRY, valueEntryIndex + 1)) {
+ return INVALID_INDEX;
+ }
+ if (!writeField1(valueEntryIndex | TERMINAL_LINK_FLAG, valueEntryIndex)) {
+ return INVALID_INDEX;
+ }
+ return valueEntryIndex + 1;
+}
+
+const TrieMap::Result TrieMap::get(const int key, const int bitmapEntryIndex) const {
+ const uint32_t unsignedKey = static_cast<uint32_t>(key);
+ return getInternal(unsignedKey, getBitShuffledKey(unsignedKey), bitmapEntryIndex,
+ 0 /* level */);
+}
+
+bool TrieMap::put(const int key, const uint64_t value, const int bitmapEntryIndex) {
+ if (value > MAX_VALUE) {
+ return false;
+ }
+ const uint32_t unsignedKey = static_cast<uint32_t>(key);
+ return putInternal(unsignedKey, value, getBitShuffledKey(unsignedKey), bitmapEntryIndex,
+ readEntry(bitmapEntryIndex), 0 /* level */);
+}
+
+bool TrieMap::save(FILE *const file) const {
+ return DictFileWritingUtils::writeBufferToFileTail(file, &mBuffer);
+}
+
+/**
+ * Iterate next entry in a certain level.
+ *
+ * @param iterationState the iteration state that will be read and updated in this method.
+ * @param outKey the output key
+ * @return Result instance. mIsValid is false when all entries are iterated.
+ */
+const TrieMap::Result TrieMap::iterateNext(std::vector<TableIterationState> *const iterationState,
+ int *const outKey) const {
+ while (!iterationState->empty()) {
+ TableIterationState &state = iterationState->back();
+ if (state.mTableSize <= state.mCurrentIndex) {
+ // Move to parent.
+ iterationState->pop_back();
+ } else {
+ const int entryIndex = state.mTableIndex + state.mCurrentIndex;
+ state.mCurrentIndex += 1;
+ const Entry entry = readEntry(entryIndex);
+ if (entry.isBitmapEntry()) {
+ // Move to child.
+ iterationState->emplace_back(popCount(entry.getBitmap()), entry.getTableIndex());
+ } else {
+ if (outKey) {
+ *outKey = entry.getKey();
+ }
+ if (!entry.hasTerminalLink()) {
+ return Result(entry.getValue(), true, INVALID_INDEX);
+ }
+ const int valueEntryIndex = entry.getValueEntryIndex();
+ const Entry valueEntry = readEntry(valueEntryIndex);
+ return Result(valueEntry.getValueOfValueEntry(), true, valueEntryIndex + 1);
+ }
+ }
+ }
+ // Visited all entries.
+ return Result(0, false, INVALID_INDEX);
+}
+
+/**
+ * Shuffle bits of the key in the fixed order.
+ *
+ * This method is used as a hash function. This returns different values for different inputs.
+ */
+uint32_t TrieMap::getBitShuffledKey(const uint32_t key) const {
+ uint32_t shuffledKey = 0;
+ for (int i = 0; i < 4; ++i) {
+ const uint32_t keyPiece = (key >> (i * 8)) & 0xFF;
+ shuffledKey ^= ((keyPiece ^ (keyPiece << 7) ^ (keyPiece << 14) ^ (keyPiece << 21))
+ & 0x11111111) << i;
+ }
+ return shuffledKey;
+}
+
+bool TrieMap::writeValue(const uint64_t value, const int terminalEntryIndex) {
+ if (value <= VALUE_MASK) {
+ // Write value into the terminal entry.
+ return writeField1(value | VALUE_FLAG, terminalEntryIndex);
+ }
+ // Create value entry and write value.
+ const int valueEntryIndex = allocateTable(2 /* entryCount */);
+ if (!writeEntry(Entry(value >> (FIELD1_SIZE * CHAR_BIT), value), valueEntryIndex)) {
+ return false;
+ }
+ if (!writeEntry(EMPTY_BITMAP_ENTRY, valueEntryIndex + 1)) {
+ return false;
+ }
+ return writeField1(valueEntryIndex | TERMINAL_LINK_FLAG, terminalEntryIndex);
+}
+
+bool TrieMap::updateValue(const Entry &terminalEntry, const uint64_t value,
+ const int terminalEntryIndex) {
+ if (!terminalEntry.hasTerminalLink()) {
+ return writeValue(value, terminalEntryIndex);
+ }
+ const int valueEntryIndex = terminalEntry.getValueEntryIndex();
+ return writeEntry(Entry(value >> (FIELD1_SIZE * CHAR_BIT), value), valueEntryIndex);
+}
+
+bool TrieMap::freeTable(const int tableIndex, const int entryCount) {
+ if (!writeField0(readEmptyTableLink(entryCount), tableIndex)) {
+ return false;
+ }
+ return writeEmptyTableLink(tableIndex, entryCount);
+}
+
+/**
+ * Allocate table with entryCount-entries. Reuse freed table if possible.
+ */
+int TrieMap::allocateTable(const int entryCount) {
+ if (entryCount > 0 && entryCount <= MAX_NUM_OF_ENTRIES_IN_ONE_LEVEL) {
+ const int tableIndex = readEmptyTableLink(entryCount);
+ if (tableIndex > 0) {
+ if (!writeEmptyTableLink(readField0(tableIndex), entryCount)) {
+ return INVALID_INDEX;
+ }
+ // Reuse the table.
+ return tableIndex;
+ }
+ }
+ // Allocate memory space at tail position of the buffer.
+ const int mapIndex = getTailEntryIndex();
+ if (!mBuffer.extend(entryCount * ENTRY_SIZE)) {
+ return INVALID_INDEX;
+ }
+ return mapIndex;
+}
+
+int TrieMap::getTerminalEntryIndex(const uint32_t key, const uint32_t hashedKey,
+ const Entry &bitmapEntry, const int level) const {
+ const int label = getLabel(hashedKey, level);
+ if (!exists(bitmapEntry.getBitmap(), label)) {
+ return INVALID_INDEX;
+ }
+ const int entryIndex = bitmapEntry.getTableIndex() + popCount(bitmapEntry.getBitmap(), label);
+ const Entry entry = readEntry(entryIndex);
+ if (entry.isBitmapEntry()) {
+ // Move to the next level.
+ return getTerminalEntryIndex(key, hashedKey, entry, level + 1);
+ }
+ if (entry.getKey() == key) {
+ // Terminal entry is found.
+ return entryIndex;
+ }
+ return INVALID_INDEX;
+}
+
+/**
+ * Get Result corresponding to the key.
+ *
+ * @param key the key.
+ * @param hashedKey the hashed key.
+ * @param bitmapEntryIndex the index of bitmap entry
+ * @param level current level
+ * @return Result instance corresponding to the key. mIsValid indicates whether the key is in the
+ * map.
+ */
+const TrieMap::Result TrieMap::getInternal(const uint32_t key, const uint32_t hashedKey,
+ const int bitmapEntryIndex, const int level) const {
+ const int terminalEntryIndex = getTerminalEntryIndex(key, hashedKey,
+ readEntry(bitmapEntryIndex), level);
+ if (terminalEntryIndex == INVALID_INDEX) {
+ // Not found.
+ return Result(0, false, INVALID_INDEX);
+ }
+ const Entry terminalEntry = readEntry(terminalEntryIndex);
+ if (!terminalEntry.hasTerminalLink()) {
+ return Result(terminalEntry.getValue(), true, INVALID_INDEX);
+ }
+ const int valueEntryIndex = terminalEntry.getValueEntryIndex();
+ const Entry valueEntry = readEntry(valueEntryIndex);
+ return Result(valueEntry.getValueOfValueEntry(), true, valueEntryIndex + 1);
+}
+
+/**
+ * Put key to value mapping to the map.
+ *
+ * @param key the key.
+ * @param value the value
+ * @param hashedKey the hashed key.
+ * @param bitmapEntryIndex the index of bitmap entry
+ * @param bitmapEntry the bitmap entry
+ * @param level current level
+ * @return whether the key-value has been correctly inserted to the map or not.
+ */
+bool TrieMap::putInternal(const uint32_t key, const uint64_t value, const uint32_t hashedKey,
+ const int bitmapEntryIndex, const Entry &bitmapEntry, const int level) {
+ const int label = getLabel(hashedKey, level);
+ const uint32_t bitmap = bitmapEntry.getBitmap();
+ const int mapIndex = bitmapEntry.getTableIndex();
+ if (!exists(bitmap, label)) {
+ // Current map doesn't contain the label.
+ return addNewEntryByExpandingTable(key, value, mapIndex, bitmap, bitmapEntryIndex, label);
+ }
+ const int entryIndex = mapIndex + popCount(bitmap, label);
+ const Entry entry = readEntry(entryIndex);
+ if (entry.isBitmapEntry()) {
+ // Bitmap entry is found. Go to the next level.
+ return putInternal(key, value, hashedKey, entryIndex, entry, level + 1);
+ }
+ if (entry.getKey() == key) {
+ // Terminal entry for the key is found. Update the value.
+ return updateValue(entry, value, entryIndex);
+ }
+ // Conflict with the existing key.
+ return addNewEntryByResolvingConflict(key, value, hashedKey, entry, entryIndex, level);
+}
+
+/**
+ * Resolve a conflict in the current level and add new entry.
+ *
+ * @param key the key
+ * @param value the value
+ * @param hashedKey the hashed key
+ * @param conflictedEntry the existing conflicted entry
+ * @param conflictedEntryIndex the index of existing conflicted entry
+ * @param level current level
+ * @return whether the key-value has been correctly inserted to the map or not.
+ */
+bool TrieMap::addNewEntryByResolvingConflict(const uint32_t key, const uint64_t value,
+ const uint32_t hashedKey, const Entry &conflictedEntry, const int conflictedEntryIndex,
+ const int level) {
+ const int conflictedKeyNextLabel =
+ getLabel(getBitShuffledKey(conflictedEntry.getKey()), level + 1);
+ const int nextLabel = getLabel(hashedKey, level + 1);
+ if (conflictedKeyNextLabel == nextLabel) {
+ // Conflicted again in the next level.
+ const int newTableIndex = allocateTable(1 /* entryCount */);
+ if (newTableIndex == INVALID_INDEX) {
+ return false;
+ }
+ if (!writeEntry(conflictedEntry, newTableIndex)) {
+ return false;
+ }
+ const Entry newBitmapEntry(setExist(0 /* bitmap */, nextLabel), newTableIndex);
+ if (!writeEntry(newBitmapEntry, conflictedEntryIndex)) {
+ return false;
+ }
+ return putInternal(key, value, hashedKey, conflictedEntryIndex, newBitmapEntry, level + 1);
+ }
+ // The conflict has been resolved. Create a table that contains 2 entries.
+ const int newTableIndex = allocateTable(2 /* entryCount */);
+ if (newTableIndex == INVALID_INDEX) {
+ return false;
+ }
+ if (nextLabel < conflictedKeyNextLabel) {
+ if (!writeTerminalEntry(key, value, newTableIndex)) {
+ return false;
+ }
+ if (!writeEntry(conflictedEntry, newTableIndex + 1)) {
+ return false;
+ }
+ } else { // nextLabel > conflictedKeyNextLabel
+ if (!writeEntry(conflictedEntry, newTableIndex)) {
+ return false;
+ }
+ if (!writeTerminalEntry(key, value, newTableIndex + 1)) {
+ return false;
+ }
+ }
+ const uint32_t updatedBitmap =
+ setExist(setExist(0 /* bitmap */, nextLabel), conflictedKeyNextLabel);
+ return writeEntry(Entry(updatedBitmap, newTableIndex), conflictedEntryIndex);
+}
+
+/**
+ * Add new entry to the existing table.
+ */
+bool TrieMap::addNewEntryByExpandingTable(const uint32_t key, const uint64_t value,
+ const int tableIndex, const uint32_t bitmap, const int bitmapEntryIndex, const int label) {
+ // Current map doesn't contain the label.
+ const int entryCount = popCount(bitmap);
+ const int newTableIndex = allocateTable(entryCount + 1);
+ if (newTableIndex == INVALID_INDEX) {
+ return false;
+ }
+ const int newEntryIndexInTable = popCount(bitmap, label);
+ // Copy from existing table to the new table.
+ for (int i = 0; i < entryCount; ++i) {
+ if (!copyEntry(tableIndex + i, newTableIndex + i + (i >= newEntryIndexInTable ? 1 : 0))) {
+ return false;
+ }
+ }
+ // Write new terminal entry.
+ if (!writeTerminalEntry(key, value, newTableIndex + newEntryIndexInTable)) {
+ return false;
+ }
+ // Update bitmap.
+ if (!writeEntry(Entry(setExist(bitmap, label), newTableIndex), bitmapEntryIndex)) {
+ return false;
+ }
+ if (entryCount > 0) {
+ return freeTable(tableIndex, entryCount);
+ }
+ return true;
+}
+
+} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.h b/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.h
new file mode 100644
index 000000000..3e5c4010c
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.h
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LATINIME_TRIE_MAP_H
+#define LATINIME_TRIE_MAP_H
+
+#include <climits>
+#include <cstdint>
+#include <cstdio>
+#include <vector>
+
+#include "defines.h"
+#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
+#include "utils/byte_array_view.h"
+
+namespace latinime {
+
+/**
+ * Trie map derived from Phil Bagwell's Hash Array Mapped Trie.
+ * key is int and value is uint64_t.
+ * This supports multiple level map. Terminal entries can have a bitmap for the next level map.
+ * This doesn't support root map resizing.
+ */
+class TrieMap {
+ public:
+ struct Result {
+ const uint64_t mValue;
+ const bool mIsValid;
+ const int mNextLevelBitmapEntryIndex;
+
+ Result(const uint64_t value, const bool isValid, const int nextLevelBitmapEntryIndex)
+ : mValue(value), mIsValid(isValid),
+ mNextLevelBitmapEntryIndex(nextLevelBitmapEntryIndex) {}
+ };
+
+ /**
+ * Struct to record iteration state in a table.
+ */
+ struct TableIterationState {
+ int mTableSize;
+ int mTableIndex;
+ int mCurrentIndex;
+
+ TableIterationState(const int tableSize, const int tableIndex)
+ : mTableSize(tableSize), mTableIndex(tableIndex), mCurrentIndex(0) {}
+ };
+
+ class TrieMapRange;
+ class TrieMapIterator {
+ public:
+ class IterationResult {
+ public:
+ IterationResult(const TrieMap *const trieMap, const int key, const uint64_t value,
+ const int nextLeveBitmapEntryIndex)
+ : mTrieMap(trieMap), mKey(key), mValue(value),
+ mNextLevelBitmapEntryIndex(nextLeveBitmapEntryIndex) {}
+
+ const TrieMapRange getEntriesInNextLevel() const {
+ return TrieMapRange(mTrieMap, mNextLevelBitmapEntryIndex);
+ }
+
+ bool hasNextLevelMap() const {
+ return mNextLevelBitmapEntryIndex != INVALID_INDEX;
+ }
+
+ AK_FORCE_INLINE int key() const {
+ return mKey;
+ }
+
+ AK_FORCE_INLINE uint64_t value() const {
+ return mValue;
+ }
+
+ private:
+ const TrieMap *const mTrieMap;
+ const int mKey;
+ const uint64_t mValue;
+ const int mNextLevelBitmapEntryIndex;
+ };
+
+ TrieMapIterator(const TrieMap *const trieMap, const int bitmapEntryIndex)
+ : mTrieMap(trieMap), mStateStack(), mBaseBitmapEntryIndex(bitmapEntryIndex),
+ mKey(0), mValue(0), mIsValid(false), mNextLevelBitmapEntryIndex(INVALID_INDEX) {
+ if (!trieMap) {
+ return;
+ }
+ const Entry bitmapEntry = mTrieMap->readEntry(mBaseBitmapEntryIndex);
+ mStateStack.emplace_back(
+ mTrieMap->popCount(bitmapEntry.getBitmap()), bitmapEntry.getTableIndex());
+ this->operator++();
+ }
+
+ const IterationResult operator*() const {
+ return IterationResult(mTrieMap, mKey, mValue, mNextLevelBitmapEntryIndex);
+ }
+
+ bool operator!=(const TrieMapIterator &other) const {
+ // Caveat: This works only for for loops.
+ return mIsValid || other.mIsValid;
+ }
+
+ const TrieMapIterator &operator++() {
+ const Result result = mTrieMap->iterateNext(&mStateStack, &mKey);
+ mValue = result.mValue;
+ mIsValid = result.mIsValid;
+ mNextLevelBitmapEntryIndex = result.mNextLevelBitmapEntryIndex;
+ return *this;
+ }
+
+ private:
+ DISALLOW_DEFAULT_CONSTRUCTOR(TrieMapIterator);
+ DISALLOW_ASSIGNMENT_OPERATOR(TrieMapIterator);
+
+ const TrieMap *const mTrieMap;
+ std::vector<TrieMap::TableIterationState> mStateStack;
+ const int mBaseBitmapEntryIndex;
+ int mKey;
+ uint64_t mValue;
+ bool mIsValid;
+ int mNextLevelBitmapEntryIndex;
+ };
+
+ /**
+ * Class to support iterating entries in TrieMap by range base for loops.
+ */
+ class TrieMapRange {
+ public:
+ TrieMapRange(const TrieMap *const trieMap, const int bitmapEntryIndex)
+ : mTrieMap(trieMap), mBaseBitmapEntryIndex(bitmapEntryIndex) {};
+
+ TrieMapIterator begin() const {
+ return TrieMapIterator(mTrieMap, mBaseBitmapEntryIndex);
+ }
+
+ const TrieMapIterator end() const {
+ return TrieMapIterator(nullptr, INVALID_INDEX);
+ }
+
+ private:
+ DISALLOW_DEFAULT_CONSTRUCTOR(TrieMapRange);
+ DISALLOW_ASSIGNMENT_OPERATOR(TrieMapRange);
+
+ const TrieMap *const mTrieMap;
+ const int mBaseBitmapEntryIndex;
+ };
+
+ static const int INVALID_INDEX;
+ static const uint64_t MAX_VALUE;
+
+ TrieMap();
+ // Construct TrieMap using existing data in the memory region written by save().
+ TrieMap(const ReadWriteByteArrayView buffer);
+ void dump(const int from = 0, const int to = 0) const;
+
+ bool isNearSizeLimit() const {
+ return mBuffer.isNearSizeLimit();
+ }
+
+ int getRootBitmapEntryIndex() const {
+ return ROOT_BITMAP_ENTRY_INDEX;
+ }
+
+ // Returns bitmapEntryIndex. Create the next level map if it doesn't exist.
+ int getNextLevelBitmapEntryIndex(const int key) {
+ return getNextLevelBitmapEntryIndex(key, ROOT_BITMAP_ENTRY_INDEX);
+ }
+
+ int getNextLevelBitmapEntryIndex(const int key, const int bitmapEntryIndex);
+
+ const Result getRoot(const int key) const {
+ return get(key, ROOT_BITMAP_ENTRY_INDEX);
+ }
+
+ const Result get(const int key, const int bitmapEntryIndex) const;
+
+ bool putRoot(const int key, const uint64_t value) {
+ return put(key, value, ROOT_BITMAP_ENTRY_INDEX);
+ }
+
+ bool put(const int key, const uint64_t value, const int bitmapEntryIndex);
+
+ const TrieMapRange getEntriesInRootLevel() const {
+ return getEntriesInSpecifiedLevel(ROOT_BITMAP_ENTRY_INDEX);
+ }
+
+ const TrieMapRange getEntriesInSpecifiedLevel(const int bitmapEntryIndex) const {
+ return TrieMapRange(this, bitmapEntryIndex);
+ }
+
+ bool save(FILE *const file) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TrieMap);
+
+ /**
+ * Struct represents an entry.
+ *
+ * Entry is one of these entry types. All entries are fixed size and have 2 fields FIELD_0 and
+ * FIELD_1.
+ * 1. bitmap entry. bitmap entry contains bitmap and the link to hash table.
+ * FIELD_0(bitmap) FIELD_1(LINK_TO_HASH_TABLE)
+ * 2. terminal entry. terminal entry contains hashed key and value or terminal link. terminal
+ * entry have terminal link when the value is not fit to FIELD_1 or there is a next level map
+ * for the key.
+ * FIELD_0(hashed key) (FIELD_1(VALUE_FLAG VALUE) | FIELD_1(TERMINAL_LINK_FLAG TERMINAL_LINK))
+ * 3. value entry. value entry represents a value. Upper order bytes are stored in FIELD_0 and
+ * lower order bytes are stored in FIELD_1.
+ * FIELD_0(value (upper order bytes)) FIELD_1(value (lower order bytes))
+ */
+ struct Entry {
+ const uint32_t mData0;
+ const uint32_t mData1;
+
+ Entry(const uint32_t data0, const uint32_t data1) : mData0(data0), mData1(data1) {}
+
+ AK_FORCE_INLINE bool isBitmapEntry() const {
+ return (mData1 & VALUE_FLAG) == 0 && (mData1 & TERMINAL_LINK_FLAG) == 0;
+ }
+
+ AK_FORCE_INLINE bool hasTerminalLink() const {
+ return (mData1 & TERMINAL_LINK_FLAG) != 0;
+ }
+
+ // For terminal entry.
+ AK_FORCE_INLINE uint32_t getKey() const {
+ return mData0;
+ }
+
+ // For terminal entry.
+ AK_FORCE_INLINE uint32_t getValue() const {
+ return mData1 & VALUE_MASK;
+ }
+
+ // For terminal entry.
+ AK_FORCE_INLINE uint32_t getValueEntryIndex() const {
+ return mData1 & TERMINAL_LINK_MASK;
+ }
+
+ // For bitmap entry.
+ AK_FORCE_INLINE uint32_t getBitmap() const {
+ return mData0;
+ }
+
+ // For bitmap entry.
+ AK_FORCE_INLINE int getTableIndex() const {
+ return static_cast<int>(mData1);
+ }
+
+ // For value entry.
+ AK_FORCE_INLINE uint64_t getValueOfValueEntry() const {
+ return ((static_cast<uint64_t>(mData0) << (FIELD1_SIZE * CHAR_BIT)) ^ mData1);
+ }
+ };
+
+ BufferWithExtendableBuffer mBuffer;
+
+ static const int FIELD0_SIZE;
+ static const int FIELD1_SIZE;
+ static const int ENTRY_SIZE;
+ static const uint32_t VALUE_FLAG;
+ static const uint32_t VALUE_MASK;
+ static const uint32_t TERMINAL_LINK_FLAG;
+ static const uint32_t TERMINAL_LINK_MASK;
+ static const int NUM_OF_BITS_USED_FOR_ONE_LEVEL;
+ static const uint32_t LABEL_MASK;
+ static const int MAX_NUM_OF_ENTRIES_IN_ONE_LEVEL;
+ static const int ROOT_BITMAP_ENTRY_INDEX;
+ static const int ROOT_BITMAP_ENTRY_POS;
+ static const Entry EMPTY_BITMAP_ENTRY;
+ static const int MAX_BUFFER_SIZE;
+
+ uint32_t getBitShuffledKey(const uint32_t key) const;
+ bool writeValue(const uint64_t value, const int terminalEntryIndex);
+ bool updateValue(const Entry &terminalEntry, const uint64_t value,
+ const int terminalEntryIndex);
+ bool freeTable(const int tableIndex, const int entryCount);
+ int allocateTable(const int entryCount);
+ int getTerminalEntryIndex(const uint32_t key, const uint32_t hashedKey,
+ const Entry &bitmapEntry, const int level) const;
+ const Result getInternal(const uint32_t key, const uint32_t hashedKey,
+ const int bitmapEntryIndex, const int level) const;
+ bool putInternal(const uint32_t key, const uint64_t value, const uint32_t hashedKey,
+ const int bitmapEntryIndex, const Entry &bitmapEntry, const int level);
+ bool addNewEntryByResolvingConflict(const uint32_t key, const uint64_t value,
+ const uint32_t hashedKey, const Entry &conflictedEntry, const int conflictedEntryIndex,
+ const int level);
+ bool addNewEntryByExpandingTable(const uint32_t key, const uint64_t value,
+ const int tableIndex, const uint32_t bitmap, const int bitmapEntryIndex,
+ const int label);
+ const Result iterateNext(std::vector<TableIterationState> *const iterationState,
+ int *const outKey) const;
+
+ AK_FORCE_INLINE const Entry readEntry(const int entryIndex) const {
+ return Entry(readField0(entryIndex), readField1(entryIndex));
+ }
+
+ // Returns whether an entry for the index is existing by testing if the index-th bit in the
+ // bitmap is set or not.
+ AK_FORCE_INLINE bool exists(const uint32_t bitmap, const int index) const {
+ return (bitmap & (1 << index)) != 0;
+ }
+
+ // Set index-th bit in the bitmap.
+ AK_FORCE_INLINE uint32_t setExist(const uint32_t bitmap, const int index) const {
+ return bitmap | (1 << index);
+ }
+
+ // Count set bits before index in the bitmap.
+ AK_FORCE_INLINE int popCount(const uint32_t bitmap, const int index) const {
+ return popCount(bitmap & ((1 << index) - 1));
+ }
+
+ // Count set bits in the bitmap.
+ AK_FORCE_INLINE int popCount(const uint32_t bitmap) const {
+ return __builtin_popcount(bitmap);
+ // int v = bitmap - ((bitmap >> 1) & 0x55555555);
+ // v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
+ // return (((v + (v >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
+ }
+
+ AK_FORCE_INLINE int getLabel(const uint32_t hashedKey, const int level) const {
+ return (hashedKey >> (level * NUM_OF_BITS_USED_FOR_ONE_LEVEL)) & LABEL_MASK;
+ }
+
+ AK_FORCE_INLINE uint32_t readField0(const int entryIndex) const {
+ return mBuffer.readUint(FIELD0_SIZE, ROOT_BITMAP_ENTRY_POS + entryIndex * ENTRY_SIZE);
+ }
+
+ AK_FORCE_INLINE uint32_t readField1(const int entryIndex) const {
+ return mBuffer.readUint(FIELD1_SIZE,
+ ROOT_BITMAP_ENTRY_POS + entryIndex * ENTRY_SIZE + FIELD0_SIZE);
+ }
+
+ AK_FORCE_INLINE int readEmptyTableLink(const int entryCount) const {
+ return mBuffer.readUint(FIELD1_SIZE, (entryCount - 1) * FIELD1_SIZE);
+ }
+
+ AK_FORCE_INLINE bool writeEmptyTableLink(const int tableIndex, const int entryCount) {
+ return mBuffer.writeUint(tableIndex, FIELD1_SIZE, (entryCount - 1) * FIELD1_SIZE);
+ }
+
+ AK_FORCE_INLINE bool writeField0(const uint32_t data, const int entryIndex) {
+ return mBuffer.writeUint(data, FIELD0_SIZE,
+ ROOT_BITMAP_ENTRY_POS + entryIndex * ENTRY_SIZE);
+ }
+
+ AK_FORCE_INLINE bool writeField1(const uint32_t data, const int entryIndex) {
+ return mBuffer.writeUint(data, FIELD1_SIZE,
+ ROOT_BITMAP_ENTRY_POS + entryIndex * ENTRY_SIZE + FIELD0_SIZE);
+ }
+
+ AK_FORCE_INLINE bool writeEntry(const Entry &entry, const int entryIndex) {
+ return writeField0(entry.mData0, entryIndex) && writeField1(entry.mData1, entryIndex);
+ }
+
+ AK_FORCE_INLINE bool writeTerminalEntry(const uint32_t key, const uint64_t value,
+ const int entryIndex) {
+ return writeField0(key, entryIndex) && writeValue(value, entryIndex);
+ }
+
+ AK_FORCE_INLINE bool copyEntry(const int originalEntryIndex, const int newEntryIndex) {
+ return writeEntry(readEntry(originalEntryIndex), newEntryIndex);
+ }
+
+ AK_FORCE_INLINE int getTailEntryIndex() const {
+ return (mBuffer.getTailPosition() - ROOT_BITMAP_ENTRY_POS) / ENTRY_SIZE;
+ }
+};
+
+} // namespace latinime
+#endif /* LATINIME_TRIE_MAP_H */
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_scoring.h b/native/jni/src/suggest/policyimpl/typing/typing_scoring.h
index 66ea62406..04cb6603a 100644
--- a/native/jni/src/suggest/policyimpl/typing/typing_scoring.h
+++ b/native/jni/src/suggest/policyimpl/typing/typing_scoring.h
@@ -69,10 +69,6 @@ class TypingScoring : public Scoring {
return 0.0f;
}
- AK_FORCE_INLINE bool doesAutoCorrectValidWord() const {
- return false;
- }
-
AK_FORCE_INLINE bool autoCorrectsToMultiWordSuggestionIfTop() const {
return true;
}
diff --git a/native/jni/src/utils/byte_array_view.h b/native/jni/src/utils/byte_array_view.h
new file mode 100644
index 000000000..2c97c6d58
--- /dev/null
+++ b/native/jni/src/utils/byte_array_view.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LATINIME_BYTE_ARRAY_VIEW_H
+#define LATINIME_BYTE_ARRAY_VIEW_H
+
+#include <cstdint>
+#include <cstdlib>
+
+#include "defines.h"
+
+namespace latinime {
+
+/**
+ * Helper class used to keep track of read accesses for a given memory region.
+ */
+class ReadOnlyByteArrayView {
+ public:
+ ReadOnlyByteArrayView() : mPtr(nullptr), mSize(0) {}
+
+ ReadOnlyByteArrayView(const uint8_t *const ptr, const size_t size)
+ : mPtr(ptr), mSize(size) {}
+
+ AK_FORCE_INLINE size_t size() const {
+ return mSize;
+ }
+
+ AK_FORCE_INLINE const uint8_t *data() const {
+ return mPtr;
+ }
+
+ private:
+ DISALLOW_ASSIGNMENT_OPERATOR(ReadOnlyByteArrayView);
+
+ const uint8_t *const mPtr;
+ const size_t mSize;
+};
+
+/**
+ * Helper class used to keep track of read-write accesses for a given memory region.
+ */
+class ReadWriteByteArrayView {
+ public:
+ ReadWriteByteArrayView() : mPtr(nullptr), mSize(0) {}
+
+ ReadWriteByteArrayView(uint8_t *const ptr, const size_t size)
+ : mPtr(ptr), mSize(size) {}
+
+ AK_FORCE_INLINE size_t size() const {
+ return mSize;
+ }
+
+ AK_FORCE_INLINE uint8_t *data() const {
+ return mPtr;
+ }
+
+ AK_FORCE_INLINE ReadOnlyByteArrayView getReadOnlyView() const {
+ return ReadOnlyByteArrayView(mPtr, mSize);
+ }
+
+ ReadWriteByteArrayView subView(const size_t start, const size_t n) const {
+ ASSERT(start + n <= mSize);
+ return ReadWriteByteArrayView(mPtr + start, n);
+ }
+
+ private:
+ DISALLOW_ASSIGNMENT_OPERATOR(ReadWriteByteArrayView);
+
+ uint8_t *const mPtr;
+ const size_t mSize;
+};
+
+} // namespace latinime
+#endif // LATINIME_BYTE_ARRAY_VIEW_H
diff --git a/native/jni/src/utils/int_array_view.h b/native/jni/src/utils/int_array_view.h
new file mode 100644
index 000000000..c1ddc9812
--- /dev/null
+++ b/native/jni/src/utils/int_array_view.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LATINIME_INT_ARRAY_VIEW_H
+#define LATINIME_INT_ARRAY_VIEW_H
+
+#include <cstdint>
+#include <cstdlib>
+#include <vector>
+
+#include "defines.h"
+
+namespace latinime {
+
+/**
+ * Helper class used to provide a read-only view of a given range of integer array. This class
+ * does not take ownership of the underlying integer array but is designed to be a lightweight
+ * object that obeys value semantics.
+ *
+ * Example:
+ * <code>
+ * bool constinsX(IntArrayView view) {
+ * for (size_t i = 0; i < view.size(); ++i) {
+ * if (view[i] == 'X') {
+ * return true;
+ * }
+ * }
+ * return false;
+ * }
+ *
+ * const int codePointArray[] = { 'A', 'B', 'X', 'Z' };
+ * auto view = IntArrayView(codePointArray, NELEMS(codePointArray));
+ * const bool hasX = constinsX(view);
+ * </code>
+ */
+class IntArrayView {
+ public:
+ IntArrayView() : mPtr(nullptr), mSize(0) {}
+
+ IntArrayView(const int *const ptr, const size_t size)
+ : mPtr(ptr), mSize(size) {}
+
+ explicit IntArrayView(const std::vector<int> &vector)
+ : mPtr(vector.data()), mSize(vector.size()) {}
+
+ template <int N>
+ AK_FORCE_INLINE static IntArrayView fromFixedSizeArray(const int (&array)[N]) {
+ return IntArrayView(array, N);
+ }
+
+ // Returns a view that points one int object. Does not take ownership of the given object.
+ AK_FORCE_INLINE static IntArrayView fromObject(const int *const object) {
+ return IntArrayView(object, 1);
+ }
+
+ AK_FORCE_INLINE int operator[](const size_t index) const {
+ ASSERT(index < mSize);
+ return mPtr[index];
+ }
+
+ AK_FORCE_INLINE bool empty() const {
+ return size() == 0;
+ }
+
+ AK_FORCE_INLINE size_t size() const {
+ return mSize;
+ }
+
+ AK_FORCE_INLINE const int *data() const {
+ return mPtr;
+ }
+
+ AK_FORCE_INLINE const int *begin() const {
+ return mPtr;
+ }
+
+ AK_FORCE_INLINE const int *end() const {
+ return mPtr + mSize;
+ }
+
+ private:
+ DISALLOW_ASSIGNMENT_OPERATOR(IntArrayView);
+
+ const int *const mPtr;
+ const size_t mSize;
+};
+
+using WordIdArrayView = IntArrayView;
+using PtNodePosArrayView = IntArrayView;
+
+} // namespace latinime
+#endif // LATINIME_MEMORY_VIEW_H
diff --git a/native/jni/tests/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content_test.cpp b/native/jni/tests/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content_test.cpp
new file mode 100644
index 000000000..6eef2040b
--- /dev/null
+++ b/native/jni/tests/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content_test.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h"
+
+#include <gtest/gtest.h>
+
+#include "utils/int_array_view.h"
+
+namespace latinime {
+namespace {
+
+TEST(LanguageModelDictContentTest, TestUnigramProbability) {
+ LanguageModelDictContent LanguageModelDictContent(false /* useHistoricalInfo */);
+
+ const int flag = 0xFF;
+ const int probability = 10;
+ const int wordId = 100;
+ const ProbabilityEntry probabilityEntry(flag, probability);
+ LanguageModelDictContent.setProbabilityEntry(wordId, &probabilityEntry);
+ const ProbabilityEntry entry =
+ LanguageModelDictContent.getProbabilityEntry(wordId);
+ EXPECT_EQ(flag, entry.getFlags());
+ EXPECT_EQ(probability, entry.getProbability());
+}
+
+TEST(LanguageModelDictContentTest, TestUnigramProbabilityWithHistoricalInfo) {
+ LanguageModelDictContent LanguageModelDictContent(true /* useHistoricalInfo */);
+
+ const int flag = 0xF0;
+ const int timestamp = 0x3FFFFFFF;
+ const int level = 3;
+ const int count = 10;
+ const int wordId = 100;
+ const HistoricalInfo historicalInfo(timestamp, level, count);
+ const ProbabilityEntry probabilityEntry(flag, NOT_A_PROBABILITY, &historicalInfo);
+ LanguageModelDictContent.setProbabilityEntry(wordId, &probabilityEntry);
+ const ProbabilityEntry entry = LanguageModelDictContent.getProbabilityEntry(wordId);
+ EXPECT_EQ(flag, entry.getFlags());
+ EXPECT_EQ(timestamp, entry.getHistoricalInfo()->getTimeStamp());
+ EXPECT_EQ(level, entry.getHistoricalInfo()->getLevel());
+ EXPECT_EQ(count, entry.getHistoricalInfo()->getCount());
+}
+
+} // namespace
+} // namespace latinime
diff --git a/native/jni/tests/suggest/policyimpl/dictionary/structure/v4/content/probability_entry_test.cpp b/native/jni/tests/suggest/policyimpl/dictionary/structure/v4/content/probability_entry_test.cpp
new file mode 100644
index 000000000..db94550ef
--- /dev/null
+++ b/native/jni/tests/suggest/policyimpl/dictionary/structure/v4/content/probability_entry_test.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h"
+
+#include <gtest/gtest.h>
+
+#include "defines.h"
+
+namespace latinime {
+namespace {
+
+TEST(ProbabilityEntryTest, TestEncodeDecode) {
+ const int flag = 0xFF;
+ const int probability = 10;
+
+ const ProbabilityEntry entry(flag, probability);
+ const uint64_t encodedEntry = entry.encode(false /* hasHistoricalInfo */);
+ const ProbabilityEntry decodedEntry =
+ ProbabilityEntry::decode(encodedEntry, false /* hasHistoricalInfo */);
+ EXPECT_EQ(0xFF0Aull, encodedEntry);
+ EXPECT_EQ(flag, decodedEntry.getFlags());
+ EXPECT_EQ(probability, decodedEntry.getProbability());
+}
+
+TEST(ProbabilityEntryTest, TestEncodeDecodeWithHistoricalInfo) {
+ const int flag = 0xF0;
+ const int timestamp = 0x3FFFFFFF;
+ const int level = 3;
+ const int count = 10;
+
+ const HistoricalInfo historicalInfo(timestamp, level, count);
+ const ProbabilityEntry entry(flag, NOT_A_PROBABILITY, &historicalInfo);
+
+ const uint64_t encodedEntry = entry.encode(true /* hasHistoricalInfo */);
+ EXPECT_EQ(0xF03FFFFFFF030Aull, encodedEntry);
+ const ProbabilityEntry decodedEntry =
+ ProbabilityEntry::decode(encodedEntry, true /* hasHistoricalInfo */);
+
+ EXPECT_EQ(flag, decodedEntry.getFlags());
+ EXPECT_EQ(timestamp, decodedEntry.getHistoricalInfo()->getTimeStamp());
+ EXPECT_EQ(level, decodedEntry.getHistoricalInfo()->getLevel());
+ EXPECT_EQ(count, decodedEntry.getHistoricalInfo()->getCount());
+}
+
+} // namespace
+} // namespace latinime
diff --git a/native/jni/tests/suggest/policyimpl/dictionary/utils/trie_map_test.cpp b/native/jni/tests/suggest/policyimpl/dictionary/utils/trie_map_test.cpp
new file mode 100644
index 000000000..df778b6cf
--- /dev/null
+++ b/native/jni/tests/suggest/policyimpl/dictionary/utils/trie_map_test.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "suggest/policyimpl/dictionary/utils/trie_map.h"
+
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <cstdlib>
+#include <functional>
+#include <map>
+#include <random>
+#include <unordered_map>
+
+namespace latinime {
+namespace {
+
+TEST(TrieMapTest, TestSetAndGet) {
+ TrieMap trieMap;
+ trieMap.putRoot(10, 10);
+ EXPECT_EQ(10ull, trieMap.getRoot(10).mValue);
+ trieMap.putRoot(0x10A, 10);
+ EXPECT_EQ(10ull, trieMap.getRoot(10).mValue);
+ EXPECT_EQ(10ull, trieMap.getRoot(0x10A).mValue);
+ trieMap.putRoot(10, 1000);
+ EXPECT_EQ(1000ull, trieMap.getRoot(10).mValue);
+ trieMap.putRoot(11, 1000);
+ EXPECT_EQ(1000ull, trieMap.getRoot(11).mValue);
+ const int next = trieMap.getNextLevelBitmapEntryIndex(10);
+ trieMap.put(9, 9, next);
+ EXPECT_EQ(9ull, trieMap.get(9, next).mValue);
+ EXPECT_FALSE(trieMap.get(11, next).mIsValid);
+ trieMap.putRoot(0, 0xFFFFFFFFFull);
+ EXPECT_EQ(0xFFFFFFFFFull, trieMap.getRoot(0).mValue);
+}
+
+TEST(TrieMapTest, TestSetAndGetLarge) {
+ static const int ELEMENT_COUNT = 200000;
+ TrieMap trieMap;
+ for (int i = 0; i < ELEMENT_COUNT; ++i) {
+ EXPECT_TRUE(trieMap.putRoot(i, i));
+ }
+ for (int i = 0; i < ELEMENT_COUNT; ++i) {
+ EXPECT_EQ(static_cast<uint64_t>(i), trieMap.getRoot(i).mValue);
+ }
+}
+
+TEST(TrieMapTest, TestRandSetAndGetLarge) {
+ static const int ELEMENT_COUNT = 100000;
+ TrieMap trieMap;
+ std::unordered_map<int, uint64_t> testKeyValuePairs;
+
+ // Use the uniform integer distribution [S_INT_MIN, S_INT_MAX].
+ std::uniform_int_distribution<int> keyDistribution(S_INT_MIN, S_INT_MAX);
+ auto keyRandomNumberGenerator = std::bind(keyDistribution, std::mt19937());
+
+ // Use the uniform distribution [0, TrieMap::MAX_VALUE].
+ std::uniform_int_distribution<uint64_t> valueDistribution(0, TrieMap::MAX_VALUE);
+ auto valueRandomNumberGenerator = std::bind(valueDistribution, std::mt19937());
+
+ for (int i = 0; i < ELEMENT_COUNT; ++i) {
+ const int key = keyRandomNumberGenerator();
+ const uint64_t value = valueRandomNumberGenerator();
+ EXPECT_TRUE(trieMap.putRoot(key, value)) << key << " " << value;
+ testKeyValuePairs[key] = value;
+ }
+ for (const auto &v : testKeyValuePairs) {
+ EXPECT_EQ(v.second, trieMap.getRoot(v.first).mValue);
+ }
+}
+
+TEST(TrieMapTest, TestMultiLevel) {
+ static const int FIRST_LEVEL_ENTRY_COUNT = 10000;
+ static const int SECOND_LEVEL_ENTRY_COUNT = 20000;
+ static const int THIRD_LEVEL_ENTRY_COUNT = 40000;
+
+ TrieMap trieMap;
+ std::vector<int> firstLevelKeys;
+ std::map<int, uint64_t> firstLevelEntries;
+ std::vector<std::pair<int, int>> secondLevelKeys;
+ std::map<int, std::map<int, uint64_t>> twoLevelMap;
+ std::map<int, std::map<int, std::map<int, uint64_t>>> threeLevelMap;
+
+ // Use the uniform integer distribution [0, S_INT_MAX].
+ std::uniform_int_distribution<int> distribution(0, S_INT_MAX);
+ auto keyRandomNumberGenerator = std::bind(distribution, std::mt19937());
+ auto randomNumberGeneratorForKeySelection = std::bind(distribution, std::mt19937());
+
+ // Use the uniform distribution [0, TrieMap::MAX_VALUE].
+ std::uniform_int_distribution<uint64_t> valueDistribution(0, TrieMap::MAX_VALUE);
+ auto valueRandomNumberGenerator = std::bind(valueDistribution, std::mt19937());
+
+ for (int i = 0; i < FIRST_LEVEL_ENTRY_COUNT; ++i) {
+ const int key = keyRandomNumberGenerator();
+ const uint64_t value = valueRandomNumberGenerator();
+ EXPECT_TRUE(trieMap.putRoot(key, value));
+ firstLevelKeys.push_back(key);
+ firstLevelEntries[key] = value;
+ }
+
+ for (int i = 0; i < SECOND_LEVEL_ENTRY_COUNT; ++i) {
+ const int key = keyRandomNumberGenerator();
+ const uint64_t value = valueRandomNumberGenerator();
+ const int firstLevelKey =
+ firstLevelKeys[randomNumberGeneratorForKeySelection() % FIRST_LEVEL_ENTRY_COUNT];
+ const int nextLevelBitmapEntryIndex = trieMap.getNextLevelBitmapEntryIndex(firstLevelKey);
+ EXPECT_NE(TrieMap::INVALID_INDEX, nextLevelBitmapEntryIndex);
+ EXPECT_TRUE(trieMap.put(key, value, nextLevelBitmapEntryIndex));
+ secondLevelKeys.push_back(std::make_pair(firstLevelKey, key));
+ twoLevelMap[firstLevelKey][key] = value;
+ }
+
+ for (int i = 0; i < THIRD_LEVEL_ENTRY_COUNT; ++i) {
+ const int key = keyRandomNumberGenerator();
+ const uint64_t value = valueRandomNumberGenerator();
+ const std::pair<int, int> secondLevelKey =
+ secondLevelKeys[randomNumberGeneratorForKeySelection() % SECOND_LEVEL_ENTRY_COUNT];
+ const int secondLevel = trieMap.getNextLevelBitmapEntryIndex(secondLevelKey.first);
+ EXPECT_NE(TrieMap::INVALID_INDEX, secondLevel);
+ const int thirdLevel = trieMap.getNextLevelBitmapEntryIndex(
+ secondLevelKey.second, secondLevel);
+ EXPECT_NE(TrieMap::INVALID_INDEX, thirdLevel);
+ EXPECT_TRUE(trieMap.put(key, value, thirdLevel));
+ threeLevelMap[secondLevelKey.first][secondLevelKey.second][key] = value;
+ }
+
+ for (const auto &firstLevelEntry : firstLevelEntries) {
+ EXPECT_EQ(firstLevelEntry.second, trieMap.getRoot(firstLevelEntry.first).mValue);
+ }
+
+ for (const auto &firstLevelEntry : twoLevelMap) {
+ const int secondLevel = trieMap.getNextLevelBitmapEntryIndex(firstLevelEntry.first);
+ EXPECT_NE(TrieMap::INVALID_INDEX, secondLevel);
+ for (const auto &secondLevelEntry : firstLevelEntry.second) {
+ EXPECT_EQ(secondLevelEntry.second,
+ trieMap.get(secondLevelEntry.first, secondLevel).mValue);
+ }
+ }
+
+ for (const auto &firstLevelEntry : threeLevelMap) {
+ const int secondLevel = trieMap.getNextLevelBitmapEntryIndex(firstLevelEntry.first);
+ EXPECT_NE(TrieMap::INVALID_INDEX, secondLevel);
+ for (const auto &secondLevelEntry : firstLevelEntry.second) {
+ const int thirdLevel =
+ trieMap.getNextLevelBitmapEntryIndex(secondLevelEntry.first, secondLevel);
+ EXPECT_NE(TrieMap::INVALID_INDEX, thirdLevel);
+ for (const auto &thirdLevelEntry : secondLevelEntry.second) {
+ EXPECT_EQ(thirdLevelEntry.second,
+ trieMap.get(thirdLevelEntry.first, thirdLevel).mValue);
+ }
+ }
+ }
+
+ // Iteration
+ for (const auto &firstLevelEntry : trieMap.getEntriesInRootLevel()) {
+ EXPECT_EQ(trieMap.getRoot(firstLevelEntry.key()).mValue, firstLevelEntry.value());
+ EXPECT_EQ(firstLevelEntries[firstLevelEntry.key()], firstLevelEntry.value());
+ firstLevelEntries.erase(firstLevelEntry.key());
+ for (const auto &secondLevelEntry : firstLevelEntry.getEntriesInNextLevel()) {
+ EXPECT_EQ(twoLevelMap[firstLevelEntry.key()][secondLevelEntry.key()],
+ secondLevelEntry.value());
+ twoLevelMap[firstLevelEntry.key()].erase(secondLevelEntry.key());
+ for (const auto &thirdLevelEntry : secondLevelEntry.getEntriesInNextLevel()) {
+ EXPECT_EQ(threeLevelMap[firstLevelEntry.key()][secondLevelEntry.key()]
+ [thirdLevelEntry.key()], thirdLevelEntry.value());
+ threeLevelMap[firstLevelEntry.key()][secondLevelEntry.key()].erase(
+ thirdLevelEntry.key());
+ }
+ }
+ }
+
+ // Ensure all entries have been traversed.
+ EXPECT_TRUE(firstLevelEntries.empty());
+ for (const auto &secondLevelEntry : twoLevelMap) {
+ EXPECT_TRUE(secondLevelEntry.second.empty());
+ }
+ for (const auto &secondLevelEntry : threeLevelMap) {
+ for (const auto &thirdLevelEntry : secondLevelEntry.second) {
+ EXPECT_TRUE(thirdLevelEntry.second.empty());
+ }
+ }
+}
+
+TEST(TrieMapTest, TestIteration) {
+ static const int ELEMENT_COUNT = 200000;
+ TrieMap trieMap;
+ std::unordered_map<int, uint64_t> testKeyValuePairs;
+
+ // Use the uniform integer distribution [S_INT_MIN, S_INT_MAX].
+ std::uniform_int_distribution<int> keyDistribution(S_INT_MIN, S_INT_MAX);
+ auto keyRandomNumberGenerator = std::bind(keyDistribution, std::mt19937());
+
+ // Use the uniform distribution [0, TrieMap::MAX_VALUE].
+ std::uniform_int_distribution<uint64_t> valueDistribution(0, TrieMap::MAX_VALUE);
+ auto valueRandomNumberGenerator = std::bind(valueDistribution, std::mt19937());
+ for (int i = 0; i < ELEMENT_COUNT; ++i) {
+ const int key = keyRandomNumberGenerator();
+ const uint64_t value = valueRandomNumberGenerator();
+ EXPECT_TRUE(trieMap.putRoot(key, value));
+ testKeyValuePairs[key] = value;
+ }
+ for (const auto &entry : trieMap.getEntriesInRootLevel()) {
+ EXPECT_EQ(trieMap.getRoot(entry.key()).mValue, entry.value());
+ EXPECT_EQ(testKeyValuePairs[entry.key()], entry.value());
+ testKeyValuePairs.erase(entry.key());
+ }
+ EXPECT_TRUE(testKeyValuePairs.empty());
+}
+
+} // namespace
+} // namespace latinime
diff --git a/native/jni/tests/utils/int_array_view_test.cpp b/native/jni/tests/utils/int_array_view_test.cpp
new file mode 100644
index 000000000..bd843ab02
--- /dev/null
+++ b/native/jni/tests/utils/int_array_view_test.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils/int_array_view.h"
+
+#include <gtest/gtest.h>
+
+#include <vector>
+
+namespace latinime {
+namespace {
+
+TEST(IntArrayViewTest, TestAccess) {
+ const std::vector<int> intVector = {3, 2, 1, 0, -1, -2};
+ IntArrayView intArrayView(intVector);
+ EXPECT_EQ(intVector.size(), intArrayView.size());
+ for (int i = 0; i < static_cast<int>(intVector.size()); ++i) {
+ EXPECT_EQ(intVector[i], intArrayView[i]);
+ }
+}
+
+TEST(IntArrayViewTest, TestIteration) {
+ const std::vector<int> intVector = {3, 2, 1, 0, -1, -2};
+ IntArrayView intArrayView(intVector);
+ size_t expectedIndex = 0;
+ for (const int element : intArrayView) {
+ EXPECT_EQ(intVector[expectedIndex], element);
+ ++expectedIndex;
+ }
+ EXPECT_EQ(expectedIndex, intArrayView.size());
+}
+
+TEST(IntArrayViewTest, TestConstructFromArray) {
+ const size_t ARRAY_SIZE = 100;
+ int intArray[ARRAY_SIZE];
+ const auto intArrayView = IntArrayView::fromFixedSizeArray(intArray);
+ EXPECT_EQ(ARRAY_SIZE, intArrayView.size());
+}
+
+TEST(IntArrayViewTest, TestConstructFromObject) {
+ const int object = 10;
+ const auto intArrayView = IntArrayView::fromObject(&object);
+ EXPECT_EQ(1, intArrayView.size());
+ EXPECT_EQ(object, intArrayView[0]);
+}
+
+} // namespace
+} // namespace latinime
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelBase.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelBase.java
new file mode 100644
index 000000000..a25d6d6e7
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelBase.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard;
+
+import android.content.res.Resources;
+import android.text.InputType;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.utils.RunInLocale;
+import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
+
+import java.util.Locale;
+
+abstract class KeyboardLayoutSetActionLabelBase extends KeyboardLayoutSetTestsBase {
+ public void testActionUnspecified() {
+ for (final InputMethodSubtype subtype : getAllSubtypesList()) {
+ final String tag = "unspecifiled "
+ + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype);
+ doTestActionKeyIcon(tag, subtype, EditorInfo.IME_ACTION_UNSPECIFIED,
+ KeyboardIconsSet.NAME_ENTER_KEY);
+ }
+ }
+
+ public void testActionNone() {
+ for (final InputMethodSubtype subtype : getAllSubtypesList()) {
+ final String tag = "none " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype);
+ doTestActionKeyIcon(tag, subtype, EditorInfo.IME_ACTION_NONE,
+ KeyboardIconsSet.NAME_ENTER_KEY);
+ }
+ }
+
+ public void testActionSearch() {
+ for (final InputMethodSubtype subtype : getAllSubtypesList()) {
+ final String tag = "search " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype);
+ doTestActionKeyIcon(tag, subtype, EditorInfo.IME_ACTION_SEARCH,
+ KeyboardIconsSet.NAME_SEARCH_KEY);
+ }
+ }
+
+ public abstract void testActionGo();
+ public abstract void testActionSend();
+ public abstract void testActionNext();
+ public abstract void testActionDone();
+ public abstract void testActionPrevious();
+
+ public void testActionCustom() {
+ for (final InputMethodSubtype subtype : getAllSubtypesList()) {
+ final String tag = "custom " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype);
+ final CharSequence customLabel = "customLabel";
+ final EditorInfo editorInfo = new EditorInfo();
+ editorInfo.imeOptions = EditorInfo.IME_ACTION_UNSPECIFIED;
+ editorInfo.actionLabel = customLabel;
+ doTestActionKeyLabel(tag, subtype, editorInfo, customLabel);
+ }
+ }
+
+ private static void doTestActionKey(final String tag, final KeyboardLayoutSet layoutSet,
+ final int elementId, final CharSequence label, final int iconId) {
+ final Keyboard keyboard = layoutSet.getKeyboard(elementId);
+ final Key enterKey = keyboard.getKey(Constants.CODE_ENTER);
+ assertNotNull(tag + " enter key on " + keyboard.mId, enterKey);
+ assertEquals(tag + " enter label " + enterKey, label, enterKey.getLabel());
+ assertEquals(tag + " enter icon " + enterKey, iconId, enterKey.getIconId());
+ }
+
+ protected void doTestActionKeyLabelResId(final String tag, final InputMethodSubtype subtype,
+ final int actionId, final int labelResId) {
+ final Locale labelLocale = subtype.getLocale().equals(SubtypeLocaleUtils.NO_LANGUAGE)
+ ? null : SubtypeLocaleUtils.getSubtypeLocale(subtype);
+ doTestActionKeyLabelResIdInLocale(tag, subtype, actionId, labelLocale, labelResId);
+ }
+
+ protected void doTestActionKeyLabelResIdInLocale(final String tag,
+ final InputMethodSubtype subtype, final int actionId, final Locale labelLocale,
+ final int labelResId) {
+ final EditorInfo editorInfo = new EditorInfo();
+ editorInfo.imeOptions = actionId;
+ final RunInLocale<String> job = new RunInLocale<String>() {
+ @Override
+ protected String job(final Resources res) {
+ return res.getString(labelResId);
+ }
+ };
+ final String label = job.runInLocale(getContext().getResources(), labelLocale);
+ doTestActionKeyLabel(tag, subtype, editorInfo, label);
+ }
+
+ protected void doTestActionKeyLabel(final String tag, final InputMethodSubtype subtype,
+ final EditorInfo editorInfo, final CharSequence label) {
+ // Test text layouts.
+ editorInfo.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+ final KeyboardLayoutSet layoutSet = createKeyboardLayoutSet(subtype, editorInfo);
+ doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_ALPHABET,
+ label, KeyboardIconsSet.ICON_UNDEFINED);
+ doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_SYMBOLS,
+ label, KeyboardIconsSet.ICON_UNDEFINED);
+ doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_SYMBOLS_SHIFTED,
+ label, KeyboardIconsSet.ICON_UNDEFINED);
+ // Test phone number layouts.
+ doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_PHONE,
+ label, KeyboardIconsSet.ICON_UNDEFINED);
+ doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_PHONE_SYMBOLS,
+ label, KeyboardIconsSet.ICON_UNDEFINED);
+ // Test normal number layout.
+ doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_NUMBER,
+ label, KeyboardIconsSet.ICON_UNDEFINED);
+ // Test number password layouts.
+ editorInfo.inputType =
+ InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD;
+ final KeyboardLayoutSet passwordSet = createKeyboardLayoutSet(subtype, editorInfo);
+ doTestActionKey(tag, passwordSet, KeyboardId.ELEMENT_NUMBER,
+ label, KeyboardIconsSet.ICON_UNDEFINED);
+ }
+
+ protected void doTestActionKeyIcon(final String tag, final InputMethodSubtype subtype,
+ final int actionId, final String iconName) {
+ final int iconId = KeyboardIconsSet.getIconId(iconName);
+ final EditorInfo editorInfo = new EditorInfo();
+ editorInfo.imeOptions = actionId;
+ // Test text layouts.
+ editorInfo.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+ final KeyboardLayoutSet layoutSet = createKeyboardLayoutSet(subtype, editorInfo);
+ doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_ALPHABET, null /* label */, iconId);
+ doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_SYMBOLS, null /* label */, iconId);
+ doTestActionKey(
+ tag, layoutSet, KeyboardId.ELEMENT_SYMBOLS_SHIFTED, null /* label */, iconId);
+ // Test phone number layouts.
+ doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_PHONE, null /* label */, iconId);
+ doTestActionKey(
+ tag, layoutSet, KeyboardId.ELEMENT_PHONE_SYMBOLS, null /* label */, iconId);
+ // Test normal number layout.
+ doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_NUMBER, null /* label */, iconId);
+ // Test number password layout.
+ editorInfo.inputType =
+ InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD;
+ final KeyboardLayoutSet passwordSet = createKeyboardLayoutSet(subtype, editorInfo);
+ doTestActionKey(tag, passwordSet, KeyboardId.ELEMENT_NUMBER, null /* label */, iconId);
+ }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelKlpTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelKlpTests.java
index 96f925554..322a344ff 100644
--- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelKlpTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelKlpTests.java
@@ -18,174 +18,125 @@ package com.android.inputmethod.keyboard;
import android.content.res.Resources;
import android.test.suitebuilder.annotation.MediumTest;
-import android.text.InputType;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
-import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodManager;
import com.android.inputmethod.latin.utils.RunInLocale;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
+import java.util.Locale;
+
@MediumTest
-public class KeyboardLayoutSetActionLabelKlpTests extends KeyboardLayoutSetTestsBase {
+public class KeyboardLayoutSetActionLabelKlpTests extends KeyboardLayoutSetActionLabelBase {
@Override
protected int getKeyboardThemeForTests() {
return KeyboardTheme.THEME_ID_KLP;
}
- private static void doTestActionKey(final String tag, final KeyboardLayoutSet layoutSet,
- final int elementId, final CharSequence label, final int iconId) {
- final Keyboard keyboard = layoutSet.getKeyboard(elementId);
- final Key enterKey = keyboard.getKey(Constants.CODE_ENTER);
- assertNotNull(tag + " enter key on " + keyboard.mId, enterKey);
- assertEquals(tag + " enter label " + enterKey, label, enterKey.getLabel());
- assertEquals(tag + " enter icon " + enterKey, iconId, enterKey.getIconId());
- }
-
- protected void doTestActionLabel(final String tag, final InputMethodSubtype subtype,
- final int actionId, final int labelResId) {
- final EditorInfo editorInfo = new EditorInfo();
- editorInfo.imeOptions = actionId;
- final RunInLocale<String> job = new RunInLocale<String>() {
- @Override
- protected String job(final Resources res) {
- return res.getString(labelResId);
- }
- };
- final Resources res = getContext().getResources();
- final String label;
- if (subtype.getLocale().equals(SubtypeLocaleUtils.NO_LANGUAGE)) {
- // Using system locale.
- label = res.getString(labelResId);
- } else {
- label = job.runInLocale(res, SubtypeLocaleUtils.getSubtypeLocale(subtype));
- }
- doTestActionLabel(tag, subtype, editorInfo, label);
- }
-
- protected void doTestActionLabel(final String tag, final InputMethodSubtype subtype,
- final EditorInfo editorInfo, final CharSequence label) {
- // Test text layouts.
- editorInfo.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
- final KeyboardLayoutSet layoutSet = createKeyboardLayoutSet(subtype, editorInfo);
- doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_ALPHABET,
- label, KeyboardIconsSet.ICON_UNDEFINED);
- doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_SYMBOLS,
- label, KeyboardIconsSet.ICON_UNDEFINED);
- doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_SYMBOLS_SHIFTED,
- label, KeyboardIconsSet.ICON_UNDEFINED);
- // Test phone number layouts.
- doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_PHONE,
- label, KeyboardIconsSet.ICON_UNDEFINED);
- doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_PHONE_SYMBOLS,
- label, KeyboardIconsSet.ICON_UNDEFINED);
- // Test normal number layout.
- doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_NUMBER,
- label, KeyboardIconsSet.ICON_UNDEFINED);
- // Test number password layouts.
- editorInfo.inputType =
- InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD;
- final KeyboardLayoutSet passwordSet = createKeyboardLayoutSet(subtype, editorInfo);
- doTestActionKey(tag, passwordSet, KeyboardId.ELEMENT_NUMBER,
- label, KeyboardIconsSet.ICON_UNDEFINED);
- }
-
- protected void doTestActionKeyIcon(final String tag, final InputMethodSubtype subtype,
- final int actionId, final String iconName) {
- final int iconId = KeyboardIconsSet.getIconId(iconName);
- final EditorInfo editorInfo = new EditorInfo();
- editorInfo.imeOptions = actionId;
- // Test text layouts.
- editorInfo.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
- final KeyboardLayoutSet layoutSet = createKeyboardLayoutSet(subtype, editorInfo);
- doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_ALPHABET, null /* label */, iconId);
- doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_SYMBOLS, null /* label */, iconId);
- doTestActionKey(
- tag, layoutSet, KeyboardId.ELEMENT_SYMBOLS_SHIFTED, null /* label */, iconId);
- // Test phone number layouts.
- doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_PHONE, null /* label */, iconId);
- doTestActionKey(
- tag, layoutSet, KeyboardId.ELEMENT_PHONE_SYMBOLS, null /* label */, iconId);
- // Test normal number layout.
- doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_NUMBER, null /* label */, iconId);
- // Test number password layout.
- editorInfo.inputType =
- InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD;
- final KeyboardLayoutSet passwordSet = createKeyboardLayoutSet(subtype, editorInfo);
- doTestActionKey(tag, passwordSet, KeyboardId.ELEMENT_NUMBER, null /* label */, iconId);
- }
-
- public void testActionUnspecified() {
- for (final InputMethodSubtype subtype : getAllSubtypesList()) {
- final String tag = "unspecifiled "
- + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype);
- doTestActionKeyIcon(tag, subtype, EditorInfo.IME_ACTION_UNSPECIFIED,
- KeyboardIconsSet.NAME_ENTER_KEY);
- }
- }
-
- public void testActionNone() {
- for (final InputMethodSubtype subtype : getAllSubtypesList()) {
- final String tag = "none " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype);
- doTestActionKeyIcon(tag, subtype, EditorInfo.IME_ACTION_NONE,
- KeyboardIconsSet.NAME_ENTER_KEY);
- }
- }
-
+ @Override
public void testActionGo() {
for (final InputMethodSubtype subtype : getAllSubtypesList()) {
final String tag = "go " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype);
- doTestActionLabel(tag, subtype, EditorInfo.IME_ACTION_GO, R.string.label_go_key);
- }
- }
-
- public void testActionSearch() {
- for (final InputMethodSubtype subtype : getAllSubtypesList()) {
- final String tag = "search " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype);
- doTestActionKeyIcon(tag, subtype, EditorInfo.IME_ACTION_SEARCH,
- KeyboardIconsSet.NAME_SEARCH_KEY);
+ doTestActionKeyLabelResId(tag, subtype, EditorInfo.IME_ACTION_GO,
+ R.string.label_go_key);
}
}
+ @Override
public void testActionSend() {
for (final InputMethodSubtype subtype : getAllSubtypesList()) {
final String tag = "send " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype);
- doTestActionLabel(tag, subtype, EditorInfo.IME_ACTION_SEND, R.string.label_send_key);
+ doTestActionKeyLabelResId(tag, subtype, EditorInfo.IME_ACTION_SEND,
+ R.string.label_send_key);
}
}
+ @Override
public void testActionNext() {
for (final InputMethodSubtype subtype : getAllSubtypesList()) {
final String tag = "next " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype);
- doTestActionLabel(tag, subtype, EditorInfo.IME_ACTION_NEXT, R.string.label_next_key);
+ doTestActionKeyLabelResId(tag, subtype, EditorInfo.IME_ACTION_NEXT,
+ R.string.label_next_key);
}
}
+ @Override
public void testActionDone() {
for (final InputMethodSubtype subtype : getAllSubtypesList()) {
final String tag = "done " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype);
- doTestActionLabel(tag, subtype, EditorInfo.IME_ACTION_DONE, R.string.label_done_key);
+ doTestActionKeyLabelResId(tag, subtype, EditorInfo.IME_ACTION_DONE,
+ R.string.label_done_key);
}
}
+ @Override
public void testActionPrevious() {
for (final InputMethodSubtype subtype : getAllSubtypesList()) {
final String tag = "previous " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype);
- doTestActionLabel(
- tag, subtype, EditorInfo.IME_ACTION_PREVIOUS, R.string.label_previous_key);
+ doTestActionKeyLabelResId(tag, subtype, EditorInfo.IME_ACTION_PREVIOUS,
+ R.string.label_previous_key);
}
}
- public void testActionCustom() {
- for (final InputMethodSubtype subtype : getAllSubtypesList()) {
- final String tag = "custom " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype);
- final CharSequence customLabel = "customLabel";
- final EditorInfo editorInfo = new EditorInfo();
- editorInfo.imeOptions = EditorInfo.IME_ACTION_UNSPECIFIED;
- editorInfo.actionLabel = customLabel;
- doTestActionLabel(tag, subtype, editorInfo, customLabel);
+ // Working variable to simulate system locale changing.
+ private Locale mSystemLocale = Locale.getDefault();
+
+ private void doTestActionLabelInLocale(final InputMethodSubtype subtype,
+ final Locale labelLocale, final Locale systemLocale) {
+ // Simulate system locale changing, see {@link SystemBroadcastReceiver}.
+ if (!systemLocale.equals(mSystemLocale)) {
+ KeyboardLayoutSet.onSystemLocaleChanged();
+ mSystemLocale = systemLocale;
}
+ final String tag = "label=" + labelLocale + " system=" + systemLocale
+ + " " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype);
+ final RunInLocale<Void> job = new RunInLocale<Void>() {
+ @Override
+ public Void job(final Resources res) {
+ doTestActionKeyIcon(tag + " unspecified", subtype,
+ EditorInfo.IME_ACTION_UNSPECIFIED, KeyboardIconsSet.NAME_ENTER_KEY);
+ doTestActionKeyIcon(tag + " none", subtype,
+ EditorInfo.IME_ACTION_NONE, KeyboardIconsSet.NAME_ENTER_KEY);
+ doTestActionKeyLabelResIdInLocale(tag + " go", subtype,
+ EditorInfo.IME_ACTION_GO, labelLocale, R.string.label_go_key);
+ doTestActionKeyIcon(tag + " search", subtype,
+ EditorInfo.IME_ACTION_SEARCH, KeyboardIconsSet.NAME_SEARCH_KEY);
+ doTestActionKeyLabelResIdInLocale(tag + " send", subtype,
+ EditorInfo.IME_ACTION_SEND, labelLocale, R.string.label_send_key);
+ doTestActionKeyLabelResIdInLocale(tag + " next", subtype,
+ EditorInfo.IME_ACTION_NEXT, labelLocale, R.string.label_next_key);
+ doTestActionKeyLabelResIdInLocale(tag + " done", subtype,
+ EditorInfo.IME_ACTION_DONE, labelLocale, R.string.label_done_key);
+ doTestActionKeyLabelResIdInLocale(tag + " previous", subtype,
+ EditorInfo.IME_ACTION_PREVIOUS, labelLocale, R.string.label_previous_key);
+ return null;
+ }
+ };
+ job.runInLocale(getContext().getResources(), systemLocale);
+ }
+
+ public void testActionLabelInOtherLocale() {
+ final RichInputMethodManager richImm = RichInputMethodManager.getInstance();
+ final InputMethodSubtype italian = richImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+ Locale.ITALIAN.toString(), SubtypeLocaleUtils.QWERTY);
+ // An action label should be displayed in subtype's locale regardless of the system locale.
+ doTestActionLabelInLocale(italian, Locale.ITALIAN, Locale.US);
+ doTestActionLabelInLocale(italian, Locale.ITALIAN, Locale.FRENCH);
+ doTestActionLabelInLocale(italian, Locale.ITALIAN, Locale.ITALIAN);
+ doTestActionLabelInLocale(italian, Locale.ITALIAN, Locale.JAPANESE);
+ }
+
+ public void testNoLanguageSubtypeActionLabel() {
+ final RichInputMethodManager richImm = RichInputMethodManager.getInstance();
+ final InputMethodSubtype noLanguage = richImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+ SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.QWERTY);
+ // An action label of no language keyboard should be displayed in the system locale.
+ doTestActionLabelInLocale(noLanguage, Locale.US, Locale.US);
+ doTestActionLabelInLocale(noLanguage, Locale.FRENCH, Locale.FRENCH);
+ doTestActionLabelInLocale(noLanguage, Locale.ITALIAN, Locale.ITALIAN);
+ doTestActionLabelInLocale(noLanguage, Locale.JAPANESE, Locale.JAPANESE);
}
}
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelLxxTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelLxxTests.java
index 7747ac5f9..028b3e400 100644
--- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelLxxTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelLxxTests.java
@@ -24,20 +24,10 @@ import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
@MediumTest
-public class KeyboardLayoutSetActionLabelLxxTests extends KeyboardLayoutSetActionLabelKlpTests {
+public class KeyboardLayoutSetActionLabelLxxTests extends KeyboardLayoutSetActionLabelBase {
@Override
protected int getKeyboardThemeForTests() {
- return KeyboardTheme.THEME_ID_LXX_DARK;
- }
-
- @Override
- public void testActionUnspecified() {
- super.testActionUnspecified();
- }
-
- @Override
- public void testActionNone() {
- super.testActionNone();
+ return KeyboardTheme.THEME_ID_LXX_LIGHT;
}
@Override
@@ -50,11 +40,6 @@ public class KeyboardLayoutSetActionLabelLxxTests extends KeyboardLayoutSetActio
}
@Override
- public void testActionSearch() {
- super.testActionSearch();
- }
-
- @Override
public void testActionSend() {
for (final InputMethodSubtype subtype : getAllSubtypesList()) {
final String tag = "send " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype);
@@ -89,9 +74,4 @@ public class KeyboardLayoutSetActionLabelLxxTests extends KeyboardLayoutSetActio
KeyboardIconsSet.NAME_PREVIOUS_KEY);
}
}
-
- @Override
- public void testActionCustom() {
- super.testActionCustom();
- }
}
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysBase.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysBase.java
new file mode 100644
index 000000000..8a55455d0
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysBase.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard;
+
+import android.text.InputType;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
+import com.android.inputmethod.keyboard.internal.MoreKeySpec;
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodManager;
+import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
+
+import java.util.Arrays;
+import java.util.Locale;
+
+abstract class KeyboardLayoutSetNavigateMoreKeysBase extends KeyboardLayoutSetTestsBase {
+ private ExpectedMoreKey mExpectedNavigateNextMoreKey;
+ private ExpectedMoreKey mExpectedNavigatePreviousMoreKey;
+ private ExpectedMoreKey mExpectedEmojiMoreKey;
+
+ protected ExpectedMoreKey getExpectedNavigateNextMoreKey() {
+ return new ExpectedMoreKey(R.string.label_next_key);
+ }
+
+ protected ExpectedMoreKey getExpectedNavigatePreviousMoreKey() {
+ return new ExpectedMoreKey(R.string.label_previous_key);
+ }
+
+ protected ExpectedMoreKey getExpectedEmojiMoreKey() {
+ return new ExpectedMoreKey(KeyboardIconsSet.NAME_EMOJI_ACTION_KEY);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mExpectedNavigateNextMoreKey = getExpectedNavigateNextMoreKey();
+ mExpectedNavigatePreviousMoreKey = getExpectedNavigatePreviousMoreKey();
+ mExpectedEmojiMoreKey = getExpectedEmojiMoreKey();
+ }
+
+ /**
+ * This class represents an expected more key.
+ */
+ protected static class ExpectedMoreKey {
+ public static final int NO_LABEL = 0;
+ public static final ExpectedMoreKey[] EMPTY_MORE_KEYS = new ExpectedMoreKey[0];
+
+ public final int mLabelResId;
+ public final int mIconId;
+
+ public ExpectedMoreKey(final String iconName) {
+ mLabelResId = NO_LABEL;
+ mIconId = KeyboardIconsSet.getIconId(iconName);
+ }
+
+ public ExpectedMoreKey(final int labelResId) {
+ mLabelResId = labelResId;
+ mIconId = KeyboardIconsSet.ICON_UNDEFINED;
+ }
+ }
+
+ private void doTestMoreKeysOf(final int code, final InputMethodSubtype subtype,
+ final int elementId, final int inputType, final int imeOptions,
+ final ExpectedMoreKey ... expectedMoreKeys) {
+ final EditorInfo editorInfo = new EditorInfo();
+ editorInfo.inputType = inputType;
+ editorInfo.imeOptions = imeOptions;
+ final KeyboardLayoutSet layoutSet = createKeyboardLayoutSet(subtype, editorInfo);
+ final Keyboard keyboard = layoutSet.getKeyboard(elementId);
+
+ final Key actualKey = keyboard.getKey(code);
+ final MoreKeySpec[] actualMoreKeys = actualKey.getMoreKeys();
+ final String tag = actualKey.toString() + " moreKeys=" + Arrays.toString(actualMoreKeys);
+ if (expectedMoreKeys.length == 0) {
+ assertEquals(tag, null, actualMoreKeys);
+ return;
+ }
+ if (expectedMoreKeys.length == 1) {
+ assertEquals(tag + " fixedOrder", false, actualKey.isMoreKeysFixedOrder());
+ assertEquals(tag + " fixedColumn", false, actualKey.isMoreKeysFixedColumn());
+ } else {
+ assertEquals(tag + " fixedOrder", true, actualKey.isMoreKeysFixedOrder());
+ assertEquals(tag + " fixedColumn", true, actualKey.isMoreKeysFixedColumn());
+ // TODO: Can't handle multiple rows of more keys.
+ assertEquals(tag + " column",
+ expectedMoreKeys.length, actualKey.getMoreKeysColumnNumber());
+ }
+ assertNotNull(tag + " moreKeys", actualMoreKeys);
+ assertEquals(tag, expectedMoreKeys.length, actualMoreKeys.length);
+ for (int index = 0; index < actualMoreKeys.length; index++) {
+ final int expectedLabelResId = expectedMoreKeys[index].mLabelResId;
+ if (expectedLabelResId == ExpectedMoreKey.NO_LABEL) {
+ assertEquals(tag + " label " + index, null, actualMoreKeys[index].mLabel);
+ } else {
+ final CharSequence expectedLabel = getContext().getText(expectedLabelResId);
+ assertEquals(tag + " label " + index, expectedLabel, actualMoreKeys[index].mLabel);
+ }
+ final int expectedIconId = expectedMoreKeys[index].mIconId;
+ assertEquals(tag + " icon " + index, expectedIconId, actualMoreKeys[index].mIconId);
+ }
+ }
+
+ private void doTestNavigationMoreKeysOf(final int code, final InputMethodSubtype subtype,
+ final int elementId, final int inputType) {
+ // No navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_NULL,
+ ExpectedMoreKey.EMPTY_MORE_KEYS);
+ // With next navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+ mExpectedNavigateNextMoreKey);
+ // With previous navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ mExpectedNavigatePreviousMoreKey);
+ // With next and previous naviagte flags.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ mExpectedNavigatePreviousMoreKey, mExpectedNavigateNextMoreKey);
+ // Action next.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_NEXT,
+ ExpectedMoreKey.EMPTY_MORE_KEYS);
+ // Action next with next navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+ ExpectedMoreKey.EMPTY_MORE_KEYS);
+ // Action next with previous navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ mExpectedNavigatePreviousMoreKey);
+ // Action next with next and previous navigate flags.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT
+ | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ mExpectedNavigatePreviousMoreKey);
+ // Action previous.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_PREVIOUS,
+ ExpectedMoreKey.EMPTY_MORE_KEYS);
+ // Action previous with next navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+ mExpectedNavigateNextMoreKey);
+ // Action previous with previous navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ ExpectedMoreKey.EMPTY_MORE_KEYS);
+ // Action previous with next and previous navigate flags.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT
+ | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ mExpectedNavigateNextMoreKey);
+ }
+
+ private void doTestNavigationWithEmojiMoreKeysOf(final int code,
+ final InputMethodSubtype subtype, final int elementId, final int inputType) {
+ // No navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_NULL,
+ mExpectedEmojiMoreKey);
+ // With next navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+ mExpectedEmojiMoreKey, mExpectedNavigateNextMoreKey);
+ // With previous navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ mExpectedEmojiMoreKey, mExpectedNavigatePreviousMoreKey);
+ // With next and previous naviagte flags.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ mExpectedEmojiMoreKey, mExpectedNavigatePreviousMoreKey,
+ mExpectedNavigateNextMoreKey);
+ // Action next.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_NEXT,
+ mExpectedEmojiMoreKey);
+ // Action next with next navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+ mExpectedEmojiMoreKey);
+ // Action next with previous navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ mExpectedEmojiMoreKey, mExpectedNavigatePreviousMoreKey);
+ // Action next with next and previous navigate flags.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT
+ | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ mExpectedEmojiMoreKey, mExpectedNavigatePreviousMoreKey);
+ // Action previous.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_PREVIOUS,
+ mExpectedEmojiMoreKey);
+ // Action previous with next navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+ mExpectedEmojiMoreKey, mExpectedNavigateNextMoreKey);
+ // Action previous with previous navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ mExpectedEmojiMoreKey);
+ // Action previous with next and previous navigate flags.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT
+ | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ mExpectedEmojiMoreKey, mExpectedNavigateNextMoreKey);
+ }
+
+ private void doTestNoNavigationMoreKeysOf(final int code, final InputMethodSubtype subtype,
+ final int elementId, final int inputType) {
+ // No navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_NULL,
+ ExpectedMoreKey.EMPTY_MORE_KEYS);
+ // With next navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+ ExpectedMoreKey.EMPTY_MORE_KEYS);
+ // With previous navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ ExpectedMoreKey.EMPTY_MORE_KEYS);
+ // With next and previous naviagte flags.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ ExpectedMoreKey.EMPTY_MORE_KEYS);
+ // Action next.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_NEXT,
+ ExpectedMoreKey.EMPTY_MORE_KEYS);
+ // Action next with next navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+ ExpectedMoreKey.EMPTY_MORE_KEYS);
+ // Action next with previous navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ ExpectedMoreKey.EMPTY_MORE_KEYS);
+ // Action next with next and previous navigate flags.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NAVIGATE_NEXT
+ | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ ExpectedMoreKey.EMPTY_MORE_KEYS);
+ // Action previous.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_PREVIOUS,
+ ExpectedMoreKey.EMPTY_MORE_KEYS);
+ // Action previous with next navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT,
+ ExpectedMoreKey.EMPTY_MORE_KEYS);
+ // Action previous with previous navigate flag.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ ExpectedMoreKey.EMPTY_MORE_KEYS);
+ // Action previous with next and previous navigate flags.
+ doTestMoreKeysOf(code, subtype, elementId, inputType,
+ EditorInfo.IME_ACTION_PREVIOUS | EditorInfo.IME_FLAG_NAVIGATE_NEXT
+ | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+ ExpectedMoreKey.EMPTY_MORE_KEYS);
+ }
+
+ public void testMoreKeysOfEnterKey() {
+ final RichInputMethodManager richImm = RichInputMethodManager.getInstance();
+ final InputMethodSubtype subtype = richImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+ Locale.US.toString(), SubtypeLocaleUtils.QWERTY);
+
+ // Password field.
+ doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_ALPHABET,
+ InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
+ // Email field.
+ doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_ALPHABET,
+ InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
+ // Url field.
+ doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_ALPHABET,
+ InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
+ // Phone number field.
+ doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_PHONE,
+ InputType.TYPE_CLASS_PHONE);
+ // Number field.
+ doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_NUMBER,
+ InputType.TYPE_CLASS_NUMBER);
+ // Date-time field.
+ doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_NUMBER,
+ InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_NORMAL);
+ // Date field.
+ doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_NUMBER,
+ InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_DATE);
+ // Time field.
+ doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype, KeyboardId.ELEMENT_NUMBER,
+ InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_TIME);
+ // Text field.
+ if (isPhone()) {
+ // The enter key has an Emoji key as one of more keys.
+ doTestNavigationWithEmojiMoreKeysOf(Constants.CODE_ENTER, subtype,
+ KeyboardId.ELEMENT_ALPHABET,
+ InputType.TYPE_CLASS_TEXT);
+ } else {
+ // Tablet has a dedicated Emoji key, so the Enter key has no Emoji more key.
+ doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype,
+ KeyboardId.ELEMENT_ALPHABET,
+ InputType.TYPE_CLASS_TEXT);
+ }
+ // Short message field.
+ if (isPhone()) {
+ // Enter key is switched to Emoji key on a short message field.
+ // Emoji key has no navigation more keys.
+ doTestNoNavigationMoreKeysOf(Constants.CODE_EMOJI, subtype,
+ KeyboardId.ELEMENT_ALPHABET,
+ InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE);
+ } else {
+ doTestNavigationMoreKeysOf(Constants.CODE_ENTER, subtype,
+ KeyboardId.ELEMENT_ALPHABET,
+ InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE);
+ }
+ }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysKlpTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysKlpTests.java
new file mode 100644
index 000000000..286c69d33
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysKlpTests.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+@SmallTest
+public class KeyboardLayoutSetNavigateMoreKeysKlpTests
+ extends KeyboardLayoutSetNavigateMoreKeysBase {
+ @Override
+ protected int getKeyboardThemeForTests() {
+ return KeyboardTheme.THEME_ID_KLP;
+ }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysLxxTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysLxxTests.java
new file mode 100644
index 000000000..d2bb41e5d
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetNavigateMoreKeysLxxTests.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
+
+@SmallTest
+public class KeyboardLayoutSetNavigateMoreKeysLxxTests
+ extends KeyboardLayoutSetNavigateMoreKeysBase {
+ @Override
+ protected int getKeyboardThemeForTests() {
+ return KeyboardTheme.THEME_ID_LXX_LIGHT;
+ }
+
+ @Override
+ protected ExpectedMoreKey getExpectedNavigateNextMoreKey() {
+ return new ExpectedMoreKey(KeyboardIconsSet.NAME_NEXT_KEY);
+ }
+
+ @Override
+ protected ExpectedMoreKey getExpectedNavigatePreviousMoreKey() {
+ return new ExpectedMoreKey(KeyboardIconsSet.NAME_PREVIOUS_KEY);
+ }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetSubtypesCountTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetSubtypesCountTests.java
index eb67bc134..6b0652c59 100644
--- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetSubtypesCountTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetSubtypesCountTests.java
@@ -25,7 +25,7 @@ import java.util.ArrayList;
@SmallTest
public class KeyboardLayoutSetSubtypesCountTests extends KeyboardLayoutSetTestsBase {
- private static final int NUMBER_OF_SUBTYPES = 77;
+ private static final int NUMBER_OF_SUBTYPES = 76;
private static final int NUMBER_OF_ASCII_CAPABLE_SUBTYPES = 45;
private static final int NUMBER_OF_PREDEFINED_ADDITIONAL_SUBTYPES = 2;
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
index cf884bfea..a002bbe48 100644
--- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
@@ -42,7 +42,6 @@ public abstract class KeyboardLayoutSetTestsBase extends AndroidTestCase {
private final ArrayList<InputMethodSubtype> mAsciiCapableSubtypesList = new ArrayList<>();
private final ArrayList<InputMethodSubtype> mAdditionalSubtypesList = new ArrayList<>();
- private Context mThemeContext;
private int mScreenMetrics;
protected abstract int getKeyboardThemeForTests();
@@ -50,12 +49,14 @@ public abstract class KeyboardLayoutSetTestsBase extends AndroidTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
- mScreenMetrics = mContext.getResources().getInteger(R.integer.config_screen_metrics);
-
final KeyboardTheme keyboardTheme = KeyboardTheme.searchKeyboardThemeById(
getKeyboardThemeForTests());
- mThemeContext = new ContextThemeWrapper(mContext, keyboardTheme.mStyleId);
- RichInputMethodManager.init(mThemeContext);
+ setContext(new ContextThemeWrapper(getContext(), keyboardTheme.mStyleId));
+ KeyboardLayoutSet.onKeyboardThemeChanged();
+
+ final Context context = getContext();
+ mScreenMetrics = context.getResources().getInteger(R.integer.config_screen_metrics);
+ RichInputMethodManager.init(context);
final RichInputMethodManager richImm = RichInputMethodManager.getInstance();
final InputMethodInfo imi = richImm.getInputMethodInfoOfThisIme();
@@ -112,16 +113,16 @@ public abstract class KeyboardLayoutSetTestsBase extends AndroidTestCase {
"Unknown subtype: locale=" + locale + " keyboardLayout=" + keyboardLayout);
}
- protected final KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
+ protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
final EditorInfo editorInfo) {
return createKeyboardLayoutSet(subtype, editorInfo, false /* voiceInputKeyEnabled */,
false /* languageSwitchKeyEnabled */);
}
- protected final KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
+ protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
final EditorInfo editorInfo, final boolean voiceInputKeyEnabled,
final boolean languageSwitchKeyEnabled) {
- final Context context = mThemeContext;
+ final Context context = getContext();
final Resources res = context.getResources();
final int keyboardWidth = ResourceUtils.getDefaultKeyboardWidth(res);
final int keyboardHeight = ResourceUtils.getDefaultKeyboardHeight(res);
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java
index 0c7e4000e..c20954f81 100644
--- a/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.keyboard;
+import static com.android.inputmethod.compat.BuildCompatUtils.VERSION_CODES_LXX;
import static com.android.inputmethod.keyboard.KeyboardTheme.THEME_ID_ICS;
import static com.android.inputmethod.keyboard.KeyboardTheme.THEME_ID_KLP;
import static com.android.inputmethod.keyboard.KeyboardTheme.THEME_ID_LXX_DARK;
@@ -31,9 +32,6 @@ import android.test.suitebuilder.annotation.SmallTest;
public class KeyboardThemeTests extends AndroidTestCase {
private SharedPreferences mPrefs;
- // TODO: Remove this constant once the *next* version becomes available.
- private static final int VERSION_CODES_LXX = VERSION_CODES.CUR_DEVELOPMENT;
-
private static final int THEME_ID_NULL = -1;
private static final int THEME_ID_UNKNOWN = -2;
private static final int THEME_ID_ILLEGAL = -3;
diff --git a/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderAutoOrderTests.java b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderAutoOrderTests.java
new file mode 100644
index 000000000..ebefe2d0e
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderAutoOrderTests.java
@@ -0,0 +1,2464 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import com.android.inputmethod.keyboard.MoreKeysKeyboard.MoreKeysKeyboardParams;
+
+@MediumTest
+public class MoreKeysKeyboardBuilderAutoOrderTests extends AndroidTestCase {
+ private static final int WIDTH = 10;
+ private static final int HEIGHT = 10;
+
+ private static final int KEYBOARD_WIDTH = WIDTH * 10;
+ private static final int XPOS_L0 = WIDTH * 0 + WIDTH / 2;
+ private static final int XPOS_L1 = WIDTH * 1 + WIDTH / 2;
+ private static final int XPOS_L2 = WIDTH * 2 + WIDTH / 2;
+ private static final int XPOS_L3 = WIDTH * 3 + WIDTH / 2;
+ private static final int XPOS_M0 = WIDTH * 4 + WIDTH / 2;
+ private static final int XPOS_M1 = WIDTH * 5 + WIDTH / 2;
+ private static final int XPOS_R3 = WIDTH * 6 + WIDTH / 2;
+ private static final int XPOS_R2 = WIDTH * 7 + WIDTH / 2;
+ private static final int XPOS_R1 = WIDTH * 8 + WIDTH / 2;
+ private static final int XPOS_R0 = WIDTH * 9 + WIDTH / 2;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ private static MoreKeysKeyboardParams createParams(final int numKeys, final int columnNum,
+ final int coordXInParent) {
+ final MoreKeysKeyboardParams params = new MoreKeysKeyboardParams();
+ params.setParameters(numKeys, columnNum, WIDTH, HEIGHT, coordXInParent, KEYBOARD_WIDTH,
+ true /* isMoreKeysFixedColumn */, false /* isMoreKeysFixedOrder */,
+ 0 /* dividerWidth */);
+ return params;
+ }
+
+ public void testLayoutError() {
+ MoreKeysKeyboardParams params = null;
+ try {
+ final int maxColumns = KEYBOARD_WIDTH / WIDTH;
+ params = createParams(maxColumns + 1, maxColumns + 1, HEIGHT);
+ fail("Should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Too small keyboard to hold more keys keyboard.
+ }
+ assertNull("Too small keyboard to hold more keys keyboard", params);
+ }
+
+ // More keys keyboard layout test.
+ // "[n]" represents n-th key position in more keys keyboard.
+ // "<1>" is the default key.
+
+ // <1>
+ public void testLayout1KeyAuto5M0() {
+ MoreKeysKeyboardParams params = createParams(1, 5, XPOS_M0);
+ assertEquals("1 key auto 5 M0 columns", 1, params.mNumColumns);
+ assertEquals("1 key auto 5 M0 rows", 1, params.mNumRows);
+ assertEquals("1 key auto 5 M0 left", 0, params.mLeftKeys);
+ assertEquals("1 key auto 5 M0 right", 1, params.mRightKeys);
+ assertEquals("1 key auto 5 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("1 key auto 5 M0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("1 key auto 5 M0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |<1>
+ public void testLayout1KeyAuto5L0() {
+ MoreKeysKeyboardParams params = createParams(1, 5, XPOS_L0);
+ assertEquals("1 key auto 5 L0 columns", 1, params.mNumColumns);
+ assertEquals("1 key auto 5 L0 rows", 1, params.mNumRows);
+ assertEquals("1 key auto 5 L0 left", 0, params.mLeftKeys);
+ assertEquals("1 key auto 5 L0 right", 1, params.mRightKeys);
+ assertEquals("1 key auto 5 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("1 key auto 5 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("1 key auto 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ <1>
+ public void testLayout1KeyAuto5L1() {
+ MoreKeysKeyboardParams params = createParams(1, 5, XPOS_L1);
+ assertEquals("1 key auto 5 L1 columns", 1, params.mNumColumns);
+ assertEquals("1 key auto 5 L1 rows", 1, params.mNumRows);
+ assertEquals("1 key auto 5 L1 left", 0, params.mLeftKeys);
+ assertEquals("1 key auto 5 L1 right", 1, params.mRightKeys);
+ assertEquals("1 key auto 5 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("1 key auto 5 L1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("1 key auto 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ ___ <1>
+ public void testLayout1KeyAuto5L2() {
+ MoreKeysKeyboardParams params = createParams(1, 5, XPOS_L2);
+ assertEquals("1 key auto 5 L2 columns", 1, params.mNumColumns);
+ assertEquals("1 key auto 5 L2 rows", 1, params.mNumRows);
+ assertEquals("1 key auto 5 L2 left", 0, params.mLeftKeys);
+ assertEquals("1 key auto 5 L2 right", 1, params.mRightKeys);
+ assertEquals("1 key auto 5 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("1 key auto 5 L2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("1 key auto 5 L2 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // <1>|
+ public void testLayout1KeyAuto5R0() {
+ MoreKeysKeyboardParams params = createParams(1, 5, XPOS_R0);
+ assertEquals("1 key auto 5 R0 columns", 1, params.mNumColumns);
+ assertEquals("1 key auto 5 R0 rows", 1, params.mNumRows);
+ assertEquals("1 key auto 5 R0 left", 0, params.mLeftKeys);
+ assertEquals("1 key auto 5 R0 right", 1, params.mRightKeys);
+ assertEquals("1 key auto 5 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("1 key auto 5 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("1 key auto 5 R0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // <1> ___|
+ public void testLayout1KeyAuto5R1() {
+ MoreKeysKeyboardParams params = createParams(1, 5, XPOS_R1);
+ assertEquals("1 key auto 5 R1 columns", 1, params.mNumColumns);
+ assertEquals("1 key auto 5 R1 rows", 1, params.mNumRows);
+ assertEquals("1 key auto 5 R1 left", 0, params.mLeftKeys);
+ assertEquals("1 key auto 5 R1 right", 1, params.mRightKeys);
+ assertEquals("1 key auto 5 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("1 key auto 5 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("1 key auto 5 R1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // <1> ___ ___|
+ public void testLayout1KeyAuto5R2() {
+ MoreKeysKeyboardParams params = createParams(1, 5, XPOS_R2);
+ assertEquals("1 key auto 5 R2 columns", 1, params.mNumColumns);
+ assertEquals("1 key auto 5 R2 rows", 1, params.mNumRows);
+ assertEquals("1 key auto 5 R2 left", 0, params.mLeftKeys);
+ assertEquals("1 key auto 5 R2 right", 1, params.mRightKeys);
+ assertEquals("1 key auto 5 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("1 key auto 5 R2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("1 key auto 5 R2 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // <1> [2]
+ public void testLayout2KeyAuto5M0() {
+ MoreKeysKeyboardParams params = createParams(2, 5, XPOS_M0);
+ assertEquals("2 key auto 5 M0 columns", 2, params.mNumColumns);
+ assertEquals("2 key auto 5 M0 rows", 1, params.mNumRows);
+ assertEquals("2 key auto 5 M0 left", 0, params.mLeftKeys);
+ assertEquals("2 key auto 5 M0 right", 2, params.mRightKeys);
+ assertEquals("2 key auto 5 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("2 key auto 5 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("2 key auto 5 M0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("2 key auto 5 M0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |<1> [2]
+ public void testLayout2KeyAuto5L0() {
+ MoreKeysKeyboardParams params = createParams(2, 5, XPOS_L0);
+ assertEquals("2 key auto 5 L0 columns", 2, params.mNumColumns);
+ assertEquals("2 key auto 5 L0 rows", 1, params.mNumRows);
+ assertEquals("2 key auto 5 L0 left", 0, params.mLeftKeys);
+ assertEquals("2 key auto 5 L0 right", 2, params.mRightKeys);
+ assertEquals("2 key auto 5 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("2 key auto 5 L0 [2]", 1, params.getColumnPos(1));
+ assertEquals("2 key auto 5 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("2 key auto 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ <1> [2]
+ public void testLayout2KeyAuto5L1() {
+ MoreKeysKeyboardParams params = createParams(2, 5, XPOS_L1);
+ assertEquals("2 key auto 5 L1 columns", 2, params.mNumColumns);
+ assertEquals("2 key auto 5 L1 rows", 1, params.mNumRows);
+ assertEquals("2 key auto 5 L1 left", 0, params.mLeftKeys);
+ assertEquals("2 key auto 5 L1 right", 2, params.mRightKeys);
+ assertEquals("2 key auto 5 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("2 key auto 5 L1 [2]", 1, params.getColumnPos(1));
+ assertEquals("2 key auto 5 L1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("2 key auto 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ ___ <1> [2]
+ public void testLayout2KeyAuto5L2() {
+ MoreKeysKeyboardParams params = createParams(2, 5, XPOS_L2);
+ assertEquals("2 key auto 5 L2 columns", 2, params.mNumColumns);
+ assertEquals("2 key auto 5 L2 rows", 1, params.mNumRows);
+ assertEquals("2 key auto 5 L2 left", 0, params.mLeftKeys);
+ assertEquals("2 key auto 5 L2 right", 2, params.mRightKeys);
+ assertEquals("2 key auto 5 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("2 key auto 5 L2 [2]", 1, params.getColumnPos(1));
+ assertEquals("2 key auto 5 L2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("2 key auto 5 L2 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // [2] <1>|
+ public void testLayout2KeyAuto5R0() {
+ MoreKeysKeyboardParams params = createParams(2, 5, XPOS_R0);
+ assertEquals("2 key auto 5 R0 columns", 2, params.mNumColumns);
+ assertEquals("2 key auto 5 R0 rows", 1, params.mNumRows);
+ assertEquals("2 key auto 5 R0 left", 1, params.mLeftKeys);
+ assertEquals("2 key auto 5 R0 right", 1, params.mRightKeys);
+ assertEquals("2 key auto 5 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("2 key auto 5 R0 [2]", -1, params.getColumnPos(1));
+ assertEquals("2 key auto 5 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("2 key auto 5 R0 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [2] <1> ___|
+ public void testLayout2KeyAuto5R1() {
+ MoreKeysKeyboardParams params = createParams(2, 5, XPOS_R1);
+ assertEquals("2 key auto 5 R1 columns", 2, params.mNumColumns);
+ assertEquals("2 key auto 5 R1 rows", 1, params.mNumRows);
+ assertEquals("2 key auto 5 R1 left", 1, params.mLeftKeys);
+ assertEquals("2 key auto 5 R1 right", 1, params.mRightKeys);
+ assertEquals("2 key auto 5 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("2 key auto 5 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("2 key auto 5 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("2 key auto 5 R1 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // <1> [2] ___|
+ public void testLayout2KeyAuto5R2() {
+ MoreKeysKeyboardParams params = createParams(2, 5, XPOS_R2);
+ assertEquals("2 key auto 5 R2 columns", 2, params.mNumColumns);
+ assertEquals("2 key auto 5 R2 rows", 1, params.mNumRows);
+ assertEquals("2 key auto 5 R2 left", 0, params.mLeftKeys);
+ assertEquals("2 key auto 5 R2 right", 2, params.mRightKeys);
+ assertEquals("2 key auto 5 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("2 key auto 5 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("2 key auto 5 R2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("2 key auto 5 R2 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // [3] <1> [2]
+ public void testLayout3KeyAuto5M0() {
+ MoreKeysKeyboardParams params = createParams(3, 5, XPOS_M0);
+ assertEquals("3 key auto 5 M0 columns", 3, params.mNumColumns);
+ assertEquals("3 key auto 5 M0 rows", 1, params.mNumRows);
+ assertEquals("3 key auto 5 M0 left", 1, params.mLeftKeys);
+ assertEquals("3 key auto 5 M0 right", 2, params.mRightKeys);
+ assertEquals("3 key auto 5 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("3 key auto 5 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("3 key auto 5 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("3 key auto 5 M0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("3 key auto 5 M0 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // |<1> [2] [3]
+ public void testLayout3KeyAuto5L0() {
+ MoreKeysKeyboardParams params = createParams(3, 5, XPOS_L0);
+ assertEquals("3 key auto 5 L0 columns", 3, params.mNumColumns);
+ assertEquals("3 key auto 5 L0 rows", 1, params.mNumRows);
+ assertEquals("3 key auto 5 L0 left", 0, params.mLeftKeys);
+ assertEquals("3 key auto 5 L0 right", 3, params.mRightKeys);
+ assertEquals("3 key auto 5 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("3 key auto 5 L0 [2]", 1, params.getColumnPos(1));
+ assertEquals("3 key auto 5 L0 [3]", 2, params.getColumnPos(2));
+ assertEquals("3 key auto 5 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("3 key auto 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ <1> [2] [3]
+ public void testLayout3KeyAuto5L1() {
+ MoreKeysKeyboardParams params = createParams(3, 5, XPOS_L1);
+ assertEquals("3 key auto 5 L1 columns", 3, params.mNumColumns);
+ assertEquals("3 key auto 5 L1 rows", 1, params.mNumRows);
+ assertEquals("3 key auto 5 L1 left", 0, params.mLeftKeys);
+ assertEquals("3 key auto 5 L1 right", 3, params.mRightKeys);
+ assertEquals("3 key auto 5 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("3 key auto 5 L1 [2]", 1, params.getColumnPos(1));
+ assertEquals("3 key auto 5 L1 [3]", 2, params.getColumnPos(2));
+ assertEquals("3 key auto 5 L1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("3 key auto 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [3] <1> [2]
+ public void testLayout3KeyAuto5L2() {
+ MoreKeysKeyboardParams params = createParams(3, 5, XPOS_L2);
+ assertEquals("3 key auto 5 L2 columns", 3, params.mNumColumns);
+ assertEquals("3 key auto 5 L2 rows", 1, params.mNumRows);
+ assertEquals("3 key auto 5 L2 left", 1, params.mLeftKeys);
+ assertEquals("3 key auto 5 L2 right", 2, params.mRightKeys);
+ assertEquals("3 key auto 5 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("3 key auto 5 L2 [2]", 1, params.getColumnPos(1));
+ assertEquals("3 key auto 5 L2 [3]", -1, params.getColumnPos(2));
+ assertEquals("3 key auto 5 L2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("3 key auto 5 L2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [3] [2] <1>|
+ public void testLayout3KeyAuto5R0() {
+ MoreKeysKeyboardParams params = createParams(3, 5, XPOS_R0);
+ assertEquals("3 key auto 5 R0 columns", 3, params.mNumColumns);
+ assertEquals("3 key auto 5 R0 rows", 1, params.mNumRows);
+ assertEquals("3 key auto 5 R0 left", 2, params.mLeftKeys);
+ assertEquals("3 key auto 5 R0 right", 1, params.mRightKeys);
+ assertEquals("3 key auto 5 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("3 key auto 5 R0 [2]", -1, params.getColumnPos(1));
+ assertEquals("3 key auto 5 R0 [3]", -2, params.getColumnPos(2));
+ assertEquals("3 key auto 5 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("3 key auto 5 R0 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // [3] [2] <1> ___|
+ public void testLayout3KeyAuto5R1() {
+ MoreKeysKeyboardParams params = createParams(3, 5, XPOS_R1);
+ assertEquals("3 key auto 5 R1 columns", 3, params.mNumColumns);
+ assertEquals("3 key auto 5 R1 rows", 1, params.mNumRows);
+ assertEquals("3 key auto 5 R1 left", 2, params.mLeftKeys);
+ assertEquals("3 key auto 5 R1 right", 1, params.mRightKeys);
+ assertEquals("3 key auto 5 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("3 key auto 5 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("3 key auto 5 R1 [3]", -2, params.getColumnPos(2));
+ assertEquals("3 key auto 5 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("3 key auto 5 R1 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // [3] <1> [2] ___|
+ public void testLayout3KeyAuto5R2() {
+ MoreKeysKeyboardParams params = createParams(3, 5, XPOS_R2);
+ assertEquals("3 key auto 5 R2 columns", 3, params.mNumColumns);
+ assertEquals("3 key auto 5 R2 rows", 1, params.mNumRows);
+ assertEquals("3 key auto 5 R2 left", 1, params.mLeftKeys);
+ assertEquals("3 key auto 5 R2 right", 2, params.mRightKeys);
+ assertEquals("3 key auto 5 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("3 key auto 5 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("3 key auto 5 R2 [3]", -1, params.getColumnPos(2));
+ assertEquals("3 key auto 5 R2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("3 key auto 5 R2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [3]
+ // <1> [2]
+ public void testLayout3KeyAuto2M0() {
+ MoreKeysKeyboardParams params = createParams(3, 2, XPOS_M0);
+ assertEquals("3 key auto 2 M0 columns", 2, params.mNumColumns);
+ assertEquals("3 key auto 2 M0 rows", 2, params.mNumRows);
+ assertEquals("3 key auto 2 M0 left", 0, params.mLeftKeys);
+ assertEquals("3 key auto 2 M0 right", 2, params.mRightKeys);
+ assertEquals("3 key auto 2 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("3 key auto 2 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("3 key auto 2 M0 [3]", 0, params.getColumnPos(2));
+ assertEquals("3 key auto 2 M0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("3 key auto 2 M0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |[3]
+ // |<1> [2]
+ public void testLayout3KeyAuto2L0() {
+ MoreKeysKeyboardParams params = createParams(3, 2, XPOS_L0);
+ assertEquals("3 key auto 2 L0 columns", 2, params.mNumColumns);
+ assertEquals("3 key auto 2 L0 rows", 2, params.mNumRows);
+ assertEquals("3 key auto 2 L0 left", 0, params.mLeftKeys);
+ assertEquals("3 key auto 2 L0 right", 2, params.mRightKeys);
+ assertEquals("3 key auto 2 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("3 key auto 2 L0 [2]", 1, params.getColumnPos(1));
+ assertEquals("3 key auto 2 L0 [3]", 0, params.getColumnPos(2));
+ assertEquals("3 key auto 2 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("3 key auto 2 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [3]
+ // |___ <1> [2]
+ public void testLayout3KeyAuto2L1() {
+ MoreKeysKeyboardParams params = createParams(3, 2, XPOS_L1);
+ assertEquals("3 key auto 2 L1 columns", 2, params.mNumColumns);
+ assertEquals("3 key auto 2 L1 rows", 2, params.mNumRows);
+ assertEquals("3 key auto 2 L1 left", 0, params.mLeftKeys);
+ assertEquals("3 key auto 2 L1 right", 2, params.mRightKeys);
+ assertEquals("3 key auto 2 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("3 key auto 2 L1 [2]", 1, params.getColumnPos(1));
+ assertEquals("3 key auto 2 L1 [3]", 0, params.getColumnPos(2));
+ assertEquals("3 key auto 2 L1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("3 key auto 2 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // | [3]
+ // |___ ___ <1> [2]
+ public void testLayout3KeyAuto2L2() {
+ MoreKeysKeyboardParams params = createParams(3, 2, XPOS_L2);
+ assertEquals("3 key auto 2 L2 columns", 2, params.mNumColumns);
+ assertEquals("3 key auto 2 L2 rows", 2, params.mNumRows);
+ assertEquals("3 key auto 2 L2 left", 0, params.mLeftKeys);
+ assertEquals("3 key auto 2 L2 right", 2, params.mRightKeys);
+ assertEquals("3 key auto 2 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("3 key auto 2 L2 [2]", 1, params.getColumnPos(1));
+ assertEquals("3 key auto 2 L2 [3]", 0, params.getColumnPos(2));
+ assertEquals("3 key auto 2 L2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("3 key auto 2 L2 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // [3]|
+ // [2] <1>|
+ public void testLayout3KeyAuto2R0() {
+ MoreKeysKeyboardParams params = createParams(3, 2, XPOS_R0);
+ assertEquals("3 key auto 2 R0 columns", 2, params.mNumColumns);
+ assertEquals("3 key auto 2 R0 rows", 2, params.mNumRows);
+ assertEquals("3 key auto 2 R0 left", 1, params.mLeftKeys);
+ assertEquals("3 key auto 2 R0 right", 1, params.mRightKeys);
+ assertEquals("3 key auto 2 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("3 key auto 2 R0 [2]", -1, params.getColumnPos(1));
+ assertEquals("3 key auto 2 R0 [3]", 0, params.getColumnPos(2));
+ assertEquals("3 key auto 2 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("3 key auto 2 R0 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [3] |
+ // [2] <1> ___|
+ public void testLayout3KeyAuto2R1() {
+ MoreKeysKeyboardParams params = createParams(3, 2, XPOS_R1);
+ assertEquals("3 key auto 2 R1 columns", 2, params.mNumColumns);
+ assertEquals("3 key auto 2 R1 rows", 2, params.mNumRows);
+ assertEquals("3 key auto 2 R1 left", 1, params.mLeftKeys);
+ assertEquals("3 key auto 2 R1 right", 1, params.mRightKeys);
+ assertEquals("3 key auto 2 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("3 key auto 2 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("3 key auto 2 R1 [3]", 0, params.getColumnPos(2));
+ assertEquals("3 key auto 2 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("3 key auto 2 R1 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [3] |
+ // <1> [2] ___|
+ public void testLayout3KeyAuto2R2() {
+ MoreKeysKeyboardParams params = createParams(3, 2, XPOS_R2);
+ assertEquals("3 key auto 2 R2 columns", 2, params.mNumColumns);
+ assertEquals("3 key auto 2 R2 rows", 2, params.mNumRows);
+ assertEquals("3 key auto 2 R2 left", 0, params.mLeftKeys);
+ assertEquals("3 key auto 2 R2 right", 2, params.mRightKeys);
+ assertEquals("3 key auto 2 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("3 key auto 2 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("3 key auto 2 R2 [3]", 0, params.getColumnPos(2));
+ assertEquals("3 key auto 2 R2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("3 key auto 2 R2 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // [4]
+ // [3] <1> [2]
+ public void testLayout4KeyAuto3M0() {
+ MoreKeysKeyboardParams params = createParams(4, 3, XPOS_M0);
+ assertEquals("4 key auto 3 M0 columns", 3, params.mNumColumns);
+ assertEquals("4 key auto 3 M0 rows", 2, params.mNumRows);
+ assertEquals("4 key auto 3 M0 left", 1, params.mLeftKeys);
+ assertEquals("4 key auto 3 M0 right", 2, params.mRightKeys);
+ assertEquals("4 key auto 3 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 3 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("4 key auto 3 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("4 key auto 3 M0 [4]", 0, params.getColumnPos(3));
+ assertEquals("4 key auto 3 M0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 3 M0 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // |[4]
+ // |<1> [2] [3]
+ public void testLayout4KeyAuto3L0() {
+ MoreKeysKeyboardParams params = createParams(4, 3, XPOS_L0);
+ assertEquals("4 key auto 3 L0 columns", 3, params.mNumColumns);
+ assertEquals("4 key auto 3 L0 rows", 2, params.mNumRows);
+ assertEquals("4 key auto 3 L0 left", 0, params.mLeftKeys);
+ assertEquals("4 key auto 3 L0 right", 3, params.mRightKeys);
+ assertEquals("4 key auto 3 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 3 L0 [2]", 1, params.getColumnPos(1));
+ assertEquals("4 key auto 3 L0 [3]", 2, params.getColumnPos(2));
+ assertEquals("4 key auto 3 L0 [4]", 0, params.getColumnPos(3));
+ assertEquals("4 key auto 3 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 3 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [4]
+ // |___ <1> [2] [3]
+ public void testLayout4KeyAuto3L1() {
+ MoreKeysKeyboardParams params = createParams(4, 3, XPOS_L1);
+ assertEquals("4 key auto 3 L1 columns", 3, params.mNumColumns);
+ assertEquals("4 key auto 3 L1 rows", 2, params.mNumRows);
+ assertEquals("4 key auto 3 L1 left", 0, params.mLeftKeys);
+ assertEquals("4 key auto 3 L1 right", 3, params.mRightKeys);
+ assertEquals("4 key auto 3 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 3 L1 [2]", 1, params.getColumnPos(1));
+ assertEquals("4 key auto 3 L1 [3]", 2, params.getColumnPos(2));
+ assertEquals("4 key auto 3 L1 [4]", 0, params.getColumnPos(3));
+ assertEquals("4 key auto 3 L1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 3 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ ___ [4]
+ // |___ [3] <1> [2]
+ public void testLayout4KeyAuto3L2() {
+ MoreKeysKeyboardParams params = createParams(4, 3, XPOS_L2);
+ assertEquals("4 key auto 3 L2 columns", 3, params.mNumColumns);
+ assertEquals("4 key auto 3 L2 rows", 2, params.mNumRows);
+ assertEquals("4 key auto 3 L2 left", 1, params.mLeftKeys);
+ assertEquals("4 key auto 3 L2 right", 2, params.mRightKeys);
+ assertEquals("4 key auto 3 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 3 L2 [2]", 1, params.getColumnPos(1));
+ assertEquals("4 key auto 3 L2 [3]", -1, params.getColumnPos(2));
+ assertEquals("4 key auto 3 L2 [4]", 0, params.getColumnPos(3));
+ assertEquals("4 key auto 3 L2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 3 L2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [4]|
+ // [3] [2] <1>|
+ public void testLayout4KeyAuto3R0() {
+ MoreKeysKeyboardParams params = createParams(4, 3, XPOS_R0);
+ assertEquals("4 key auto 3 R0 columns", 3, params.mNumColumns);
+ assertEquals("4 key auto 3 R0 rows", 2, params.mNumRows);
+ assertEquals("4 key auto 3 R0 left", 2, params.mLeftKeys);
+ assertEquals("4 key auto 3 R0 right", 1, params.mRightKeys);
+ assertEquals("4 key auto 3 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 3 R0 [2]", -1, params.getColumnPos(1));
+ assertEquals("4 key auto 3 R0 [3]", -2, params.getColumnPos(2));
+ assertEquals("4 key auto 3 R0 [4]", 0, params.getColumnPos(3));
+ assertEquals("4 key auto 3 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 3 R0 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // [4] ___|
+ // [3] [2] <1> ___|
+ public void testLayout4KeyAuto3R1() {
+ MoreKeysKeyboardParams params = createParams(4, 3, XPOS_R1);
+ assertEquals("4 key auto 3 R1 columns", 3, params.mNumColumns);
+ assertEquals("4 key auto 3 R1 rows", 2, params.mNumRows);
+ assertEquals("4 key auto 3 R1 left", 2, params.mLeftKeys);
+ assertEquals("4 key auto 3 R1 right", 1, params.mRightKeys);
+ assertEquals("4 key auto 3 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 3 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("4 key auto 3 R1 [3]", -2, params.getColumnPos(2));
+ assertEquals("4 key auto 3 R1 [4]", 0, params.getColumnPos(3));
+ assertEquals("4 key auto 3 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 3 R1 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // [4] ___|
+ // [3] <1> [2] ___|
+ public void testLayout4KeyAuto3R2() {
+ MoreKeysKeyboardParams params = createParams(4, 3, XPOS_R2);
+ assertEquals("4 key auto 3 R2 columns", 3, params.mNumColumns);
+ assertEquals("4 key auto 3 R2 rows", 2, params.mNumRows);
+ assertEquals("4 key auto 3 R2 left", 1, params.mLeftKeys);
+ assertEquals("4 key auto 3 R2 right", 2, params.mRightKeys);
+ assertEquals("4 key auto 3 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 3 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("4 key auto 3 R2 [3]", -1, params.getColumnPos(2));
+ assertEquals("4 key auto 3 R2 [4]", 0, params.getColumnPos(3));
+ assertEquals("4 key auto 3 R2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 3 R2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [3] <1> [2] [4]
+ public void testLayout4KeyAuto4M0() {
+ MoreKeysKeyboardParams params = createParams(4, 4, XPOS_M0);
+ assertEquals("4 key auto 4 M0 columns", 4, params.mNumColumns);
+ assertEquals("4 key auto 4 M0 rows", 1, params.mNumRows);
+ assertEquals("4 key auto 4 M0 left", 1, params.mLeftKeys);
+ assertEquals("4 key auto 4 M0 right", 3, params.mRightKeys);
+ assertEquals("4 key auto 4 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 4 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("4 key auto 4 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("4 key auto 4 M0 [4]", 2, params.getColumnPos(3));
+ assertEquals("4 key auto 4 M0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 4 M0 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // |<1> [2] [3] [4]
+ public void testLayout4KeyAuto4L0() {
+ MoreKeysKeyboardParams params = createParams(4, 4, XPOS_L0);
+ assertEquals("4 key auto 4 L0 columns", 4, params.mNumColumns);
+ assertEquals("4 key auto 4 L0 rows", 1, params.mNumRows);
+ assertEquals("4 key auto 4 L0 left", 0, params.mLeftKeys);
+ assertEquals("4 key auto 4 L0 right", 4, params.mRightKeys);
+ assertEquals("4 key auto 4 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 4 L0 [2]", 1, params.getColumnPos(1));
+ assertEquals("4 key auto 4 L0 [3]", 2, params.getColumnPos(2));
+ assertEquals("4 key auto 4 L0 [4]", 3, params.getColumnPos(3));
+ assertEquals("4 key auto 4 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 4 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ <1> [2] [3] [4]
+ public void testLayout4KeyAuto4L1() {
+ MoreKeysKeyboardParams params = createParams(4, 4, XPOS_L1);
+ assertEquals("4 key auto 4 L1 columns", 4, params.mNumColumns);
+ assertEquals("4 key auto 4 L1 rows", 1, params.mNumRows);
+ assertEquals("4 key auto 4 L1 left", 0, params.mLeftKeys);
+ assertEquals("4 key auto 4 L1 right", 4, params.mRightKeys);
+ assertEquals("4 key auto 4 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 4 L1 [2]", 1, params.getColumnPos(1));
+ assertEquals("4 key auto 4 L1 [3]", 2, params.getColumnPos(2));
+ assertEquals("4 key auto 4 L1 [4]", 3, params.getColumnPos(3));
+ assertEquals("4 key auto 4 L1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 4 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [3] <1> [2] [4]
+ public void testLayout4KeyAuto4L2() {
+ MoreKeysKeyboardParams params = createParams(4, 4, XPOS_L2);
+ assertEquals("4 key auto 4 L2 columns", 4, params.mNumColumns);
+ assertEquals("4 key auto 4 L2 rows", 1, params.mNumRows);
+ assertEquals("4 key auto 4 L2 left", 1, params.mLeftKeys);
+ assertEquals("4 key auto 4 L2 right", 3, params.mRightKeys);
+ assertEquals("4 key auto 4 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 4 L2 [2]", 1, params.getColumnPos(1));
+ assertEquals("4 key auto 4 L2 [3]", -1, params.getColumnPos(2));
+ assertEquals("4 key auto 4 L2 [4]", 2, params.getColumnPos(3));
+ assertEquals("4 key auto 4 L2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 4 L2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [4] [3] [2] <1>|
+ public void testLayout4KeyAuto4R0() {
+ MoreKeysKeyboardParams params = createParams(4, 4, XPOS_R0);
+ assertEquals("4 key auto 4 R0 columns", 4, params.mNumColumns);
+ assertEquals("4 key auto 4 R0 rows", 1, params.mNumRows);
+ assertEquals("4 key auto 4 R0 left", 3, params.mLeftKeys);
+ assertEquals("4 key auto 4 R0 right", 1, params.mRightKeys);
+ assertEquals("4 key auto 4 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 4 R0 [2]", -1, params.getColumnPos(1));
+ assertEquals("4 key auto 4 R0 [3]", -2, params.getColumnPos(2));
+ assertEquals("4 key auto 4 R0 [4]", -3, params.getColumnPos(3));
+ assertEquals("4 key auto 4 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 4 R0 default", WIDTH * 3, params.getDefaultKeyCoordX());
+ }
+
+ // [4] [3] [2] <1> ___|
+ public void testLayout4KeyAuto4R1() {
+ MoreKeysKeyboardParams params = createParams(4, 4, XPOS_R1);
+ assertEquals("4 key auto 4 R1 columns", 4, params.mNumColumns);
+ assertEquals("4 key auto 4 R1 rows", 1, params.mNumRows);
+ assertEquals("4 key auto 4 R1 left", 3, params.mLeftKeys);
+ assertEquals("4 key auto 4 R1 right", 1, params.mRightKeys);
+ assertEquals("4 key auto 4 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 4 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("4 key auto 4 R1 [3]", -2, params.getColumnPos(2));
+ assertEquals("4 key auto 4 R1 [4]", -3, params.getColumnPos(3));
+ assertEquals("4 key auto 4 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 4 R1 default", WIDTH * 3, params.getDefaultKeyCoordX());
+ }
+
+ // [4] [3] <1> [2] ___|
+ public void testLayout4KeyAuto4R2() {
+ MoreKeysKeyboardParams params = createParams(4, 4, XPOS_R2);
+ assertEquals("4 key auto 4 R2 columns", 4, params.mNumColumns);
+ assertEquals("4 key auto 4 R2 rows", 1, params.mNumRows);
+ assertEquals("4 key auto 4 R2 left", 2, params.mLeftKeys);
+ assertEquals("4 key auto 4 R2 right", 2, params.mRightKeys);
+ assertEquals("4 key auto 4 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 4 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("4 key auto 4 R2 [3]", -1, params.getColumnPos(2));
+ assertEquals("4 key auto 4 R2 [4]", -2, params.getColumnPos(3));
+ assertEquals("4 key auto 4 R2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 4 R2 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // [3] <1> [2] [4]
+ public void testLayout4KeyAuto5M0() {
+ MoreKeysKeyboardParams params = createParams(4, 5, XPOS_M0);
+ assertEquals("4 key auto 5 M0 columns", 4, params.mNumColumns);
+ assertEquals("4 key auto 5 M0 rows", 1, params.mNumRows);
+ assertEquals("4 key auto 5 M0 left", 1, params.mLeftKeys);
+ assertEquals("4 key auto 5 M0 right", 3, params.mRightKeys);
+ assertEquals("4 key auto 5 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 5 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("4 key auto 5 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("4 key auto 5 M0 [4]", 2, params.getColumnPos(3));
+ assertEquals("4 key auto 5 M0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 5 M0 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // |<1> [2] [3] [4]
+ public void testLayout4KeyAuto5L0() {
+ MoreKeysKeyboardParams params = createParams(4, 5, XPOS_L0);
+ assertEquals("4 key auto 5 L0 columns", 4, params.mNumColumns);
+ assertEquals("4 key auto 5 L0 rows", 1, params.mNumRows);
+ assertEquals("4 key auto 5 L0 left", 0, params.mLeftKeys);
+ assertEquals("4 key auto 5 L0 right", 4, params.mRightKeys);
+ assertEquals("4 key auto 5 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 5 L0 [2]", 1, params.getColumnPos(1));
+ assertEquals("4 key auto 5 L0 [3]", 2, params.getColumnPos(2));
+ assertEquals("4 key auto 5 L0 [4]", 3, params.getColumnPos(3));
+ assertEquals("4 key auto 5 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ <1> [2] [3] [4]
+ public void testLayout4KeyAuto5L1() {
+ MoreKeysKeyboardParams params = createParams(4, 5, XPOS_L1);
+ assertEquals("4 key auto 5 L1 columns", 4, params.mNumColumns);
+ assertEquals("4 key auto 5 L1 rows", 1, params.mNumRows);
+ assertEquals("4 key auto 5 L1 left", 0, params.mLeftKeys);
+ assertEquals("4 key auto 5 L1 right", 4, params.mRightKeys);
+ assertEquals("4 key auto 5 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 5 L1 [2]", 1, params.getColumnPos(1));
+ assertEquals("4 key auto 5 L1 [3]", 2, params.getColumnPos(2));
+ assertEquals("4 key auto 5 L1 [4]", 3, params.getColumnPos(3));
+ assertEquals("4 key auto 5 L1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [3] <1> [2] [4]
+ public void testLayout4KeyAuto5L2() {
+ MoreKeysKeyboardParams params = createParams(4, 5, XPOS_L2);
+ assertEquals("4 key auto 5 L2 columns", 4, params.mNumColumns);
+ assertEquals("4 key auto 5 L2 rows", 1, params.mNumRows);
+ assertEquals("4 key auto 5 L2 left", 1, params.mLeftKeys);
+ assertEquals("4 key auto 5 L2 right", 3, params.mRightKeys);
+ assertEquals("4 key auto 5 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 5 L2 [2]", 1, params.getColumnPos(1));
+ assertEquals("4 key auto 5 L2 [3]", -1, params.getColumnPos(2));
+ assertEquals("4 key auto 5 L2 [4]", 2, params.getColumnPos(3));
+ assertEquals("4 key auto 5 L2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 5 L2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [4] [3] [2] <1>|
+ public void testLayout4KeyAuto5R0() {
+ MoreKeysKeyboardParams params = createParams(4, 5, XPOS_R0);
+ assertEquals("4 key auto 5 R0 columns", 4, params.mNumColumns);
+ assertEquals("4 key auto 5 R0 rows", 1, params.mNumRows);
+ assertEquals("4 key auto 5 R0 left", 3, params.mLeftKeys);
+ assertEquals("4 key auto 5 R0 right", 1, params.mRightKeys);
+ assertEquals("4 key auto 5 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 5 R0 [2]", -1, params.getColumnPos(1));
+ assertEquals("4 key auto 5 R0 [3]", -2, params.getColumnPos(2));
+ assertEquals("4 key auto 5 R0 [4]", -3, params.getColumnPos(3));
+ assertEquals("4 key auto 5 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 5 R0 default", WIDTH * 3, params.getDefaultKeyCoordX());
+ }
+
+ // [4] [3] [2] <1> ___|
+ public void testLayout4KeyAuto5R1() {
+ MoreKeysKeyboardParams params = createParams(4, 5, XPOS_R1);
+ assertEquals("4 key auto 5 R1 columns", 4, params.mNumColumns);
+ assertEquals("4 key auto 5 R1 rows", 1, params.mNumRows);
+ assertEquals("4 key auto 5 R1 left", 3, params.mLeftKeys);
+ assertEquals("4 key auto 5 R1 right", 1, params.mRightKeys);
+ assertEquals("4 key auto 5 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 5 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("4 key auto 5 R1 [3]", -2, params.getColumnPos(2));
+ assertEquals("4 key auto 5 R1 [4]", -3, params.getColumnPos(3));
+ assertEquals("4 key auto 5 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 5 R1 default", WIDTH * 3, params.getDefaultKeyCoordX());
+ }
+
+ // [4] [3] <1> [2] ___|
+ public void testLayout4KeyAuto5R2() {
+ MoreKeysKeyboardParams params = createParams(4, 5, XPOS_R2);
+ assertEquals("4 key auto 5 R2 columns", 4, params.mNumColumns);
+ assertEquals("4 key auto 5 R2 rows", 1, params.mNumRows);
+ assertEquals("4 key auto 5 R2 left", 2, params.mLeftKeys);
+ assertEquals("4 key auto 5 R2 right", 2, params.mRightKeys);
+ assertEquals("4 key auto 5 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("4 key auto 5 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("4 key auto 5 R2 [3]", -1, params.getColumnPos(2));
+ assertEquals("4 key auto 5 R2 [4]", -2, params.getColumnPos(3));
+ assertEquals("4 key auto 5 R2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("4 key auto 5 R2 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // [4] [5]
+ // [3] <1> [2]
+ public void testLayout5KeyAuto3M0() {
+ MoreKeysKeyboardParams params = createParams(5, 3, XPOS_M0);
+ assertEquals("5 key auto 3 M0 columns", 3, params.mNumColumns);
+ assertEquals("5 key auto 3 M0 rows", 2, params.mNumRows);
+ assertEquals("5 key auto 3 M0 left", 1, params.mLeftKeys);
+ assertEquals("5 key auto 3 M0 right", 2, params.mRightKeys);
+ assertEquals("5 key auto 3 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 3 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("5 key auto 3 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("5 key auto 3 M0 [4]", 0, params.getColumnPos(3));
+ assertEquals("5 key auto 3 M0 [5]", 1, params.getColumnPos(4));
+ assertEquals("5 key auto 3 M0 adjust", -1, params.mTopRowAdjustment);
+ assertEquals("5 key auto 3 M0 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // |[4] [5]
+ // |<1> [2] [3]
+ public void testLayout5KeyAuto3L0() {
+ MoreKeysKeyboardParams params = createParams(5, 3, XPOS_L0);
+ assertEquals("5 key auto 3 L0 columns", 3, params.mNumColumns);
+ assertEquals("5 key auto 3 L0 rows", 2, params.mNumRows);
+ assertEquals("5 key auto 3 L0 left", 0, params.mLeftKeys);
+ assertEquals("5 key auto 3 L0 right", 3, params.mRightKeys);
+ assertEquals("5 key auto 3 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 3 L0 [2]", 1, params.getColumnPos(1));
+ assertEquals("5 key auto 3 L0 [3]", 2, params.getColumnPos(2));
+ assertEquals("5 key auto 3 L0 [4]", 0, params.getColumnPos(3));
+ assertEquals("5 key auto 3 L0 [5]", 1, params.getColumnPos(4));
+ assertEquals("5 key auto 3 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 3 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [4] [5]
+ // |___ <1> [2] [3]
+ public void testLayout5KeyAuto3L1() {
+ MoreKeysKeyboardParams params = createParams(5, 3, XPOS_L1);
+ assertEquals("5 key auto 3 L1 columns", 3, params.mNumColumns);
+ assertEquals("5 key auto 3 L1 rows", 2, params.mNumRows);
+ assertEquals("5 key auto 3 L1 left", 0, params.mLeftKeys);
+ assertEquals("5 key auto 3 L1 right", 3, params.mRightKeys);
+ assertEquals("5 key auto 3 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 3 L1 [2]", 1, params.getColumnPos(1));
+ assertEquals("5 key auto 3 L1 [3]", 2, params.getColumnPos(2));
+ assertEquals("5 key auto 3 L1 [4]", 0, params.getColumnPos(3));
+ assertEquals("5 key auto 3 L1 [5]", 1, params.getColumnPos(4));
+ assertEquals("5 key auto 3 L1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 3 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [4] [5]
+ // |___ [3] <1> [2]
+ public void testLayout5KeyAuto3L2() {
+ MoreKeysKeyboardParams params = createParams(5, 3, XPOS_L2);
+ assertEquals("5 key auto 3 L2 columns", 3, params.mNumColumns);
+ assertEquals("5 key auto 3 L2 rows", 2, params.mNumRows);
+ assertEquals("5 key auto 3 L2 left", 1, params.mLeftKeys);
+ assertEquals("5 key auto 3 L2 right", 2, params.mRightKeys);
+ assertEquals("5 key auto 3 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 3 L2 [2]", 1, params.getColumnPos(1));
+ assertEquals("5 key auto 3 L2 [3]", -1, params.getColumnPos(2));
+ assertEquals("5 key auto 3 L2 [4]", 0, params.getColumnPos(3));
+ assertEquals("5 key auto 3 L2 [5]", 1, params.getColumnPos(4));
+ assertEquals("5 key auto 3 L2 adjust", -1, params.mTopRowAdjustment);
+ assertEquals("5 key auto 3 L2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [5] [4]|
+ // [3] [2] <1>|
+ public void testLayout5KeyAuto3R0() {
+ MoreKeysKeyboardParams params = createParams(5, 3, XPOS_R0);
+ assertEquals("5 key auto 3 R0 columns", 3, params.mNumColumns);
+ assertEquals("5 key auto 3 R0 rows", 2, params.mNumRows);
+ assertEquals("5 key auto 3 R0 left", 2, params.mLeftKeys);
+ assertEquals("5 key auto 3 R0 right", 1, params.mRightKeys);
+ assertEquals("5 key auto 3 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 3 R0 [2]", -1, params.getColumnPos(1));
+ assertEquals("5 key auto 3 R0 [3]", -2, params.getColumnPos(2));
+ assertEquals("5 key auto 3 R0 [4]", 0, params.getColumnPos(3));
+ assertEquals("5 key auto 3 R0 [5]", -1, params.getColumnPos(4));
+ assertEquals("5 key auto 3 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 3 R0 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // [5] [4] ___|
+ // [3] [2] <1> ___|
+ public void testLayout5KeyAuto3R1() {
+ MoreKeysKeyboardParams params = createParams(5, 3, XPOS_R1);
+ assertEquals("5 key auto 3 R1 columns", 3, params.mNumColumns);
+ assertEquals("5 key auto 3 R1 rows", 2, params.mNumRows);
+ assertEquals("5 key auto 3 R1 left", 2, params.mLeftKeys);
+ assertEquals("5 key auto 3 R1 right", 1, params.mRightKeys);
+ assertEquals("5 key auto 3 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 3 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("5 key auto 3 R1 [3]", -2, params.getColumnPos(2));
+ assertEquals("5 key auto 3 R1 [4]", 0, params.getColumnPos(3));
+ assertEquals("5 key auto 3 R1 [5]", -1, params.getColumnPos(4));
+ assertEquals("5 key auto 3 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 3 R1 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // [4] [5] ___|
+ // [3] <1> [2] ___|
+ public void testLayout5KeyAuto3R2() {
+ MoreKeysKeyboardParams params = createParams(5, 3, XPOS_R2);
+ assertEquals("5 key auto 3 R2 columns", 3, params.mNumColumns);
+ assertEquals("5 key auto 3 R2 rows", 2, params.mNumRows);
+ assertEquals("5 key auto 3 R2 left", 1, params.mLeftKeys);
+ assertEquals("5 key auto 3 R2 right", 2, params.mRightKeys);
+ assertEquals("5 key auto 3 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 3 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("5 key auto 3 R2 [3]", -1, params.getColumnPos(2));
+ assertEquals("5 key auto 3 R2 [4]", 0, params.getColumnPos(3));
+ assertEquals("5 key auto 3 R2 [5]", 1, params.getColumnPos(4));
+ assertEquals("5 key auto 3 R2 adjust", -1, params.mTopRowAdjustment);
+ assertEquals("5 key auto 3 R2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [5]
+ // [3] <1> [2] [4]
+ public void testLayout5KeyAuto4M0() {
+ MoreKeysKeyboardParams params = createParams(5, 4, XPOS_M0);
+ assertEquals("5 key auto 4 M0 columns", 4, params.mNumColumns);
+ assertEquals("5 key auto 4 M0 rows", 2, params.mNumRows);
+ assertEquals("5 key auto 4 M0 left", 1, params.mLeftKeys);
+ assertEquals("5 key auto 4 M0 right", 3, params.mRightKeys);
+ assertEquals("5 key auto 4 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 4 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("5 key auto 4 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("5 key auto 4 M0 [4]", 2, params.getColumnPos(3));
+ assertEquals("5 key auto 4 M0 [5]", 0, params.getColumnPos(4));
+ assertEquals("5 key auto 4 M0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 4 M0 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // |[5]
+ // |<1> [2] [3] [4]
+ public void testLayout5KeyAuto4L0() {
+ MoreKeysKeyboardParams params = createParams(5, 4, XPOS_L0);
+ assertEquals("5 key auto 4 L0 columns", 4, params.mNumColumns);
+ assertEquals("5 key auto 4 L0 rows", 2, params.mNumRows);
+ assertEquals("5 key auto 4 L0 left", 0, params.mLeftKeys);
+ assertEquals("5 key auto 4 L0 right", 4, params.mRightKeys);
+ assertEquals("5 key auto 4 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 4 L0 [2]", 1, params.getColumnPos(1));
+ assertEquals("5 key auto 4 L0 [3]", 2, params.getColumnPos(2));
+ assertEquals("5 key auto 4 L0 [4]", 3, params.getColumnPos(3));
+ assertEquals("5 key auto 4 L0 [5]", 0, params.getColumnPos(4));
+ assertEquals("5 key auto 4 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 4 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [5]
+ // |___ <1> [2] [3] [4]
+ public void testLayout5KeyAuto4L1() {
+ MoreKeysKeyboardParams params = createParams(5, 4, XPOS_L1);
+ assertEquals("5 key auto 4 L1 columns", 4, params.mNumColumns);
+ assertEquals("5 key auto 4 L1 rows", 2, params.mNumRows);
+ assertEquals("5 key auto 4 L1 left", 0, params.mLeftKeys);
+ assertEquals("5 key auto 4 L1 right", 4, params.mRightKeys);
+ assertEquals("5 key auto 4 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 4 L1 [2]", 1, params.getColumnPos(1));
+ assertEquals("5 key auto 4 L1 [3]", 2, params.getColumnPos(2));
+ assertEquals("5 key auto 4 L1 [4]", 3, params.getColumnPos(3));
+ assertEquals("5 key auto 4 L1 [5]", 0, params.getColumnPos(4));
+ assertEquals("5 key auto 4 L1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 4 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [5]
+ // |___ [3] <1> [2] [4]
+ public void testLayout5KeyAuto4L2() {
+ MoreKeysKeyboardParams params = createParams(5, 4, XPOS_L2);
+ assertEquals("5 key auto 4 L2 columns", 4, params.mNumColumns);
+ assertEquals("5 key auto 4 L2 rows", 2, params.mNumRows);
+ assertEquals("5 key auto 4 L2 left", 1, params.mLeftKeys);
+ assertEquals("5 key auto 4 L2 right", 3, params.mRightKeys);
+ assertEquals("5 key auto 4 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 4 L2 [2]", 1, params.getColumnPos(1));
+ assertEquals("5 key auto 4 L2 [3]", -1, params.getColumnPos(2));
+ assertEquals("5 key auto 4 L2 [4]", 2, params.getColumnPos(3));
+ assertEquals("5 key auto 4 L2 [5]", 0, params.getColumnPos(4));
+ assertEquals("5 key auto 4 L2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 4 L2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [5]|
+ // [4] [3] [2] <1>|
+ public void testLayout5KeyAuto4R0() {
+ MoreKeysKeyboardParams params = createParams(5, 4, XPOS_R0);
+ assertEquals("5 key auto 4 R0 columns", 4, params.mNumColumns);
+ assertEquals("5 key auto 4 R0 rows", 2, params.mNumRows);
+ assertEquals("5 key auto 4 R0 left", 3, params.mLeftKeys);
+ assertEquals("5 key auto 4 R0 right", 1, params.mRightKeys);
+ assertEquals("5 key auto 4 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 4 R0 [2]", -1, params.getColumnPos(1));
+ assertEquals("5 key auto 4 R0 [3]", -2, params.getColumnPos(2));
+ assertEquals("5 key auto 4 R0 [4]", -3, params.getColumnPos(3));
+ assertEquals("5 key auto 4 R0 [5]", 0, params.getColumnPos(4));
+ assertEquals("5 key auto 4 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 4 R0 default", WIDTH * 3, params.getDefaultKeyCoordX());
+ }
+
+ // [5] ___|
+ // [4] [3] [2] <1> ___|
+ public void testLayout5KeyAuto4R1() {
+ MoreKeysKeyboardParams params = createParams(5, 4, XPOS_R1);
+ assertEquals("5 key auto 4 R1 columns", 4, params.mNumColumns);
+ assertEquals("5 key auto 4 R1 rows", 2, params.mNumRows);
+ assertEquals("5 key auto 4 R1 left", 3, params.mLeftKeys);
+ assertEquals("5 key auto 4 R1 right", 1, params.mRightKeys);
+ assertEquals("5 key auto 4 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 4 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("5 key auto 4 R1 [3]", -2, params.getColumnPos(2));
+ assertEquals("5 key auto 4 R1 [4]", -3, params.getColumnPos(3));
+ assertEquals("5 key auto 4 R1 [5]", 0, params.getColumnPos(4));
+ assertEquals("5 key auto 4 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 4 R1 default", WIDTH * 3, params.getDefaultKeyCoordX());
+ }
+
+ // [5] ___|
+ // [4] [3] <1> [2] ___|
+ public void testLayout5KeyAuto4R2() {
+ MoreKeysKeyboardParams params = createParams(5, 4, XPOS_R2);
+ assertEquals("5 key auto 4 R2 columns", 4, params.mNumColumns);
+ assertEquals("5 key auto 4 R2 rows", 2, params.mNumRows);
+ assertEquals("5 key auto 4 R2 left", 2, params.mLeftKeys);
+ assertEquals("5 key auto 4 R2 right", 2, params.mRightKeys);
+ assertEquals("5 key auto 4 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 4 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("5 key auto 4 R2 [3]", -1, params.getColumnPos(2));
+ assertEquals("5 key auto 4 R2 [4]", -2, params.getColumnPos(3));
+ assertEquals("5 key auto 4 R2 [5]", 0, params.getColumnPos(4));
+ assertEquals("5 key auto 4 R2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 4 R2 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // [5] [3] <1> [2] [4]
+ public void testLayout5KeyAuto5M0() {
+ MoreKeysKeyboardParams params = createParams(5, 5, XPOS_M0);
+ assertEquals("5 key auto 5 M0 columns", 5, params.mNumColumns);
+ assertEquals("5 key auto 5 M0 rows", 1, params.mNumRows);
+ assertEquals("5 key auto 5 M0 left", 2, params.mLeftKeys);
+ assertEquals("5 key auto 5 M0 right", 3, params.mRightKeys);
+ assertEquals("5 key auto 5 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 5 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("5 key auto 5 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("5 key auto 5 M0 [4]", 2, params.getColumnPos(3));
+ assertEquals("5 key auto 5 M0 [5]", -2, params.getColumnPos(4));
+ assertEquals("5 key auto 5 M0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 5 M0 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // |<1> [2] [3] [4] [5]
+ public void testLayout5KeyAuto5L0() {
+ MoreKeysKeyboardParams params = createParams(5, 5, XPOS_L0);
+ assertEquals("5 key auto 5 L0 columns", 5, params.mNumColumns);
+ assertEquals("5 key auto 5 L0 rows", 1, params.mNumRows);
+ assertEquals("5 key auto 5 L0 left", 0, params.mLeftKeys);
+ assertEquals("5 key auto 5 L0 right", 5, params.mRightKeys);
+ assertEquals("5 key auto 5 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 5 L0 [2]", 1, params.getColumnPos(1));
+ assertEquals("5 key auto 5 L0 [3]", 2, params.getColumnPos(2));
+ assertEquals("5 key auto 5 L0 [4]", 3, params.getColumnPos(3));
+ assertEquals("5 key auto 5 L0 [5]", 4, params.getColumnPos(4));
+ assertEquals("5 key auto 5 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ <1> [2] [3] [4] [5]
+ public void testLayout5KeyAuto5L1() {
+ MoreKeysKeyboardParams params = createParams(5, 5, XPOS_L1);
+ assertEquals("5 key auto 5 L1 columns", 5, params.mNumColumns);
+ assertEquals("5 key auto 5 L1 rows", 1, params.mNumRows);
+ assertEquals("5 key auto 5 L1 left", 0, params.mLeftKeys);
+ assertEquals("5 key auto 5 L1 right", 5, params.mRightKeys);
+ assertEquals("5 key auto 5 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 5 L1 [2]", 1, params.getColumnPos(1));
+ assertEquals("5 key auto 5 L1 [3]", 2, params.getColumnPos(2));
+ assertEquals("5 key auto 5 L1 [4]", 3, params.getColumnPos(3));
+ assertEquals("5 key auto 5 L1 [5]", 4, params.getColumnPos(4));
+ assertEquals("5 key auto 5 L1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [3] <1> [2] [4] [5]
+ public void testLayout5KeyAuto5L2() {
+ MoreKeysKeyboardParams params = createParams(5, 5, XPOS_L2);
+ assertEquals("5 key auto 5 L2 columns", 5, params.mNumColumns);
+ assertEquals("5 key auto 5 L2 rows", 1, params.mNumRows);
+ assertEquals("5 key auto 5 L2 left", 1, params.mLeftKeys);
+ assertEquals("5 key auto 5 L2 right", 4, params.mRightKeys);
+ assertEquals("5 key auto 5 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 5 L2 [2]", 1, params.getColumnPos(1));
+ assertEquals("5 key auto 5 L2 [3]", -1, params.getColumnPos(2));
+ assertEquals("5 key auto 5 L2 [4]", 2, params.getColumnPos(3));
+ assertEquals("5 key auto 5 L2 [5]", 3, params.getColumnPos(4));
+ assertEquals("5 key auto 5 L2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 5 L2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [5] [4] [3] [2] <1>|
+ public void testLayout5KeyAuto5R0() {
+ MoreKeysKeyboardParams params = createParams(5, 5, XPOS_R0);
+ assertEquals("5 key auto 5 R0 columns", 5, params.mNumColumns);
+ assertEquals("5 key auto 5 R0 rows", 1, params.mNumRows);
+ assertEquals("5 key auto 5 R0 left", 4, params.mLeftKeys);
+ assertEquals("5 key auto 5 R0 right", 1, params.mRightKeys);
+ assertEquals("5 key auto 5 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 5 R0 [2]", -1, params.getColumnPos(1));
+ assertEquals("5 key auto 5 R0 [3]", -2, params.getColumnPos(2));
+ assertEquals("5 key auto 5 R0 [4]", -3, params.getColumnPos(3));
+ assertEquals("5 key auto 5 R0 [5]", -4, params.getColumnPos(4));
+ assertEquals("5 key auto 5 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 5 R0 default", WIDTH * 4, params.getDefaultKeyCoordX());
+ }
+
+ // [5] [4] [3] [2] <1> ___|
+ public void testLayout5KeyAuto5R1() {
+ MoreKeysKeyboardParams params = createParams(5, 5, XPOS_R1);
+ assertEquals("5 key auto 5 R1 columns", 5, params.mNumColumns);
+ assertEquals("5 key auto 5 R1 rows", 1, params.mNumRows);
+ assertEquals("5 key auto 5 R1 left", 4, params.mLeftKeys);
+ assertEquals("5 key auto 5 R1 right", 1, params.mRightKeys);
+ assertEquals("5 key auto 5 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 5 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("5 key auto 5 R1 [3]", -2, params.getColumnPos(2));
+ assertEquals("5 key auto 5 R1 [4]", -3, params.getColumnPos(3));
+ assertEquals("5 key auto 5 R1 [5]", -4, params.getColumnPos(4));
+ assertEquals("5 key auto 5 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 5 R1 default", WIDTH * 4, params.getDefaultKeyCoordX());
+ }
+
+ // [5] [4] [3] <1> [2] ___|
+ public void testLayout5KeyAuto5R2() {
+ MoreKeysKeyboardParams params = createParams(5, 5, XPOS_R2);
+ assertEquals("5 key auto 5 R2 columns", 5, params.mNumColumns);
+ assertEquals("5 key auto 5 R2 rows", 1, params.mNumRows);
+ assertEquals("5 key auto 5 R2 left", 3, params.mLeftKeys);
+ assertEquals("5 key auto 5 R2 right", 2, params.mRightKeys);
+ assertEquals("5 key auto 5 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("5 key auto 5 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("5 key auto 5 R2 [3]", -1, params.getColumnPos(2));
+ assertEquals("5 key auto 5 R2 [4]", -2, params.getColumnPos(3));
+ assertEquals("5 key auto 5 R2 [5]", -3, params.getColumnPos(4));
+ assertEquals("5 key auto 5 R2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("5 key auto 5 R2 default", WIDTH * 3, params.getDefaultKeyCoordX());
+ }
+
+ // [5] [6]
+ // [3] <1> [2] [4]
+ public void testLayout6KeyAuto4M0() {
+ MoreKeysKeyboardParams params = createParams(6, 4, XPOS_M0);
+ assertEquals("6 key auto 4 M0 columns", 4, params.mNumColumns);
+ assertEquals("6 key auto 4 M0 rows", 2, params.mNumRows);
+ assertEquals("6 key auto 4 M0 left", 1, params.mLeftKeys);
+ assertEquals("6 key auto 4 M0 right", 3, params.mRightKeys);
+ assertEquals("6 key auto 4 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("6 key auto 4 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("6 key auto 4 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("6 key auto 4 M0 [4]", 2, params.getColumnPos(3));
+ assertEquals("6 key auto 4 M0 [5]", 0, params.getColumnPos(4));
+ assertEquals("6 key auto 4 M0 [6]", 1, params.getColumnPos(5));
+ assertEquals("6 key auto 4 M0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("6 key auto 4 M0 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // |[5] [6]
+ // |<1> [2] [3] [4]
+ public void testLayout6KeyAuto4L0() {
+ MoreKeysKeyboardParams params = createParams(6, 4, XPOS_L0);
+ assertEquals("6 key auto 4 L0 columns", 4, params.mNumColumns);
+ assertEquals("6 key auto 4 L0 rows", 2, params.mNumRows);
+ assertEquals("6 key auto 4 L0 left", 0, params.mLeftKeys);
+ assertEquals("6 key auto 4 L0 right", 4, params.mRightKeys);
+ assertEquals("6 key auto 4 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("6 key auto 4 L0 [2]", 1, params.getColumnPos(1));
+ assertEquals("6 key auto 4 L0 [3]", 2, params.getColumnPos(2));
+ assertEquals("6 key auto 4 L0 [4]", 3, params.getColumnPos(3));
+ assertEquals("6 key auto 4 L0 [5]", 0, params.getColumnPos(4));
+ assertEquals("6 key auto 4 L0 [6]", 1, params.getColumnPos(5));
+ assertEquals("6 key auto 4 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("6 key auto 4 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [5] [6]
+ // |___ <1> [2] [3] [4]
+ public void testLayout6KeyAuto4L1() {
+ MoreKeysKeyboardParams params = createParams(6, 4, XPOS_L1);
+ assertEquals("6 key auto 4 L1 columns", 4, params.mNumColumns);
+ assertEquals("6 key auto 4 L1 rows", 2, params.mNumRows);
+ assertEquals("6 key auto 4 L1 left", 0, params.mLeftKeys);
+ assertEquals("6 key auto 4 L1 right", 4, params.mRightKeys);
+ assertEquals("6 key auto 4 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("6 key auto 4 L1 [2]", 1, params.getColumnPos(1));
+ assertEquals("6 key auto 4 L1 [3]", 2, params.getColumnPos(2));
+ assertEquals("6 key auto 4 L1 [4]", 3, params.getColumnPos(3));
+ assertEquals("6 key auto 4 L1 [5]", 0, params.getColumnPos(4));
+ assertEquals("6 key auto 4 L1 [6]", 1, params.getColumnPos(5));
+ assertEquals("6 key auto 4 L1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("6 key auto 4 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [5] [6]
+ // |___ [3] <1> [2] [4]
+ public void testLayout6KeyAuto4L2() {
+ MoreKeysKeyboardParams params = createParams(6, 4, XPOS_L2);
+ assertEquals("6 key auto 4 L2 columns", 4, params.mNumColumns);
+ assertEquals("6 key auto 4 L2 rows", 2, params.mNumRows);
+ assertEquals("6 key auto 4 L2 left", 1, params.mLeftKeys);
+ assertEquals("6 key auto 4 L2 right", 3, params.mRightKeys);
+ assertEquals("6 key auto 4 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("6 key auto 4 L2 [2]", 1, params.getColumnPos(1));
+ assertEquals("6 key auto 4 L2 [3]", -1, params.getColumnPos(2));
+ assertEquals("6 key auto 4 L2 [4]", 2, params.getColumnPos(3));
+ assertEquals("6 key auto 4 L2 [5]", 0, params.getColumnPos(4));
+ assertEquals("6 key auto 4 L2 [6]", 1, params.getColumnPos(5));
+ assertEquals("6 key auto 4 L2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("6 key auto 4 L2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [6] [5]|
+ // [4] [3] [2] <1>|
+ public void testLayout6KeyAuto4R0() {
+ MoreKeysKeyboardParams params = createParams(6, 4, XPOS_R0);
+ assertEquals("6 key auto 4 R0 columns", 4, params.mNumColumns);
+ assertEquals("6 key auto 4 R0 rows", 2, params.mNumRows);
+ assertEquals("6 key auto 4 R0 left", 3, params.mLeftKeys);
+ assertEquals("6 key auto 4 R0 right", 1, params.mRightKeys);
+ assertEquals("6 key auto 4 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("6 key auto 4 R0 [2]", -1, params.getColumnPos(1));
+ assertEquals("6 key auto 4 R0 [3]", -2, params.getColumnPos(2));
+ assertEquals("6 key auto 4 R0 [4]", -3, params.getColumnPos(3));
+ assertEquals("6 key auto 4 R0 [5]", 0, params.getColumnPos(4));
+ assertEquals("6 key auto 4 R0 [6]", -1, params.getColumnPos(5));
+ assertEquals("6 key auto 4 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("6 key auto 4 R0 default", WIDTH * 3, params.getDefaultKeyCoordX());
+ }
+
+ // [6] [5] ___|
+ // [4] [3] [2] <1> ___|
+ public void testLayout6KeyAuto4R1() {
+ MoreKeysKeyboardParams params = createParams(6, 4, XPOS_R1);
+ assertEquals("6 key auto 4 R1 columns", 4, params.mNumColumns);
+ assertEquals("6 key auto 4 R1 rows", 2, params.mNumRows);
+ assertEquals("6 key auto 4 R1 left", 3, params.mLeftKeys);
+ assertEquals("6 key auto 4 R1 right", 1, params.mRightKeys);
+ assertEquals("6 key auto 4 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("6 key auto 4 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("6 key auto 4 R1 [3]", -2, params.getColumnPos(2));
+ assertEquals("6 key auto 4 R1 [4]", -3, params.getColumnPos(3));
+ assertEquals("6 key auto 4 R1 [5]", 0, params.getColumnPos(4));
+ assertEquals("6 key auto 4 R1 [6]", -1, params.getColumnPos(5));
+ assertEquals("6 key auto 4 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("6 key auto 4 R1 default", WIDTH * 3, params.getDefaultKeyCoordX());
+ }
+
+ // [5] [6] ___|
+ // [4] [3] <1> [2] ___|
+ public void testLayout6KeyAuto4R2() {
+ MoreKeysKeyboardParams params = createParams(6, 4, XPOS_R2);
+ assertEquals("6 key auto 4 R2 columns", 4, params.mNumColumns);
+ assertEquals("6 key auto 4 R2 rows", 2, params.mNumRows);
+ assertEquals("6 key auto 4 R2 left", 2, params.mLeftKeys);
+ assertEquals("6 key auto 4 R2 right", 2, params.mRightKeys);
+ assertEquals("6 key auto 4 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("6 key auto 4 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("6 key auto 4 R2 [3]", -1, params.getColumnPos(2));
+ assertEquals("6 key auto 4 R2 [4]", -2, params.getColumnPos(3));
+ assertEquals("6 key auto 4 R2 [5]", 0, params.getColumnPos(4));
+ assertEquals("6 key auto 4 R2 [6]", 1, params.getColumnPos(5));
+ assertEquals("6 key auto 4 R2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("6 key auto 4 R2 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // [6]
+ // [5] [3] <1> [2] [4]
+ public void testLayout6KeyAuto5M0() {
+ MoreKeysKeyboardParams params = createParams(6, 5, XPOS_M0);
+ assertEquals("6 key auto 5 M0 columns", 5, params.mNumColumns);
+ assertEquals("6 key auto 5 M0 rows", 2, params.mNumRows);
+ assertEquals("6 key auto 5 M0 left", 2, params.mLeftKeys);
+ assertEquals("6 key auto 5 M0 right", 3, params.mRightKeys);
+ assertEquals("6 key auto 5 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("6 key auto 5 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("6 key auto 5 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("6 key auto 5 M0 [4]", 2, params.getColumnPos(3));
+ assertEquals("6 key auto 5 M0 [5]", -2, params.getColumnPos(4));
+ assertEquals("6 key auto 5 M0 [6]", 0, params.getColumnPos(5));
+ assertEquals("6 key auto 5 M0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("6 key auto 5 M0 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // |[6]
+ // |<1> [2] [3] [4] [5]
+ public void testLayout6KeyAuto5L0() {
+ MoreKeysKeyboardParams params = createParams(6, 5, XPOS_L0);
+ assertEquals("6 key auto 5 L0 columns", 5, params.mNumColumns);
+ assertEquals("6 key auto 5 L0 rows", 2, params.mNumRows);
+ assertEquals("6 key auto 5 L0 left", 0, params.mLeftKeys);
+ assertEquals("6 key auto 5 L0 right", 5, params.mRightKeys);
+ assertEquals("6 key auto 5 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("6 key auto 5 L0 [2]", 1, params.getColumnPos(1));
+ assertEquals("6 key auto 5 L0 [3]", 2, params.getColumnPos(2));
+ assertEquals("6 key auto 5 L0 [4]", 3, params.getColumnPos(3));
+ assertEquals("6 key auto 5 L0 [5]", 4, params.getColumnPos(4));
+ assertEquals("6 key auto 5 L0 [6]", 0, params.getColumnPos(5));
+ assertEquals("6 key auto 5 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("6 key auto 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [6]
+ // |___ <1> [2] [3] [4] [5]
+ public void testLayout6KeyAuto5L1() {
+ MoreKeysKeyboardParams params = createParams(6, 5, XPOS_L1);
+ assertEquals("6 key auto 5 L1 columns", 5, params.mNumColumns);
+ assertEquals("6 key auto 5 L1 rows", 2, params.mNumRows);
+ assertEquals("6 key auto 5 L1 left", 0, params.mLeftKeys);
+ assertEquals("6 key auto 5 L1 right", 5, params.mRightKeys);
+ assertEquals("6 key auto 5 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("6 key auto 5 L1 [2]", 1, params.getColumnPos(1));
+ assertEquals("6 key auto 5 L1 [3]", 2, params.getColumnPos(2));
+ assertEquals("6 key auto 5 L1 [4]", 3, params.getColumnPos(3));
+ assertEquals("6 key auto 5 L1 [5]", 4, params.getColumnPos(4));
+ assertEquals("6 key auto 5 L1 [6]", 0, params.getColumnPos(5));
+ assertEquals("6 key auto 5 L1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("6 key auto 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [6]
+ // |___ [3] <1> [2] [4] [5]
+ public void testLayout6KeyAuto5L2() {
+ MoreKeysKeyboardParams params = createParams(6, 5, XPOS_L2);
+ assertEquals("6 key auto 5 L2 columns", 5, params.mNumColumns);
+ assertEquals("6 key auto 5 L2 rows", 2, params.mNumRows);
+ assertEquals("6 key auto 5 L2 left", 1, params.mLeftKeys);
+ assertEquals("6 key auto 5 L2 right", 4, params.mRightKeys);
+ assertEquals("6 key auto 5 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("6 key auto 5 L2 [2]", 1, params.getColumnPos(1));
+ assertEquals("6 key auto 5 L2 [3]", -1, params.getColumnPos(2));
+ assertEquals("6 key auto 5 L2 [4]", 2, params.getColumnPos(3));
+ assertEquals("6 key auto 5 L2 [5]", 3, params.getColumnPos(4));
+ assertEquals("6 key auto 5 L2 [6]", 0, params.getColumnPos(5));
+ assertEquals("6 key auto 5 L2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("6 key auto 5 L2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [6]|
+ // [5] [4] [3] [2] <1>|
+ public void testLayout6KeyAuto5R0() {
+ MoreKeysKeyboardParams params = createParams(6, 5, XPOS_R0);
+ assertEquals("6 key auto 5 R0 columns", 5, params.mNumColumns);
+ assertEquals("6 key auto 5 R0 rows", 2, params.mNumRows);
+ assertEquals("6 key auto 5 R0 left", 4, params.mLeftKeys);
+ assertEquals("6 key auto 5 R0 right", 1, params.mRightKeys);
+ assertEquals("6 key auto 5 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("6 key auto 5 R0 [2]", -1, params.getColumnPos(1));
+ assertEquals("6 key auto 5 R0 [3]", -2, params.getColumnPos(2));
+ assertEquals("6 key auto 5 R0 [4]", -3, params.getColumnPos(3));
+ assertEquals("6 key auto 5 R0 [5]", -4, params.getColumnPos(4));
+ assertEquals("6 key auto 5 R0 [6]", 0, params.getColumnPos(5));
+ assertEquals("6 key auto 5 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("6 key auto 5 R0 default", WIDTH * 4, params.getDefaultKeyCoordX());
+ }
+
+ // [6] ___|
+ // [5] [4] [3] [2] <1> ___|
+ public void testLayout6KeyAuto5R1() {
+ MoreKeysKeyboardParams params = createParams(6, 5, XPOS_R1);
+ assertEquals("6 key auto 5 R1 columns", 5, params.mNumColumns);
+ assertEquals("6 key auto 5 R1 rows", 2, params.mNumRows);
+ assertEquals("6 key auto 5 R1 left", 4, params.mLeftKeys);
+ assertEquals("6 key auto 5 R1 right", 1, params.mRightKeys);
+ assertEquals("6 key auto 5 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("6 key auto 5 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("6 key auto 5 R1 [3]", -2, params.getColumnPos(2));
+ assertEquals("6 key auto 5 R1 [4]", -3, params.getColumnPos(3));
+ assertEquals("6 key auto 5 R1 [5]", -4, params.getColumnPos(4));
+ assertEquals("6 key auto 5 R1 [6]", 0, params.getColumnPos(5));
+ assertEquals("6 key auto 5 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("6 key auto 5 R1 default", WIDTH * 4, params.getDefaultKeyCoordX());
+ }
+
+ // [6] ___|
+ // [5] [4] [3] <1> [2] ___|
+ public void testLayout6KeyAuto5R2() {
+ MoreKeysKeyboardParams params = createParams(6, 5, XPOS_R2);
+ assertEquals("6 key auto 5 R2 columns", 5, params.mNumColumns);
+ assertEquals("6 key auto 5 R2 rows", 2, params.mNumRows);
+ assertEquals("6 key auto 5 R2 left", 3, params.mLeftKeys);
+ assertEquals("6 key auto 5 R2 right", 2, params.mRightKeys);
+ assertEquals("6 key auto 5 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("6 key auto 5 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("6 key auto 5 R2 [3]", -1, params.getColumnPos(2));
+ assertEquals("6 key auto 5 R2 [4]", -2, params.getColumnPos(3));
+ assertEquals("6 key auto 5 R2 [5]", -3, params.getColumnPos(4));
+ assertEquals("6 key auto 5 R2 [6]", 0, params.getColumnPos(5));
+ assertEquals("6 key auto 5 R2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("6 key auto 5 R2 default", WIDTH * 3, params.getDefaultKeyCoordX());
+ }
+
+ // |<1> [2] [3] [4] [5] [6] [7] ___ ___ ___|
+ public void testLayout7KeyAuto7L0() {
+ MoreKeysKeyboardParams params = createParams(7, 7, XPOS_L0);
+ assertEquals("7 key auto 7 L0 columns", 7, params.mNumColumns);
+ assertEquals("7 key auto 7 L0 rows", 1, params.mNumRows);
+ assertEquals("7 key auto 7 L0 left", 0, params.mLeftKeys);
+ assertEquals("7 key auto 7 L0 right", 7, params.mRightKeys);
+ assertEquals("7 key auto 7 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 7 L0 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 7 L0 [3]", 2, params.getColumnPos(2));
+ assertEquals("7 key auto 7 L0 [4]", 3, params.getColumnPos(3));
+ assertEquals("7 key auto 7 L0 [5]", 4, params.getColumnPos(4));
+ assertEquals("7 key auto 7 L0 [6]", 5, params.getColumnPos(5));
+ assertEquals("7 key auto 7 L0 [7]", 6, params.getColumnPos(6));
+ assertEquals("7 key auto 7 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 7 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ <1> [2] [3] [4] [5] [6] [7] ___ ___|
+ public void testLayout7KeyAuto7L1() {
+ MoreKeysKeyboardParams params = createParams(7, 7, XPOS_L1);
+ assertEquals("7 key auto 7 L1 columns", 7, params.mNumColumns);
+ assertEquals("7 key auto 7 L1 rows", 1, params.mNumRows);
+ assertEquals("7 key auto 7 L1 left", 0, params.mLeftKeys);
+ assertEquals("7 key auto 7 L1 right", 7, params.mRightKeys);
+ assertEquals("7 key auto 7 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 7 L1 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 7 L1 [3]", 2, params.getColumnPos(2));
+ assertEquals("7 key auto 7 L1 [4]", 3, params.getColumnPos(3));
+ assertEquals("7 key auto 7 L1 [5]", 4, params.getColumnPos(4));
+ assertEquals("7 key auto 7 L1 [6]", 5, params.getColumnPos(5));
+ assertEquals("7 key auto 7 L1 [7]", 6, params.getColumnPos(6));
+ assertEquals("7 key auto 7 L1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 7 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [3] <1> [2] [4] [5] [6] [7] ___ ___|
+ public void testLayout7KeyAuto7L2() {
+ MoreKeysKeyboardParams params = createParams(7, 7, XPOS_L2);
+ assertEquals("7 key auto 7 L2 columns", 7, params.mNumColumns);
+ assertEquals("7 key auto 7 L2 rows", 1, params.mNumRows);
+ assertEquals("7 key auto 7 L2 left", 1, params.mLeftKeys);
+ assertEquals("7 key auto 7 L2 right", 6, params.mRightKeys);
+ assertEquals("7 key auto 7 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 7 L2 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 7 L2 [3]", -1, params.getColumnPos(2));
+ assertEquals("7 key auto 7 L2 [4]", 2, params.getColumnPos(3));
+ assertEquals("7 key auto 7 L2 [5]", 3, params.getColumnPos(4));
+ assertEquals("7 key auto 7 L2 [6]", 4, params.getColumnPos(5));
+ assertEquals("7 key auto 7 L2 [7]", 5, params.getColumnPos(6));
+ assertEquals("7 key auto 7 L2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 7 L2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [5] [3] <1> [2] [4] [6] [7] ___ ___|
+ public void testLayout7KeyAuto7L3() {
+ MoreKeysKeyboardParams params = createParams(7, 7, XPOS_L3);
+ assertEquals("7 key auto 7 L3 columns", 7, params.mNumColumns);
+ assertEquals("7 key auto 7 L3 rows", 1, params.mNumRows);
+ assertEquals("7 key auto 7 L3 left", 2, params.mLeftKeys);
+ assertEquals("7 key auto 7 L3 right", 5, params.mRightKeys);
+ assertEquals("7 key auto 7 L3 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 7 L3 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 7 L3 [3]", -1, params.getColumnPos(2));
+ assertEquals("7 key auto 7 L3 [4]", 2, params.getColumnPos(3));
+ assertEquals("7 key auto 7 L3 [5]", -2, params.getColumnPos(4));
+ assertEquals("7 key auto 7 L3 [6]", 3, params.getColumnPos(5));
+ assertEquals("7 key auto 7 L3 [7]", 4, params.getColumnPos(6));
+ assertEquals("7 key auto 7 L3 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 7 L3 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [7] [5] [3] <1> [2] [4] [6] ___ ___|
+ public void testLayout7KeyAuto7M0() {
+ MoreKeysKeyboardParams params = createParams(7, 7, XPOS_M0);
+ assertEquals("7 key auto 7 M0 columns", 7, params.mNumColumns);
+ assertEquals("7 key auto 7 M0 rows", 1, params.mNumRows);
+ assertEquals("7 key auto 7 M0 left", 3, params.mLeftKeys);
+ assertEquals("7 key auto 7 M0 right", 4, params.mRightKeys);
+ assertEquals("7 key auto 7 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 7 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 7 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("7 key auto 7 M0 [4]", 2, params.getColumnPos(3));
+ assertEquals("7 key auto 7 M0 [5]", -2, params.getColumnPos(4));
+ assertEquals("7 key auto 7 M0 [6]", 3, params.getColumnPos(5));
+ assertEquals("7 key auto 7 M0 [7]", -3, params.getColumnPos(6));
+ assertEquals("7 key auto 7 M0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 7 M0 default", WIDTH * 3, params.getDefaultKeyCoordX());
+ }
+
+ // |___ ___ [7] [5] [3] <1> [2] [4] [6] ___|
+ public void testLayout7KeyAuto7M1() {
+ MoreKeysKeyboardParams params = createParams(7, 7, XPOS_M1);
+ assertEquals("7 key auto 7 M1 columns", 7, params.mNumColumns);
+ assertEquals("7 key auto 7 M1 rows", 1, params.mNumRows);
+ assertEquals("7 key auto 7 M1 left", 3, params.mLeftKeys);
+ assertEquals("7 key auto 7 M1 right", 4, params.mRightKeys);
+ assertEquals("7 key auto 7 M1 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 7 M1 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 7 M1 [3]", -1, params.getColumnPos(2));
+ assertEquals("7 key auto 7 M1 [4]", 2, params.getColumnPos(3));
+ assertEquals("7 key auto 7 M1 [5]", -2, params.getColumnPos(4));
+ assertEquals("7 key auto 7 M1 [6]", 3, params.getColumnPos(5));
+ assertEquals("7 key auto 7 M1 [7]", -3, params.getColumnPos(6));
+ assertEquals("7 key auto 7 M1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 7 M1 default", WIDTH * 3, params.getDefaultKeyCoordX());
+ }
+
+ // |___ ___ [7] [6] [5] [3] <1> [2] [4] ___|
+ public void testLayout7KeyAuto7R3() {
+ MoreKeysKeyboardParams params = createParams(7, 7, XPOS_R3);
+ assertEquals("7 key auto 7 R3 columns", 7, params.mNumColumns);
+ assertEquals("7 key auto 7 R3 rows", 1, params.mNumRows);
+ assertEquals("7 key auto 7 R3 left", 4, params.mLeftKeys);
+ assertEquals("7 key auto 7 R3 right", 3, params.mRightKeys);
+ assertEquals("7 key auto 7 R3 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 7 R3 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 7 R3 [3]", -1, params.getColumnPos(2));
+ assertEquals("7 key auto 7 R3 [4]", 2, params.getColumnPos(3));
+ assertEquals("7 key auto 7 R3 [5]", -2, params.getColumnPos(4));
+ assertEquals("7 key auto 7 R3 [6]", -3, params.getColumnPos(5));
+ assertEquals("7 key auto 7 R3 [7]", -4, params.getColumnPos(6));
+ assertEquals("7 key auto 7 R3 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 7 R3 default", WIDTH * 4, params.getDefaultKeyCoordX());
+ }
+
+ // |___ ___ [7] [6] [5] [4] [3] <1> [2] ___|
+ public void testLayout7KeyAuto7R2() {
+ MoreKeysKeyboardParams params = createParams(7, 7, XPOS_R2);
+ assertEquals("7 key auto 7 R2 columns", 7, params.mNumColumns);
+ assertEquals("7 key auto 7 R2 rows", 1, params.mNumRows);
+ assertEquals("7 key auto 7 R2 left", 5, params.mLeftKeys);
+ assertEquals("7 key auto 7 R2 right", 2, params.mRightKeys);
+ assertEquals("7 key auto 7 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 7 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 7 R2 [3]", -1, params.getColumnPos(2));
+ assertEquals("7 key auto 7 R2 [4]", -2, params.getColumnPos(3));
+ assertEquals("7 key auto 7 R2 [5]", -3, params.getColumnPos(4));
+ assertEquals("7 key auto 7 R2 [6]", -4, params.getColumnPos(5));
+ assertEquals("7 key auto 7 R2 [7]", -5, params.getColumnPos(6));
+ assertEquals("7 key auto 7 R2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 7 R2 default", WIDTH * 5, params.getDefaultKeyCoordX());
+ }
+
+ // |___ ___ [7] [6] [5] [4] [3] [2] <1> ___|
+ public void testLayout7KeyAuto7R1() {
+ MoreKeysKeyboardParams params = createParams(7, 7, XPOS_R1);
+ assertEquals("7 key auto 7 R1 columns", 7, params.mNumColumns);
+ assertEquals("7 key auto 7 R1 rows", 1, params.mNumRows);
+ assertEquals("7 key auto 7 R1 left", 6, params.mLeftKeys);
+ assertEquals("7 key auto 7 R1 right", 1, params.mRightKeys);
+ assertEquals("7 key auto 7 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 7 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("7 key auto 7 R1 [3]", -2, params.getColumnPos(2));
+ assertEquals("7 key auto 7 R1 [4]", -3, params.getColumnPos(3));
+ assertEquals("7 key auto 7 R1 [5]", -4, params.getColumnPos(4));
+ assertEquals("7 key auto 7 R1 [6]", -5, params.getColumnPos(5));
+ assertEquals("7 key auto 7 R1 [7]", -6, params.getColumnPos(6));
+ assertEquals("7 key auto 7 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 7 R1 default", WIDTH * 6, params.getDefaultKeyCoordX());
+ }
+
+ // |___ ___ [7] [6] [5] [4] [3] [2] <1>|
+ public void testLayout7KeyAuto7R0() {
+ MoreKeysKeyboardParams params = createParams(7, 7, XPOS_R0);
+ assertEquals("7 key auto 7 R0 columns", 7, params.mNumColumns);
+ assertEquals("7 key auto 7 R0 rows", 1, params.mNumRows);
+ assertEquals("7 key auto 7 R0 left", 6, params.mLeftKeys);
+ assertEquals("7 key auto 7 R0 right", 1, params.mRightKeys);
+ assertEquals("7 key auto 7 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 7 R0 [2]", -1, params.getColumnPos(1));
+ assertEquals("7 key auto 7 R0 [3]", -2, params.getColumnPos(2));
+ assertEquals("7 key auto 7 R0 [4]", -3, params.getColumnPos(3));
+ assertEquals("7 key auto 7 R0 [5]", -4, params.getColumnPos(4));
+ assertEquals("7 key auto 7 R0 [6]", -5, params.getColumnPos(5));
+ assertEquals("7 key auto 7 R0 [7]", -6, params.getColumnPos(6));
+ assertEquals("7 key auto 7 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 7 R0 default", WIDTH * 6, params.getDefaultKeyCoordX());
+ }
+
+ // [6] [7]
+ // [5] [3] <1> [2] [4]
+ public void testLayout7KeyAuto5M0() {
+ MoreKeysKeyboardParams params = createParams(7, 5, XPOS_M0);
+ assertEquals("7 key auto 5 M0 columns", 5, params.mNumColumns);
+ assertEquals("7 key auto 5 M0 rows", 2, params.mNumRows);
+ assertEquals("7 key auto 5 M0 left", 2, params.mLeftKeys);
+ assertEquals("7 key auto 5 M0 right", 3, params.mRightKeys);
+ assertEquals("7 key auto 5 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 5 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 5 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("7 key auto 5 M0 [4]", 2, params.getColumnPos(3));
+ assertEquals("7 key auto 5 M0 [5]", -2, params.getColumnPos(4));
+ assertEquals("7 key auto 5 M0 [6]", 0, params.getColumnPos(5));
+ assertEquals("7 key auto 5 M0 [7]", 1, params.getColumnPos(6));
+ assertEquals("7 key auto 5 M0 adjust", -1, params.mTopRowAdjustment);
+ assertEquals("7 key auto 5 M0 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // |[6] [7]
+ // |<1> [2] [3] [4] [5]
+ public void testLayout7KeyAuto5L0() {
+ MoreKeysKeyboardParams params = createParams(7, 5, XPOS_L0);
+ assertEquals("7 key auto 5 L0 columns", 5, params.mNumColumns);
+ assertEquals("7 key auto 5 L0 rows", 2, params.mNumRows);
+ assertEquals("7 key auto 5 L0 left", 0, params.mLeftKeys);
+ assertEquals("7 key auto 5 L0 right", 5, params.mRightKeys);
+ assertEquals("7 key auto 5 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 5 L0 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 5 L0 [3]", 2, params.getColumnPos(2));
+ assertEquals("7 key auto 5 L0 [4]", 3, params.getColumnPos(3));
+ assertEquals("7 key auto 5 L0 [5]", 4, params.getColumnPos(4));
+ assertEquals("7 key auto 5 L0 [6]", 0, params.getColumnPos(5));
+ assertEquals("7 key auto 5 L0 [7]", 1, params.getColumnPos(6));
+ assertEquals("7 key auto 5 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [6] [7]
+ // |___ <1> [2] [3] [4] [5]
+ public void testLayout7KeyAuto5L1() {
+ MoreKeysKeyboardParams params = createParams(7, 5, XPOS_L1);
+ assertEquals("7 key auto 5 L1 columns", 5, params.mNumColumns);
+ assertEquals("7 key auto 5 L1 rows", 2, params.mNumRows);
+ assertEquals("7 key auto 5 L1 left", 0, params.mLeftKeys);
+ assertEquals("7 key auto 5 L1 right", 5, params.mRightKeys);
+ assertEquals("7 key auto 5 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 5 L1 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 5 L1 [3]", 2, params.getColumnPos(2));
+ assertEquals("7 key auto 5 L1 [4]", 3, params.getColumnPos(3));
+ assertEquals("7 key auto 5 L1 [5]", 4, params.getColumnPos(4));
+ assertEquals("7 key auto 5 L1 [6]", 0, params.getColumnPos(5));
+ assertEquals("7 key auto 5 L1 [7]", 1, params.getColumnPos(6));
+ assertEquals("7 key auto 5 L1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [6] [7]
+ // |___ [3] <1> [2] [4] [5]
+ public void testLayout7KeyAuto5L2() {
+ MoreKeysKeyboardParams params = createParams(7, 5, XPOS_L2);
+ assertEquals("7 key auto 5 L2 columns", 5, params.mNumColumns);
+ assertEquals("7 key auto 5 L2 rows", 2, params.mNumRows);
+ assertEquals("7 key auto 5 L2 left", 1, params.mLeftKeys);
+ assertEquals("7 key auto 5 L2 right", 4, params.mRightKeys);
+ assertEquals("7 key auto 5 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 5 L2 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 5 L2 [3]", -1, params.getColumnPos(2));
+ assertEquals("7 key auto 5 L2 [4]", 2, params.getColumnPos(3));
+ assertEquals("7 key auto 5 L2 [5]", 3, params.getColumnPos(4));
+ assertEquals("7 key auto 5 L2 [6]", 0, params.getColumnPos(5));
+ assertEquals("7 key auto 5 L2 [7]", 1, params.getColumnPos(6));
+ assertEquals("7 key auto 5 L2 adjust", -1, params.mTopRowAdjustment);
+ assertEquals("7 key auto 5 L2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [7] [6]|
+ // [5] [4] [3] [2] <1>|
+ public void testLayout7KeyAuto5R0() {
+ MoreKeysKeyboardParams params = createParams(7, 5, XPOS_R0);
+ assertEquals("7 key auto 5 R0 columns", 5, params.mNumColumns);
+ assertEquals("7 key auto 5 R0 rows", 2, params.mNumRows);
+ assertEquals("7 key auto 5 R0 left", 4, params.mLeftKeys);
+ assertEquals("7 key auto 5 R0 right", 1, params.mRightKeys);
+ assertEquals("7 key auto 5 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 5 R0 [2]", -1, params.getColumnPos(1));
+ assertEquals("7 key auto 5 R0 [3]", -2, params.getColumnPos(2));
+ assertEquals("7 key auto 5 R0 [4]", -3, params.getColumnPos(3));
+ assertEquals("7 key auto 5 R0 [5]", -4, params.getColumnPos(4));
+ assertEquals("7 key auto 5 R0 [6]", 0, params.getColumnPos(5));
+ assertEquals("7 key auto 5 R0 [7]", -1, params.getColumnPos(6));
+ assertEquals("7 key auto 5 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 5 R0 default", WIDTH * 4, params.getDefaultKeyCoordX());
+ }
+
+ // [7] [6] ___|
+ // [5] [4] [3] [2] <1> ___|
+ public void testLayout7KeyAuto5R1() {
+ MoreKeysKeyboardParams params = createParams(7, 5, XPOS_R1);
+ assertEquals("7 key auto 5 R1 columns", 5, params.mNumColumns);
+ assertEquals("7 key auto 5 R1 rows", 2, params.mNumRows);
+ assertEquals("7 key auto 5 R1 left", 4, params.mLeftKeys);
+ assertEquals("7 key auto 5 R1 right", 1, params.mRightKeys);
+ assertEquals("7 key auto 5 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 5 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("7 key auto 5 R1 [3]", -2, params.getColumnPos(2));
+ assertEquals("7 key auto 5 R1 [4]", -3, params.getColumnPos(3));
+ assertEquals("7 key auto 5 R1 [5]", -4, params.getColumnPos(4));
+ assertEquals("7 key auto 5 R1 [6]", 0, params.getColumnPos(5));
+ assertEquals("7 key auto 5 R1 [7]", -1, params.getColumnPos(6));
+ assertEquals("7 key auto 5 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 5 R1 default", WIDTH * 4, params.getDefaultKeyCoordX());
+ }
+
+ // [6] [7] ___|
+ // [5] [4] [3] <1> [2] ___|
+ public void testLayout7KeyAuto5R2() {
+ MoreKeysKeyboardParams params = createParams(7, 5, XPOS_R2);
+ assertEquals("7 key auto 5 R2 columns", 5, params.mNumColumns);
+ assertEquals("7 key auto 5 R2 rows", 2, params.mNumRows);
+ assertEquals("7 key auto 5 R2 left", 3, params.mLeftKeys);
+ assertEquals("7 key auto 5 R2 right", 2, params.mRightKeys);
+ assertEquals("7 key auto 5 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 5 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 5 R2 [3]", -1, params.getColumnPos(2));
+ assertEquals("7 key auto 5 R2 [4]", -2, params.getColumnPos(3));
+ assertEquals("7 key auto 5 R2 [5]", -3, params.getColumnPos(4));
+ assertEquals("7 key auto 5 R2 [6]", 0, params.getColumnPos(5));
+ assertEquals("7 key auto 5 R2 [7]", 1, params.getColumnPos(6));
+ assertEquals("7 key auto 5 R2 adjust", -1, params.mTopRowAdjustment);
+ assertEquals("7 key auto 5 R2 default", WIDTH * 3, params.getDefaultKeyCoordX());
+ }
+
+ // [7]
+ // [6] [4] [5]
+ // [3] <1> [2]
+ public void testLayout7KeyAuto3M0() {
+ MoreKeysKeyboardParams params = createParams(7, 3, XPOS_M0);
+ assertEquals("7 key auto 3 M0 columns", 3, params.mNumColumns);
+ assertEquals("7 key auto 3 M0 rows", 3, params.mNumRows);
+ assertEquals("7 key auto 3 M0 left", 1, params.mLeftKeys);
+ assertEquals("7 key auto 3 M0 right", 2, params.mRightKeys);
+ assertEquals("7 key auto 3 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 3 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 3 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("7 key auto 3 M0 [4]", 0, params.getColumnPos(3));
+ assertEquals("7 key auto 3 M0 [5]", 1, params.getColumnPos(4));
+ assertEquals("7 key auto 3 M0 [6]", -1, params.getColumnPos(5));
+ assertEquals("7 key auto 3 M0 [7]", 0, params.getColumnPos(6));
+ assertEquals("7 key auto 3 M0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 3 M0 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // |[7]
+ // |[4] [5] [6]
+ // |<1> [2] [3]
+ public void testLayout7KeyAuto3L0() {
+ MoreKeysKeyboardParams params = createParams(7, 3, XPOS_L0);
+ assertEquals("7 key auto 3 L0 columns", 3, params.mNumColumns);
+ assertEquals("7 key auto 3 L0 rows", 3, params.mNumRows);
+ assertEquals("7 key auto 3 L0 left", 0, params.mLeftKeys);
+ assertEquals("7 key auto 3 L0 right", 3, params.mRightKeys);
+ assertEquals("7 key auto 3 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 3 L0 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 3 L0 [3]", 2, params.getColumnPos(2));
+ assertEquals("7 key auto 3 L0 [4]", 0, params.getColumnPos(3));
+ assertEquals("7 key auto 3 L0 [5]", 1, params.getColumnPos(4));
+ assertEquals("7 key auto 3 L0 [6]", 2, params.getColumnPos(5));
+ assertEquals("7 key auto 3 L0 [7]", 0, params.getColumnPos(6));
+ assertEquals("7 key auto 3 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 3 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [7]
+ // |___ [4] [5] [6]
+ // |___ <1> [2] [3]
+ public void testLayout7KeyAuto3L1() {
+ MoreKeysKeyboardParams params = createParams(7, 3, XPOS_L1);
+ assertEquals("7 key auto 3 L1 columns", 3, params.mNumColumns);
+ assertEquals("7 key auto 3 L1 rows", 3, params.mNumRows);
+ assertEquals("7 key auto 3 L1 left", 0, params.mLeftKeys);
+ assertEquals("7 key auto 3 L1 right", 3, params.mRightKeys);
+ assertEquals("7 key auto 3 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 3 L1 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 3 L1 [3]", 2, params.getColumnPos(2));
+ assertEquals("7 key auto 3 L1 [4]", 0, params.getColumnPos(3));
+ assertEquals("7 key auto 3 L1 [5]", 1, params.getColumnPos(4));
+ assertEquals("7 key auto 3 L1 [6]", 2, params.getColumnPos(5));
+ assertEquals("7 key auto 3 L1 [7]", 0, params.getColumnPos(6));
+ assertEquals("7 key auto 3 L1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 3 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [7]
+ // |___ [6] [4] [5]
+ // |___ [3] <1> [2]
+ public void testLayout7KeyAuto3L2() {
+ MoreKeysKeyboardParams params = createParams(7, 3, XPOS_L2);
+ assertEquals("7 key auto 3 L2 columns", 3, params.mNumColumns);
+ assertEquals("7 key auto 3 L2 rows", 3, params.mNumRows);
+ assertEquals("7 key auto 3 L2 left", 1, params.mLeftKeys);
+ assertEquals("7 key auto 3 L2 right", 2, params.mRightKeys);
+ assertEquals("7 key auto 3 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 3 L2 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 3 L2 [3]", -1, params.getColumnPos(2));
+ assertEquals("7 key auto 3 L2 [4]", 0, params.getColumnPos(3));
+ assertEquals("7 key auto 3 L2 [5]", 1, params.getColumnPos(4));
+ assertEquals("7 key auto 3 L2 [6]", -1, params.getColumnPos(5));
+ assertEquals("7 key auto 3 L2 [7]", 0, params.getColumnPos(6));
+ assertEquals("7 key auto 3 L2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 3 L2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [7]|
+ // [6] [5] [4]|
+ // [3] [2] <1>|
+ public void testLayout7KeyAuto3R0() {
+ MoreKeysKeyboardParams params = createParams(7, 3, XPOS_R0);
+ assertEquals("7 key auto 3 R0 columns", 3, params.mNumColumns);
+ assertEquals("7 key auto 3 R0 rows", 3, params.mNumRows);
+ assertEquals("7 key auto 3 R0 left", 2, params.mLeftKeys);
+ assertEquals("7 key auto 3 R0 right", 1, params.mRightKeys);
+ assertEquals("7 key auto 3 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 3 R0 [2]", -1, params.getColumnPos(1));
+ assertEquals("7 key auto 3 R0 [3]", -2, params.getColumnPos(2));
+ assertEquals("7 key auto 3 R0 [4]", 0, params.getColumnPos(3));
+ assertEquals("7 key auto 3 R0 [5]", -1, params.getColumnPos(4));
+ assertEquals("7 key auto 3 R0 [6]", -2, params.getColumnPos(5));
+ assertEquals("7 key auto 3 R0 [7]", 0, params.getColumnPos(6));
+ assertEquals("7 key auto 3 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 3 R0 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // [7] ___|
+ // [6] [5] [4] ___|
+ // [3] [2] <1> ___|
+ public void testLayout7KeyAuto3R1() {
+ MoreKeysKeyboardParams params = createParams(7, 3, XPOS_R1);
+ assertEquals("7 key auto 3 R1 columns", 3, params.mNumColumns);
+ assertEquals("7 key auto 3 R1 rows", 3, params.mNumRows);
+ assertEquals("7 key auto 3 R1 left", 2, params.mLeftKeys);
+ assertEquals("7 key auto 3 R1 right", 1, params.mRightKeys);
+ assertEquals("7 key auto 3 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 3 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("7 key auto 3 R1 [3]", -2, params.getColumnPos(2));
+ assertEquals("7 key auto 3 R1 [4]", 0, params.getColumnPos(3));
+ assertEquals("7 key auto 3 R1 [5]", -1, params.getColumnPos(4));
+ assertEquals("7 key auto 3 R1 [6]", -2, params.getColumnPos(5));
+ assertEquals("7 key auto 3 R1 [7]", 0, params.getColumnPos(6));
+ assertEquals("7 key auto 3 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 3 R1 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // [7] ___|
+ // [6] [4] [5] ___|
+ // [3] <1> [2] ___|
+ public void testLayout7KeyAuto3R2() {
+ MoreKeysKeyboardParams params = createParams(7, 3, XPOS_R2);
+ assertEquals("7 key auto 3 R2 columns", 3, params.mNumColumns);
+ assertEquals("7 key auto 3 R2 rows", 3, params.mNumRows);
+ assertEquals("7 key auto 3 R2 left", 1, params.mLeftKeys);
+ assertEquals("7 key auto 3 R2 right", 2, params.mRightKeys);
+ assertEquals("7 key auto 3 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("7 key auto 3 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("7 key auto 3 R2 [3]", -1, params.getColumnPos(2));
+ assertEquals("7 key auto 3 R2 [4]", 0, params.getColumnPos(3));
+ assertEquals("7 key auto 3 R2 [5]", 1, params.getColumnPos(4));
+ assertEquals("7 key auto 3 R2 [6]", -1, params.getColumnPos(5));
+ assertEquals("7 key auto 3 R2 [7]", 0, params.getColumnPos(6));
+ assertEquals("7 key auto 3 R2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("7 key auto 3 R2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [8] [6] [7]
+ // [5] [3] <1> [2] [4]
+ public void testLayout8KeyAuto5M0() {
+ MoreKeysKeyboardParams params = createParams(8, 5, XPOS_M0);
+ assertEquals("8 key auto 5 M0 columns", 5, params.mNumColumns);
+ assertEquals("8 key auto 5 M0 rows", 2, params.mNumRows);
+ assertEquals("8 key auto 5 M0 left", 2, params.mLeftKeys);
+ assertEquals("8 key auto 5 M0 right", 3, params.mRightKeys);
+ assertEquals("8 key auto 5 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("8 key auto 5 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("8 key auto 5 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("8 key auto 5 M0 [4]", 2, params.getColumnPos(3));
+ assertEquals("8 key auto 5 M0 [5]", -2, params.getColumnPos(4));
+ assertEquals("8 key auto 5 M0 [6]", 0, params.getColumnPos(5));
+ assertEquals("8 key auto 5 M0 [7]", 1, params.getColumnPos(6));
+ assertEquals("8 key auto 5 M0 [8]", -1, params.getColumnPos(7));
+ assertEquals("8 key auto 5 M0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("8 key auto 5 M0 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // |[6] [7] [8]
+ // |<1> [2] [3] [4] [5]
+ public void testLayout8KeyAuto5L0() {
+ MoreKeysKeyboardParams params = createParams(8, 5, XPOS_L0);
+ assertEquals("8 key auto 5 L0 columns", 5, params.mNumColumns);
+ assertEquals("8 key auto 5 L0 rows", 2, params.mNumRows);
+ assertEquals("8 key auto 5 L0 left", 0, params.mLeftKeys);
+ assertEquals("8 key auto 5 L0 right", 5, params.mRightKeys);
+ assertEquals("8 key auto 5 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("8 key auto 5 L0 [2]", 1, params.getColumnPos(1));
+ assertEquals("8 key auto 5 L0 [3]", 2, params.getColumnPos(2));
+ assertEquals("8 key auto 5 L0 [4]", 3, params.getColumnPos(3));
+ assertEquals("8 key auto 5 L0 [5]", 4, params.getColumnPos(4));
+ assertEquals("8 key auto 5 L0 [6]", 0, params.getColumnPos(5));
+ assertEquals("8 key auto 5 L0 [7]", 1, params.getColumnPos(6));
+ assertEquals("8 key auto 5 L0 [8]", 2, params.getColumnPos(7));
+ assertEquals("8 key auto 5 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("8 key auto 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [6] [7] [8]
+ // |___ <1> [2] [3] [4] [5]
+ public void testLayout8KeyAuto5L1() {
+ MoreKeysKeyboardParams params = createParams(8, 5, XPOS_L1);
+ assertEquals("8 key auto 5 L1 columns", 5, params.mNumColumns);
+ assertEquals("8 key auto 5 L1 rows", 2, params.mNumRows);
+ assertEquals("8 key auto 5 L1 left", 0, params.mLeftKeys);
+ assertEquals("8 key auto 5 L1 right", 5, params.mRightKeys);
+ assertEquals("8 key auto 5 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("8 key auto 5 L1 [2]", 1, params.getColumnPos(1));
+ assertEquals("8 key auto 5 L1 [3]", 2, params.getColumnPos(2));
+ assertEquals("8 key auto 5 L1 [4]", 3, params.getColumnPos(3));
+ assertEquals("8 key auto 5 L1 [5]", 4, params.getColumnPos(4));
+ assertEquals("8 key auto 5 L1 [6]", 0, params.getColumnPos(5));
+ assertEquals("8 key auto 5 L1 [7]", 1, params.getColumnPos(6));
+ assertEquals("8 key auto 5 L1 [8]", 2, params.getColumnPos(7));
+ assertEquals("8 key auto 5 L1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("8 key auto 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [8] [6] [7]
+ // |___ [3] <1> [2] [4] [5]
+ public void testLayout8KeyAuto5L2() {
+ MoreKeysKeyboardParams params = createParams(8, 5, XPOS_L2);
+ assertEquals("8 key auto 5 L2 columns", 5, params.mNumColumns);
+ assertEquals("8 key auto 5 L2 rows", 2, params.mNumRows);
+ assertEquals("8 key auto 5 L2 left", 1, params.mLeftKeys);
+ assertEquals("8 key auto 5 L2 right", 4, params.mRightKeys);
+ assertEquals("8 key auto 5 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("8 key auto 5 L2 [2]", 1, params.getColumnPos(1));
+ assertEquals("8 key auto 5 L2 [3]", -1, params.getColumnPos(2));
+ assertEquals("8 key auto 5 L2 [4]", 2, params.getColumnPos(3));
+ assertEquals("8 key auto 5 L2 [5]", 3, params.getColumnPos(4));
+ assertEquals("8 key auto 5 L2 [6]", 0, params.getColumnPos(5));
+ assertEquals("8 key auto 5 L2 [7]", 1, params.getColumnPos(6));
+ assertEquals("8 key auto 5 L2 [8]", -1, params.getColumnPos(7));
+ assertEquals("8 key auto 5 L2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("8 key auto 5 L2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [8] [7] [6]|
+ // [5] [4] [3] [2] <1>|
+ public void testLayout8KeyAuto5R0() {
+ MoreKeysKeyboardParams params = createParams(8, 5, XPOS_R0);
+ assertEquals("8 key auto 5 R0 columns", 5, params.mNumColumns);
+ assertEquals("8 key auto 5 R0 rows", 2, params.mNumRows);
+ assertEquals("8 key auto 5 R0 left", 4, params.mLeftKeys);
+ assertEquals("8 key auto 5 R0 right", 1, params.mRightKeys);
+ assertEquals("8 key auto 5 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("8 key auto 5 R0 [2]", -1, params.getColumnPos(1));
+ assertEquals("8 key auto 5 R0 [3]", -2, params.getColumnPos(2));
+ assertEquals("8 key auto 5 R0 [4]", -3, params.getColumnPos(3));
+ assertEquals("8 key auto 5 R0 [5]", -4, params.getColumnPos(4));
+ assertEquals("8 key auto 5 R0 [6]", 0, params.getColumnPos(5));
+ assertEquals("8 key auto 5 R0 [7]", -1, params.getColumnPos(6));
+ assertEquals("8 key auto 5 R0 [8]", -2, params.getColumnPos(7));
+ assertEquals("8 key auto 5 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("8 key auto 5 R0 default", WIDTH * 4, params.getDefaultKeyCoordX());
+ }
+
+ // [8] [7] [6] ___|
+ // [5] [4] [3] [2] <1> ___|
+ public void testLayout8KeyAuto5R1() {
+ MoreKeysKeyboardParams params = createParams(8, 5, XPOS_R1);
+ assertEquals("8 key auto 5 R1 columns", 5, params.mNumColumns);
+ assertEquals("8 key auto 5 R1 rows", 2, params.mNumRows);
+ assertEquals("8 key auto 5 R1 left", 4, params.mLeftKeys);
+ assertEquals("8 key auto 5 R1 right", 1, params.mRightKeys);
+ assertEquals("8 key auto 5 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("8 key auto 5 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("8 key auto 5 R1 [3]", -2, params.getColumnPos(2));
+ assertEquals("8 key auto 5 R1 [4]", -3, params.getColumnPos(3));
+ assertEquals("8 key auto 5 R1 [5]", -4, params.getColumnPos(4));
+ assertEquals("8 key auto 5 R1 [6]", 0, params.getColumnPos(5));
+ assertEquals("8 key auto 5 R1 [7]", -1, params.getColumnPos(6));
+ assertEquals("8 key auto 5 R1 [8]", -2, params.getColumnPos(7));
+ assertEquals("8 key auto 5 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("8 key auto 5 R1 default", WIDTH * 4, params.getDefaultKeyCoordX());
+ }
+
+ // [8] [6] [7] ___|
+ // [5] [4] [3] <1> [2] ___|
+ public void testLayout8KeyAuto5R2() {
+ MoreKeysKeyboardParams params = createParams(8, 5, XPOS_R2);
+ assertEquals("8 key auto 5 R2 columns", 5, params.mNumColumns);
+ assertEquals("8 key auto 5 R2 rows", 2, params.mNumRows);
+ assertEquals("8 key auto 5 R2 left", 3, params.mLeftKeys);
+ assertEquals("8 key auto 5 R2 right", 2, params.mRightKeys);
+ assertEquals("8 key auto 5 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("8 key auto 5 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("8 key auto 5 R2 [3]", -1, params.getColumnPos(2));
+ assertEquals("8 key auto 5 R2 [4]", -2, params.getColumnPos(3));
+ assertEquals("8 key auto 5 R2 [5]", -3, params.getColumnPos(4));
+ assertEquals("8 key auto 5 R2 [6]", 0, params.getColumnPos(5));
+ assertEquals("8 key auto 5 R2 [7]", 1, params.getColumnPos(6));
+ assertEquals("8 key auto 5 R2 [8]", -1, params.getColumnPos(7));
+ assertEquals("8 key auto 5 R2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("8 key auto 5 R2 default", WIDTH * 3, params.getDefaultKeyCoordX());
+ }
+
+ // [8] [6] [7] [9]
+ // [5] [3] <1> [2] [4]
+ public void testLayout9KeyAuto5M0() {
+ MoreKeysKeyboardParams params = createParams(9, 5, XPOS_M0);
+ assertEquals("9 key auto 5 M0 columns", 5, params.mNumColumns);
+ assertEquals("9 key auto 5 M0 rows", 2, params.mNumRows);
+ assertEquals("9 key auto 5 M0 left", 2, params.mLeftKeys);
+ assertEquals("9 key auto 5 M0 right", 3, params.mRightKeys);
+ assertEquals("9 key auto 5 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("9 key auto 5 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("9 key auto 5 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("9 key auto 5 M0 [4]", 2, params.getColumnPos(3));
+ assertEquals("9 key auto 5 M0 [5]", -2, params.getColumnPos(4));
+ assertEquals("9 key auto 5 M0 [6]", 0, params.getColumnPos(5));
+ assertEquals("9 key auto 5 M0 [7]", 1, params.getColumnPos(6));
+ assertEquals("9 key auto 5 M0 [8]", -1, params.getColumnPos(7));
+ assertEquals("9 key auto 5 M0 [9]", 2, params.getColumnPos(8));
+ assertEquals("9 key auto 5 M0 adjust", -1, params.mTopRowAdjustment);
+ assertEquals("9 key auto 5 M0 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // |[6] [7] [8] [9]
+ // |<1> [2] [3] [4] [5]
+ public void testLayout9KeyAuto5L0() {
+ MoreKeysKeyboardParams params = createParams(9, 5, XPOS_L0);
+ assertEquals("9 key auto 5 L0 columns", 5, params.mNumColumns);
+ assertEquals("9 key auto 5 L0 rows", 2, params.mNumRows);
+ assertEquals("9 key auto 5 L0 left", 0, params.mLeftKeys);
+ assertEquals("9 key auto 5 L0 right", 5, params.mRightKeys);
+ assertEquals("9 key auto 5 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("9 key auto 5 L0 [2]", 1, params.getColumnPos(1));
+ assertEquals("9 key auto 5 L0 [3]", 2, params.getColumnPos(2));
+ assertEquals("9 key auto 5 L0 [4]", 3, params.getColumnPos(3));
+ assertEquals("9 key auto 5 L0 [5]", 4, params.getColumnPos(4));
+ assertEquals("9 key auto 5 L0 [6]", 0, params.getColumnPos(5));
+ assertEquals("9 key auto 5 L0 [7]", 1, params.getColumnPos(6));
+ assertEquals("9 key auto 5 L0 [8]", 2, params.getColumnPos(7));
+ assertEquals("9 key auto 5 L0 [9]", 3, params.getColumnPos(8));
+ assertEquals("9 key auto 5 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("9 key auto 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [6] [7] [8] [9]
+ // |___ <1> [2] [3] [4] [5]
+ public void testLayout9KeyAuto5L1() {
+ MoreKeysKeyboardParams params = createParams(9, 5, XPOS_L1);
+ assertEquals("9 key auto 5 L1 columns", 5, params.mNumColumns);
+ assertEquals("9 key auto 5 L1 rows", 2, params.mNumRows);
+ assertEquals("9 key auto 5 L1 left", 0, params.mLeftKeys);
+ assertEquals("9 key auto 5 L1 right", 5, params.mRightKeys);
+ assertEquals("9 key auto 5 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("9 key auto 5 L1 [2]", 1, params.getColumnPos(1));
+ assertEquals("9 key auto 5 L1 [3]", 2, params.getColumnPos(2));
+ assertEquals("9 key auto 5 L1 [4]", 3, params.getColumnPos(3));
+ assertEquals("9 key auto 5 L1 [5]", 4, params.getColumnPos(4));
+ assertEquals("9 key auto 5 L1 [6]", 0, params.getColumnPos(5));
+ assertEquals("9 key auto 5 L1 [7]", 1, params.getColumnPos(6));
+ assertEquals("9 key auto 5 L1 [8]", 2, params.getColumnPos(7));
+ assertEquals("9 key auto 5 L1 [9]", 3, params.getColumnPos(8));
+ assertEquals("9 key auto 5 L1 adjust",0, params.mTopRowAdjustment);
+ assertEquals("9 key auto 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [6] [7] [8] [9]
+ // |___ [3] <1> [2] [4] [5]
+ public void testLayout9KeyAuto5L2() {
+ MoreKeysKeyboardParams params = createParams(9, 5, XPOS_L2);
+ assertEquals("9 key auto 5 L2 columns", 5, params.mNumColumns);
+ assertEquals("9 key auto 5 L2 rows", 2, params.mNumRows);
+ assertEquals("9 key auto 5 L2 left", 1, params.mLeftKeys);
+ assertEquals("9 key auto 5 L2 right", 4, params.mRightKeys);
+ assertEquals("9 key auto 5 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("9 key auto 5 L2 [2]", 1, params.getColumnPos(1));
+ assertEquals("9 key auto 5 L2 [3]", -1, params.getColumnPos(2));
+ assertEquals("9 key auto 5 L2 [4]", 2, params.getColumnPos(3));
+ assertEquals("9 key auto 5 L2 [5]", 3, params.getColumnPos(4));
+ assertEquals("9 key auto 5 L2 [6]", 0, params.getColumnPos(5));
+ assertEquals("9 key auto 5 L2 [7]", 1, params.getColumnPos(6));
+ assertEquals("9 key auto 5 L2 [8]", 2, params.getColumnPos(7));
+ assertEquals("9 key auto 5 L2 [9]", 3, params.getColumnPos(8));
+ assertEquals("9 key auto 5 L2 adjust", -1, params.mTopRowAdjustment);
+ assertEquals("9 key auto 5 L2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [9] [8] [7] [6]|
+ // [5] [4] [3] [2] <1>|
+ public void testLayout9KeyAuto5R0() {
+ MoreKeysKeyboardParams params = createParams(9, 5, XPOS_R0);
+ assertEquals("9 key auto 5 R0 columns", 5, params.mNumColumns);
+ assertEquals("9 key auto 5 R0 rows", 2, params.mNumRows);
+ assertEquals("9 key auto 5 R0 left", 4, params.mLeftKeys);
+ assertEquals("9 key auto 5 R0 right", 1, params.mRightKeys);
+ assertEquals("9 key auto 5 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("9 key auto 5 R0 [2]", -1, params.getColumnPos(1));
+ assertEquals("9 key auto 5 R0 [3]", -2, params.getColumnPos(2));
+ assertEquals("9 key auto 5 R0 [4]", -3, params.getColumnPos(3));
+ assertEquals("9 key auto 5 R0 [5]", -4, params.getColumnPos(4));
+ assertEquals("9 key auto 5 R0 [6]", 0, params.getColumnPos(5));
+ assertEquals("9 key auto 5 R0 [7]", -1, params.getColumnPos(6));
+ assertEquals("9 key auto 5 R0 [8]", -2, params.getColumnPos(7));
+ assertEquals("9 key auto 5 R0 [9]", -3, params.getColumnPos(8));
+ assertEquals("9 key auto 5 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("9 key auto 5 R0 default", WIDTH * 4, params.getDefaultKeyCoordX());
+ }
+
+ // [9] [8] [7] [6] ___|
+ // [5] [4] [3] [2] <1> ___|
+ public void testLayout9KeyAuto5R1() {
+ MoreKeysKeyboardParams params = createParams(9, 5, XPOS_R1);
+ assertEquals("9 key auto 5 R1 columns", 5, params.mNumColumns);
+ assertEquals("9 key auto 5 R1 rows", 2, params.mNumRows);
+ assertEquals("9 key auto 5 R1 left", 4, params.mLeftKeys);
+ assertEquals("9 key auto 5 R1 right", 1, params.mRightKeys);
+ assertEquals("9 key auto 5 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("9 key auto 5 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("9 key auto 5 R1 [3]", -2, params.getColumnPos(2));
+ assertEquals("9 key auto 5 R1 [4]", -3, params.getColumnPos(3));
+ assertEquals("9 key auto 5 R1 [5]", -4, params.getColumnPos(4));
+ assertEquals("9 key auto 5 R1 [6]", 0, params.getColumnPos(5));
+ assertEquals("9 key auto 5 R1 [7]", -1, params.getColumnPos(6));
+ assertEquals("9 key auto 5 R1 [8]", -2, params.getColumnPos(7));
+ assertEquals("9 key auto 5 R1 [9]", -3, params.getColumnPos(8));
+ assertEquals("9 key auto 5 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("9 key auto 5 R1 default", WIDTH * 4, params.getDefaultKeyCoordX());
+ }
+
+ // [9] [8] [6] [7] ___|
+ // [5] [4] [3] <1> [2] ___|
+ public void testLayout9KeyAuto5R2() {
+ MoreKeysKeyboardParams params = createParams(9, 5, XPOS_R2);
+ assertEquals("9 key auto 5 R2 columns", 5, params.mNumColumns);
+ assertEquals("9 key auto 5 R2 rows", 2, params.mNumRows);
+ assertEquals("9 key auto 5 R2 left", 3, params.mLeftKeys);
+ assertEquals("9 key auto 5 R2 right", 2, params.mRightKeys);
+ assertEquals("9 key auto 5 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("9 key auto 5 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("9 key auto 5 R2 [3]", -1, params.getColumnPos(2));
+ assertEquals("9 key auto 5 R2 [4]", -2, params.getColumnPos(3));
+ assertEquals("9 key auto 5 R2 [5]", -3, params.getColumnPos(4));
+ assertEquals("9 key auto 5 R2 [6]", 0, params.getColumnPos(5));
+ assertEquals("9 key auto 5 R2 [7]", 1, params.getColumnPos(6));
+ assertEquals("9 key auto 5 R2 [8]", -1, params.getColumnPos(7));
+ assertEquals("9 key auto 5 R2 [9]", -2, params.getColumnPos(8));
+ assertEquals("9 key auto 5 R2 adjust", -1, params.mTopRowAdjustment);
+ assertEquals("9 key auto 5 R2 default", WIDTH * 3, params.getDefaultKeyCoordX());
+ }
+
+ // [A] [8] [6] [7] [9]
+ // [5] [3] <1> [2] [4]
+ public void testLayout10KeyAuto5M0() {
+ MoreKeysKeyboardParams params = createParams(10, 5, XPOS_M0);
+ assertEquals("10 key auto 5 M0 columns", 5, params.mNumColumns);
+ assertEquals("10 key auto 5 M0 rows", 2, params.mNumRows);
+ assertEquals("10 key auto 5 M0 left", 2, params.mLeftKeys);
+ assertEquals("10 key auto 5 M0 right", 3, params.mRightKeys);
+ assertEquals("10 key auto 5 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("10 key auto 5 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("10 key auto 5 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("10 key auto 5 M0 [4]", 2, params.getColumnPos(3));
+ assertEquals("10 key auto 5 M0 [5]", -2, params.getColumnPos(4));
+ assertEquals("10 key auto 5 M0 [6]", 0, params.getColumnPos(5));
+ assertEquals("10 key auto 5 M0 [7]", 1, params.getColumnPos(6));
+ assertEquals("10 key auto 5 M0 [8]", -1, params.getColumnPos(7));
+ assertEquals("10 key auto 5 M0 [9]", 2, params.getColumnPos(8));
+ assertEquals("10 key auto 5 M0 [A]", -2, params.getColumnPos(9));
+ assertEquals("10 key auto 5 M0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("10 key auto 5 M0 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // |[6] [7] [8] [9] [A]
+ // |<1> [2] [3] [4] [5]
+ public void testLayout10KeyAuto5L0() {
+ MoreKeysKeyboardParams params = createParams(10, 5, XPOS_L0);
+ assertEquals("10 key auto 5 L0 columns", 5, params.mNumColumns);
+ assertEquals("10 key auto 5 L0 rows", 2, params.mNumRows);
+ assertEquals("10 key auto 5 L0 left", 0, params.mLeftKeys);
+ assertEquals("10 key auto 5 L0 right", 5, params.mRightKeys);
+ assertEquals("10 key auto 5 L0 <1>", 0, params.getColumnPos(0));
+ assertEquals("10 key auto 5 L0 [2]", 1, params.getColumnPos(1));
+ assertEquals("10 key auto 5 L0 [3]", 2, params.getColumnPos(2));
+ assertEquals("10 key auto 5 L0 [4]", 3, params.getColumnPos(3));
+ assertEquals("10 key auto 5 L0 [5]", 4, params.getColumnPos(4));
+ assertEquals("10 key auto 5 L0 [6]", 0, params.getColumnPos(5));
+ assertEquals("10 key auto 5 L0 [7]", 1, params.getColumnPos(6));
+ assertEquals("10 key auto 5 L0 [8]", 2, params.getColumnPos(7));
+ assertEquals("10 key auto 5 L0 [9]", 3, params.getColumnPos(8));
+ assertEquals("10 key auto 5 L0 [A]", 4, params.getColumnPos(9));
+ assertEquals("10 key auto 5 L0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("10 key auto 5 L0 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [6] [7] [8] [9] [A]
+ // |___ <1> [2] [3] [4] [5]
+ public void testLayout10KeyAuto5L1() {
+ MoreKeysKeyboardParams params = createParams(10, 5, XPOS_L1);
+ assertEquals("10 key auto 5 L1 columns", 5, params.mNumColumns);
+ assertEquals("10 key auto 5 L1 rows", 2, params.mNumRows);
+ assertEquals("10 key auto 5 L1 left", 0, params.mLeftKeys);
+ assertEquals("10 key auto 5 L1 right", 5, params.mRightKeys);
+ assertEquals("10 key auto 5 L1 <1>", 0, params.getColumnPos(0));
+ assertEquals("10 key auto 5 L1 [2]", 1, params.getColumnPos(1));
+ assertEquals("10 key auto 5 L1 [3]", 2, params.getColumnPos(2));
+ assertEquals("10 key auto 5 L1 [4]", 3, params.getColumnPos(3));
+ assertEquals("10 key auto 5 L1 [5]", 4, params.getColumnPos(4));
+ assertEquals("10 key auto 5 L1 [6]", 0, params.getColumnPos(5));
+ assertEquals("10 key auto 5 L1 [7]", 1, params.getColumnPos(6));
+ assertEquals("10 key auto 5 L1 [8]", 2, params.getColumnPos(7));
+ assertEquals("10 key auto 5 L1 [9]", 3, params.getColumnPos(8));
+ assertEquals("10 key auto 5 L1 [A]", 4, params.getColumnPos(9));
+ assertEquals("10 key auto 5 L1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("10 key auto 5 L1 default", WIDTH * 0, params.getDefaultKeyCoordX());
+ }
+
+ // |___ [8] [6] [7] [9] [A]
+ // |___ [3] <1> [2] [4] [5]
+ public void testLayout10KeyAuto5L2() {
+ MoreKeysKeyboardParams params = createParams(10, 5, XPOS_L2);
+ assertEquals("10 key auto 5 L2 columns", 5, params.mNumColumns);
+ assertEquals("10 key auto 5 L2 rows", 2, params.mNumRows);
+ assertEquals("10 key auto 5 L2 left", 1, params.mLeftKeys);
+ assertEquals("10 key auto 5 L2 right", 4, params.mRightKeys);
+ assertEquals("10 key auto 5 L2 <1>", 0, params.getColumnPos(0));
+ assertEquals("10 key auto 5 L2 [2]", 1, params.getColumnPos(1));
+ assertEquals("10 key auto 5 L2 [3]", -1, params.getColumnPos(2));
+ assertEquals("10 key auto 5 L2 [4]", 2, params.getColumnPos(3));
+ assertEquals("10 key auto 5 L2 [5]", 3, params.getColumnPos(4));
+ assertEquals("10 key auto 5 L2 [6]", 0, params.getColumnPos(5));
+ assertEquals("10 key auto 5 L2 [7]", 1, params.getColumnPos(6));
+ assertEquals("10 key auto 5 L2 [8]", -1, params.getColumnPos(7));
+ assertEquals("10 key auto 5 L2 [9]", 2, params.getColumnPos(8));
+ assertEquals("10 key auto 5 L2 [A]", 3, params.getColumnPos(9));
+ assertEquals("10 key auto 5 L2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("10 key auto 5 L2 default", WIDTH * 1, params.getDefaultKeyCoordX());
+ }
+
+ // [A] [9] [8] [7] [6]|
+ // [5] [4] [3] [2] <1>|
+ public void testLayout10KeyAuto5R0() {
+ MoreKeysKeyboardParams params = createParams(10, 5, XPOS_R0);
+ assertEquals("10 key auto 5 R0 columns", 5, params.mNumColumns);
+ assertEquals("10 key auto 5 R0 rows", 2, params.mNumRows);
+ assertEquals("10 key auto 5 R0 left", 4, params.mLeftKeys);
+ assertEquals("10 key auto 5 R0 right", 1, params.mRightKeys);
+ assertEquals("10 key auto 5 R0 <1>", 0, params.getColumnPos(0));
+ assertEquals("10 key auto 5 R0 [2]", -1, params.getColumnPos(1));
+ assertEquals("10 key auto 5 R0 [3]", -2, params.getColumnPos(2));
+ assertEquals("10 key auto 5 R0 [4]", -3, params.getColumnPos(3));
+ assertEquals("10 key auto 5 R0 [5]", -4, params.getColumnPos(4));
+ assertEquals("10 key auto 5 R0 [6]", 0, params.getColumnPos(5));
+ assertEquals("10 key auto 5 R0 [7]", -1, params.getColumnPos(6));
+ assertEquals("10 key auto 5 R0 [8]", -2, params.getColumnPos(7));
+ assertEquals("10 key auto 5 R0 [9]", -3, params.getColumnPos(8));
+ assertEquals("10 key auto 5 R0 [A]", -4, params.getColumnPos(9));
+ assertEquals("10 key auto 5 R0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("10 key auto 5 R0 default", WIDTH * 4, params.getDefaultKeyCoordX());
+ }
+
+ // [A] [9] [8] [7] [6] ___|
+ // [5] [4] [3] [2] <1> ___|
+ public void testLayout10KeyAuto5R1() {
+ MoreKeysKeyboardParams params = createParams(10, 5, XPOS_R1);
+ assertEquals("10 key auto 5 R1 columns", 5, params.mNumColumns);
+ assertEquals("10 key auto 5 R1 rows", 2, params.mNumRows);
+ assertEquals("10 key auto 5 R1 left", 4, params.mLeftKeys);
+ assertEquals("10 key auto 5 R1 right", 1, params.mRightKeys);
+ assertEquals("10 key auto 5 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("10 key auto 5 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("10 key auto 5 R1 [3]", -2, params.getColumnPos(2));
+ assertEquals("10 key auto 5 R1 [4]", -3, params.getColumnPos(3));
+ assertEquals("10 key auto 5 R1 [5]", -4, params.getColumnPos(4));
+ assertEquals("10 key auto 5 R1 [6]", 0, params.getColumnPos(5));
+ assertEquals("10 key auto 5 R1 [7]", -1, params.getColumnPos(6));
+ assertEquals("10 key auto 5 R1 [8]", -2, params.getColumnPos(7));
+ assertEquals("10 key auto 5 R1 [9]", -3, params.getColumnPos(8));
+ assertEquals("10 key auto 5 R1 [A]", -4, params.getColumnPos(9));
+ assertEquals("10 key auto 5 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("10 key auto 5 R1 default", WIDTH * 4, params.getDefaultKeyCoordX());
+ }
+
+ // [A] [9] [8] [6] [7] ___|
+ // [5] [4] [3] <1> [2] ___|
+ public void testLayout10KeyAuto5R2() {
+ MoreKeysKeyboardParams params = createParams(10, 5, XPOS_R2);
+ assertEquals("10 key auto 5 R2 columns", 5, params.mNumColumns);
+ assertEquals("10 key auto 5 R2 rows", 2, params.mNumRows);
+ assertEquals("10 key auto 5 R2 left", 3, params.mLeftKeys);
+ assertEquals("10 key auto 5 R2 right", 2, params.mRightKeys);
+ assertEquals("10 key auto 5 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("10 key auto 5 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("10 key auto 5 R2 [3]", -1, params.getColumnPos(2));
+ assertEquals("10 key auto 5 R2 [4]", -2, params.getColumnPos(3));
+ assertEquals("10 key auto 5 R2 [5]", -3, params.getColumnPos(4));
+ assertEquals("10 key auto 5 R2 [6]", 0, params.getColumnPos(5));
+ assertEquals("10 key auto 5 R2 [7]", 1, params.getColumnPos(6));
+ assertEquals("10 key auto 5 R2 [8]", -1, params.getColumnPos(7));
+ assertEquals("10 key auto 5 R2 [9]", -2, params.getColumnPos(8));
+ assertEquals("10 key auto 5 R2 [A]", -3, params.getColumnPos(9));
+ assertEquals("10 key auto 5 R2 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("10 key auto 5 R2 default", WIDTH * 3, params.getDefaultKeyCoordX());
+ }
+
+ // [B]
+ // [A] [8] [6] [7] [9]
+ // [5] [3] <1> [2] [4]
+ public void testLayout11KeyAuto5M0() {
+ MoreKeysKeyboardParams params = createParams(11, 5, XPOS_M0);
+ assertEquals("11 key auto 5 M0 columns", 5, params.mNumColumns);
+ assertEquals("11 key auto 5 M0 rows", 3, params.mNumRows);
+ assertEquals("11 key auto 5 M0 left", 2, params.mLeftKeys);
+ assertEquals("11 key auto 5 M0 right", 3, params.mRightKeys);
+ assertEquals("11 key auto 5 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("11 key auto 5 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("11 key auto 5 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("11 key auto 5 M0 [4]", 2, params.getColumnPos(3));
+ assertEquals("11 key auto 5 M0 [5]", -2, params.getColumnPos(4));
+ assertEquals("11 key auto 5 M0 [6]", 0, params.getColumnPos(5));
+ assertEquals("11 key auto 5 M0 [7]", 1, params.getColumnPos(6));
+ assertEquals("11 key auto 5 M0 [8]", -1, params.getColumnPos(7));
+ assertEquals("11 key auto 5 M0 [9]", 2, params.getColumnPos(8));
+ assertEquals("11 key auto 5 M0 [A]", -2, params.getColumnPos(9));
+ assertEquals("11 key auto 5 M0 [B]", 0, params.getColumnPos(10));
+ assertEquals("11 key auto 5 M0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("11 key auto 5 M0 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // [B] [C]
+ // [A] [8] [6] [7] [9]
+ // [5] [3] <1> [2] [4]
+ public void testLayout12KeyAuto5M0() {
+ MoreKeysKeyboardParams params = createParams(12, 5, XPOS_M0);
+ assertEquals("12 key auto 5 M0 columns", 5, params.mNumColumns);
+ assertEquals("12 key auto 5 M0 rows", 3, params.mNumRows);
+ assertEquals("12 key auto 5 M0 left", 2, params.mLeftKeys);
+ assertEquals("12 key auto 5 M0 right", 3, params.mRightKeys);
+ assertEquals("12 key auto 5 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("12 key auto 5 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("12 key auto 5 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("12 key auto 5 M0 [4]", 2, params.getColumnPos(3));
+ assertEquals("12 key auto 5 M0 [5]", -2, params.getColumnPos(4));
+ assertEquals("12 key auto 5 M0 [6]", 0, params.getColumnPos(5));
+ assertEquals("12 key auto 5 M0 [7]", 1, params.getColumnPos(6));
+ assertEquals("12 key auto 5 M0 [8]", -1, params.getColumnPos(7));
+ assertEquals("12 key auto 5 M0 [9]", 2, params.getColumnPos(8));
+ assertEquals("12 key auto 5 M0 [A]", -2, params.getColumnPos(9));
+ assertEquals("12 key auto 5 M0 [B]", 0, params.getColumnPos(10));
+ assertEquals("12 key auto 5 M0 [C]", 1, params.getColumnPos(11));
+ assertEquals("12 key auto 5 M0 adjust", -1, params.mTopRowAdjustment);
+ assertEquals("12 key auto 5 M0 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // [D] [B] [C]
+ // [A] [8] [6] [7] [9]
+ // [5] [3] <1> [2] [4]
+ public void testLayout13KeyAuto5M0() {
+ MoreKeysKeyboardParams params = createParams(13, 5, XPOS_M0);
+ assertEquals("13 key auto 5 M0 columns", 5, params.mNumColumns);
+ assertEquals("13 key auto 5 M0 rows", 3, params.mNumRows);
+ assertEquals("13 key auto 5 M0 left", 2, params.mLeftKeys);
+ assertEquals("13 key auto 5 M0 right", 3, params.mRightKeys);
+ assertEquals("13 key auto 5 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("13 key auto 5 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("13 key auto 5 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("13 key auto 5 M0 [4]", 2, params.getColumnPos(3));
+ assertEquals("13 key auto 5 M0 [5]", -2, params.getColumnPos(4));
+ assertEquals("13 key auto 5 M0 [6]", 0, params.getColumnPos(5));
+ assertEquals("13 key auto 5 M0 [7]", 1, params.getColumnPos(6));
+ assertEquals("13 key auto 5 M0 [8]", -1, params.getColumnPos(7));
+ assertEquals("13 key auto 5 M0 [9]", 2, params.getColumnPos(8));
+ assertEquals("13 key auto 5 M0 [A]", -2, params.getColumnPos(9));
+ assertEquals("13 key auto 5 M0 [B]", 0, params.getColumnPos(10));
+ assertEquals("13 key auto 5 M0 [C]", 1, params.getColumnPos(11));
+ assertEquals("13 key auto 5 M0 [D]", -1, params.getColumnPos(12));
+ assertEquals("13 key auto 5 M0 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("13 key auto 5 M0 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // [D] [B] [C] [E]
+ // [A] [8] [6] [7] [9]
+ // [5] [3] <1> [2] [4]
+ public void testLayout14KeyAuto5M0() {
+ MoreKeysKeyboardParams params = createParams(14, 5, XPOS_M0);
+ assertEquals("13 key auto 5 M0 columns", 5, params.mNumColumns);
+ assertEquals("13 key auto 5 M0 rows", 3, params.mNumRows);
+ assertEquals("13 key auto 5 M0 left", 2, params.mLeftKeys);
+ assertEquals("13 key auto 5 M0 right", 3, params.mRightKeys);
+ assertEquals("13 key auto 5 M0 <1>", 0, params.getColumnPos(0));
+ assertEquals("13 key auto 5 M0 [2]", 1, params.getColumnPos(1));
+ assertEquals("13 key auto 5 M0 [3]", -1, params.getColumnPos(2));
+ assertEquals("13 key auto 5 M0 [4]", 2, params.getColumnPos(3));
+ assertEquals("13 key auto 5 M0 [5]", -2, params.getColumnPos(4));
+ assertEquals("13 key auto 5 M0 [6]", 0, params.getColumnPos(5));
+ assertEquals("13 key auto 5 M0 [7]", 1, params.getColumnPos(6));
+ assertEquals("13 key auto 5 M0 [8]", -1, params.getColumnPos(7));
+ assertEquals("13 key auto 5 M0 [9]", 2, params.getColumnPos(8));
+ assertEquals("13 key auto 5 M0 [A]", -2, params.getColumnPos(9));
+ assertEquals("13 key auto 5 M0 [B]", 0, params.getColumnPos(10));
+ assertEquals("13 key auto 5 M0 [C]", 1, params.getColumnPos(11));
+ assertEquals("13 key auto 5 M0 [D]", -1, params.getColumnPos(12));
+ assertEquals("13 key auto 5 M0 [E]", 2, params.getColumnPos(13));
+ assertEquals("13 key auto 5 M0 adjust", -1, params.mTopRowAdjustment);
+ assertEquals("13 key auto 5 M0 default", WIDTH * 2, params.getDefaultKeyCoordX());
+ }
+
+ // [J] [I] [H] ___|
+ // [G] [F] [E] [D] [C] [B] [A] [9] ___|
+ // [8] [7] [6] [5] [4] [3] [2] <1> ___|
+ public void testLayout19KeyAuto8R1() {
+ MoreKeysKeyboardParams params = createParams(19, 8, XPOS_R1);
+ assertEquals("19 key auto 8 R1 columns", 8, params.mNumColumns);
+ assertEquals("19 key auto 8 R1 rows", 3, params.mNumRows);
+ assertEquals("19 key auto 8 R1 left", 7, params.mLeftKeys);
+ assertEquals("19 key auto 8 R1 right", 1, params.mRightKeys);
+ assertEquals("19 key auto 8 R1 <1>", 0, params.getColumnPos(0));
+ assertEquals("19 key auto 8 R1 [2]", -1, params.getColumnPos(1));
+ assertEquals("19 key auto 8 R1 [3]", -2, params.getColumnPos(2));
+ assertEquals("19 key auto 8 R1 [4]", -3, params.getColumnPos(3));
+ assertEquals("19 key auto 8 R1 [5]", -4, params.getColumnPos(4));
+ assertEquals("19 key auto 8 R1 [6]", -5, params.getColumnPos(5));
+ assertEquals("19 key auto 8 R1 [7]", -6, params.getColumnPos(6));
+ assertEquals("19 key auto 8 R1 [8]", -7, params.getColumnPos(7));
+ assertEquals("19 key auto 8 R1 [9]", 0, params.getColumnPos(8));
+ assertEquals("19 key auto 8 R1 [A]", -1, params.getColumnPos(9));
+ assertEquals("19 key auto 8 R1 [B]", -2, params.getColumnPos(10));
+ assertEquals("19 key auto 8 R1 [C]", -3, params.getColumnPos(11));
+ assertEquals("19 key auto 8 R1 [D]", -4, params.getColumnPos(12));
+ assertEquals("19 key auto 8 R1 [E]", -5, params.getColumnPos(13));
+ assertEquals("19 key auto 8 R1 [F]", -6, params.getColumnPos(14));
+ assertEquals("19 key auto 8 R1 [G]", -7, params.getColumnPos(15));
+ assertEquals("19 key auto 8 R1 [H]", 0, params.getColumnPos(16));
+ assertEquals("19 key auto 8 R1 [I]", -1, params.getColumnPos(17));
+ assertEquals("19 key auto 8 R1 [J]", -2, params.getColumnPos(18));
+ assertEquals("19 key auto 8 R1 adjust", 0, params.mTopRowAdjustment);
+ assertEquals("19 key auto 8 R1 default", WIDTH * 7, params.getDefaultKeyCoordX());
+ }
+
+ // [J] [H] [I] ___|
+ // [G] [F] [E] [D] [C] [B] [9] [A] ___|
+ // [8] [7] [6] [5] [4] [3] <1> [2] ___|
+ public void testLayout19KeyAuto8R2() {
+ MoreKeysKeyboardParams params = createParams(19, 8, XPOS_R2);
+ assertEquals("19 key auto 8 R2 columns", 8, params.mNumColumns);
+ assertEquals("19 key auto 8 R2 rows", 3, params.mNumRows);
+ assertEquals("19 key auto 8 R2 left", 6, params.mLeftKeys);
+ assertEquals("19 key auto 8 R2 right", 2, params.mRightKeys);
+ assertEquals("19 key auto 8 R2 <1>", 0, params.getColumnPos(0));
+ assertEquals("19 key auto 8 R2 [2]", 1, params.getColumnPos(1));
+ assertEquals("19 key auto 8 R2 [3]", -1, params.getColumnPos(2));
+ assertEquals("19 key auto 8 R2 [4]", -2, params.getColumnPos(3));
+ assertEquals("19 key auto 8 R2 [5]", -3, params.getColumnPos(4));
+ assertEquals("19 key auto 8 R2 [6]", -4, params.getColumnPos(5));
+ assertEquals("19 key auto 8 R2 [7]", -5, params.getColumnPos(6));
+ assertEquals("19 key auto 8 R2 [8]", -6, params.getColumnPos(7));
+ assertEquals("19 key auto 8 R2 [9]", 0, params.getColumnPos(8));
+ assertEquals("19 key auto 8 R2 [A]", 1, params.getColumnPos(9));
+ assertEquals("19 key auto 8 R2 [B]", -1, params.getColumnPos(10));
+ assertEquals("19 key auto 8 R2 [C]", -2, params.getColumnPos(11));
+ assertEquals("19 key auto 8 R2 [D]", -3, params.getColumnPos(12));
+ assertEquals("19 key auto 8 R2 [E]", -4, params.getColumnPos(13));
+ assertEquals("19 key auto 8 R2 [F]", -5, params.getColumnPos(14));
+ assertEquals("19 key auto 8 R2 [G]", -6, params.getColumnPos(15));
+ assertEquals("19 key auto 8 R2 [H]", 0, params.getColumnPos(16));
+ assertEquals("19 key auto 8 R2 [I]", 1, params.getColumnPos(17));
+ assertEquals("19 key auto 8 R2 [J]", -1, params.getColumnPos(18));
+ assertEquals("19 key auto 8 R2 adjust", -1, params.mTopRowAdjustment);
+ assertEquals("19 key auto 8 R2 default", WIDTH * 6, params.getDefaultKeyCoordX());
+ }
+
+ // [J] [H] [I] ___|
+ // [G] [F] [E] [D] [B] [9] [A] [C] ___|
+ // [8] [7] [6] [5] [3] <1> [2] [4] ___|
+ public void testLayout19KeyAuto8R3() {
+ MoreKeysKeyboardParams params = createParams(19, 8, XPOS_R3);
+ assertEquals("19 key auto 8 R3 columns", 8, params.mNumColumns);
+ assertEquals("19 key auto 8 R3 rows", 3, params.mNumRows);
+ assertEquals("19 key auto 8 R3 left", 5, params.mLeftKeys);
+ assertEquals("19 key auto 8 R3 right", 3, params.mRightKeys);
+ assertEquals("19 key auto 8 R3 <1>", 0, params.getColumnPos(0));
+ assertEquals("19 key auto 8 R3 [2]", 1, params.getColumnPos(1));
+ assertEquals("19 key auto 8 R3 [3]", -1, params.getColumnPos(2));
+ assertEquals("19 key auto 8 R3 [4]", 2, params.getColumnPos(3));
+ assertEquals("19 key auto 8 R3 [5]", -2, params.getColumnPos(4));
+ assertEquals("19 key auto 8 R3 [6]", -3, params.getColumnPos(5));
+ assertEquals("19 key auto 8 R3 [7]", -4, params.getColumnPos(6));
+ assertEquals("19 key auto 8 R3 [8]", -5, params.getColumnPos(7));
+ assertEquals("19 key auto 8 R3 [9]", 0, params.getColumnPos(8));
+ assertEquals("19 key auto 8 R3 [A]", 1, params.getColumnPos(9));
+ assertEquals("19 key auto 8 R3 [B]", -1, params.getColumnPos(10));
+ assertEquals("19 key auto 8 R3 [C]", 2, params.getColumnPos(11));
+ assertEquals("19 key auto 8 R3 [D]", -2, params.getColumnPos(12));
+ assertEquals("19 key auto 8 R3 [E]", -3, params.getColumnPos(13));
+ assertEquals("19 key auto 8 R3 [F]", -4, params.getColumnPos(14));
+ assertEquals("19 key auto 8 R3 [G]", -5, params.getColumnPos(15));
+ assertEquals("19 key auto 8 R3 [H]", 0, params.getColumnPos(16));
+ assertEquals("19 key auto 8 R3 [I]", 1, params.getColumnPos(17));
+ assertEquals("19 key auto 8 R3 [J]", -1, params.getColumnPos(18));
+ assertEquals("19 key auto 8 R3 adjust", -1, params.mTopRowAdjustment);
+ assertEquals("19 key auto 8 R3 default", WIDTH * 5, params.getDefaultKeyCoordX());
+ }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderFixedOrderTests.java b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderFixedOrderTests.java
index 6d9c3fdbb..7e51d955d 100644
--- a/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderFixedOrderTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderFixedOrderTests.java
@@ -47,7 +47,8 @@ public class MoreKeysKeyboardBuilderFixedOrderTests extends AndroidTestCase {
final int coordXInParent) {
final MoreKeysKeyboardParams params = new MoreKeysKeyboardParams();
params.setParameters(numKeys, columnNum, WIDTH, HEIGHT, coordXInParent, KEYBOARD_WIDTH,
- true /* isFixedOrderColumn */, 0 /* dividerWidth */);
+ true /* isMoreKeysFixedColumn */, true /* isMoreKeysFixedOrder */,
+ 0 /* dividerWidth */);
return params;
}
diff --git a/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderTests.java b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderMaxOrderTests.java
index b213721bd..806790eff 100644
--- a/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderMaxOrderTests.java
@@ -22,7 +22,7 @@ import android.test.suitebuilder.annotation.MediumTest;
import com.android.inputmethod.keyboard.MoreKeysKeyboard.MoreKeysKeyboardParams;
@MediumTest
-public class MoreKeysKeyboardBuilderTests extends AndroidTestCase {
+public class MoreKeysKeyboardBuilderMaxOrderTests extends AndroidTestCase {
private static final int WIDTH = 10;
private static final int HEIGHT = 10;
@@ -47,7 +47,8 @@ public class MoreKeysKeyboardBuilderTests extends AndroidTestCase {
final int coordXInParent) {
final MoreKeysKeyboardParams params = new MoreKeysKeyboardParams();
params.setParameters(numKeys, maxColumns, WIDTH, HEIGHT, coordXInParent, KEYBOARD_WIDTH,
- false /* isFixedOrderColumn */, 0 /* dividerWidth */);
+ false /* isMoreKeysFixedColumn */, false /* isMoreKeysFixedOrder */,
+ 0 /* dividerWidth */);
return params;
}
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecSplitTests.java b/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecSplitTests.java
index 29b169d80..922d2a8c8 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecSplitTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/MoreKeySpecSplitTests.java
@@ -53,7 +53,7 @@ public class MoreKeySpecSplitTests extends InstrumentationTestCase {
private static String[] getAllResourceIdNames(final Class<?> resourceIdClass) {
final ArrayList<String> names = new ArrayList<>();
for (final Field field : resourceIdClass.getFields()) {
- if (field.getType() == Integer.TYPE) {
+ if (field.getType() == int.class) {
names.add(field.getName());
}
}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Arabic.java b/tests/src/com/android/inputmethod/keyboard/layout/Arabic.java
index fa818654e..3f85e4baa 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Arabic.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Arabic.java
@@ -78,8 +78,7 @@ public final class Arabic extends LayoutBase {
// U+061F: "؟" ARABIC QUESTION MARK
// U+061B: "؛" ARABIC SEMICOLON
return joinKeys(key("\u060C", joinMoreKeys(
- ":", "!", "\u061F", "\u061B", "-", "\"", "'", SETTINGS_KEY)),
- "_");
+ ":", "!", "\u061F", "\u061B", "-", "\"", "'", SETTINGS_KEY)));
}
@Override
@@ -90,7 +89,7 @@ public final class Arabic extends LayoutBase {
// U+060C: "،" ARABIC COMMA
// U+061F: "؟" ARABIC QUESTION MARK
// U+061B: "؛" ARABIC SEMICOLON
- return joinKeys("/", key(".", getPunctuationMoreKeys(isPhone)));
+ return joinKeys(key(".", getPunctuationMoreKeys(isPhone)));
}
@Override
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/ArmenianPhonetic.java b/tests/src/com/android/inputmethod/keyboard/layout/ArmenianPhonetic.java
index 42ce0c1ea..2cecedceb 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/ArmenianPhonetic.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/ArmenianPhonetic.java
@@ -39,6 +39,9 @@ public final class ArmenianPhonetic extends LayoutBase {
public ArmenianPhoneticCustomizer(final Locale locale) { super(locale); }
@Override
+ public int getNumberOfRows() { return 5; }
+
+ @Override
public ExpectedKey getAlphabetKey() { return ARMENIAN_ALPHABET_KEY; }
@Override
@@ -59,14 +62,14 @@ public final class ArmenianPhonetic extends LayoutBase {
public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
// U+055D: "՝" ARMENIAN COMMA
return isPhone ? joinKeys(key("\u055D", SETTINGS_KEY))
- : joinKeys(key("\u055D", SETTINGS_KEY), "_");
+ : joinKeys(key("\u055D", SETTINGS_KEY));
}
@Override
public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) {
// U+0589: "։" ARMENIAN FULL STOP
final ExpectedKey fullStopKey = key("\u0589", getPunctuationMoreKeys(isPhone));
- return isPhone ? joinKeys(fullStopKey) : joinKeys("/", fullStopKey);
+ return joinKeys(fullStopKey);
}
@Override
@@ -112,29 +115,6 @@ public final class ArmenianPhonetic extends LayoutBase {
return builder.build();
}
- // Helper method to create alphabet layout by adding special function keys.
- @Override
- ExpectedKeyboardBuilder convertCommonLayoutToKeyboard(final ExpectedKeyboardBuilder builder,
- final boolean isPhone) {
- final LayoutCustomizer customizer = getCustomizer();
- builder.setKeysOfRow(5, (Object[])customizer.getSpaceKeys(isPhone));
- builder.addKeysOnTheLeftOfRow(5, (Object[])customizer.getKeysLeftToSpacebar(isPhone));
- builder.addKeysOnTheRightOfRow(5, (Object[])customizer.getKeysRightToSpacebar(isPhone));
- if (isPhone) {
- builder.addKeysOnTheRightOfRow(4, DELETE_KEY)
- .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey())
- .addKeysOnTheRightOfRow(5, key(ENTER_KEY, EMOJI_KEY));
- } else {
- builder.addKeysOnTheRightOfRow(1, DELETE_KEY)
- .addKeysOnTheRightOfRow(3, ENTER_KEY)
- .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey())
- .addKeysOnTheRightOfRow(5, EMOJI_KEY);
- }
- builder.addKeysOnTheLeftOfRow(4, (Object[])customizer.getLeftShiftKeys(isPhone))
- .addKeysOnTheRightOfRow(4, (Object[])customizer.getRightShiftKeys(isPhone));
- return builder;
- }
-
private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder()
.setKeysOfRow(1,
// U+0567: "է" ARMENIAN SMALL LETTER EH
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Dvorak.java b/tests/src/com/android/inputmethod/keyboard/layout/Dvorak.java
index e75cfd0ff..ba94c8dee 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Dvorak.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Dvorak.java
@@ -20,13 +20,14 @@ import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKey.ExpectedAdditionalMoreKey;
+import com.android.inputmethod.latin.settings.CustomInputStyleSettingsFragment;
import java.util.Locale;
/**
- * The QWERTY alphabet keyboard.
+ * The Dvorak alphabet keyboard.
*/
-public final class Dvorak extends LayoutBase {
+public class Dvorak extends LayoutBase {
private static final String LAYOUT_NAME = "dvorak";
public Dvorak(final LayoutCustomizer customizer) {
@@ -51,17 +52,19 @@ public final class Dvorak extends LayoutBase {
@Override
public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
- return isPhone ? joinKeys(key("q", SETTINGS_KEY)) :
- joinKeys(SETTINGS_KEY, key("_", moreKey("-")));
+ // U+00A1: "¡" INVERTED EXCLAMATION MARK
+ return isPhone ? joinKeys(key("q", SETTINGS_KEY))
+ : joinKeys(key("!", joinMoreKeys("\u00A1", SETTINGS_KEY)));
}
@Override
public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) {
final ExpectedAdditionalMoreKey[] punctuationMoreKeys =
convertToAdditionalMoreKeys(getPunctuationMoreKeys(isPhone));
+ // U+00BF: "¿" INVERTED QUESTION MARK
return isPhone
? joinKeys(key("z", punctuationMoreKeys))
- : joinKeys("/", key("?", moreKey("!")));
+ : joinKeys(key("?", joinMoreKeys(punctuationMoreKeys, "\u00BF")));
}
private static ExpectedAdditionalMoreKey[] convertToAdditionalMoreKeys(
@@ -76,7 +79,33 @@ public final class Dvorak extends LayoutBase {
}
@Override
- ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; }
+ public ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) {
+ return ALPHABET_COMMON;
+ }
+
+ protected ExpectedKey getRow1_1Key(final boolean isPhone, final int elementId) {
+ if (elementId == KeyboardId.ELEMENT_ALPHABET
+ || elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) {
+ return key("'", joinMoreKeys(additionalMoreKey("1"), "!", "\""));
+ }
+ return key("\"", additionalMoreKey("1"));
+ }
+
+ protected ExpectedKey getRow1_2Key(final boolean isPhone, final int elementId) {
+ if (elementId == KeyboardId.ELEMENT_ALPHABET
+ || elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) {
+ return key(",", joinMoreKeys(additionalMoreKey("2"), "?", "<"));
+ }
+ return key("<", additionalMoreKey("2"));
+ }
+
+ protected ExpectedKey getRow1_3Key(final boolean isPhone, final int elementId) {
+ if (elementId == KeyboardId.ELEMENT_ALPHABET
+ || elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) {
+ return key(".", joinMoreKeys(additionalMoreKey("3"), ">"));
+ }
+ return key(">", additionalMoreKey("3"));
+ }
@Override
public ExpectedKey[][] getLayout(final boolean isPhone, final int elementId) {
@@ -86,18 +115,9 @@ public final class Dvorak extends LayoutBase {
}
final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(
getCommonAlphabetLayout(isPhone));
- if (elementId == KeyboardId.ELEMENT_ALPHABET
- || elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) {
- builder.addKeysOnTheLeftOfRow(1,
- key("'", joinMoreKeys(additionalMoreKey("1"), "!", "\"")),
- key(",", joinMoreKeys(additionalMoreKey("2"), "?", "<")),
- key(".", joinMoreKeys(additionalMoreKey("3"), ">")));
- } else {
- builder.addKeysOnTheLeftOfRow(1,
- key("\"", additionalMoreKey("1")),
- key("<", additionalMoreKey("2")),
- key(">", additionalMoreKey("3")));
- }
+ builder.replaceKeyOfLabel(ROW1_1, getRow1_1Key(isPhone, elementId))
+ .replaceKeyOfLabel(ROW1_2, getRow1_2Key(isPhone, elementId))
+ .replaceKeyOfLabel(ROW1_3, getRow1_3Key(isPhone, elementId));
convertCommonLayoutToKeyboard(builder, isPhone);
getCustomizer().setAccentedLetters(builder);
if (elementId != KeyboardId.ELEMENT_ALPHABET) {
@@ -107,8 +127,13 @@ public final class Dvorak extends LayoutBase {
return builder.build();
}
+ public static final String ROW1_1 = "ROW1_1";
+ public static final String ROW1_2 = "ROW1_2";
+ public static final String ROW1_3 = "ROW1_3";
+
private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder()
.setKeysOfRow(1,
+ ROW1_1, ROW1_2, ROW1_3,
key("p", additionalMoreKey("4")),
key("y", additionalMoreKey("5")),
key("f", additionalMoreKey("6")),
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Farsi.java b/tests/src/com/android/inputmethod/keyboard/layout/Farsi.java
index a513740e7..7390457d0 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Farsi.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Farsi.java
@@ -77,8 +77,7 @@ public final class Farsi extends LayoutBase {
// U+061B: "؛" ARABIC SEMICOLON
return joinKeys(key("\u060C", joinMoreKeys(
":", "!", "\u061F", "\u061B", "-", RtlSymbols.DOUBLE_ANGLE_QUOTES_LR_RTL,
- SETTINGS_KEY)),
- "_");
+ SETTINGS_KEY)));
}
@Override
@@ -86,7 +85,7 @@ public final class Farsi extends LayoutBase {
if (isPhone) {
return super.getKeysRightToSpacebar(isPhone);
}
- return joinKeys("/", key(".", getPunctuationMoreKeys(isPhone)));
+ return joinKeys(key(".", getPunctuationMoreKeys(isPhone)));
}
@Override
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/HindiCompact.java b/tests/src/com/android/inputmethod/keyboard/layout/HindiCompact.java
index 2b625c32b..c2a15f3f3 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/HindiCompact.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/HindiCompact.java
@@ -50,7 +50,7 @@ public final class HindiCompact extends LayoutBase {
public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) {
// U+0964: "।" DEVANAGARI DANDA
final ExpectedKey periodKey = key("\u0964", getPunctuationMoreKeys(isPhone));
- return isPhone ? joinKeys(periodKey) : joinKeys("/", periodKey);
+ return joinKeys(periodKey);
}
@Override
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Kannada.java b/tests/src/com/android/inputmethod/keyboard/layout/Kannada.java
index 5ce7f4d9c..8bee1f83b 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Kannada.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Kannada.java
@@ -171,11 +171,12 @@ public final class Kannada extends LayoutBase {
// U+0C8E: "ಎ" KANNADA LETTER E
key("\u0C82", moreKey("\u0C8E")),
// U+0CAE: "ಮ" KANNADA LETTER MA
- // U+0CA3: "ಣ" KANNADA LETTER NNA
- key("\u0CAE", moreKey("\u0CA3")),
+ "\u0CAE",
// U+0CA8: "ನ" KANNADA LETTER NA
+ // U+0CA3: "ಣ" KANNADA LETTER NNA
+ key("\u0CA8", moreKey("\u0CA3")),
// U+0CB5: "ವ" KANNADA LETTER VA
- "\u0CA8", "\u0CB5",
+ "\u0CB5",
// U+0CB2: "ಲ" KANNADA LETTER LA
// U+0CB3: "ಳ" KANNADA LETTER LLA
key("\u0CB2", moreKey("\u0CB3")),
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Khmer.java b/tests/src/com/android/inputmethod/keyboard/layout/Khmer.java
index 143ccf6eb..7e4f159ab 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Khmer.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Khmer.java
@@ -40,6 +40,9 @@ public final class Khmer extends LayoutBase {
public KhmerCustomizer(final Locale locale) { super(locale); }
@Override
+ public int getNumberOfRows() { return 5; }
+
+ @Override
public ExpectedKey getAlphabetKey() { return KHMER_ALPHABET_KEY; }
@Override
@@ -79,29 +82,6 @@ public final class Khmer extends LayoutBase {
return ALPHABET_SHIFTED_COMMON;
}
- // Helper method to create alphabet layout by adding special function keys.
- @Override
- ExpectedKeyboardBuilder convertCommonLayoutToKeyboard(final ExpectedKeyboardBuilder builder,
- final boolean isPhone) {
- final LayoutCustomizer customizer = getCustomizer();
- builder.setKeysOfRow(5, (Object[])customizer.getSpaceKeys(isPhone));
- builder.addKeysOnTheLeftOfRow(5, (Object[])customizer.getKeysLeftToSpacebar(isPhone));
- builder.addKeysOnTheRightOfRow(5, (Object[])customizer.getKeysRightToSpacebar(isPhone));
- if (isPhone) {
- builder.addKeysOnTheRightOfRow(4, DELETE_KEY)
- .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey())
- .addKeysOnTheRightOfRow(5, key(ENTER_KEY, EMOJI_KEY));
- } else {
- builder.addKeysOnTheRightOfRow(1, DELETE_KEY)
- .addKeysOnTheRightOfRow(3, ENTER_KEY)
- .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey())
- .addKeysOnTheRightOfRow(5, EMOJI_KEY);
- }
- builder.addKeysOnTheLeftOfRow(4, (Object[])customizer.getLeftShiftKeys(isPhone))
- .addKeysOnTheRightOfRow(4, (Object[])customizer.getRightShiftKeys(isPhone));
- return builder;
- }
-
private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder()
.setKeysOfRow(1,
// U+17E1: "១" KHMER DIGIT ONE
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Lao.java b/tests/src/com/android/inputmethod/keyboard/layout/Lao.java
index e7be9982a..aaa1c8a8a 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Lao.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Lao.java
@@ -40,6 +40,9 @@ public final class Lao extends LayoutBase {
public LaoCustomizer(final Locale locale) { super(locale); }
@Override
+ public int getNumberOfRows() { return 5; }
+
+ @Override
public ExpectedKey getAlphabetKey() { return LAO_ALPHABET_KEY; }
@Override
@@ -83,29 +86,6 @@ public final class Lao extends LayoutBase {
return ALPHABET_SHIFTED_COMMON;
}
- // Helper method to create alphabet layout by adding special function keys.
- @Override
- ExpectedKeyboardBuilder convertCommonLayoutToKeyboard(final ExpectedKeyboardBuilder builder,
- final boolean isPhone) {
- final LayoutCustomizer customizer = getCustomizer();
- builder.setKeysOfRow(5, (Object[])customizer.getSpaceKeys(isPhone));
- builder.addKeysOnTheLeftOfRow(5, (Object[])customizer.getKeysLeftToSpacebar(isPhone));
- builder.addKeysOnTheRightOfRow(5, (Object[])customizer.getKeysRightToSpacebar(isPhone));
- if (isPhone) {
- builder.addKeysOnTheRightOfRow(4, DELETE_KEY)
- .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey())
- .addKeysOnTheRightOfRow(5, key(ENTER_KEY, EMOJI_KEY));
- } else {
- builder.addKeysOnTheRightOfRow(1, DELETE_KEY)
- .addKeysOnTheRightOfRow(3, ENTER_KEY)
- .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey())
- .addKeysOnTheRightOfRow(5, EMOJI_KEY);
- }
- builder.addKeysOnTheLeftOfRow(4, (Object[])customizer.getLeftShiftKeys(isPhone))
- .addKeysOnTheRightOfRow(4, (Object[])customizer.getRightShiftKeys(isPhone));
- return builder;
- }
-
private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder()
.setKeysOfRow(1,
// U+0EA2: "ຢ" LAO LETTER YO
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java b/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java
index c5223720c..b05789b73 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java
@@ -46,6 +46,10 @@ public abstract class LayoutBase extends AbstractLayoutBase {
return mLocale;
}
+ public int getNumberOfRows() {
+ return 4;
+ }
+
/**
* Set accented letters to common layout.
* @param builder the {@link ExpectedKeyboardBuilder} object that contains common keyboard
@@ -145,6 +149,24 @@ public abstract class LayoutBase extends AbstractLayoutBase {
}
/**
+ * Get the enter key.
+ * @param isPhone true if requesting phone's key.
+ * @return the array of {@link ExpectedKey} that should be placed as an enter key.
+ */
+ public ExpectedKey getEnterKey(final boolean isPhone) {
+ return isPhone ? key(ENTER_KEY, EMOJI_ACTION_KEY) : ENTER_KEY;
+ }
+
+ /**
+ * Get the emoji key.
+ * @param isPhone true if requesting phone's key.
+ * @return the array of {@link ExpectedKey} that should be placed as an emoji key.
+ */
+ public ExpectedKey getEmojiKey(final boolean isPhone) {
+ return EMOJI_NORMAL_KEY;
+ }
+
+ /**
* Get the space keys.
* @param isPhone true if requesting phone's keys.
* @return the array of {@link ExpectedKey} that should be placed at the center of the
@@ -161,8 +183,7 @@ public abstract class LayoutBase extends AbstractLayoutBase {
*/
public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
// U+002C: "," COMMA
- return isPhone ? joinKeys(key("\u002C", SETTINGS_KEY))
- : joinKeys(key("\u002C", SETTINGS_KEY), "_");
+ return joinKeys(key("\u002C", SETTINGS_KEY));
}
/**
@@ -172,7 +193,7 @@ public abstract class LayoutBase extends AbstractLayoutBase {
*/
public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) {
final ExpectedKey periodKey = key(".", getPunctuationMoreKeys(isPhone));
- return isPhone ? joinKeys(periodKey) : joinKeys("/", periodKey);
+ return joinKeys(periodKey);
}
/**
@@ -237,7 +258,25 @@ public abstract class LayoutBase extends AbstractLayoutBase {
*/
public final LayoutCustomizer getCustomizer() { return mCustomizer; }
- // Icon id.
+ // Icon ids.
+ private static final int ICON_DELETE = KeyboardIconsSet.getIconId(
+ KeyboardIconsSet.NAME_DELETE_KEY);
+ private static final int ICON_SPACE = KeyboardIconsSet.getIconId(
+ KeyboardIconsSet.NAME_SPACE_KEY);
+ private static final int ICON_TAB = KeyboardIconsSet.getIconId(
+ KeyboardIconsSet.NAME_TAB_KEY);
+ private static final int ICON_SHORTCUT = KeyboardIconsSet.getIconId(
+ KeyboardIconsSet.NAME_SHORTCUT_KEY);
+ private static final int ICON_SETTINGS = KeyboardIconsSet.getIconId(
+ KeyboardIconsSet.NAME_SETTINGS_KEY);
+ private static final int ICON_LANGUAGE_SWITCH = KeyboardIconsSet.getIconId(
+ KeyboardIconsSet.NAME_LANGUAGE_SWITCH_KEY);
+ private static final int ICON_ENTER = KeyboardIconsSet.getIconId(
+ KeyboardIconsSet.NAME_ENTER_KEY);
+ private static final int ICON_EMOJI_ACTION = KeyboardIconsSet.getIconId(
+ KeyboardIconsSet.NAME_EMOJI_ACTION_KEY);
+ private static final int ICON_EMOJI_NORMAL = KeyboardIconsSet.getIconId(
+ KeyboardIconsSet.NAME_EMOJI_NORMAL_KEY);
private static final int ICON_SHIFT = KeyboardIconsSet.getIconId(
KeyboardIconsSet.NAME_SHIFT_KEY);
private static final int ICON_SHIFTED_SHIFT = KeyboardIconsSet.getIconId(
@@ -247,11 +286,21 @@ public abstract class LayoutBase extends AbstractLayoutBase {
private static final int ICON_ZWJ = KeyboardIconsSet.getIconId(
KeyboardIconsSet.NAME_ZWJ_KEY);
- // Functional key.
+ // Functional keys.
+ public static final ExpectedKey DELETE_KEY = key(ICON_DELETE, Constants.CODE_DELETE);
+ public static final ExpectedKey TAB_KEY = key(ICON_TAB, Constants.CODE_TAB);
+ public static final ExpectedKey SHORTCUT_KEY = key(ICON_SHORTCUT, Constants.CODE_SHORTCUT);
+ public static final ExpectedKey SETTINGS_KEY = key(ICON_SETTINGS, Constants.CODE_SETTINGS);
+ public static final ExpectedKey LANGUAGE_SWITCH_KEY = key(
+ ICON_LANGUAGE_SWITCH, Constants.CODE_LANGUAGE_SWITCH);
+ public static final ExpectedKey ENTER_KEY = key(ICON_ENTER, Constants.CODE_ENTER);
+ public static final ExpectedKey EMOJI_ACTION_KEY = key(ICON_EMOJI_ACTION, Constants.CODE_EMOJI);
+ public static final ExpectedKey EMOJI_NORMAL_KEY = key(ICON_EMOJI_NORMAL, Constants.CODE_EMOJI);
+ public static final ExpectedKey SPACE_KEY = key(ICON_SPACE, Constants.CODE_SPACE);
static final ExpectedKey CAPSLOCK_MORE_KEY = key(" ", Constants.CODE_CAPSLOCK);
- static final ExpectedKey SHIFT_KEY = key(ICON_SHIFT,
+ public static final ExpectedKey SHIFT_KEY = key(ICON_SHIFT,
Constants.CODE_SHIFT, CAPSLOCK_MORE_KEY);
- static final ExpectedKey SHIFTED_SHIFT_KEY = key(ICON_SHIFTED_SHIFT,
+ public static final ExpectedKey SHIFTED_SHIFT_KEY = key(ICON_SHIFTED_SHIFT,
Constants.CODE_SHIFT, CAPSLOCK_MORE_KEY);
static final ExpectedKey ALPHABET_KEY = key("ABC", Constants.CODE_SWITCH_ALPHA_SYMBOL);
static final ExpectedKey SYMBOLS_KEY = key("?123", Constants.CODE_SWITCH_ALPHA_SYMBOL);
@@ -267,6 +316,9 @@ public abstract class LayoutBase extends AbstractLayoutBase {
// U+200D: ZERO WIDTH JOINER
static final ExpectedKey ZWNJ_KEY = key(ICON_ZWNJ, "\u200C");
static final ExpectedKey ZWJ_KEY = key(ICON_ZWJ, "\u200D");
+ // Domain key
+ public static final ExpectedKey DOMAIN_KEY =
+ key(".com", joinMoreKeys(".net", ".org", ".gov", ".edu")).preserveCase();
// Punctuation more keys for phone form factor.
public static final ExpectedKey[] PHONE_PUNCTUATION_MORE_KEYS = joinKeys(
@@ -277,7 +329,7 @@ public abstract class LayoutBase extends AbstractLayoutBase {
",", "'", "#", ")", "(", "/", ";",
"@", ":", "-", "\"", "+", "%", "&");
- /**
+ /**
* Helper method to create alphabet layout adding special function keys.
* @param builder the {@link ExpectedKeyboardBuilder} object that contains common keyboard
* layout
@@ -287,21 +339,26 @@ public abstract class LayoutBase extends AbstractLayoutBase {
ExpectedKeyboardBuilder convertCommonLayoutToKeyboard(final ExpectedKeyboardBuilder builder,
final boolean isPhone) {
final LayoutCustomizer customizer = getCustomizer();
- builder.setKeysOfRow(4, (Object[])customizer.getSpaceKeys(isPhone));
- builder.addKeysOnTheLeftOfRow(4, (Object[])customizer.getKeysLeftToSpacebar(isPhone));
- builder.addKeysOnTheRightOfRow(4, (Object[])customizer.getKeysRightToSpacebar(isPhone));
+ final int numberOfRows = customizer.getNumberOfRows();
+ builder.setKeysOfRow(numberOfRows, (Object[])customizer.getSpaceKeys(isPhone));
+ builder.addKeysOnTheLeftOfRow(
+ numberOfRows, (Object[])customizer.getKeysLeftToSpacebar(isPhone));
+ builder.addKeysOnTheRightOfRow(
+ numberOfRows, (Object[])customizer.getKeysRightToSpacebar(isPhone));
if (isPhone) {
- builder.addKeysOnTheRightOfRow(3, DELETE_KEY)
- .addKeysOnTheLeftOfRow(4, customizer.getSymbolsKey())
- .addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_KEY));
+ builder.addKeysOnTheRightOfRow(numberOfRows - 1, DELETE_KEY)
+ .addKeysOnTheLeftOfRow(numberOfRows, customizer.getSymbolsKey())
+ .addKeysOnTheRightOfRow(numberOfRows, customizer.getEnterKey(isPhone));
} else {
builder.addKeysOnTheRightOfRow(1, DELETE_KEY)
- .addKeysOnTheRightOfRow(2, ENTER_KEY)
- .addKeysOnTheLeftOfRow(4, customizer.getSymbolsKey())
- .addKeysOnTheRightOfRow(4, EMOJI_KEY);
+ .addKeysOnTheRightOfRow(numberOfRows - 2, customizer.getEnterKey(isPhone))
+ .addKeysOnTheLeftOfRow(numberOfRows, customizer.getSymbolsKey())
+ .addKeysOnTheRightOfRow(numberOfRows, customizer.getEmojiKey(isPhone));
}
- builder.addKeysOnTheLeftOfRow(3, (Object[])customizer.getLeftShiftKeys(isPhone))
- .addKeysOnTheRightOfRow(3, (Object[])customizer.getRightShiftKeys(isPhone));
+ builder.addKeysOnTheLeftOfRow(
+ numberOfRows - 1, (Object[])customizer.getLeftShiftKeys(isPhone));
+ builder.addKeysOnTheRightOfRow(
+ numberOfRows - 1, (Object[])customizer.getRightShiftKeys(isPhone));
return builder;
}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Myanmar.java b/tests/src/com/android/inputmethod/keyboard/layout/Myanmar.java
index f2a2dfdd8..3c70d3266 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Myanmar.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Myanmar.java
@@ -40,6 +40,9 @@ public final class Myanmar extends LayoutBase {
public MyanmarCustomizer(final Locale locale) { super(locale); }
@Override
+ public int getNumberOfRows() { return 5; }
+
+ @Override
public ExpectedKey getAlphabetKey() { return MYANMAR_ALPHABET_KEY; }
@Override
@@ -52,14 +55,14 @@ public final class Myanmar extends LayoutBase {
// U+002C: "," COMMA
// U+104A: "၊" MYANMAR SIGN LITTLE SECTION
return isPhone ? joinKeys(key("\u002C", SETTINGS_KEY))
- : joinKeys(key("\u104A", moreKey(","), SETTINGS_KEY), "_");
+ : joinKeys(key("\u104A", moreKey(","), SETTINGS_KEY));
}
@Override
public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) {
// U+104B: "။" MYANMAR SIGN SECTION
final ExpectedKey periodKey = key("\u104B", getPunctuationMoreKeys(isPhone));
- return isPhone ? joinKeys(periodKey) : joinKeys("/", periodKey);
+ return joinKeys(periodKey);
}
@Override
@@ -97,29 +100,6 @@ public final class Myanmar extends LayoutBase {
return ALPHABET_SHIFTED_COMMON;
}
- // Helper method to create alphabet layout by adding special function keys.
- @Override
- ExpectedKeyboardBuilder convertCommonLayoutToKeyboard(final ExpectedKeyboardBuilder builder,
- final boolean isPhone) {
- final LayoutCustomizer customizer = getCustomizer();
- builder.setKeysOfRow(5, (Object[])customizer.getSpaceKeys(isPhone));
- builder.addKeysOnTheLeftOfRow(5, (Object[])customizer.getKeysLeftToSpacebar(isPhone));
- builder.addKeysOnTheRightOfRow(5, (Object[])customizer.getKeysRightToSpacebar(isPhone));
- if (isPhone) {
- builder.addKeysOnTheRightOfRow(4, DELETE_KEY)
- .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey())
- .addKeysOnTheRightOfRow(5, key(ENTER_KEY, EMOJI_KEY));
- } else {
- builder.addKeysOnTheRightOfRow(1, DELETE_KEY)
- .addKeysOnTheRightOfRow(3, ENTER_KEY)
- .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey())
- .addKeysOnTheRightOfRow(5, EMOJI_KEY);
- }
- builder.addKeysOnTheLeftOfRow(4, (Object[])customizer.getLeftShiftKeys(isPhone))
- .addKeysOnTheRightOfRow(4, (Object[])customizer.getRightShiftKeys(isPhone));
- return builder;
- }
-
private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder()
.setKeysOfRow(1,
// U+1041: "၁" MYANMAR DIGIT ONE
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/PcQwerty.java b/tests/src/com/android/inputmethod/keyboard/layout/PcQwerty.java
index 9da6dcc44..3f7340fd0 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/PcQwerty.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/PcQwerty.java
@@ -39,6 +39,9 @@ public final class PcQwerty extends LayoutBase {
public PcQwertyCustomizer(final Locale locale) { super(locale); }
@Override
+ public int getNumberOfRows() { return 5; }
+
+ @Override
public ExpectedKey[] getLeftShiftKeys(final boolean isPhone) {
return joinKeys(SHIFT_KEY);
}
@@ -55,7 +58,9 @@ public final class PcQwerty extends LayoutBase {
@Override
public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) {
- return isPhone ? joinKeys(key(ENTER_KEY, EMOJI_KEY)) : joinKeys(EMOJI_KEY);
+ return isPhone
+ ? joinKeys(key(ENTER_KEY, EMOJI_ACTION_KEY))
+ : joinKeys(EMOJI_NORMAL_KEY);
}
}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Sinhala.java b/tests/src/com/android/inputmethod/keyboard/layout/Sinhala.java
index 5c0ffb4f9..354141d5a 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Sinhala.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Sinhala.java
@@ -43,6 +43,14 @@ public final class Sinhala extends LayoutBase {
public ExpectedKey getAlphabetKey() { return SINHALA_ALPHABET_KEY; }
@Override
+ public ExpectedKey getCurrencyKey() { return CURRENCY_RUPEE; }
+
+ @Override
+ public ExpectedKey[] getOtherCurrencyKeys() {
+ return SymbolsShifted.CURRENCIES_OTHER_GENERIC;
+ }
+
+ @Override
public ExpectedKey[] getRightShiftKeys(final boolean isPhone) {
return isPhone ? EMPTY_KEYS : EXCLAMATION_AND_QUESTION_MARKS;
}
@@ -51,6 +59,10 @@ public final class Sinhala extends LayoutBase {
// U+0D86: "ආ" SINHALA LETTER AAYANNA
private static final ExpectedKey SINHALA_ALPHABET_KEY = key(
"\u0D85,\u0D86", Constants.CODE_SWITCH_ALPHA_SYMBOL);
+
+ // U+0DBB/U+0DD4: "රු" SINHALA LETTER RAYANNA/SINHALA VOWEL SIGN KETTI PAA-PILLA
+ private static final ExpectedKey CURRENCY_RUPEE = key("\u0DBB\u0DD4",
+ Symbols.CURRENCY_GENERIC_MORE_KEYS);
}
@Override
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Symbols.java b/tests/src/com/android/inputmethod/keyboard/layout/Symbols.java
index 5f3e4b196..803089721 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Symbols.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Symbols.java
@@ -41,18 +41,18 @@ public class Symbols extends AbstractLayoutBase {
customizer.getSingleQuoteMoreKeys(), customizer.getSingleAngleQuoteKeys())));
if (isPhone) {
builder.addKeysOnTheLeftOfRow(3, customizer.getSymbolsShiftKey(isPhone))
- .addKeysOnTheRightOfRow(3, DELETE_KEY)
+ .addKeysOnTheRightOfRow(3, LayoutBase.DELETE_KEY)
.addKeysOnTheLeftOfRow(4, customizer.getAlphabetKey())
- .addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_KEY));
+ .addKeysOnTheRightOfRow(4, customizer.getEnterKey(isPhone));
} else {
// Tablet symbols keyboard has extra two keys at the left edge of the 3rd row.
builder.addKeysOnTheLeftOfRow(3, (Object[])joinKeys("\\", "="));
- builder.addKeysOnTheRightOfRow(1, DELETE_KEY)
- .addKeysOnTheRightOfRow(2, ENTER_KEY)
+ builder.addKeysOnTheRightOfRow(1, LayoutBase.DELETE_KEY)
+ .addKeysOnTheRightOfRow(2, customizer.getEnterKey(isPhone))
.addKeysOnTheLeftOfRow(3, customizer.getSymbolsShiftKey(isPhone))
.addKeysOnTheRightOfRow(3, customizer.getSymbolsShiftKey(isPhone))
.addKeysOnTheLeftOfRow(4, customizer.getAlphabetKey())
- .addKeysOnTheRightOfRow(4, EMOJI_KEY);
+ .addKeysOnTheRightOfRow(4, customizer.getEmojiKey(isPhone));
}
return builder.build();
}
@@ -167,7 +167,7 @@ public class Symbols extends AbstractLayoutBase {
// U+00BF: "¿" INVERTED QUESTION MARK
key("?", moreKey("\u00BF")))
.setKeysOfRow(4,
- key(","), key("_"), SPACE_KEY, key("/"),
+ key(","), key("_"), LayoutBase.SPACE_KEY, key("/"),
// U+2026: "…" HORIZONTAL ELLIPSIS
key(".", moreKey("\u2026")))
.build();
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/SymbolsShifted.java b/tests/src/com/android/inputmethod/keyboard/layout/SymbolsShifted.java
index 3265e10e1..19cb6075a 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/SymbolsShifted.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/SymbolsShifted.java
@@ -37,20 +37,20 @@ public class SymbolsShifted extends AbstractLayoutBase {
builder.replaceKeyOfLabel(OTHER_CURRENCIES, (Object[])customizer.getOtherCurrencyKeys());
if (isPhone) {
builder.addKeysOnTheLeftOfRow(3, customizer.getBackToSymbolsKey())
- .addKeysOnTheRightOfRow(3, DELETE_KEY)
+ .addKeysOnTheRightOfRow(3, LayoutBase.DELETE_KEY)
.addKeysOnTheLeftOfRow(4, customizer.getAlphabetKey())
- .addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_KEY));
+ .addKeysOnTheRightOfRow(4, customizer.getEnterKey(isPhone));
} else {
// Tablet symbols shifted keyboard has extra two keys at the right edge of the 3rd row.
// U+00BF: "¿" INVERTED QUESTION MARK
// U+00A1: "¡" INVERTED EXCLAMATION MARK
builder.addKeysOnTheRightOfRow(3, (Object[])joinKeys("\u00A1", "\u00BF"));
- builder.addKeysOnTheRightOfRow(1, DELETE_KEY)
- .addKeysOnTheRightOfRow(2, ENTER_KEY)
+ builder.addKeysOnTheRightOfRow(1, LayoutBase.DELETE_KEY)
+ .addKeysOnTheRightOfRow(2, customizer.getEnterKey(isPhone))
.addKeysOnTheLeftOfRow(3, customizer.getBackToSymbolsKey())
.addKeysOnTheRightOfRow(3, customizer.getBackToSymbolsKey())
.addKeysOnTheLeftOfRow(4, customizer.getAlphabetKey())
- .addKeysOnTheRightOfRow(4, EMOJI_KEY);
+ .addKeysOnTheRightOfRow(4, customizer.getEmojiKey(isPhone));
}
return builder.build();
}
@@ -122,7 +122,7 @@ public class SymbolsShifted extends AbstractLayoutBase {
// U+2264: "≤" LESS-THAN OR EQUAL TO
// U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
key("<", joinMoreKeys("\u2039", "\u2264", "\u00AB")),
- SPACE_KEY,
+ LayoutBase.SPACE_KEY,
// U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
// U+2265: "≥" GREATER-THAN EQUAL TO
// U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Tamil.java b/tests/src/com/android/inputmethod/keyboard/layout/Tamil.java
index 70385c7d0..597b6fa55 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Tamil.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Tamil.java
@@ -42,14 +42,6 @@ public final class Tamil extends LayoutBase {
public ExpectedKey getAlphabetKey() { return TAMIL_ALPHABET_KEY; }
@Override
- public ExpectedKey getCurrencyKey() { return CURRENCY_RUPEE; }
-
- @Override
- public ExpectedKey[] getOtherCurrencyKeys() {
- return SymbolsShifted.CURRENCIES_OTHER_GENERIC;
- }
-
- @Override
public ExpectedKey[] getLeftShiftKeys(final boolean isPhone) {
return EMPTY_KEYS;
}
@@ -64,10 +56,6 @@ public final class Tamil extends LayoutBase {
// U+0BB4/U+0BCD: "ழ்" TAMIL LETTER LLLA/TAMIL SIGN VIRAMA
private static final ExpectedKey TAMIL_ALPHABET_KEY = key(
"\u0BA4\u0BAE\u0BBF\u0BB4\u0BCD", Constants.CODE_SWITCH_ALPHA_SYMBOL);
-
- // U+0BF9: "௹" TAMIL RUPEE SIGN
- private static final ExpectedKey CURRENCY_RUPEE = key("\u0BF9",
- Symbols.CURRENCY_GENERIC_MORE_KEYS);
}
@Override
@@ -81,15 +69,20 @@ public final class Tamil extends LayoutBase {
private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder()
.setKeysOfRow(1,
// U+0B94: "ஔ" TAMIL LETTER AU
- key("\u0B94", moreKey("1")),
+ // U+0BCC: "ௌ" TAMIL VOWEL SIGN AU
+ key("\u0B94", joinMoreKeys("\u0BCC", "1")),
// U+0B90: "ஐ" TAMIL LETTER AI
- key("\u0B90", moreKey("2")),
+ // U+0BC8: "ை" TAMIL VOWEL SIGN AI
+ key("\u0B90", joinMoreKeys("\u0BC8", "2")),
// U+0B86: "ஆ" TAMIL LETTER AA
- key("\u0B86", moreKey("3")),
+ // U+0BBE: "ா" TAMIL VOWEL SIGN AA
+ key("\u0B86", joinMoreKeys("\u0BBE", "3")),
// U+0B88: "ஈ" TAMIL LETTER II
- key("\u0B88", moreKey("4")),
+ // U+0BC0: "ீ" TAMIL VOWEL SIGN II
+ key("\u0B88", joinMoreKeys("\u0BC0", "4")),
// U+0B8A: "ஊ" TAMIL LETTER UU
- key("\u0B8A", moreKey("5")),
+ // U+0BC2: "ூ" TAMIL VOWEL SIGN UU
+ key("\u0B8A", joinMoreKeys("\u0BC2","5")),
// U+0BAE: "ம" TAMIL LETTER MA
key("\u0BAE", moreKey("6")),
// U+0BA9: "ன" TAMIL LETTER NNNA
@@ -104,18 +97,24 @@ public final class Tamil extends LayoutBase {
"\u0B9E")
.setKeysOfRow(2,
// U+0B93: "ஓ" TAMIL LETTER OO
+ // U+0BCB: "ோ" TAMIL VOWEL SIGN OO
// U+0BD0: "ௐ" TAMIL OM
- key("\u0B93", moreKey("\u0BD0")),
+ key("\u0B93", joinMoreKeys("\u0BCB", "\u0BD0")),
// U+0B8F: "ஏ" TAMIL LETTER EE
- "\u0B8F",
+ // U+0BC7: "ே" TAMIL VOWEL SIGN EE
+ key("\u0B8F", moreKey("\u0BC7")),
// U+0B85: "அ" TAMIL LETTER A
// U+0B83: "ஃ" TAMIL SIGN VISARGA
key("\u0B85", moreKey("\u0B83")),
// U+0B87: "இ" TAMIL LETTER I
+ // U+0BBF: "ி" TAMIL VOWEL SIGN I
+ key("\u0B87", moreKey("\u0BBF")),
// U+0B89: "உ" TAMIL LETTER U
+ // U+0BC1: "ு" TAMIL VOWEL SIGN U
+ key("\u0B89", moreKey("\u0BC1")),
// U+0BB1: "ற" TAMIL LETTER RRA
// U+0BAA: "ப" TAMIL LETTER PA
- "\u0B87", "\u0B89", "\u0BB1", "\u0BAA",
+ "\u0BB1", "\u0BAA",
// U+0B95: "க" TAMIL LETTER KA
// U+0BB9: "ஹ" TAMIL LETTER HA
// U+0B95/U+0BCD/U+0BB7:
@@ -133,7 +132,11 @@ public final class Tamil extends LayoutBase {
"\u0B9F")
.setKeysOfRow(3,
// U+0B92: "ஒ" TAMIL LETTER O
+ // U+0BCA: "ொ" TAMIL VOWEL SIGN O
+ key("\u0B92", moreKey("\u0BCA")),
// U+0B8E: "எ" TAMIL LETTER E
+ // U+0BC6: "ெ" TAMIL VOWEL SIGN E
+ key("\u0B8E", moreKey("\u0BC6")),
// U+0BCD: "்" TAMIL SIGN VIRAMA
// U+0BB0: "ர" TAMIL LETTER RA
// U+0BB5: "வ" TAMIL LETTER VA
@@ -141,8 +144,7 @@ public final class Tamil extends LayoutBase {
// U+0BB2: "ல" TAMIL LETTER LA
// U+0BB3: "ள" TAMIL LETTER LLA
// U+0BAF: "ய" TAMIL LETTER YA
- "\u0B92", "\u0B8E", "\u0BCD", "\u0BB0", "\u0BB5", "\u0BB4", "\u0BB2", "\u0BB3",
- "\u0BAF",
+ "\u0BCD", "\u0BB0", "\u0BB5", "\u0BB4", "\u0BB2", "\u0BB3", "\u0BAF",
// U+0BB7: "ஷ" TAMIL LETTER SSA
// U+0B9C: "ஜ" TAMIL LETTER JA
key("\u0BB7", moreKey("\u0B9C")))
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Thai.java b/tests/src/com/android/inputmethod/keyboard/layout/Thai.java
index af4abea93..cfda2947c 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Thai.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Thai.java
@@ -40,6 +40,9 @@ public final class Thai extends LayoutBase {
public ThaiCustomizer(final Locale locale) { super(locale); }
@Override
+ public int getNumberOfRows() { return 5; }
+
+ @Override
public ExpectedKey getAlphabetKey() { return THAI_ALPHABET_KEY; }
@Override
@@ -96,29 +99,6 @@ public final class Thai extends LayoutBase {
return builder.build();
}
- // Helper method to create alphabet layout by adding special function keys.
- @Override
- ExpectedKeyboardBuilder convertCommonLayoutToKeyboard(final ExpectedKeyboardBuilder builder,
- final boolean isPhone) {
- final LayoutCustomizer customizer = getCustomizer();
- builder.setKeysOfRow(5, (Object[])customizer.getSpaceKeys(isPhone));
- builder.addKeysOnTheLeftOfRow(5, (Object[])customizer.getKeysLeftToSpacebar(isPhone));
- builder.addKeysOnTheRightOfRow(5, (Object[])customizer.getKeysRightToSpacebar(isPhone));
- if (isPhone) {
- builder.addKeysOnTheRightOfRow(4, DELETE_KEY)
- .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey())
- .addKeysOnTheRightOfRow(5, key(ENTER_KEY, EMOJI_KEY));
- } else {
- builder.addKeysOnTheRightOfRow(1, DELETE_KEY)
- .addKeysOnTheRightOfRow(3, ENTER_KEY)
- .addKeysOnTheLeftOfRow(5, customizer.getSymbolsKey())
- .addKeysOnTheRightOfRow(5, EMOJI_KEY);
- }
- builder.addKeysOnTheLeftOfRow(4, (Object[])customizer.getLeftShiftKeys(isPhone))
- .addKeysOnTheRightOfRow(4, (Object[])customizer.getRightShiftKeys(isPhone));
- return builder;
- }
-
private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder()
.setKeysOfRow(1,
// U+0E45: "ๅ" THAI CHARACTER LAKKHANGYAO
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java
index 9e0039d84..3556cb4bf 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java
@@ -16,9 +16,7 @@
package com.android.inputmethod.keyboard.layout.expected;
-import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
import com.android.inputmethod.keyboard.layout.expected.ExpectedKey.ExpectedAdditionalMoreKey;
-import com.android.inputmethod.latin.Constants;
/**
* Base class to create an expected keyboard for unit test.
@@ -104,33 +102,4 @@ public abstract class AbstractLayoutBase {
public static ExpectedKey[] joinKeys(final Object ... keys) {
return ExpectedKeyboardBuilder.joinKeys(keys);
}
-
- // Icon ids.
- private static final int ICON_DELETE = KeyboardIconsSet.getIconId(
- KeyboardIconsSet.NAME_DELETE_KEY);
- private static final int ICON_SPACE = KeyboardIconsSet.getIconId(
- KeyboardIconsSet.NAME_SPACE_KEY);
- private static final int ICON_TAB = KeyboardIconsSet.getIconId(
- KeyboardIconsSet.NAME_TAB_KEY);
- private static final int ICON_SHORTCUT = KeyboardIconsSet.getIconId(
- KeyboardIconsSet.NAME_SHORTCUT_KEY);
- private static final int ICON_SETTINGS = KeyboardIconsSet.getIconId(
- KeyboardIconsSet.NAME_SETTINGS_KEY);
- private static final int ICON_LANGUAGE_SWITCH = KeyboardIconsSet.getIconId(
- KeyboardIconsSet.NAME_LANGUAGE_SWITCH_KEY);
- private static final int ICON_ENTER = KeyboardIconsSet.getIconId(
- KeyboardIconsSet.NAME_ENTER_KEY);
- private static final int ICON_EMOJI = KeyboardIconsSet.getIconId(
- KeyboardIconsSet.NAME_EMOJI_KEY);
-
- // Functional keys.
- public static final ExpectedKey DELETE_KEY = key(ICON_DELETE, Constants.CODE_DELETE);
- public static final ExpectedKey TAB_KEY = key(ICON_TAB, Constants.CODE_TAB);
- public static final ExpectedKey SHORTCUT_KEY = key(ICON_SHORTCUT, Constants.CODE_SHORTCUT);
- public static final ExpectedKey SETTINGS_KEY = key(ICON_SETTINGS, Constants.CODE_SETTINGS);
- public static final ExpectedKey LANGUAGE_SWITCH_KEY = key(
- ICON_LANGUAGE_SWITCH, Constants.CODE_LANGUAGE_SWITCH);
- public static final ExpectedKey ENTER_KEY = key(ICON_ENTER, Constants.CODE_ENTER);
- public static final ExpectedKey EMOJI_KEY = key(ICON_EMOJI, Constants.CODE_EMOJI);
- public static final ExpectedKey SPACE_KEY = key(ICON_SPACE, Constants.CODE_SPACE);
}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKey.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKey.java
index 0e1c71cd1..2674a6a69 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKey.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKey.java
@@ -148,6 +148,18 @@ public class ExpectedKey {
return newInstance(mVisual.toUpperCase(locale), mOutput.toUpperCase(locale));
}
+ public ExpectedKey preserveCase() {
+ final ExpectedKey[] moreKeys = getMoreKeys();
+ final ExpectedKey[] casePreservedMoreKeys = new ExpectedKey[moreKeys.length];
+ for (int index = 0; index < moreKeys.length; index++) {
+ final ExpectedKey moreKey = moreKeys[index];
+ casePreservedMoreKeys[index] = newInstance(
+ moreKey.getVisual().preserveCase(), moreKey.getOutput().preserveCase());
+ }
+ return newInstance(
+ getVisual().preserveCase(), getOutput().preserveCase(), casePreservedMoreKeys);
+ }
+
public boolean equalsTo(final Key key) {
// This key has no "more keys".
return mVisual.equalsTo(key) && mOutput.equalsTo(key) && key.getMoreKeys() == null;
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java
index 1be51e60b..8b2bb4289 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java
@@ -42,6 +42,7 @@ abstract class ExpectedKeyOutput {
}
abstract ExpectedKeyOutput toUpperCase(final Locale locale);
+ abstract ExpectedKeyOutput preserveCase();
abstract boolean equalsTo(final String text);
abstract boolean equalsTo(final Key key);
abstract boolean equalsTo(final MoreKeySpec moreKeySpec);
@@ -62,13 +63,19 @@ abstract class ExpectedKeyOutput {
final String codeString = StringUtils.newSingleCodePointString(mCode);
// A letter may have an upper case counterpart that consists of multiple code
// points, for instance the upper case of "ß" is "SS".
- return newInstance(codeString.toUpperCase(locale));
+ return newInstance(StringUtils.toUpperCaseOfStringForLocale(
+ codeString, true /* needsToUpperCase */, locale));
}
// A special negative value has no upper case.
return this;
}
@Override
+ ExpectedKeyOutput preserveCase() {
+ return new CasePreservedCode(mCode);
+ }
+
+ @Override
boolean equalsTo(final String text) {
return StringUtils.codePointCount(text) == 1 && text.codePointAt(0) == mCode;
}
@@ -93,6 +100,16 @@ abstract class ExpectedKeyOutput {
return Constants.isLetterCode(mCode) ? StringUtils.newSingleCodePointString(mCode)
: Constants.printableCode(mCode);
}
+
+ private static class CasePreservedCode extends Code {
+ CasePreservedCode(final int code) { super(code); }
+
+ @Override
+ ExpectedKeyOutput toUpperCase(final Locale locale) { return this; }
+
+ @Override
+ ExpectedKeyOutput preserveCase() { return this; }
+ }
}
/**
@@ -109,6 +126,11 @@ abstract class ExpectedKeyOutput {
}
@Override
+ ExpectedKeyOutput preserveCase() {
+ return new CasePreservedText(mText);
+ }
+
+ @Override
boolean equalsTo(final String text) {
return text.equals(text);
}
@@ -134,5 +156,15 @@ abstract class ExpectedKeyOutput {
public String toString() {
return mText;
}
+
+ private static class CasePreservedText extends Text {
+ CasePreservedText(final String text) { super(text); }
+
+ @Override
+ ExpectedKeyOutput toUpperCase(final Locale locale) { return this; }
+
+ @Override
+ ExpectedKeyOutput preserveCase() { return this; }
+ }
}
}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyVisual.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyVisual.java
index 0a0da32b6..34024a5e0 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyVisual.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyVisual.java
@@ -19,6 +19,7 @@ package com.android.inputmethod.keyboard.layout.expected;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
import com.android.inputmethod.keyboard.internal.MoreKeySpec;
+import com.android.inputmethod.latin.utils.StringUtils;
import java.util.Locale;
@@ -37,6 +38,7 @@ abstract class ExpectedKeyVisual {
}
abstract ExpectedKeyVisual toUpperCase(final Locale locale);
+ abstract ExpectedKeyVisual preserveCase();
abstract boolean equalsTo(final String text);
abstract boolean equalsTo(final Key key);
abstract boolean equalsTo(final MoreKeySpec moreKeySpec);
@@ -59,6 +61,11 @@ abstract class ExpectedKeyVisual {
}
@Override
+ ExpectedKeyVisual preserveCase() {
+ return this;
+ }
+
+ @Override
boolean equalsTo(final String text) {
return false;
}
@@ -99,7 +106,13 @@ abstract class ExpectedKeyVisual {
@Override
ExpectedKeyVisual toUpperCase(final Locale locale) {
- return new Label(mLabel.toUpperCase(locale));
+ return new Label(StringUtils.toUpperCaseOfStringForLocale(
+ mLabel, true /* needsToUpperCase */, locale));
+ }
+
+ @Override
+ ExpectedKeyVisual preserveCase() {
+ return new CasePreservedLabel(mLabel);
}
@Override
@@ -131,5 +144,15 @@ abstract class ExpectedKeyVisual {
public String toString() {
return mLabel;
}
+
+ private static class CasePreservedLabel extends Label {
+ CasePreservedLabel(final String label) { super(label); }
+
+ @Override
+ ExpectedKeyVisual toUpperCase(final Locale locale) { return this; }
+
+ @Override
+ ExpectedKeyVisual preserveCase() { return this; }
+ }
}
}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakEmail.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakEmail.java
new file mode 100644
index 000000000..37ca09238
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakEmail.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.layout.tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.InputType;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.keyboard.KeyboardLayoutSet;
+import com.android.inputmethod.keyboard.layout.Dvorak;
+import com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
+import com.android.inputmethod.keyboard.layout.tests.TestsEnglishDvorak.EnglishDvorakCustomizer;
+
+import java.util.Locale;
+
+/**
+ * en_US: English (United States)/dvorak, email input field.
+ */
+@SmallTest
+public class TestsDvorakEmail extends LayoutTestsBase {
+ private static final Locale LOCALE = new Locale("en", "US");
+ private static final LayoutBase LAYOUT = new DvorakEmail(new DvorakEmailCustomizer(LOCALE));
+
+ @Override
+ LayoutBase getLayout() { return LAYOUT; }
+
+ @Override
+ protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
+ final EditorInfo editorInfo, final boolean voiceInputKeyEnabled,
+ final boolean languageSwitchKeyEnabled) {
+ final EditorInfo emailField = new EditorInfo();
+ emailField.inputType =
+ InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
+ return super.createKeyboardLayoutSet(
+ subtype, emailField, voiceInputKeyEnabled, languageSwitchKeyEnabled);
+ }
+
+ private static class DvorakEmailCustomizer extends EnglishDvorakCustomizer {
+ DvorakEmailCustomizer(final Locale locale) {
+ super(locale);
+ }
+
+ @Override
+ public ExpectedKey getEnterKey(final boolean isPhone) {
+ return isPhone ? LayoutBase.ENTER_KEY : super.getEnterKey(isPhone);
+ }
+
+ @Override
+ public ExpectedKey getEmojiKey(final boolean isPhone) {
+ return LayoutBase.DOMAIN_KEY;
+ }
+
+ @Override
+ public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
+ return isPhone ? super.getKeysLeftToSpacebar(isPhone)
+ : joinKeys(key("@", LayoutBase.SETTINGS_KEY));
+ }
+ }
+
+ private static class DvorakEmail extends Dvorak {
+ public DvorakEmail(final LayoutCustomizer customizer) {
+ super(customizer);
+ }
+
+ @Override
+ protected ExpectedKey getRow1_1Key(final boolean isPhone, final int elementId) {
+ if (isPhone && (elementId == KeyboardId.ELEMENT_ALPHABET
+ || elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED)) {
+ return key("@", joinMoreKeys(additionalMoreKey("1")));
+ }
+ return super.getRow1_1Key(isPhone, elementId);
+ }
+ }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakUrl.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakUrl.java
new file mode 100644
index 000000000..3bcae0ce4
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakUrl.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.layout.tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.InputType;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.keyboard.KeyboardLayoutSet;
+import com.android.inputmethod.keyboard.layout.Dvorak;
+import com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
+import com.android.inputmethod.keyboard.layout.tests.TestsEnglishDvorak.EnglishDvorakCustomizer;
+
+import java.util.Locale;
+
+/**
+ * en_US: English (United States)/dvorak, URL input field.
+ */
+@SmallTest
+public class TestsDvorakUrl extends LayoutTestsBase {
+ private static final Locale LOCALE = new Locale("en", "US");
+ private static final LayoutBase LAYOUT = new DvorakEmail(new DvorakUrlCustomizer(LOCALE));
+
+ @Override
+ LayoutBase getLayout() { return LAYOUT; }
+
+ @Override
+ protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
+ final EditorInfo editorInfo, final boolean voiceInputKeyEnabled,
+ final boolean languageSwitchKeyEnabled) {
+ final EditorInfo emailField = new EditorInfo();
+ emailField.inputType =
+ InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI;
+ return super.createKeyboardLayoutSet(
+ subtype, emailField, voiceInputKeyEnabled, languageSwitchKeyEnabled);
+ }
+
+ private static class DvorakUrlCustomizer extends EnglishDvorakCustomizer {
+ DvorakUrlCustomizer(final Locale locale) {
+ super(locale);
+ }
+
+ @Override
+ public ExpectedKey getEnterKey(final boolean isPhone) {
+ return isPhone ? LayoutBase.ENTER_KEY : super.getEnterKey(isPhone);
+ }
+
+ @Override
+ public ExpectedKey getEmojiKey(final boolean isPhone) {
+ return LayoutBase.DOMAIN_KEY;
+ }
+
+ @Override
+ public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
+ return isPhone ? super.getKeysLeftToSpacebar(isPhone)
+ : joinKeys(key("/", LayoutBase.SETTINGS_KEY));
+ }
+ }
+
+ private static class DvorakEmail extends Dvorak {
+ public DvorakEmail(final LayoutCustomizer customizer) {
+ super(customizer);
+ }
+
+ @Override
+ protected ExpectedKey getRow1_1Key(final boolean isPhone, final int elementId) {
+ if (isPhone && (elementId == KeyboardId.ELEMENT_ALPHABET
+ || elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED)) {
+ return key("/", joinMoreKeys(additionalMoreKey("1")));
+ }
+ return super.getRow1_1Key(isPhone, elementId);
+ }
+ }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishDvorak.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishDvorak.java
index a05269312..e647f8aea 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishDvorak.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishDvorak.java
@@ -36,7 +36,7 @@ public class TestsEnglishDvorak extends LayoutTestsBase {
@Override
LayoutBase getLayout() { return LAYOUT; }
- private static class EnglishDvorakCustomizer extends DvorakCustomizer {
+ public static class EnglishDvorakCustomizer extends DvorakCustomizer {
private final EnglishCustomizer mEnglishCustomizer;
EnglishDvorakCustomizer(final Locale locale) {
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMalayalamIN.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMalayalamIN.java
index f937de89a..b494ad37b 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMalayalamIN.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMalayalamIN.java
@@ -25,7 +25,7 @@ import com.android.inputmethod.keyboard.layout.Malayalam.MalayalamCustomizer;
import java.util.Locale;
/**
- * ta_IN: Malayalam (India)/malayalam
+ * ml_IN: Malayalam (India)/malayalam
*/
@SmallTest
public final class TestsMalayalamIN extends LayoutTestsBase {
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMyanmarMM.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMyanmarMM.java
index e6d3b3b92..a0bd50c9a 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMyanmarMM.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMyanmarMM.java
@@ -16,7 +16,7 @@
package com.android.inputmethod.keyboard.layout.tests;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
import com.android.inputmethod.keyboard.layout.LayoutBase;
import com.android.inputmethod.keyboard.layout.Myanmar;
@@ -27,7 +27,7 @@ import java.util.Locale;
/**
* my_MM: Myanmar (Myanmar)/myanmar
*/
-@SmallTest
+@Suppress
public final class TestsMyanmarMM extends LayoutTestsBase {
private static final Locale LOCALE = new Locale("my", "MM");
private static final LayoutBase LAYOUT = new Myanmar(new MyanmarCustomizer(LOCALE));
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyEmail.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyEmail.java
new file mode 100644
index 000000000..8563d6933
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyEmail.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.layout.tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.InputType;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.keyboard.KeyboardLayoutSet;
+import com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.Qwerty;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
+
+import java.util.Locale;
+
+/**
+ * en_US: English (United States)/qwerty, email input field.
+ */
+@SmallTest
+public class TestsQwertyEmail extends LayoutTestsBase {
+ private static final Locale LOCALE = new Locale("en", "US");
+ private static final LayoutBase LAYOUT = new Qwerty(new EnglishEmailCustomizer(LOCALE));
+
+ @Override
+ LayoutBase getLayout() { return LAYOUT; }
+
+ @Override
+ protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
+ final EditorInfo editorInfo, final boolean voiceInputKeyEnabled,
+ final boolean languageSwitchKeyEnabled) {
+ final EditorInfo emailField = new EditorInfo();
+ emailField.inputType =
+ InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
+ return super.createKeyboardLayoutSet(
+ subtype, emailField, voiceInputKeyEnabled, languageSwitchKeyEnabled);
+ }
+
+ private static class EnglishEmailCustomizer extends EnglishCustomizer {
+ EnglishEmailCustomizer(final Locale locale) {
+ super(locale);
+ }
+
+ @Override
+ public ExpectedKey getEnterKey(final boolean isPhone) {
+ return isPhone ? LayoutBase.ENTER_KEY : super.getEnterKey(isPhone);
+ }
+
+ @Override
+ public ExpectedKey getEmojiKey(final boolean isPhone) {
+ return LayoutBase.DOMAIN_KEY;
+ }
+
+ @Override
+ public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
+ return joinKeys(key("@", LayoutBase.SETTINGS_KEY));
+ }
+ }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyUrl.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyUrl.java
new file mode 100644
index 000000000..1c1a2bbbd
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyUrl.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.layout.tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.InputType;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.keyboard.KeyboardLayoutSet;
+import com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.Qwerty;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
+
+import java.util.Locale;
+
+/**
+ * en_US: English (United States)/qwerty, URL input field.
+ */
+@SmallTest
+public class TestsQwertyUrl extends LayoutTestsBase {
+ private static final Locale LOCALE = new Locale("en", "US");
+ private static final LayoutBase LAYOUT = new Qwerty(new EnglishUrlCustomizer(LOCALE));
+
+ @Override
+ LayoutBase getLayout() { return LAYOUT; }
+
+ @Override
+ protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
+ final EditorInfo editorInfo, final boolean voiceInputKeyEnabled,
+ final boolean languageSwitchKeyEnabled) {
+ final EditorInfo emailField = new EditorInfo();
+ emailField.inputType =
+ InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI;
+ return super.createKeyboardLayoutSet(
+ subtype, emailField, voiceInputKeyEnabled, languageSwitchKeyEnabled);
+ }
+
+ private static class EnglishUrlCustomizer extends EnglishCustomizer {
+ EnglishUrlCustomizer(final Locale locale) {
+ super(locale);
+ }
+
+ @Override
+ public ExpectedKey getEnterKey(final boolean isPhone) {
+ return isPhone ? LayoutBase.ENTER_KEY : super.getEnterKey(isPhone);
+ }
+
+ @Override
+ public ExpectedKey getEmojiKey(final boolean isPhone) {
+ return LayoutBase.DOMAIN_KEY;
+ }
+
+ @Override
+ public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
+ return joinKeys(key("/", LayoutBase.SETTINGS_KEY));
+ }
+ }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSinhalaLK.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSinhalaLK.java
index 1cea49760..8b861359b 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSinhalaLK.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSinhalaLK.java
@@ -16,7 +16,7 @@
package com.android.inputmethod.keyboard.layout.tests;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
import com.android.inputmethod.keyboard.layout.LayoutBase;
import com.android.inputmethod.keyboard.layout.Sinhala;
@@ -27,7 +27,7 @@ import java.util.Locale;
/**
* si_LK: Sinhala (Sri Lanka)/sinhala
*/
-@SmallTest
+@Suppress
public final class TestsSinhalaLK extends LayoutTestsBase {
private static final Locale LOCALE = new Locale("si", "LK");
private static final LayoutBase LAYOUT = new Sinhala(new SinhalaCustomizer(LOCALE));
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTamilIN.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTamilIN.java
index 5b3649d2b..31df53c0b 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTamilIN.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTamilIN.java
@@ -19,8 +19,11 @@ package com.android.inputmethod.keyboard.layout.tests;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.Symbols;
+import com.android.inputmethod.keyboard.layout.SymbolsShifted;
import com.android.inputmethod.keyboard.layout.Tamil;
import com.android.inputmethod.keyboard.layout.Tamil.TamilCustomizer;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
import java.util.Locale;
@@ -30,8 +33,24 @@ import java.util.Locale;
@SmallTest
public final class TestsTamilIN extends LayoutTestsBase {
private static final Locale LOCALE = new Locale("ta", "IN");
- private static final LayoutBase LAYOUT = new Tamil(new TamilCustomizer(LOCALE));
+ private static final LayoutBase LAYOUT = new Tamil(new TamilINCustomizer(LOCALE));
@Override
LayoutBase getLayout() { return LAYOUT; }
+
+ private static class TamilINCustomizer extends TamilCustomizer {
+ public TamilINCustomizer(final Locale locale) { super(locale); }
+
+ @Override
+ public ExpectedKey getCurrencyKey() { return CURRENCY_RUPEE; }
+
+ @Override
+ public ExpectedKey[] getOtherCurrencyKeys() {
+ return SymbolsShifted.CURRENCIES_OTHER_GENERIC;
+ }
+
+ // U+20B9: "₹" INDIAN RUPEE SIGN
+ private static final ExpectedKey CURRENCY_RUPEE = key("\u20B9",
+ Symbols.CURRENCY_GENERIC_MORE_KEYS);
+ }
}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTamilLK.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTamilLK.java
new file mode 100644
index 000000000..65ec0b036
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTamilLK.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.layout.tests;
+
+import android.test.suitebuilder.annotation.Suppress;
+
+import com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.Symbols;
+import com.android.inputmethod.keyboard.layout.SymbolsShifted;
+import com.android.inputmethod.keyboard.layout.Tamil;
+import com.android.inputmethod.keyboard.layout.Tamil.TamilCustomizer;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
+
+import java.util.Locale;
+
+/**
+ * ta_LK: Tamil (Sri Lanka)/tamil
+ */
+@Suppress
+public final class TestsTamilLK extends LayoutTestsBase {
+ private static final Locale LOCALE = new Locale("ta", "LK");
+ private static final LayoutBase LAYOUT = new Tamil(new TamilLKCustomizer(LOCALE));
+
+ @Override
+ LayoutBase getLayout() { return LAYOUT; }
+
+ private static class TamilLKCustomizer extends TamilCustomizer {
+ public TamilLKCustomizer(final Locale locale) { super(locale); }
+
+ @Override
+ public ExpectedKey getCurrencyKey() { return CURRENCY_RUPEE; }
+
+ @Override
+ public ExpectedKey[] getOtherCurrencyKeys() {
+ return SymbolsShifted.CURRENCIES_OTHER_GENERIC;
+ }
+
+ // U+0DBB/U+0DD4: "රු" SINHALA LETTER RAYANNA/SINHALA VOWEL SIGN KETTI PAA-PILLA
+ private static final ExpectedKey CURRENCY_RUPEE = key("\u0DBB\u0DD4",
+ Symbols.CURRENCY_GENERIC_MORE_KEYS);
+ }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTamilSG.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTamilSG.java
new file mode 100644
index 000000000..ade7abaf9
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsTamilSG.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.layout.tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.Tamil;
+import com.android.inputmethod.keyboard.layout.Tamil.TamilCustomizer;
+
+import java.util.Locale;
+
+/**
+ * ta_SG: Tamil (Singapore)/tamil
+ */
+@SmallTest
+public final class TestsTamilSG extends LayoutTestsBase {
+ private static final Locale LOCALE = new Locale("ta", "SG");
+ private static final LayoutBase LAYOUT = new Tamil(new TamilCustomizer(LOCALE));
+
+ @Override
+ LayoutBase getLayout() { return LAYOUT; }
+}
diff --git a/tests/src/com/android/inputmethod/latin/DistracterFilterTest.java b/tests/src/com/android/inputmethod/latin/DistracterFilterTest.java
index 70b8f530a..e6fb28260 100644
--- a/tests/src/com/android/inputmethod/latin/DistracterFilterTest.java
+++ b/tests/src/com/android/inputmethod/latin/DistracterFilterTest.java
@@ -16,24 +16,38 @@
package com.android.inputmethod.latin;
+import java.util.ArrayList;
import java.util.Locale;
+import android.content.Context;
+import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
+import android.view.inputmethod.InputMethodSubtype;
-import com.android.inputmethod.latin.utils.DistracterFilterCheckingExactMatches;
+import com.android.inputmethod.latin.utils.DistracterFilterCheckingExactMatchesAndSuggestions;
/**
* Unit test for DistracterFilter
*/
@LargeTest
-public class DistracterFilterTest extends InputTestsBase {
- private DistracterFilterCheckingExactMatches mDistracterFilter;
+public class DistracterFilterTest extends AndroidTestCase {
+ private DistracterFilterCheckingExactMatchesAndSuggestions mDistracterFilter;
@Override
protected void setUp() throws Exception {
super.setUp();
- mDistracterFilter = new DistracterFilterCheckingExactMatches(getContext());
- mDistracterFilter.updateEnabledSubtypes(mLatinIME.getEnabledSubtypesForTest());
+ final Context context = getContext();
+ mDistracterFilter = new DistracterFilterCheckingExactMatchesAndSuggestions(context);
+ RichInputMethodManager.init(context);
+ final RichInputMethodManager richImm = RichInputMethodManager.getInstance();
+ final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
+ subtypes.add(richImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+ Locale.US.toString(), "qwerty"));
+ subtypes.add(richImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+ Locale.FRENCH.toString(), "azerty"));
+ subtypes.add(richImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+ Locale.GERMAN.toString(), "qwertz"));
+ mDistracterFilter.updateEnabledSubtypes(subtypes);
}
public void testIsDistractorToWordsInDictionaries() {
@@ -104,24 +118,56 @@ public class DistracterFilterTest extends InputTestsBase {
assertFalse(mDistracterFilter.isDistracterToWordsInDictionaries(
EMPTY_PREV_WORDS_INFO, typedWord, localeEnUs));
- final Locale localeDeDe = new Locale("de", "DE");
+ typedWord = "thabk";
+ // For this test case, we consider "thabk" is a distracter to "thank"
+ assertTrue(mDistracterFilter.isDistracterToWordsInDictionaries(
+ EMPTY_PREV_WORDS_INFO, typedWord, localeEnUs));
- typedWord = "fuer";
- // For this test case, we consider "fuer" is a distracter to "für".
+ typedWord = "thanks";
+ // For this test case, we consider "thanks" is not a distracter to any other word
+ // in dictionaries.
+ assertFalse(mDistracterFilter.isDistracterToWordsInDictionaries(
+ EMPTY_PREV_WORDS_INFO, typedWord, localeEnUs));
+
+ typedWord = "thabks";
+ // For this test case, we consider "thabks" is a distracter to "thanks"
assertTrue(mDistracterFilter.isDistracterToWordsInDictionaries(
- EMPTY_PREV_WORDS_INFO, typedWord, localeDeDe));
+ EMPTY_PREV_WORDS_INFO, typedWord, localeEnUs));
+
+ typedWord = "think";
+ // For this test case, we consider "think" is not a distracter to any other word
+ // in dictionaries.
+ assertFalse(mDistracterFilter.isDistracterToWordsInDictionaries(
+ EMPTY_PREV_WORDS_INFO, typedWord, localeEnUs));
+
+ typedWord = "thibk";
+ // For this test case, we consider "thibk" is a distracter to "think"
+ assertTrue(mDistracterFilter.isDistracterToWordsInDictionaries(
+ EMPTY_PREV_WORDS_INFO, typedWord, localeEnUs));
+
+ typedWord = "tgis";
+ // For this test case, we consider "tgis" is a distracter to "this"
+ assertTrue(mDistracterFilter.isDistracterToWordsInDictionaries(
+ EMPTY_PREV_WORDS_INFO, typedWord, localeEnUs));
+
+ final Locale localeDeDe = new Locale("de");
typedWord = "fUEr";
// For this test case, we consider "fUEr" is a distracter to "für".
assertTrue(mDistracterFilter.isDistracterToWordsInDictionaries(
EMPTY_PREV_WORDS_INFO, typedWord, localeDeDe));
+ typedWord = "fuer";
+ // For this test case, we consider "fuer" is a distracter to "für".
+ assertTrue(mDistracterFilter.isDistracterToWordsInDictionaries(
+ EMPTY_PREV_WORDS_INFO, typedWord, localeDeDe));
+
typedWord = "fur";
// For this test case, we consider "fur" is a distracter to "für".
assertTrue(mDistracterFilter.isDistracterToWordsInDictionaries(
EMPTY_PREV_WORDS_INFO, typedWord, localeDeDe));
- final Locale localeFrFr = new Locale("fr", "FR");
+ final Locale localeFrFr = new Locale("fr");
typedWord = "a";
// For this test case, we consider "a" is a distracter to "à".
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTestsReorderingMyanmar.java b/tests/src/com/android/inputmethod/latin/InputLogicTestsReorderingMyanmar.java
index 61eae4e8b..ab69c8592 100644
--- a/tests/src/com/android/inputmethod/latin/InputLogicTestsReorderingMyanmar.java
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTestsReorderingMyanmar.java
@@ -17,6 +17,7 @@
package com.android.inputmethod.latin;
import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.Suppress;
import android.util.Pair;
/*
@@ -77,6 +78,8 @@ import android.util.Pair;
*/
@LargeTest
+// These tests are inactive until the combining code for Myanmar Reordering is sorted out.
+@Suppress
@SuppressWarnings("rawtypes")
public class InputLogicTestsReorderingMyanmar extends InputTestsBase {
// The tests are formatted as follows.
diff --git a/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java b/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java
index 199922491..f9d72269e 100644
--- a/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java
+++ b/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java
@@ -215,18 +215,23 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
"abc 'def", mSpacingAndPunctuations, 2), PrevWordsInfo.EMPTY_PREV_WORDS_INFO);
}
- /**
- * Test logic in getting the word range at the cursor.
- */
- private static final int[] SPACE = { Constants.CODE_SPACE };
- static final int[] TAB = { Constants.CODE_TAB };
- private static final int[] SPACE_TAB = StringUtils.toSortedCodePointArray(" \t");
- // A character that needs surrogate pair to represent its code point (U+2008A).
- private static final String SUPPLEMENTARY_CHAR = "\uD840\uDC8A";
- private static final String HIRAGANA_WORD = "\u3042\u3044\u3046\u3048\u304A"; // あいうえお
- private static final String GREEK_WORD = "\u03BA\u03B1\u03B9"; // και
-
public void testGetWordRangeAtCursor() {
+ /**
+ * Test logic in getting the word range at the cursor.
+ */
+ final SpacingAndPunctuations SPACE = new SpacingAndPunctuations(
+ mSpacingAndPunctuations, new int[] { Constants.CODE_SPACE });
+ final SpacingAndPunctuations TAB = new SpacingAndPunctuations(
+ mSpacingAndPunctuations, new int[] { Constants.CODE_TAB });
+ final int[] SPACE_TAB = StringUtils.toSortedCodePointArray(" \t");
+ // A character that needs surrogate pair to represent its code point (U+2008A).
+ final String SUPPLEMENTARY_CHAR_STRING = "\uD840\uDC8A";
+ final SpacingAndPunctuations SUPPLEMENTARY_CHAR = new SpacingAndPunctuations(
+ mSpacingAndPunctuations, StringUtils.toSortedCodePointArray(
+ SUPPLEMENTARY_CHAR_STRING));
+ final String HIRAGANA_WORD = "\u3042\u3044\u3046\u3048\u304A"; // あいうえお
+ final String GREEK_WORD = "\u03BA\u03B1\u03B9"; // και
+
ExtractedText et = new ExtractedText();
final MockInputMethodService mockInputMethodService = new MockInputMethodService();
final RichInputConnection ic = new RichInputConnection(mockInputMethodService);
@@ -249,10 +254,9 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
// splitting on supplementary character
mockInputMethodService.setInputConnection(
- new MockConnection("one word" + SUPPLEMENTARY_CHAR + "wo", "rd", et));
+ new MockConnection("one word" + SUPPLEMENTARY_CHAR_STRING + "wo", "rd", et));
ic.beginBatchEdit();
- r = ic.getWordRangeAtCursor(StringUtils.toSortedCodePointArray(SUPPLEMENTARY_CHAR),
- ScriptUtils.SCRIPT_LATIN);
+ r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_LATIN);
ic.endBatchEdit();
assertTrue(TextUtils.equals("word", r.mWord));
@@ -260,8 +264,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
mockInputMethodService.setInputConnection(
new MockConnection(HIRAGANA_WORD + "wo", "rd" + GREEK_WORD, et));
ic.beginBatchEdit();
- r = ic.getWordRangeAtCursor(StringUtils.toSortedCodePointArray(SUPPLEMENTARY_CHAR),
- ScriptUtils.SCRIPT_LATIN);
+ r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_LATIN);
ic.endBatchEdit();
assertTrue(TextUtils.equals("word", r.mWord));
@@ -269,8 +272,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
mockInputMethodService.setInputConnection(
new MockConnection("text" + GREEK_WORD, "text", et));
ic.beginBatchEdit();
- r = ic.getWordRangeAtCursor(StringUtils.toSortedCodePointArray(SUPPLEMENTARY_CHAR),
- ScriptUtils.SCRIPT_GREEK);
+ r = ic.getWordRangeAtCursor(SUPPLEMENTARY_CHAR, ScriptUtils.SCRIPT_GREEK);
ic.endBatchEdit();
assertTrue(TextUtils.equals(GREEK_WORD, r.mWord));
}
@@ -286,6 +288,8 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
}
private void helpTestGetSuggestionSpansAtWord(final int cursorPos) {
+ final SpacingAndPunctuations SPACE = new SpacingAndPunctuations(
+ mSpacingAndPunctuations, new int[] { Constants.CODE_SPACE });
final MockInputMethodService mockInputMethodService = new MockInputMethodService();
final RichInputConnection ic = new RichInputConnection(mockInputMethodService);
diff --git a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
index 66b4a9c71..869c550e0 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
@@ -23,24 +23,50 @@ import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import java.util.ArrayList;
import java.util.Locale;
-import java.util.Random;
@SmallTest
public class SuggestedWordsTests extends AndroidTestCase {
+
+ /**
+ * Helper method to create a dummy {@link SuggestedWordInfo} with specifying
+ * {@link SuggestedWordInfo#KIND_TYPED}.
+ *
+ * @param word the word to be used to create {@link SuggestedWordInfo}.
+ * @return a new instance of {@link SuggestedWordInfo}.
+ */
+ private static SuggestedWordInfo createTypedWordInfo(final String word) {
+ // Use 100 as the frequency because the numerical value does not matter as
+ // long as it's > 1 and < INT_MAX.
+ return new SuggestedWordInfo(word, 100 /* score */,
+ SuggestedWordInfo.KIND_TYPED,
+ null /* sourceDict */,
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ 1 /* autoCommitFirstWordConfidence */);
+ }
+
+ /**
+ * Helper method to create a dummy {@link SuggestedWordInfo} with specifying
+ * {@link SuggestedWordInfo#KIND_CORRECTION}.
+ *
+ * @param word the word to be used to create {@link SuggestedWordInfo}.
+ * @return a new instance of {@link SuggestedWordInfo}.
+ */
+ private static SuggestedWordInfo createCorrectionWordInfo(final String word) {
+ return new SuggestedWordInfo(word, 1 /* score */,
+ SuggestedWordInfo.KIND_CORRECTION,
+ null /* sourceDict */,
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */);
+ }
+
public void testGetSuggestedWordsExcludingTypedWord() {
final String TYPED_WORD = "typed";
- final int TYPED_WORD_FREQ = 5;
final int NUMBER_OF_ADDED_SUGGESTIONS = 5;
+ final int KIND_OF_SECOND_CORRECTION = SuggestedWordInfo.KIND_CORRECTION;
final ArrayList<SuggestedWordInfo> list = new ArrayList<>();
- list.add(new SuggestedWordInfo(TYPED_WORD, TYPED_WORD_FREQ,
- SuggestedWordInfo.KIND_TYPED, null /* sourceDict */,
- SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
- SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
+ list.add(createTypedWordInfo(TYPED_WORD));
for (int i = 0; i < NUMBER_OF_ADDED_SUGGESTIONS; ++i) {
- list.add(new SuggestedWordInfo("" + i, 1, SuggestedWordInfo.KIND_CORRECTION,
- null /* sourceDict */,
- SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
- SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
+ list.add(createCorrectionWordInfo(Integer.toString(i)));
}
final SuggestedWords words = new SuggestedWords(
@@ -48,35 +74,29 @@ public class SuggestedWordsTests extends AndroidTestCase {
false /* typedWordValid */,
false /* willAutoCorrect */,
false /* isObsoleteSuggestions */,
- false /* isPrediction*/);
+ SuggestedWords.INPUT_STYLE_NONE);
assertEquals(NUMBER_OF_ADDED_SUGGESTIONS + 1, words.size());
assertEquals("typed", words.getWord(0));
assertTrue(words.getInfo(0).isKindOf(SuggestedWordInfo.KIND_TYPED));
assertEquals("0", words.getWord(1));
- assertTrue(words.getInfo(1).isKindOf(SuggestedWordInfo.KIND_CORRECTION));
+ assertTrue(words.getInfo(1).isKindOf(KIND_OF_SECOND_CORRECTION));
assertEquals("4", words.getWord(5));
- assertTrue(words.getInfo(5).isKindOf(SuggestedWordInfo.KIND_CORRECTION));
+ assertTrue(words.getInfo(5).isKindOf(KIND_OF_SECOND_CORRECTION));
- final SuggestedWords wordsWithoutTyped = words.getSuggestedWordsExcludingTypedWord();
+ final SuggestedWords wordsWithoutTyped =
+ words.getSuggestedWordsExcludingTypedWordForRecorrection();
+ // Make sure that the typed word has indeed been excluded, by testing the size of the
+ // suggested words, the string and the kind of the top suggestion, which should match
+ // the string and kind of what we inserted after the typed word.
assertEquals(words.size() - 1, wordsWithoutTyped.size());
assertEquals("0", wordsWithoutTyped.getWord(0));
- assertTrue(wordsWithoutTyped.getInfo(0).isKindOf(SuggestedWordInfo.KIND_CORRECTION));
- }
-
- // 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 */,
- new Random().nextInt(1000000) /* autoCommitFirstWordConfidence */);
+ assertTrue(wordsWithoutTyped.getInfo(0).isKindOf(KIND_OF_SECOND_CORRECTION));
}
// Helper for testGetTransformedWordInfo
private SuggestedWordInfo transformWordInfo(final String info,
final int trailingSingleQuotesCount) {
- final SuggestedWordInfo suggestedWordInfo = createWordInfo(info);
+ final SuggestedWordInfo suggestedWordInfo = createTypedWordInfo(info);
final SuggestedWordInfo returnedWordInfo =
Suggest.getTransformedSuggestedWordInfo(suggestedWordInfo,
Locale.ENGLISH, false /* isAllUpperCase */, false /* isFirstCharCapitalized */,
@@ -100,4 +120,43 @@ public class SuggestedWordsTests extends AndroidTestCase {
result = transformWordInfo("didn't", 3);
assertEquals(result.mWord, "didn't''");
}
+
+ public void testGetTypedWordInfoOrNull() {
+ final String TYPED_WORD = "typed";
+ final int NUMBER_OF_ADDED_SUGGESTIONS = 5;
+ final ArrayList<SuggestedWordInfo> list = new ArrayList<>();
+ list.add(createTypedWordInfo(TYPED_WORD));
+ for (int i = 0; i < NUMBER_OF_ADDED_SUGGESTIONS; ++i) {
+ list.add(createCorrectionWordInfo(Integer.toString(i)));
+ }
+
+ // Make sure getTypedWordInfoOrNull() returns non-null object.
+ final SuggestedWords wordsWithTypedWord = new SuggestedWords(
+ list, null /* rawSuggestions */,
+ false /* typedWordValid */,
+ false /* willAutoCorrect */,
+ false /* isObsoleteSuggestions */,
+ SuggestedWords.INPUT_STYLE_NONE);
+ final SuggestedWordInfo typedWord = wordsWithTypedWord.getTypedWordInfoOrNull();
+ assertNotNull(typedWord);
+ assertEquals(TYPED_WORD, typedWord.mWord);
+
+ // Make sure getTypedWordInfoOrNull() returns null.
+ final SuggestedWords wordsWithoutTypedWord =
+ wordsWithTypedWord.getSuggestedWordsExcludingTypedWordForRecorrection();
+ assertNull(wordsWithoutTypedWord.getTypedWordInfoOrNull());
+
+ // Make sure getTypedWordInfoOrNull() returns null.
+ assertNull(SuggestedWords.EMPTY.getTypedWordInfoOrNull());
+
+ final SuggestedWords emptySuggestedWords = new SuggestedWords(
+ new ArrayList<SuggestedWordInfo>(), null /* rawSuggestions */,
+ false /* typedWordValid */,
+ false /* willAutoCorrect */,
+ false /* isObsoleteSuggestions */,
+ SuggestedWords.INPUT_STYLE_NONE);
+ assertNull(emptySuggestedWords.getTypedWordInfoOrNull());
+
+ assertNull(SuggestedWords.EMPTY.getTypedWordInfoOrNull());
+ }
}
diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java
index 084371944..eabd8d722 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java
@@ -802,20 +802,13 @@ public class BinaryDictEncoderUtils {
}
MakedictLog.i("Statistics:\n"
- + " total file size " + size + "\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"
+ + " 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]);
- }
}
/**
diff --git a/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java b/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java
index 2cc22fae4..eb76032b1 100644
--- a/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java
+++ b/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java
@@ -429,7 +429,7 @@ public class SpacingAndPunctuationsTests extends AndroidTestCase {
assertFalse("willAutoCorrect", suggestedWords.mWillAutoCorrect);
assertTrue("isPunctuationSuggestions", suggestedWords.isPunctuationSuggestions());
assertFalse("isObsoleteSuggestions", suggestedWords.mIsObsoleteSuggestions);
- assertFalse("isPrediction", suggestedWords.mIsPrediction);
+ assertFalse("isPrediction", suggestedWords.isPrediction());
assertEquals("size", punctuationLabels.length, suggestedWords.size());
for (int index = 0; index < suggestedWords.size(); index++) {
assertEquals("punctuation label at " + index,
diff --git a/tests/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelperTests.java b/tests/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelperTests.java
new file mode 100644
index 000000000..f3273a2d1
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelperTests.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.suggestions;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.inputmethod.latin.SuggestedWords;
+
+@SmallTest
+public class SuggestionStripLayoutHelperTests extends AndroidTestCase {
+ private static void confirmShowTypedWord(final String message, final int inputType) {
+ assertFalse(message, SuggestionStripLayoutHelper.shouldOmitTypedWord(
+ inputType,
+ false /* gestureFloatingPreviewTextEnabled */,
+ false /* shouldShowUiToAcceptTypedWord */));
+ assertFalse(message, SuggestionStripLayoutHelper.shouldOmitTypedWord(
+ inputType,
+ true /* gestureFloatingPreviewTextEnabled */,
+ false /* shouldShowUiToAcceptTypedWord */));
+ assertFalse(message, SuggestionStripLayoutHelper.shouldOmitTypedWord(
+ inputType,
+ false /* gestureFloatingPreviewTextEnabled */,
+ true /* shouldShowUiToAcceptTypedWord */));
+ assertFalse(message, SuggestionStripLayoutHelper.shouldOmitTypedWord(
+ inputType,
+ true /* gestureFloatingPreviewTextEnabled */,
+ true /* shouldShowUiToAcceptTypedWord */));
+ }
+
+ public void testShouldShowTypedWord() {
+ confirmShowTypedWord("no input style",
+ SuggestedWords.INPUT_STYLE_NONE);
+ confirmShowTypedWord("application specifed",
+ SuggestedWords.INPUT_STYLE_APPLICATION_SPECIFIED);
+ confirmShowTypedWord("recorrection",
+ SuggestedWords.INPUT_STYLE_RECORRECTION);
+ }
+
+ public void testshouldOmitTypedWordWhileTyping() {
+ assertFalse("typing", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+ SuggestedWords.INPUT_STYLE_TYPING,
+ false /* gestureFloatingPreviewTextEnabled */,
+ false /* shouldShowUiToAcceptTypedWord */));
+ assertFalse("typing", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+ SuggestedWords.INPUT_STYLE_TYPING,
+ true /* gestureFloatingPreviewTextEnabled */,
+ false /* shouldShowUiToAcceptTypedWord */));
+ assertTrue("typing", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+ SuggestedWords.INPUT_STYLE_TYPING,
+ false /* gestureFloatingPreviewTextEnabled */,
+ true /* shouldShowUiToAcceptTypedWord */));
+ assertTrue("typing", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+ SuggestedWords.INPUT_STYLE_TYPING,
+ true /* gestureFloatingPreviewTextEnabled */,
+ true /* shouldShowUiToAcceptTypedWord */));
+ }
+
+ public void testshouldOmitTypedWordWhileGesturing() {
+ assertFalse("gesturing", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+ SuggestedWords.INPUT_STYLE_UPDATE_BATCH,
+ false /* gestureFloatingPreviewTextEnabled */,
+ false /* shouldShowUiToAcceptTypedWord */));
+ assertFalse("gesturing", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+ SuggestedWords.INPUT_STYLE_UPDATE_BATCH,
+ true /* gestureFloatingPreviewTextEnabled */,
+ false /* shouldShowUiToAcceptTypedWord */));
+ assertFalse("gesturing", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+ SuggestedWords.INPUT_STYLE_UPDATE_BATCH,
+ false /* gestureFloatingPreviewTextEnabled */,
+ true /* shouldShowUiToAcceptTypedWord */));
+ assertTrue("gesturing", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+ SuggestedWords.INPUT_STYLE_UPDATE_BATCH,
+ true /* gestureFloatingPreviewTextEnabled */,
+ true /* shouldShowUiToAcceptTypedWord */));
+ }
+
+ public void testshouldOmitTypedWordWhenGestured() {
+ assertFalse("gestured", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+ SuggestedWords.INPUT_STYLE_TAIL_BATCH,
+ false /* gestureFloatingPreviewTextEnabled */,
+ false /* shouldShowUiToAcceptTypedWord */));
+ assertFalse("gestured", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+ SuggestedWords.INPUT_STYLE_TAIL_BATCH,
+ true /* gestureFloatingPreviewTextEnabled */,
+ false /* shouldShowUiToAcceptTypedWord */));
+ assertTrue("gestured", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+ SuggestedWords.INPUT_STYLE_TAIL_BATCH,
+ false /* gestureFloatingPreviewTextEnabled */,
+ true /* shouldShowUiToAcceptTypedWord */));
+ assertTrue("gestured", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+ SuggestedWords.INPUT_STYLE_TAIL_BATCH,
+ true /* gestureFloatingPreviewTextEnabled */,
+ true /* shouldShowUiToAcceptTypedWord */));
+ }
+
+ // Note that this unit test assumes that the number of suggested words in the suggestion strip
+ // is 3.
+ private static final int POSITION_OMIT = -1;
+ private static final int POSITION_LEFT = 0;
+ private static final int POSITION_CENTER = 1;
+ private static final int POSITION_RIGHT = 2;
+
+ public void testGetPositionInSuggestionStrip() {
+ assertEquals("1st word without auto correction", POSITION_CENTER,
+ SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+ SuggestedWords.INDEX_OF_TYPED_WORD /* indexInSuggestedWords */,
+ false /* willAutoCorrect */,
+ false /* omitTypedWord */,
+ POSITION_CENTER /* centerPositionInStrip */,
+ POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+ assertEquals("2nd word without auto correction", POSITION_LEFT,
+ SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+ SuggestedWords.INDEX_OF_AUTO_CORRECTION /* indexInSuggestedWords */,
+ false /* willAutoCorrect */,
+ false /* omitTypedWord */,
+ POSITION_CENTER /* centerPositionInStrip */,
+ POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+ assertEquals("3rd word without auto correction", POSITION_RIGHT,
+ SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+ 2 /* indexInSuggestedWords */,
+ false /* willAutoCorrect */,
+ false /* omitTypedWord */,
+ POSITION_CENTER /* centerPositionInStrip */,
+ POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+
+ assertEquals("typed word with auto correction", POSITION_LEFT,
+ SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+ SuggestedWords.INDEX_OF_TYPED_WORD /* indexInSuggestedWords */,
+ true /* willAutoCorrect */,
+ false /* omitTypedWord */,
+ POSITION_CENTER /* centerPositionInStrip */,
+ POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+ assertEquals("2nd word with auto correction", POSITION_CENTER,
+ SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+ SuggestedWords.INDEX_OF_AUTO_CORRECTION /* indexInSuggestedWords */,
+ true /* willAutoCorrect */,
+ false /* omitTypedWord */,
+ POSITION_CENTER /* centerPositionInStrip */,
+ POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+ assertEquals("3rd word with auto correction", POSITION_RIGHT,
+ SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+ 2 /* indexInSuggestedWords */,
+ true /* willAutoCorrect */,
+ false /* omitTypedWord */,
+ POSITION_CENTER /* centerPositionInStrip */,
+ POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+
+ assertEquals("1st word without auto correction", POSITION_OMIT,
+ SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+ SuggestedWords.INDEX_OF_TYPED_WORD /* indexInSuggestedWords */,
+ false /* willAutoCorrect */,
+ true /* omitTypedWord */,
+ POSITION_CENTER /* centerPositionInStrip */,
+ POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+ assertEquals("2nd word without auto correction", POSITION_CENTER,
+ SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+ SuggestedWords.INDEX_OF_AUTO_CORRECTION /* indexInSuggestedWords */,
+ false /* willAutoCorrect */,
+ true /* omitTypedWord */,
+ POSITION_CENTER /* centerPositionInStrip */,
+ POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+ assertEquals("3rd word without auto correction", POSITION_LEFT,
+ SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+ 2 /* indexInSuggestedWords */,
+ false /* willAutoCorrect */,
+ true /* omitTypedWord */,
+ POSITION_CENTER /* centerPositionInStrip */,
+ POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+ assertEquals("4th word without auto correction", POSITION_RIGHT,
+ SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+ 3 /* indexInSuggestedWords */,
+ false /* willAutoCorrect */,
+ true /* omitTypedWord */,
+ POSITION_CENTER /* centerPositionInStrip */,
+ POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+
+ assertEquals("typed word with auto correction", POSITION_OMIT,
+ SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+ SuggestedWords.INDEX_OF_TYPED_WORD /* indexInSuggestedWords */,
+ true /* willAutoCorrect */,
+ true /* omitTypedWord */,
+ POSITION_CENTER /* centerPositionInStrip */,
+ POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+ assertEquals("2nd word with auto correction", POSITION_CENTER,
+ SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+ SuggestedWords.INDEX_OF_AUTO_CORRECTION /* indexInSuggestedWords */,
+ true /* willAutoCorrect */,
+ true /* omitTypedWord */,
+ POSITION_CENTER /* centerPositionInStrip */,
+ POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+ assertEquals("3rd word with auto correction", POSITION_LEFT,
+ SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+ 2 /* indexInSuggestedWords */,
+ true /* willAutoCorrect */,
+ true /* omitTypedWord */,
+ POSITION_CENTER /* centerPositionInStrip */,
+ POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+ assertEquals("4th word with auto correction", POSITION_RIGHT,
+ SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+ 3 /* indexInSuggestedWords */,
+ true /* willAutoCorrect */,
+ true /* omitTypedWord */,
+ POSITION_CENTER /* centerPositionInStrip */,
+ POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+ }
+}
diff --git a/tests/src/com/android/inputmethod/latin/utils/ImportantNoticeUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/ImportantNoticeUtilsTests.java
new file mode 100644
index 000000000..819d76328
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/utils/ImportantNoticeUtilsTests.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.utils;
+
+import static com.android.inputmethod.latin.utils.ImportantNoticeUtils.KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE;
+import static com.android.inputmethod.latin.utils.ImportantNoticeUtils.KEY_IMPORTANT_NOTICE_VERSION;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
+
+import java.util.concurrent.TimeUnit;
+
+@SmallTest
+public class ImportantNoticeUtilsTests extends AndroidTestCase {
+ // This should be aligned with R.integer.config_important_notice_version.
+ private static final int CURRENT_IMPORTANT_NOTICE_VERSION = 1;
+
+ private ImportantNoticePreferences mImportantNoticePreferences;
+
+ private static class ImportantNoticePreferences {
+ private final SharedPreferences mPref;
+
+ private Integer mVersion;
+ private Long mLastTime;
+
+ public ImportantNoticePreferences(final Context context) {
+ mPref = ImportantNoticeUtils.getImportantNoticePreferences(context);
+ }
+
+ private Integer getInt(final String key) {
+ if (mPref.contains(key)) {
+ return mPref.getInt(key, 0);
+ }
+ return null;
+ }
+
+ public Long getLong(final String key) {
+ if (mPref.contains(key)) {
+ return mPref.getLong(key, 0);
+ }
+ return null;
+ }
+
+ private void putInt(final String key, final Integer value) {
+ if (value == null) {
+ removePreference(key);
+ } else {
+ mPref.edit().putInt(key, value).apply();
+ }
+ }
+
+ private void putLong(final String key, final Long value) {
+ if (value == null) {
+ removePreference(key);
+ } else {
+ mPref.edit().putLong(key, value).apply();
+ }
+ }
+
+ private void removePreference(final String key) {
+ mPref.edit().remove(key).apply();
+ }
+
+ public void save() {
+ mVersion = getInt(KEY_IMPORTANT_NOTICE_VERSION);
+ mLastTime = getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE);
+ }
+
+ public void restore() {
+ putInt(KEY_IMPORTANT_NOTICE_VERSION, mVersion);
+ putLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE, mLastTime);
+ }
+
+ public void clear() {
+ removePreference(KEY_IMPORTANT_NOTICE_VERSION);
+ removePreference(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE);
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mImportantNoticePreferences = new ImportantNoticePreferences(getContext());
+ mImportantNoticePreferences.save();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ mImportantNoticePreferences.restore();
+ }
+
+ public void testCurrentVersion() {
+ assertEquals("Current version", CURRENT_IMPORTANT_NOTICE_VERSION,
+ ImportantNoticeUtils.getCurrentImportantNoticeVersion(getContext()));
+ }
+
+ public void testUpdateVersion() {
+ mImportantNoticePreferences.clear();
+
+ assertEquals("Current boolean before update", true,
+ ImportantNoticeUtils.shouldShowImportantNotice(getContext()));
+ assertEquals("Last version before update", 0,
+ ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
+ assertEquals("Next version before update ", 1,
+ ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
+ assertEquals("Current title before update", false, TextUtils.isEmpty(
+ ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
+ assertEquals("Current contents before update", false, TextUtils.isEmpty(
+ ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
+
+ ImportantNoticeUtils.updateLastImportantNoticeVersion(getContext());
+
+ assertEquals("Current boolean after update", false,
+ ImportantNoticeUtils.shouldShowImportantNotice(getContext()));
+ assertEquals("Last version after update", 1,
+ ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
+ assertEquals("Next version after update", 2,
+ ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
+ assertEquals("Current title after update", true, TextUtils.isEmpty(
+ ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
+ assertEquals("Current contents after update", true, TextUtils.isEmpty(
+ ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
+ }
+
+ private static void sleep(final long millseconds) {
+ try { Thread.sleep(millseconds); } catch (final Exception e) { /* ignore */ }
+ }
+
+ public void testTimeout() {
+ final long lastTime = System.currentTimeMillis()
+ - ImportantNoticeUtils.TIMEOUT_OF_IMPORTANT_NOTICE
+ + TimeUnit.MILLISECONDS.toMillis(1000);
+ mImportantNoticePreferences.clear();
+ assertEquals("Before set last time", null,
+ mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
+ assertEquals("Set last time", false,
+ ImportantNoticeUtils.hasTimeoutPassed(getContext(), lastTime));
+ assertEquals("After set last time", (Long)lastTime,
+ mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
+
+ // Call {@link ImportantNoticeUtils#shouldShowImportantNotice(Context)} before timeout.
+ assertEquals("Current boolean before timeout 1", true,
+ ImportantNoticeUtils.shouldShowImportantNotice(getContext()));
+ assertEquals("Last version before timeout 1", 0,
+ ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
+ assertEquals("Next version before timeout 1", 1,
+ ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
+ assertEquals("Last time before timeout 1", (Long)lastTime,
+ mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
+ assertEquals("Current title before timeout 1", false, TextUtils.isEmpty(
+ ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
+ assertEquals("Current contents before timeout 1", false, TextUtils.isEmpty(
+ ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
+
+ sleep(TimeUnit.MILLISECONDS.toMillis(600));
+
+ // Call {@link ImportantNoticeUtils#shouldShowImportantNotice(Context)} before timeout
+ // again.
+ assertEquals("Current boolean before timeout 2", true,
+ ImportantNoticeUtils.shouldShowImportantNotice(getContext()));
+ assertEquals("Last version before timeout 2", 0,
+ ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
+ assertEquals("Next version before timeout 2", 1,
+ ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
+ assertEquals("Last time before timeout 2", (Long)lastTime,
+ mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
+ assertEquals("Current title before timeout 2", false, TextUtils.isEmpty(
+ ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
+ assertEquals("Current contents before timeout 2", false, TextUtils.isEmpty(
+ ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
+
+ sleep(TimeUnit.MILLISECONDS.toMillis(600));
+
+ // Call {@link ImportantNoticeUtils#shouldShowImportantNotice(Context)} after timeout.
+ assertEquals("Current boolean after timeout 1", false,
+ ImportantNoticeUtils.shouldShowImportantNotice(getContext()));
+ assertEquals("Last version after timeout 1", 1,
+ ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
+ assertEquals("Next version after timeout 1", 2,
+ ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
+ assertEquals("Last time aflter timeout 1", null,
+ mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
+ assertEquals("Current title after timeout 1", true, TextUtils.isEmpty(
+ ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
+ assertEquals("Current contents after timeout 1", true, TextUtils.isEmpty(
+ ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
+
+ sleep(TimeUnit.MILLISECONDS.toMillis(600));
+
+ // Call {@link ImportantNoticeUtils#shouldShowImportantNotice(Context)} after timeout again.
+ assertEquals("Current boolean after timeout 2", false,
+ ImportantNoticeUtils.shouldShowImportantNotice(getContext()));
+ assertEquals("Last version after timeout 2", 1,
+ ImportantNoticeUtils.getLastImportantNoticeVersion(getContext()));
+ assertEquals("Next version after timeout 2", 2,
+ ImportantNoticeUtils.getNextImportantNoticeVersion(getContext()));
+ assertEquals("Last time aflter timeout 2", null,
+ mImportantNoticePreferences.getLong(KEY_TIMESTAMP_OF_FIRST_IMPORTANT_NOTICE));
+ assertEquals("Current title after timeout 2", true, TextUtils.isEmpty(
+ ImportantNoticeUtils.getNextImportantNoticeTitle(getContext())));
+ assertEquals("Current contents after timeout 2", true, TextUtils.isEmpty(
+ ImportantNoticeUtils.getNextImportantNoticeContents(getContext())));
+ }
+}
diff --git a/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java
new file mode 100644
index 000000000..ba2e99802
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.utils;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.utils.StringUtils;
+
+import java.util.Locale;
+
+@SmallTest
+public class StringUtilsTests extends AndroidTestCase {
+ private static final Locale US = Locale.US;
+ private static final Locale GERMAN = Locale.GERMAN;
+ private static final Locale TURKEY = new Locale("tr", "TR");
+ private static final Locale GREECE = new Locale("el", "GR");
+
+ private static void assert_toUpperCaseOfStringForLocale(final Locale locale,
+ final String lowerCase, final String expected) {
+ assertEquals(lowerCase + " in " + locale, expected,
+ StringUtils.toUpperCaseOfStringForLocale(
+ lowerCase, true /* needsToUpperCase */, locale));
+ }
+
+ public void test_toUpperCaseOfStringForLocale() {
+ assert_toUpperCaseOfStringForLocale(US, null, null);
+ assert_toUpperCaseOfStringForLocale(US, "", "");
+ assert_toUpperCaseOfStringForLocale(US, "aeiou", "AEIOU");
+ // U+00E0: "à" LATIN SMALL LETTER A WITH GRAVE
+ // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE
+ // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+ // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+ // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+ // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
+ // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+ // U+00C0: "À" LATIN CAPITAL LETTER A WITH GRAVE
+ // U+00C8: "È" LATIN CAPITAL LETTER E WITH GRAVE
+ // U+00CE: "Î" LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ // U+00D6: "Ö" LATIN CAPITAL LETTER O WITH DIAERESIS
+ // U+016A: "Ū" LATIN CAPITAL LETTER U WITH MACRON
+ // U+00D1: "Ñ" LATIN CAPITAL LETTER N WITH TILDE
+ // U+00C7: "Ç" LATIN CAPITAL LETTER C WITH CEDILLA
+ assert_toUpperCaseOfStringForLocale(US,
+ "\u00E0\u00E8\u00EE\u00F6\u016B\u00F1\u00E7",
+ "\u00C0\u00C8\u00CE\u00D6\u016A\u00D1\u00C7");
+ // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+ // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+ // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+ // U+015A: "Ś" LATIN CAPITAL LETTER S WITH ACUTE
+ // U+0160: "Š" LATIN CAPITAL LETTER S WITH CARONZ
+ assert_toUpperCaseOfStringForLocale(GERMAN,
+ "\u00DF\u015B\u0161",
+ "SS\u015A\u0160");
+ // U+0259: "ə" LATIN SMALL LETTER SCHWA
+ // U+0069: "i" LATIN SMALL LETTER I
+ // U+0131: "ı" LATIN SMALL LETTER DOTLESS I
+ // U+018F: "Ə" LATIN SMALL LETTER SCHWA
+ // U+0130: "İ" LATIN SMALL LETTER I WITH DOT ABOVE
+ // U+0049: "I" LATIN SMALL LETTER I
+ assert_toUpperCaseOfStringForLocale(TURKEY,
+ "\u0259\u0069\u0131",
+ "\u018F\u0130\u0049");
+ // U+03C3: "σ" GREEK SMALL LETTER SIGMA
+ // U+03C2: "ς" GREEK SMALL LETTER FINAL SIGMA
+ // U+03A3: "Σ" GREEK CAPITAL LETTER SIGMA
+ assert_toUpperCaseOfStringForLocale(GREECE,
+ "\u03C3\u03C2",
+ "\u03A3\u03A3");
+ // U+03AC: "ά" GREEK SMALL LETTER ALPHA WITH TONOS
+ // U+03AD: "έ" GREEK SMALL LETTER EPSILON WITH TONOS
+ // U+03AE: "ή" GREEK SMALL LETTER ETA WITH TONOS
+ // U+03AF: "ί" GREEK SMALL LETTER IOTA WITH TONOS
+ // U+03CC: "ό" GREEK SMALL LETTER OMICRON WITH TONOS
+ // U+03CD: "ύ" GREEK SMALL LETTER UPSILON WITH TONOS
+ // U+03CE: "ώ" GREEK SMALL LETTER OMEGA WITH TONOS
+ // U+0386: "Ά" GREEK CAPITAL LETTER ALPHA WITH TONOS
+ // U+0388: "Έ" GREEK CAPITAL LETTER EPSILON WITH TONOS
+ // U+0389: "Ή" GREEK CAPITAL LETTER ETA WITH TONOS
+ // U+038A: "Ί" GREEK CAPITAL LETTER IOTA WITH TONOS
+ // U+038C: "Ό" GREEK CAPITAL LETTER OMICRON WITH TONOS
+ // U+038E: "Ύ" GREEK CAPITAL LETTER UPSILON WITH TONOS
+ // U+038F: "Ώ" GREEK CAPITAL LETTER OMEGA WITH TONOS
+ assert_toUpperCaseOfStringForLocale(GREECE,
+ "\u03AC\u03AD\u03AE\u03AF\u03CC\u03CD\u03CE",
+ "\u0386\u0388\u0389\u038A\u038C\u038E\u038F");
+ // U+03CA: "ϊ" GREEK SMALL LETTER IOTA WITH DIALYTIKA
+ // U+03CB: "ϋ" GREEK SMALL LETTER UPSILON WITH DIALYTIKA
+ // U+0390: "ΐ" GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+ // U+03B0: "ΰ" GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+ // U+03AA: "Ϊ" GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
+ // U+03AB: "Ϋ" GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+ // U+0399: "Ι" GREEK CAPITAL LETTER IOTA
+ // U+03A5: "Υ" GREEK CAPITAL LETTER UPSILON
+ // U+0308: COMBINING DIAERESIS
+ // U+0301: COMBINING GRAVE ACCENT
+ assert_toUpperCaseOfStringForLocale(GREECE,
+ "\u03CA\u03CB\u0390\u03B0",
+ "\u03AA\u03AB\u0399\u0308\u0301\u03A5\u0308\u0301");
+ }
+
+ private static void assert_toUpperCaseOfCodeForLocale(final Locale locale, final int lowerCase,
+ final int expected) {
+ assertEquals(lowerCase + " in " + locale, expected,
+ StringUtils.toUpperCaseOfCodeForLocale(
+ lowerCase, true /* needsToUpperCase */, locale));
+ }
+
+ public void test_toUpperCaseOfCodeForLocale() {
+ assert_toUpperCaseOfCodeForLocale(US, Constants.CODE_ENTER, Constants.CODE_ENTER);
+ assert_toUpperCaseOfCodeForLocale(US, Constants.CODE_SPACE, Constants.CODE_SPACE);
+ assert_toUpperCaseOfCodeForLocale(US, Constants.CODE_COMMA, Constants.CODE_COMMA);
+ // U+0069: "i" LATIN SMALL LETTER I
+ // U+0131: "ı" LATIN SMALL LETTER DOTLESS I
+ // U+0130: "İ" LATIN SMALL LETTER I WITH DOT ABOVE
+ // U+0049: "I" LATIN SMALL LETTER I
+ assert_toUpperCaseOfCodeForLocale(US, 0x0069, 0x0049); // i -> I
+ assert_toUpperCaseOfCodeForLocale(US, 0x0131, 0x0049); // ı -> I
+ assert_toUpperCaseOfCodeForLocale(TURKEY, 0x0069, 0x0130); // i -> İ
+ assert_toUpperCaseOfCodeForLocale(TURKEY, 0x0131, 0x0049); // ı -> I
+ // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+ // The title case of "ß" is "SS".
+ assert_toUpperCaseOfCodeForLocale(US, 0x00DF, Constants.CODE_UNSPECIFIED);
+ // U+03AC: "ά" GREEK SMALL LETTER ALPHA WITH TONOS
+ // U+0386: "Ά" GREEK CAPITAL LETTER ALPHA WITH TONOS
+ assert_toUpperCaseOfCodeForLocale(GREECE, 0x03AC, 0x0386);
+ // U+03CA: "ϊ" GREEK SMALL LETTER IOTA WITH DIALYTIKA
+ // U+03AA: "Ϊ" GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
+ assert_toUpperCaseOfCodeForLocale(GREECE, 0x03CA, 0x03AA);
+ // U+03B0: "ΰ" GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+ // The title case of "ΰ" is "\u03A5\u0308\u0301".
+ assert_toUpperCaseOfCodeForLocale(GREECE, 0x03B0, Constants.CODE_UNSPECIFIED);
+ }
+
+ private static void assert_capitalizeFirstCodePoint(final Locale locale, final String text,
+ final String expected) {
+ assertEquals(text + " in " + locale, expected,
+ StringUtils.capitalizeFirstCodePoint(text, locale));
+ }
+
+ public void test_capitalizeFirstCodePoint() {
+ assert_capitalizeFirstCodePoint(US, "", "");
+ assert_capitalizeFirstCodePoint(US, "a", "A");
+ assert_capitalizeFirstCodePoint(US, "à", "À");
+ assert_capitalizeFirstCodePoint(US, "ß", "SS");
+ assert_capitalizeFirstCodePoint(US, "text", "Text");
+ assert_capitalizeFirstCodePoint(US, "iGoogle", "IGoogle");
+ assert_capitalizeFirstCodePoint(TURKEY, "iyi", "İyi");
+ assert_capitalizeFirstCodePoint(TURKEY, "ısırdı", "Isırdı");
+ assert_capitalizeFirstCodePoint(GREECE, "ά", "Ά");
+ assert_capitalizeFirstCodePoint(GREECE, "άνεση", "Άνεση");
+ }
+
+ private static void assert_capitalizeFirstAndDowncaseRest(final Locale locale,
+ final String text, final String expected) {
+ assertEquals(text + " in " + locale, expected,
+ StringUtils.capitalizeFirstAndDowncaseRest(text, locale));
+ }
+
+ public void test_capitalizeFirstAndDowncaseRest() {
+ assert_capitalizeFirstAndDowncaseRest(US, "", "");
+ assert_capitalizeFirstAndDowncaseRest(US, "a", "A");
+ assert_capitalizeFirstAndDowncaseRest(US, "à", "À");
+ assert_capitalizeFirstAndDowncaseRest(US, "ß", "SS");
+ assert_capitalizeFirstAndDowncaseRest(US, "text", "Text");
+ assert_capitalizeFirstAndDowncaseRest(US, "iGoogle", "Igoogle");
+ assert_capitalizeFirstAndDowncaseRest(US, "invite", "Invite");
+ assert_capitalizeFirstAndDowncaseRest(US, "INVITE", "Invite");
+ assert_capitalizeFirstAndDowncaseRest(TURKEY, "iyi", "İyi");
+ assert_capitalizeFirstAndDowncaseRest(TURKEY, "İYİ", "İyi");
+ assert_capitalizeFirstAndDowncaseRest(TURKEY, "ısırdı", "Isırdı");
+ assert_capitalizeFirstAndDowncaseRest(TURKEY, "ISIRDI", "Isırdı");
+ assert_capitalizeFirstAndDowncaseRest(GREECE, "ά", "Ά");
+ assert_capitalizeFirstAndDowncaseRest(GREECE, "άνεση", "Άνεση");
+ assert_capitalizeFirstAndDowncaseRest(GREECE, "ΆΝΕΣΗ", "Άνεση");
+ }
+}
diff --git a/tools/dicttool/Android.mk b/tools/dicttool/Android.mk
index b108a8a81..3e3d419e6 100644
--- a/tools/dicttool/Android.mk
+++ b/tools/dicttool/Android.mk
@@ -13,6 +13,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+# Only build if it's explicitly requested, or running mm/mmm.
+ifneq ($(ONE_SHOT_MAKEFILE)$(filter $(MAKECMDGOALS),dicttool_aosp),)
+
# HACK: Temporarily disable host tool build on Mac until the build system is ready for C++11.
LATINIME_HOST_OSNAME := $(shell uname -s)
ifeq ($(LATINIME_HOST_OSNAME), Darwin) # TODO: Remove this
@@ -29,10 +32,12 @@ LOCAL_PATH := $(LATINIME_DICTTOOL_AOSP_LOCAL_PATH)
include $(CLEAR_VARS)
LATINIME_LOCAL_DIR := ../..
-LATINIME_BASE_SOURCE_DIRECTORY := $(LATINIME_LOCAL_DIR)/java/src/com/android/inputmethod
-LATINIME_ANNOTATIONS_SOURCE_DIRECTORY := $(LATINIME_BASE_SOURCE_DIRECTORY)/annotations
-MAKEDICT_CORE_SOURCE_DIRECTORY := $(LATINIME_BASE_SOURCE_DIRECTORY)/latin/makedict
-LATINIME_TESTS_SOURCE_DIRECTORY := $(LATINIME_LOCAL_DIR)/tests/src/com/android/inputmethod/latin
+LATINIME_BASE_SRC_DIR := $(LATINIME_LOCAL_DIR)/java/src/com/android/inputmethod
+LATINIME_BASE_OVERRIDABLE_SRC_DIR := \
+ $(LATINIME_LOCAL_DIR)/java-overridable/src/com/android/inputmethod
+LATINIME_ANNOTATIONS_SRC_DIR := $(LATINIME_BASE_SRC_DIR)/annotations
+MAKEDICT_CORE_SRC_DIR := $(LATINIME_BASE_SRC_DIR)/latin/makedict
+LATINIME_TESTS_SRC_DIR := $(LATINIME_LOCAL_DIR)/tests/src/com/android/inputmethod/latin
# Dependencies for Dicttool. Most of these files are needed by BinaryDictionary.java. Note that
# a significant part of the dependencies are mocked in the compat/ directory, with empty or
@@ -48,7 +53,6 @@ LATINIME_SRC_FILES_FOR_DICTTOOL := \
latin/PrevWordsInfo.java \
latin/SuggestedWords.java \
latin/WordComposer.java \
- latin/define/DebugFlags.java \
latin/settings/NativeSuggestOptions.java \
latin/settings/SettingsValuesForSuggestion.java \
latin/utils/BinaryDictionaryUtils.java \
@@ -60,31 +64,36 @@ LATINIME_SRC_FILES_FOR_DICTTOOL := \
latin/utils/ResizableIntArray.java \
latin/utils/StringUtils.java
+LATINIME_OVERRIDABLE_SRC_FILES_FOR_DICTTOOL := \
+ latin/define/DebugFlags.java
+
LATINIME_TEST_SRC_FILES_FOR_DICTTOOL := \
utils/ByteArrayDictBuffer.java
-USED_TARGETED_SRCS := \
- $(addprefix $(LATINIME_BASE_SOURCE_DIRECTORY)/, $(LATINIME_SRC_FILES_FOR_DICTTOOL)) \
- $(addprefix $(LATINIME_TESTS_SOURCE_DIRECTORY)/, $(LATINIME_TEST_SRC_FILES_FOR_DICTTOOL))
+USED_TARGETED_SRC_FILES := \
+ $(addprefix $(LATINIME_BASE_SRC_DIR)/, $(LATINIME_SRC_FILES_FOR_DICTTOOL)) \
+ $(addprefix $(LATINIME_BASE_OVERRIDABLE_SRC_DIR)/, \
+ $(LATINIME_OVERRIDABLE_SRC_FILES_FOR_DICTTOOL)) \
+ $(addprefix $(LATINIME_TESTS_SRC_DIR)/, $(LATINIME_TEST_SRC_FILES_FOR_DICTTOOL))
-DICTTOOL_ONDEVICE_TESTS_DIRECTORY := \
+DICTTOOL_ONDEVICE_TESTS_DIR := \
$(LATINIME_LOCAL_DIR)/tests/src/com/android/inputmethod/latin/makedict/
-DICTTOOL_COMPAT_TESTS_DIRECTORY := compat
+DICTTOOL_COMPAT_TESTS_DIR := compat
-LOCAL_MAIN_SRC_FILES := $(call all-java-files-under, $(MAKEDICT_CORE_SOURCE_DIRECTORY))
+LOCAL_MAIN_SRC_FILES := $(call all-java-files-under, $(MAKEDICT_CORE_SRC_DIR))
LOCAL_TOOL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_ANNOTATIONS_SRC_FILES := \
- $(call all-java-files-under, $(LATINIME_ANNOTATIONS_SOURCE_DIRECTORY))
+LOCAL_ANNOTATIONS_SRC_FILES := $(call all-java-files-under, $(LATINIME_ANNOTATIONS_SRC_DIR))
LOCAL_SRC_FILES := $(LOCAL_TOOL_SRC_FILES) \
$(filter-out $(addprefix %/, $(notdir $(LOCAL_TOOL_SRC_FILES))), $(LOCAL_MAIN_SRC_FILES)) \
- $(call all-java-files-under, $(DICTTOOL_COMPAT_TESTS_DIRECTORY)) \
- $(LOCAL_ANNOTATIONS_SRC_FILES) $(USED_TARGETED_SRCS) \
- $(LATINIME_BASE_SOURCE_DIRECTORY)/latin/Constants.java \
+ $(call all-java-files-under, $(DICTTOOL_COMPAT_TESTS_DIR)) \
+ $(LOCAL_ANNOTATIONS_SRC_FILES) $(USED_TARGETED_SRC_FILES) \
+ $(LATINIME_BASE_SRC_DIR)/latin/Constants.java \
$(call all-java-files-under, tests) \
- $(call all-java-files-under, $(DICTTOOL_ONDEVICE_TESTS_DIRECTORY))
+ $(call all-java-files-under, $(DICTTOOL_ONDEVICE_TESTS_DIR))
LOCAL_JAVA_LIBRARIES := junit
+LOCAL_STATIC_JAVA_LIBRARIES := jsr305lib
LOCAL_REQUIRED_MODULES := $(LATINIME_HOST_NATIVE_LIBNAME)
LOCAL_JAR_MANIFEST := etc/manifest.txt
LOCAL_MODULE := dicttool_aosp
@@ -98,3 +107,5 @@ endif # Darwin - TODO: Remove this
LATINIME_DICTTOOL_AOSP_LOCAL_PATH :=
LATINIME_LOCAL_DIR :=
LATINIME_HOST_OSNAME :=
+
+endif
diff --git a/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java b/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java
index 458f22c45..c4457a1b7 100644
--- a/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java
+++ b/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java
@@ -31,8 +31,12 @@ public class CombinerChain {
mComposingWord = new StringBuilder(initialText);
}
- public void processEvent(final ArrayList<Event> previousEvents, final Event newEvent) {
- mComposingWord.append(newEvent.getTextToCommit());
+ public Event processEvent(final ArrayList<Event> previousEvents, final Event newEvent) {
+ return newEvent;
+ }
+
+ public void applyProcessedEvent(final Event event) {
+ mComposingWord.append(event.getTextToCommit());
}
public CharSequence getComposingWordWithCombiningFeedback() {
diff --git a/tools/make-keyboard-text/res/values-bn-rIN/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-bn-rIN/donottranslate-more-keys.xml
index 4955cd46a..1ec4249d0 100644
--- a/tools/make-keyboard-text/res/values-bn-rIN/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-bn-rIN/donottranslate-more-keys.xml
@@ -23,6 +23,6 @@
U+0996: "ख" BENGALI LETTER KHA
U+0997: "ग" BENGALI LETTER GA -->
<string name="keylabel_to_alpha">&#x0995;&#x0996;&#x0997;</string>
- <!-- U+09F3: "৳" BENGALI RUPEE SIGN -->
- <string name="keyspec_currency">&#x09F3;</string>
+ <!-- U+20B9: "₹" INDIAN RUPEE SIGN -->
+ <string name="keyspec_currency">&#x20B9;</string>
</resources>
diff --git a/tools/make-keyboard-text/res/values-si-rLK/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-si-rLK/donottranslate-more-keys.xml
index 89c9195e8..871d82ab0 100644
--- a/tools/make-keyboard-text/res/values-si-rLK/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-si-rLK/donottranslate-more-keys.xml
@@ -22,4 +22,6 @@
U+0D85: "අ" SINHALA LETTER AYANNA
U+0D86: "ආ" SINHALA LETTER AAYANNA -->
<string name="keylabel_to_alpha">&#x0D85;,&#x0D86;</string>
+ <!-- U+0DBB/U+0DD4: "රු" SINHALA LETTER RAYANNA/SINHALA VOWEL SIGN KETTI PAA-PILLA -->
+ <string name="keyspec_currency">&#x0DBB;&#x0DD4;</string>
</resources>
diff --git a/tools/make-keyboard-text/res/values-ta-rLK/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-ta-rLK/donottranslate-more-keys.xml
new file mode 100644
index 000000000..9e900a6b1
--- /dev/null
+++ b/tools/make-keyboard-text/res/values-ta-rLK/donottranslate-more-keys.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Label for "switch to alphabetic" key.
+ U+0BA4: "த" TAMIL LETTER TA
+ U+0BAE/U+0BBF: "மி" TAMIL LETTER MA/TAMIL VOWEL SIGN I
+ U+0BB4/U+0BCD: "ழ்" TAMIL LETTER LLLA/TAMIL SIGN VIRAMA -->
+ <string name="keylabel_to_alpha">&#x0BA4;&#x0BAE;&#x0BBF;&#x0BB4;&#x0BCD;</string>
+ <!-- U+0DBB/U+0DD4: "රු" SINHALA LETTER RAYANNA/SINHALA VOWEL SIGN KETTI PAA-PILLA -->
+ <string name="keyspec_currency">&#x0DBB;&#x0DD4;</string>
+</resources>
diff --git a/tools/make-keyboard-text/res/values-ta-rSG/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-ta-rSG/donottranslate-more-keys.xml
new file mode 100644
index 000000000..07e4d8beb
--- /dev/null
+++ b/tools/make-keyboard-text/res/values-ta-rSG/donottranslate-more-keys.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Label for "switch to alphabetic" key.
+ U+0BA4: "த" TAMIL LETTER TA
+ U+0BAE/U+0BBF: "மி" TAMIL LETTER MA/TAMIL VOWEL SIGN I
+ U+0BB4/U+0BCD: "ழ்" TAMIL LETTER LLLA/TAMIL SIGN VIRAMA -->
+ <string name="keylabel_to_alpha">&#x0BA4;&#x0BAE;&#x0BBF;&#x0BB4;&#x0BCD;</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 4b9ca162e..c4a1b889e 100644
--- a/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml
@@ -87,7 +87,7 @@
U+20B1: "₱" PESO SIGN -->
<string name="morekeys_currency_dollar">&#x00A2;,&#x00A3;,&#x20AC;,&#x00A5;,&#x20B1;</string>
<string name="keyspec_currency">$</string>
- <string name="morekeys_currency">$,&#x00A2;,&#x20AC;,&#x00A3;,&#x00A5;,&#x20B1;</string>
+ <string name="morekeys_currency_generic">$,&#x00A2;,&#x20AC;,&#x00A3;,&#x00A5;,&#x20B1;</string>
<string name="morekeys_punctuation">"!autoColumnOrder!8,\\,,?,!,#,!text/keyspec_right_parenthesis,!text/keyspec_left_parenthesis,/,;,',@,:,-,\",+,\\%,&amp;"</string>
<string name="morekeys_tablet_punctuation">"!autoColumnOrder!7,\\,,',#,!text/keyspec_right_parenthesis,!text/keyspec_left_parenthesis,/,;,@,:,-,\",+,\\%,&amp;"</string>
<!-- U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE -->
@@ -258,5 +258,5 @@
<string name="morekeys_single_quote">!fixedColumnOrder!5,!text/single_quotes,!text/single_angle_quotes</string>
<string name="morekeys_double_quote">!fixedColumnOrder!5,!text/double_quotes,!text/double_angle_quotes</string>
<string name="morekeys_tablet_double_quote">!fixedColumnOrder!6,!text/double_quotes,!text/single_quotes,!text/double_angle_quotes,!text/single_angle_quotes</string>
- <string name="keyspec_emoji_key">!icon/emoji_key|!code/key_emoji</string>
+ <string name="keyspec_emoji_action_key">!icon/emoji_action_key|!code/key_emoji</string>
</resources>