diff --git a/CleanSpec.mk b/CleanSpec.mk index 7cdf69a6a..44ff0a29d 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -47,6 +47,7 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/LatinIME*) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/LatinIME.apk) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libjni_latinime_intermediates) # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST # ************************************************ diff --git a/java/res/drawable-en-hdpi/sym_keyboard_delete.png b/java/res/drawable-en-hdpi/sym_keyboard_delete.png deleted file mode 100755 index 569369e79..000000000 Binary files a/java/res/drawable-en-hdpi/sym_keyboard_delete.png and /dev/null differ diff --git a/java/res/drawable-en-mdpi/sym_keyboard_delete.png b/java/res/drawable-en-mdpi/sym_keyboard_delete.png deleted file mode 100644 index f1f7c58cf..000000000 Binary files a/java/res/drawable-en-mdpi/sym_keyboard_delete.png and /dev/null differ diff --git a/java/res/drawable-en-mdpi/sym_keyboard_feedback_delete.png b/java/res/drawable-en-mdpi/sym_keyboard_feedback_delete.png deleted file mode 100644 index 3c9083972..000000000 Binary files a/java/res/drawable-en-mdpi/sym_keyboard_feedback_delete.png and /dev/null differ diff --git a/java/res/drawable-hdpi/btn_close_normal.png b/java/res/drawable-hdpi/btn_close_normal.png deleted file mode 100644 index 38b49f1a3..000000000 Binary files a/java/res/drawable-hdpi/btn_close_normal.png and /dev/null differ diff --git a/java/res/drawable-hdpi/btn_close_pressed.png b/java/res/drawable-hdpi/btn_close_pressed.png deleted file mode 100644 index aa9ea49f0..000000000 Binary files a/java/res/drawable-hdpi/btn_close_pressed.png and /dev/null differ diff --git a/java/res/drawable-hdpi/btn_close_selected.png b/java/res/drawable-hdpi/btn_close_selected.png deleted file mode 100644 index 870c670f7..000000000 Binary files a/java/res/drawable-hdpi/btn_close_selected.png and /dev/null differ diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal.9.png new file mode 100644 index 000000000..045e1bba7 Binary files /dev/null and b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal.9.png differ diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off.9.png new file mode 100644 index 000000000..14424b4c2 Binary files /dev/null and b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off.9.png differ diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on.9.png new file mode 100644 index 000000000..f30ad1e7b Binary files /dev/null and b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on.9.png differ diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed.9.png new file mode 100644 index 000000000..3622e6203 Binary files /dev/null and b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed.9.png differ diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off.9.png new file mode 100644 index 000000000..2733f9af7 Binary files /dev/null and b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off.9.png differ diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on.9.png new file mode 100644 index 000000000..a351be7a2 Binary files /dev/null and b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on.9.png differ diff --git a/java/res/drawable-hdpi/btn_keyboard_key_light_normal.9.png b/java/res/drawable-hdpi/btn_keyboard_key_light_normal.9.png new file mode 100644 index 000000000..e9e889c29 Binary files /dev/null and b/java/res/drawable-hdpi/btn_keyboard_key_light_normal.9.png differ diff --git a/java/res/drawable-hdpi/btn_keyboard_key_light_popup_normal.9.png b/java/res/drawable-hdpi/btn_keyboard_key_light_popup_normal.9.png new file mode 100644 index 000000000..959c6d14a Binary files /dev/null and b/java/res/drawable-hdpi/btn_keyboard_key_light_popup_normal.9.png differ diff --git a/java/res/drawable-hdpi/btn_keyboard_key_light_popup_selected.9.png b/java/res/drawable-hdpi/btn_keyboard_key_light_popup_selected.9.png new file mode 100644 index 000000000..1e6688c91 Binary files /dev/null and b/java/res/drawable-hdpi/btn_keyboard_key_light_popup_selected.9.png differ diff --git a/java/res/drawable-hdpi/btn_keyboard_key_light_pressed.9.png b/java/res/drawable-hdpi/btn_keyboard_key_light_pressed.9.png new file mode 100644 index 000000000..597eb15b2 Binary files /dev/null and b/java/res/drawable-hdpi/btn_keyboard_key_light_pressed.9.png differ diff --git a/java/res/drawable-hdpi/btn_keyboard_normal_metal.9.png b/java/res/drawable-hdpi/btn_keyboard_normal_metal.9.png deleted file mode 100644 index b29d6d174..000000000 Binary files a/java/res/drawable-hdpi/btn_keyboard_normal_metal.9.png and /dev/null differ diff --git a/java/res/drawable-hdpi/btn_keyboard_toggle_off.png b/java/res/drawable-hdpi/btn_keyboard_toggle_off.png deleted file mode 100644 index bfe78402f..000000000 Binary files a/java/res/drawable-hdpi/btn_keyboard_toggle_off.png and /dev/null differ diff --git a/java/res/drawable-hdpi/btn_keyboard_toggle_on.png b/java/res/drawable-hdpi/btn_keyboard_toggle_on.png deleted file mode 100644 index 0a1221e97..000000000 Binary files a/java/res/drawable-hdpi/btn_keyboard_toggle_on.png and /dev/null differ diff --git a/java/res/drawable-hdpi/btn_led_off.9.png b/java/res/drawable-hdpi/btn_led_off.9.png deleted file mode 100644 index a60f96539..000000000 Binary files a/java/res/drawable-hdpi/btn_led_off.9.png and /dev/null differ diff --git a/java/res/drawable-hdpi/btn_led_on.9.png b/java/res/drawable-hdpi/btn_led_on.9.png deleted file mode 100644 index c90260967..000000000 Binary files a/java/res/drawable-hdpi/btn_led_on.9.png and /dev/null differ diff --git a/java/res/drawable-hdpi/cancel.png b/java/res/drawable-hdpi/cancel.png index 6585bde17..506cf99d0 100755 Binary files a/java/res/drawable-hdpi/cancel.png and b/java/res/drawable-hdpi/cancel.png differ diff --git a/java/res/drawable-hdpi/dialog_top_dark_bottom_medium.9.png b/java/res/drawable-hdpi/dialog_top_dark_bottom_medium.9.png deleted file mode 100644 index ab6c036c3..000000000 Binary files a/java/res/drawable-hdpi/dialog_top_dark_bottom_medium.9.png and /dev/null differ diff --git a/java/res/drawable-hdpi/ic_dialog_alert_large.png b/java/res/drawable-hdpi/ic_dialog_alert_large.png deleted file mode 100755 index 7e2646d65..000000000 Binary files a/java/res/drawable-hdpi/ic_dialog_alert_large.png and /dev/null differ diff --git a/java/res/drawable-hdpi/ic_dialog_voice_input.png b/java/res/drawable-hdpi/ic_dialog_voice_input.png deleted file mode 100755 index 11a3cfe77..000000000 Binary files a/java/res/drawable-hdpi/ic_dialog_voice_input.png and /dev/null differ diff --git a/java/res/drawable-hdpi/ic_dialog_wave_0_0.png b/java/res/drawable-hdpi/ic_dialog_wave_0_0.png deleted file mode 100755 index 33023c3f7..000000000 Binary files a/java/res/drawable-hdpi/ic_dialog_wave_0_0.png and /dev/null differ diff --git a/java/res/drawable-hdpi/ic_dialog_wave_1_3.png b/java/res/drawable-hdpi/ic_dialog_wave_1_3.png deleted file mode 100755 index 662686c0f..000000000 Binary files a/java/res/drawable-hdpi/ic_dialog_wave_1_3.png and /dev/null differ diff --git a/java/res/drawable-hdpi/ic_dialog_wave_2_3.png b/java/res/drawable-hdpi/ic_dialog_wave_2_3.png deleted file mode 100755 index e23ada57e..000000000 Binary files a/java/res/drawable-hdpi/ic_dialog_wave_2_3.png and /dev/null differ diff --git a/java/res/drawable-hdpi/ic_dialog_wave_3_3.png b/java/res/drawable-hdpi/ic_dialog_wave_3_3.png deleted file mode 100755 index 5fe5492ad..000000000 Binary files a/java/res/drawable-hdpi/ic_dialog_wave_3_3.png and /dev/null differ diff --git a/java/res/drawable-hdpi/ic_dialog_wave_4_3.png b/java/res/drawable-hdpi/ic_dialog_wave_4_3.png deleted file mode 100755 index 81b803fd0..000000000 Binary files a/java/res/drawable-hdpi/ic_dialog_wave_4_3.png and /dev/null differ diff --git a/java/res/drawable-hdpi/ic_suggest_strip_scroll_left_arrow.png b/java/res/drawable-hdpi/ic_suggest_strip_scroll_left_arrow.png deleted file mode 100755 index e375f262f..000000000 Binary files a/java/res/drawable-hdpi/ic_suggest_strip_scroll_left_arrow.png and /dev/null differ diff --git a/java/res/drawable-hdpi/ic_suggest_strip_scroll_right_arrow.png b/java/res/drawable-hdpi/ic_suggest_strip_scroll_right_arrow.png deleted file mode 100755 index d38ae7562..000000000 Binary files a/java/res/drawable-hdpi/ic_suggest_strip_scroll_right_arrow.png and /dev/null differ diff --git a/java/res/drawable-hdpi/keyboard_dark_background.9.png b/java/res/drawable-hdpi/keyboard_dark_background.9.png new file mode 100755 index 000000000..2d5c02080 Binary files /dev/null and b/java/res/drawable-hdpi/keyboard_dark_background.9.png differ diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_background.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_background.9.png index 6ba42db82..92b478854 100644 Binary files a/java/res/drawable-hdpi/keyboard_key_feedback_background.9.png and b/java/res/drawable-hdpi/keyboard_key_feedback_background.9.png differ diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_more_background.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_more_background.9.png index 4d0b60109..cfeeefb22 100644 Binary files a/java/res/drawable-hdpi/keyboard_key_feedback_more_background.9.png and b/java/res/drawable-hdpi/keyboard_key_feedback_more_background.9.png differ diff --git a/java/res/drawable-hdpi/keyboard_popup_panel_background.9.png b/java/res/drawable-hdpi/keyboard_popup_panel_background.9.png old mode 100644 new mode 100755 index 8e2461b3f..f94bc38ed Binary files a/java/res/drawable-hdpi/keyboard_popup_panel_background.9.png and b/java/res/drawable-hdpi/keyboard_popup_panel_background.9.png differ diff --git a/java/res/drawable-hdpi/keyboard_popup_panel_trans_background.9.png b/java/res/drawable-hdpi/keyboard_popup_panel_trans_background.9.png deleted file mode 100644 index fd7366e20..000000000 Binary files a/java/res/drawable-hdpi/keyboard_popup_panel_trans_background.9.png and /dev/null differ diff --git a/java/res/drawable-hdpi/keyboard_suggest_strip.9.png b/java/res/drawable-hdpi/keyboard_suggest_strip.9.png index 0cbb3ed86..0ccdb6ab2 100755 Binary files a/java/res/drawable-hdpi/keyboard_suggest_strip.9.png and b/java/res/drawable-hdpi/keyboard_suggest_strip.9.png differ diff --git a/java/res/drawable-hdpi/keyboard_suggest_strip_divider.png b/java/res/drawable-hdpi/keyboard_suggest_strip_divider.png index a5980388a..7ca3e6131 100644 Binary files a/java/res/drawable-hdpi/keyboard_suggest_strip_divider.png and b/java/res/drawable-hdpi/keyboard_suggest_strip_divider.png differ diff --git a/java/res/drawable-hdpi/mic_slash.png b/java/res/drawable-hdpi/mic_slash.png old mode 100644 new mode 100755 index a7b734c71..dc8da6252 Binary files a/java/res/drawable-hdpi/mic_slash.png and b/java/res/drawable-hdpi/mic_slash.png differ diff --git a/java/res/drawable-hdpi/ok_cancel.png b/java/res/drawable-hdpi/ok_cancel.png index 6a99528ef..f11e57a38 100755 Binary files a/java/res/drawable-hdpi/ok_cancel.png and b/java/res/drawable-hdpi/ok_cancel.png differ diff --git a/java/res/drawable-hdpi/speak_now_level0.png b/java/res/drawable-hdpi/speak_now_level0.png index a681da606..342849cfe 100755 Binary files a/java/res/drawable-hdpi/speak_now_level0.png and b/java/res/drawable-hdpi/speak_now_level0.png differ diff --git a/java/res/drawable-hdpi/speak_now_level1.png b/java/res/drawable-hdpi/speak_now_level1.png index 0dbec69a7..8947a4306 100755 Binary files a/java/res/drawable-hdpi/speak_now_level1.png and b/java/res/drawable-hdpi/speak_now_level1.png differ diff --git a/java/res/drawable-hdpi/speak_now_level2.png b/java/res/drawable-hdpi/speak_now_level2.png index 45cbff2b7..44fc58c4e 100755 Binary files a/java/res/drawable-hdpi/speak_now_level2.png and b/java/res/drawable-hdpi/speak_now_level2.png differ diff --git a/java/res/drawable-hdpi/speak_now_level3.png b/java/res/drawable-hdpi/speak_now_level3.png index abda8f683..cfa5c1b87 100755 Binary files a/java/res/drawable-hdpi/speak_now_level3.png and b/java/res/drawable-hdpi/speak_now_level3.png differ diff --git a/java/res/drawable-hdpi/speak_now_level4.png b/java/res/drawable-hdpi/speak_now_level4.png index 18356351a..a050d8836 100755 Binary files a/java/res/drawable-hdpi/speak_now_level4.png and b/java/res/drawable-hdpi/speak_now_level4.png differ diff --git a/java/res/drawable-hdpi/speak_now_level5.png b/java/res/drawable-hdpi/speak_now_level5.png index 7d4fd5f20..8cd5ae7ad 100755 Binary files a/java/res/drawable-hdpi/speak_now_level5.png and b/java/res/drawable-hdpi/speak_now_level5.png differ diff --git a/java/res/drawable-hdpi/speak_now_level6.png b/java/res/drawable-hdpi/speak_now_level6.png index e06990faa..9f4481eb4 100755 Binary files a/java/res/drawable-hdpi/speak_now_level6.png and b/java/res/drawable-hdpi/speak_now_level6.png differ diff --git a/java/res/drawable-hdpi/sym_bkeyboard_globe.png b/java/res/drawable-hdpi/sym_bkeyboard_globe.png deleted file mode 100644 index f5dbe0cd1..000000000 Binary files a/java/res/drawable-hdpi/sym_bkeyboard_globe.png and /dev/null differ diff --git a/java/res/drawable-hdpi/sym_bkeyboard_settings.png b/java/res/drawable-hdpi/sym_bkeyboard_settings.png new file mode 100644 index 000000000..08ba18f28 Binary files /dev/null and b/java/res/drawable-hdpi/sym_bkeyboard_settings.png differ diff --git a/java/res/drawable-hdpi/sym_bkeyboard_tabprev.png b/java/res/drawable-hdpi/sym_bkeyboard_tabprev.png deleted file mode 100644 index eb4f0eb68..000000000 Binary files a/java/res/drawable-hdpi/sym_bkeyboard_tabprev.png and /dev/null differ diff --git a/java/res/drawable-hdpi/sym_keyboard_delete.png b/java/res/drawable-hdpi/sym_keyboard_delete.png index 59d78bec0..3c89e2820 100755 Binary files a/java/res/drawable-hdpi/sym_keyboard_delete.png and b/java/res/drawable-hdpi/sym_keyboard_delete.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_feedback_123_mic.png b/java/res/drawable-hdpi/sym_keyboard_feedback_123_mic.png index f57e581d5..eef789680 100644 Binary files a/java/res/drawable-hdpi/sym_keyboard_feedback_123_mic.png and b/java/res/drawable-hdpi/sym_keyboard_feedback_123_mic.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_feedback_delete.png b/java/res/drawable-hdpi/sym_keyboard_feedback_delete.png index ca7637552..f13a52365 100755 Binary files a/java/res/drawable-hdpi/sym_keyboard_feedback_delete.png and b/java/res/drawable-hdpi/sym_keyboard_feedback_delete.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_left.png b/java/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_left.png index c7638bff1..889477cfb 100644 Binary files a/java/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_left.png and b/java/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_left.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_right.png b/java/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_right.png index 7acb07c86..b0f6d7feb 100644 Binary files a/java/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_right.png and b/java/res/drawable-hdpi/sym_keyboard_feedback_language_arrows_right.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_feedback_mic.png b/java/res/drawable-hdpi/sym_keyboard_feedback_mic.png old mode 100644 new mode 100755 index cb86a5598..f82c33ae3 Binary files a/java/res/drawable-hdpi/sym_keyboard_feedback_mic.png and b/java/res/drawable-hdpi/sym_keyboard_feedback_mic.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_feedback_numalt.png b/java/res/drawable-hdpi/sym_keyboard_feedback_numalt.png old mode 100755 new mode 100644 index 728c6f7d4..819236c8e Binary files a/java/res/drawable-hdpi/sym_keyboard_feedback_numalt.png and b/java/res/drawable-hdpi/sym_keyboard_feedback_numalt.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_feedback_return.png b/java/res/drawable-hdpi/sym_keyboard_feedback_return.png old mode 100755 new mode 100644 index ae57299e4..f038d3abe Binary files a/java/res/drawable-hdpi/sym_keyboard_feedback_return.png and b/java/res/drawable-hdpi/sym_keyboard_feedback_return.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_feedback_search.png b/java/res/drawable-hdpi/sym_keyboard_feedback_search.png index d931b39e2..337f9e4fe 100755 Binary files a/java/res/drawable-hdpi/sym_keyboard_feedback_search.png and b/java/res/drawable-hdpi/sym_keyboard_feedback_search.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_feedback_settings.png b/java/res/drawable-hdpi/sym_keyboard_feedback_settings.png new file mode 100755 index 000000000..7dee8984f Binary files /dev/null and b/java/res/drawable-hdpi/sym_keyboard_feedback_settings.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_feedback_shift.png b/java/res/drawable-hdpi/sym_keyboard_feedback_shift.png index 4db31c849..4484d0306 100755 Binary files a/java/res/drawable-hdpi/sym_keyboard_feedback_shift.png and b/java/res/drawable-hdpi/sym_keyboard_feedback_shift.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_feedback_shift_locked.png b/java/res/drawable-hdpi/sym_keyboard_feedback_shift_locked.png index 3fd5659fd..26000da50 100755 Binary files a/java/res/drawable-hdpi/sym_keyboard_feedback_shift_locked.png and b/java/res/drawable-hdpi/sym_keyboard_feedback_shift_locked.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_feedback_space.png b/java/res/drawable-hdpi/sym_keyboard_feedback_space.png index 98266ee52..70debca9b 100755 Binary files a/java/res/drawable-hdpi/sym_keyboard_feedback_space.png and b/java/res/drawable-hdpi/sym_keyboard_feedback_space.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_feedback_tab.png b/java/res/drawable-hdpi/sym_keyboard_feedback_tab.png old mode 100644 new mode 100755 index 7754752f3..d2efb1619 Binary files a/java/res/drawable-hdpi/sym_keyboard_feedback_tab.png and b/java/res/drawable-hdpi/sym_keyboard_feedback_tab.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_feedback_tabprev.png b/java/res/drawable-hdpi/sym_keyboard_feedback_tabprev.png deleted file mode 100644 index 36f6b5364..000000000 Binary files a/java/res/drawable-hdpi/sym_keyboard_feedback_tabprev.png and /dev/null differ diff --git a/java/res/drawable-hdpi/sym_keyboard_globe.png b/java/res/drawable-hdpi/sym_keyboard_globe.png deleted file mode 100644 index fa747642d..000000000 Binary files a/java/res/drawable-hdpi/sym_keyboard_globe.png and /dev/null differ diff --git a/java/res/drawable-hdpi/sym_keyboard_language_arrows_left.png b/java/res/drawable-hdpi/sym_keyboard_language_arrows_left.png index 65ccfda87..dcc4bd59b 100644 Binary files a/java/res/drawable-hdpi/sym_keyboard_language_arrows_left.png and b/java/res/drawable-hdpi/sym_keyboard_language_arrows_left.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_language_arrows_right.png b/java/res/drawable-hdpi/sym_keyboard_language_arrows_right.png index 0d01bc224..ecf61a98e 100644 Binary files a/java/res/drawable-hdpi/sym_keyboard_language_arrows_right.png and b/java/res/drawable-hdpi/sym_keyboard_language_arrows_right.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_mic.png b/java/res/drawable-hdpi/sym_keyboard_mic.png old mode 100644 new mode 100755 index 0a0a68a96..c8dca62a0 Binary files a/java/res/drawable-hdpi/sym_keyboard_mic.png and b/java/res/drawable-hdpi/sym_keyboard_mic.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_return.png b/java/res/drawable-hdpi/sym_keyboard_return.png index 58505c5e0..9d97e1efd 100755 Binary files a/java/res/drawable-hdpi/sym_keyboard_return.png and b/java/res/drawable-hdpi/sym_keyboard_return.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_search.png b/java/res/drawable-hdpi/sym_keyboard_search.png index e72cde3bb..1aa22d7e2 100755 Binary files a/java/res/drawable-hdpi/sym_keyboard_search.png and b/java/res/drawable-hdpi/sym_keyboard_search.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_settings.png b/java/res/drawable-hdpi/sym_keyboard_settings.png new file mode 100755 index 000000000..d57f7a43a Binary files /dev/null and b/java/res/drawable-hdpi/sym_keyboard_settings.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_shift.png b/java/res/drawable-hdpi/sym_keyboard_shift.png index 814908178..1a64dcce6 100755 Binary files a/java/res/drawable-hdpi/sym_keyboard_shift.png and b/java/res/drawable-hdpi/sym_keyboard_shift.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_shift_locked.png b/java/res/drawable-hdpi/sym_keyboard_shift_locked.png index 31ca27718..807e97751 100755 Binary files a/java/res/drawable-hdpi/sym_keyboard_shift_locked.png and b/java/res/drawable-hdpi/sym_keyboard_shift_locked.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_space.png b/java/res/drawable-hdpi/sym_keyboard_space.png index 3e98b3014..fcd20de7d 100755 Binary files a/java/res/drawable-hdpi/sym_keyboard_space.png and b/java/res/drawable-hdpi/sym_keyboard_space.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_space_led.9.png b/java/res/drawable-hdpi/sym_keyboard_space_led.9.png new file mode 100644 index 000000000..af5c7d80f Binary files /dev/null and b/java/res/drawable-hdpi/sym_keyboard_space_led.9.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_tab.png b/java/res/drawable-hdpi/sym_keyboard_tab.png old mode 100644 new mode 100755 index 1d4d92bd1..51d17d989 Binary files a/java/res/drawable-hdpi/sym_keyboard_tab.png and b/java/res/drawable-hdpi/sym_keyboard_tab.png differ diff --git a/java/res/drawable-hdpi/sym_keyboard_tabprev.png b/java/res/drawable-hdpi/sym_keyboard_tabprev.png deleted file mode 100644 index 51bff1bcd..000000000 Binary files a/java/res/drawable-hdpi/sym_keyboard_tabprev.png and /dev/null differ diff --git a/java/res/drawable-hdpi/voice_ime_background.9.png b/java/res/drawable-hdpi/voice_ime_background.9.png old mode 100755 new mode 100644 index 73fb0901e..42868522f Binary files a/java/res/drawable-hdpi/voice_ime_background.9.png and b/java/res/drawable-hdpi/voice_ime_background.9.png differ diff --git a/java/res/drawable-land-hdpi/keyboard_suggest_strip_divider.png b/java/res/drawable-land-hdpi/keyboard_suggest_strip_divider.png deleted file mode 100755 index 1a03c52e6..000000000 Binary files a/java/res/drawable-land-hdpi/keyboard_suggest_strip_divider.png and /dev/null differ diff --git a/java/res/drawable-land-mdpi/keyboard_suggest_strip_divider.png b/java/res/drawable-land-mdpi/keyboard_suggest_strip_divider.png deleted file mode 100644 index e54c5b099..000000000 Binary files a/java/res/drawable-land-mdpi/keyboard_suggest_strip_divider.png and /dev/null differ diff --git a/java/res/drawable-mdpi/btn_close_normal.png b/java/res/drawable-mdpi/btn_close_normal.png deleted file mode 100644 index 4c6e79dc8..000000000 Binary files a/java/res/drawable-mdpi/btn_close_normal.png and /dev/null differ diff --git a/java/res/drawable-mdpi/btn_close_pressed.png b/java/res/drawable-mdpi/btn_close_pressed.png deleted file mode 100644 index fc983afdc..000000000 Binary files a/java/res/drawable-mdpi/btn_close_pressed.png and /dev/null differ diff --git a/java/res/drawable-mdpi/btn_close_selected.png b/java/res/drawable-mdpi/btn_close_selected.png deleted file mode 100644 index f2bf91a2d..000000000 Binary files a/java/res/drawable-mdpi/btn_close_selected.png and /dev/null differ diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal.9.png new file mode 100755 index 000000000..48ebb6183 Binary files /dev/null and b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal.9.png differ diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off.9.png new file mode 100755 index 000000000..38b8b48aa Binary files /dev/null and b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off.9.png differ diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on.9.png new file mode 100755 index 000000000..147c1b22e Binary files /dev/null and b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on.9.png differ diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed.9.png new file mode 100755 index 000000000..f8affea64 Binary files /dev/null and b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed.9.png differ diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off.9.png new file mode 100755 index 000000000..75962e9b0 Binary files /dev/null and b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off.9.png differ diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on.9.png new file mode 100755 index 000000000..b7dccfe3c Binary files /dev/null and b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on.9.png differ diff --git a/java/res/drawable-mdpi/btn_keyboard_key_light_normal.9.png b/java/res/drawable-mdpi/btn_keyboard_key_light_normal.9.png new file mode 100755 index 000000000..9ccad8020 Binary files /dev/null and b/java/res/drawable-mdpi/btn_keyboard_key_light_normal.9.png differ diff --git a/java/res/drawable-mdpi/btn_keyboard_key_light_popup_normal.9.png b/java/res/drawable-mdpi/btn_keyboard_key_light_popup_normal.9.png new file mode 100755 index 000000000..ce58880db Binary files /dev/null and b/java/res/drawable-mdpi/btn_keyboard_key_light_popup_normal.9.png differ diff --git a/java/res/drawable-mdpi/btn_keyboard_key_light_popup_selected.9.png b/java/res/drawable-mdpi/btn_keyboard_key_light_popup_selected.9.png new file mode 100644 index 000000000..fe6c517f9 Binary files /dev/null and b/java/res/drawable-mdpi/btn_keyboard_key_light_popup_selected.9.png differ diff --git a/java/res/drawable-mdpi/btn_keyboard_key_light_pressed.9.png b/java/res/drawable-mdpi/btn_keyboard_key_light_pressed.9.png new file mode 100755 index 000000000..d09bd3db3 Binary files /dev/null and b/java/res/drawable-mdpi/btn_keyboard_key_light_pressed.9.png differ diff --git a/java/res/drawable-mdpi/btn_keyboard_normal_metal.9.png b/java/res/drawable-mdpi/btn_keyboard_normal_metal.9.png deleted file mode 100644 index f4fe0a8a0..000000000 Binary files a/java/res/drawable-mdpi/btn_keyboard_normal_metal.9.png and /dev/null differ diff --git a/java/res/drawable-mdpi/btn_keyboard_toggle_off.png b/java/res/drawable-mdpi/btn_keyboard_toggle_off.png deleted file mode 100644 index 21399a4f3..000000000 Binary files a/java/res/drawable-mdpi/btn_keyboard_toggle_off.png and /dev/null differ diff --git a/java/res/drawable-mdpi/btn_keyboard_toggle_on.png b/java/res/drawable-mdpi/btn_keyboard_toggle_on.png deleted file mode 100644 index 22d5683e2..000000000 Binary files a/java/res/drawable-mdpi/btn_keyboard_toggle_on.png and /dev/null differ diff --git a/java/res/drawable-mdpi/btn_led_off.9.png b/java/res/drawable-mdpi/btn_led_off.9.png deleted file mode 100644 index 68ce7a67a..000000000 Binary files a/java/res/drawable-mdpi/btn_led_off.9.png and /dev/null differ diff --git a/java/res/drawable-mdpi/btn_led_on.9.png b/java/res/drawable-mdpi/btn_led_on.9.png deleted file mode 100644 index fe77abb08..000000000 Binary files a/java/res/drawable-mdpi/btn_led_on.9.png and /dev/null differ diff --git a/java/res/drawable-mdpi/dialog_top_dark_bottom_medium.9.png b/java/res/drawable-mdpi/dialog_top_dark_bottom_medium.9.png deleted file mode 100644 index cf7ecaf1e..000000000 Binary files a/java/res/drawable-mdpi/dialog_top_dark_bottom_medium.9.png and /dev/null differ diff --git a/java/res/drawable-mdpi/ic_dialog_alert_large.png b/java/res/drawable-mdpi/ic_dialog_alert_large.png deleted file mode 100644 index 2d4a164a7..000000000 Binary files a/java/res/drawable-mdpi/ic_dialog_alert_large.png and /dev/null differ diff --git a/java/res/drawable-mdpi/ic_dialog_voice_input.png b/java/res/drawable-mdpi/ic_dialog_voice_input.png deleted file mode 100644 index d28914132..000000000 Binary files a/java/res/drawable-mdpi/ic_dialog_voice_input.png and /dev/null differ diff --git a/java/res/drawable-mdpi/ic_dialog_wave_0_0.png b/java/res/drawable-mdpi/ic_dialog_wave_0_0.png deleted file mode 100644 index 9c3c28f37..000000000 Binary files a/java/res/drawable-mdpi/ic_dialog_wave_0_0.png and /dev/null differ diff --git a/java/res/drawable-mdpi/ic_dialog_wave_1_3.png b/java/res/drawable-mdpi/ic_dialog_wave_1_3.png deleted file mode 100644 index d33bd0d9b..000000000 Binary files a/java/res/drawable-mdpi/ic_dialog_wave_1_3.png and /dev/null differ diff --git a/java/res/drawable-mdpi/ic_dialog_wave_2_3.png b/java/res/drawable-mdpi/ic_dialog_wave_2_3.png deleted file mode 100644 index 5094a6e6c..000000000 Binary files a/java/res/drawable-mdpi/ic_dialog_wave_2_3.png and /dev/null differ diff --git a/java/res/drawable-mdpi/ic_dialog_wave_3_3.png b/java/res/drawable-mdpi/ic_dialog_wave_3_3.png deleted file mode 100644 index 69917564d..000000000 Binary files a/java/res/drawable-mdpi/ic_dialog_wave_3_3.png and /dev/null differ diff --git a/java/res/drawable-mdpi/ic_dialog_wave_4_3.png b/java/res/drawable-mdpi/ic_dialog_wave_4_3.png deleted file mode 100644 index af5a84c31..000000000 Binary files a/java/res/drawable-mdpi/ic_dialog_wave_4_3.png and /dev/null differ diff --git a/java/res/drawable-mdpi/ic_suggest_strip_scroll_left_arrow.png b/java/res/drawable-mdpi/ic_suggest_strip_scroll_left_arrow.png deleted file mode 100644 index a9adef2ba..000000000 Binary files a/java/res/drawable-mdpi/ic_suggest_strip_scroll_left_arrow.png and /dev/null differ diff --git a/java/res/drawable-mdpi/ic_suggest_strip_scroll_right_arrow.png b/java/res/drawable-mdpi/ic_suggest_strip_scroll_right_arrow.png deleted file mode 100644 index 639a28711..000000000 Binary files a/java/res/drawable-mdpi/ic_suggest_strip_scroll_right_arrow.png and /dev/null differ diff --git a/java/res/drawable-mdpi/keyboard_dark_background.9.png b/java/res/drawable-mdpi/keyboard_dark_background.9.png new file mode 100755 index 000000000..2d5c02080 Binary files /dev/null and b/java/res/drawable-mdpi/keyboard_dark_background.9.png differ diff --git a/java/res/drawable-mdpi/keyboard_popup_panel_trans_background.9.png b/java/res/drawable-mdpi/keyboard_popup_panel_trans_background.9.png deleted file mode 100644 index 4ba2a4908..000000000 Binary files a/java/res/drawable-mdpi/keyboard_popup_panel_trans_background.9.png and /dev/null differ diff --git a/java/res/drawable-mdpi/sym_bkeyboard_globe.png b/java/res/drawable-mdpi/sym_bkeyboard_globe.png deleted file mode 100644 index c6595cf62..000000000 Binary files a/java/res/drawable-mdpi/sym_bkeyboard_globe.png and /dev/null differ diff --git a/java/res/drawable-mdpi/sym_bkeyboard_settings.png b/java/res/drawable-mdpi/sym_bkeyboard_settings.png new file mode 100644 index 000000000..08ba18f28 Binary files /dev/null and b/java/res/drawable-mdpi/sym_bkeyboard_settings.png differ diff --git a/java/res/drawable-mdpi/sym_bkeyboard_tabprev.png b/java/res/drawable-mdpi/sym_bkeyboard_tabprev.png deleted file mode 100644 index 5298291d5..000000000 Binary files a/java/res/drawable-mdpi/sym_bkeyboard_tabprev.png and /dev/null differ diff --git a/java/res/drawable-mdpi/sym_keyboard_feedback_settings.png b/java/res/drawable-mdpi/sym_keyboard_feedback_settings.png new file mode 100644 index 000000000..08ba18f28 Binary files /dev/null and b/java/res/drawable-mdpi/sym_keyboard_feedback_settings.png differ diff --git a/java/res/drawable-mdpi/sym_keyboard_feedback_tabprev.png b/java/res/drawable-mdpi/sym_keyboard_feedback_tabprev.png deleted file mode 100644 index d4b3e7db3..000000000 Binary files a/java/res/drawable-mdpi/sym_keyboard_feedback_tabprev.png and /dev/null differ diff --git a/java/res/drawable-mdpi/sym_keyboard_globe.png b/java/res/drawable-mdpi/sym_keyboard_globe.png deleted file mode 100644 index f30c1b640..000000000 Binary files a/java/res/drawable-mdpi/sym_keyboard_globe.png and /dev/null differ diff --git a/java/res/drawable-mdpi/sym_keyboard_settings.png b/java/res/drawable-mdpi/sym_keyboard_settings.png new file mode 100644 index 000000000..f3bcdbcac Binary files /dev/null and b/java/res/drawable-mdpi/sym_keyboard_settings.png differ diff --git a/java/res/drawable-mdpi/sym_keyboard_space_led.9.png b/java/res/drawable-mdpi/sym_keyboard_space_led.9.png new file mode 100644 index 000000000..71da57319 Binary files /dev/null and b/java/res/drawable-mdpi/sym_keyboard_space_led.9.png differ diff --git a/java/res/drawable-mdpi/sym_keyboard_tabprev.png b/java/res/drawable-mdpi/sym_keyboard_tabprev.png deleted file mode 100644 index eb90872fc..000000000 Binary files a/java/res/drawable-mdpi/sym_keyboard_tabprev.png and /dev/null differ diff --git a/java/res/drawable/btn_close.xml b/java/res/drawable/btn_close.xml deleted file mode 100644 index ee5813898..000000000 --- a/java/res/drawable/btn_close.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - diff --git a/java/res/drawable/btn_keyboard_key_gingerbread.xml b/java/res/drawable/btn_keyboard_key_gingerbread.xml new file mode 100644 index 000000000..4a113a8a1 --- /dev/null +++ b/java/res/drawable/btn_keyboard_key_gingerbread.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/res/layout/candidates.xml b/java/res/layout/candidates.xml index 068c17e56..478e20ba1 100755 --- a/java/res/layout/candidates.xml +++ b/java/res/layout/candidates.xml @@ -18,7 +18,7 @@ */ --> - - - - - - - - - - - - - - + diff --git a/java/res/layout/input_gingerbread.xml b/java/res/layout/input_gingerbread.xml new file mode 100755 index 000000000..8f59cae21 --- /dev/null +++ b/java/res/layout/input_gingerbread.xml @@ -0,0 +1,33 @@ + + + + diff --git a/java/res/layout/input_gingerbread_popup.xml b/java/res/layout/input_gingerbread_popup.xml new file mode 100755 index 000000000..0cc953edf --- /dev/null +++ b/java/res/layout/input_gingerbread_popup.xml @@ -0,0 +1,39 @@ + + + + + + diff --git a/java/res/layout/input_stone_popup.xml b/java/res/layout/input_stone_popup.xml index 1efa56c5e..f159625f7 100755 --- a/java/res/layout/input_stone_popup.xml +++ b/java/res/layout/input_stone_popup.xml @@ -38,13 +38,4 @@ latin:shadowColor="@color/latinkeyboard_key_color_white" latin:popupLayout="@layout/input_stone_popup" /> - diff --git a/java/res/layout/keyboard_key_preview.xml b/java/res/layout/keyboard_key_preview.xml index 64eaa6579..de03506ad 100644 --- a/java/res/layout/keyboard_key_preview.xml +++ b/java/res/layout/keyboard_key_preview.xml @@ -22,7 +22,7 @@ android:layout_width="wrap_content" android:layout_height="80sp" android:textSize="40sp" - android:textColor="?android:attr/textColorPrimaryInverse" + android:textColor="@color/latinkeyboard_key_color_white" android:minWidth="32dip" android:gravity="center" android:background="@drawable/keyboard_key_feedback" diff --git a/java/res/layout/keyboard_popup_keyboard.xml b/java/res/layout/keyboard_popup_keyboard.xml index a1b571ace..6d3985065 100644 --- a/java/res/layout/keyboard_popup_keyboard.xml +++ b/java/res/layout/keyboard_popup_keyboard.xml @@ -32,16 +32,8 @@ android:layout_height="wrap_content" android:background="@android:color/transparent" + latin:keyBackground="@drawable/btn_keyboard_key_gingerbread" latin:keyPreviewLayout="@layout/keyboard_key_preview" latin:popupLayout="@layout/keyboard_popup_keyboard" /> - diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml index 823027692..877c2019a 100644 --- a/java/res/values-cs/strings.xml +++ b/java/res/values-cs/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml index 3480a645c..78941429c 100644 --- a/java/res/values-da/strings.xml +++ b/java/res/values-da/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml index d73a72a02..dc3151df9 100644 --- a/java/res/values-de/strings.xml +++ b/java/res/values-de/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml index 754b870ec..de579586b 100644 --- a/java/res/values-el/strings.xml +++ b/java/res/values-el/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-en/donottranslate.xml b/java/res/values-en/donottranslate.xml new file mode 100644 index 000000000..f5692735a --- /dev/null +++ b/java/res/values-en/donottranslate.xml @@ -0,0 +1,31 @@ + + + + + èéêë3 + + ìíîï8 + + òóôõöœø9 + + ùúûü7 + + ýÿ6 + diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml index 0844582fa..448feb7cd 100644 --- a/java/res/values-es-rUS/strings.xml +++ b/java/res/values-es-rUS/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml index aa46a98e9..09114757a 100644 --- a/java/res/values-es/strings.xml +++ b/java/res/values-es/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml index 2cfb73323..d2c7df852 100644 --- a/java/res/values-fr/strings.xml +++ b/java/res/values-fr/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml index 9452edd63..8acd65aed 100644 --- a/java/res/values-it/strings.xml +++ b/java/res/values-it/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml index 157e4660d..e3dbe23cb 100644 --- a/java/res/values-ja/strings.xml +++ b/java/res/values-ja/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml index 37b91036c..610f165dc 100644 --- a/java/res/values-ko/strings.xml +++ b/java/res/values-ko/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml index 280927da9..786ae242c 100644 --- a/java/res/values-nb/strings.xml +++ b/java/res/values-nb/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml index 45ca9acc8..ba8840201 100644 --- a/java/res/values-nl/strings.xml +++ b/java/res/values-nl/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml index 18580c680..d4f31f737 100644 --- a/java/res/values-pl/strings.xml +++ b/java/res/values-pl/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml index ddba099bc..8d27de9eb 100644 --- a/java/res/values-pt-rPT/strings.xml +++ b/java/res/values-pt-rPT/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml index 83f2f4b56..5a348ce31 100644 --- a/java/res/values-pt/strings.xml +++ b/java/res/values-pt/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-rm/strings.xml b/java/res/values-rm/strings.xml index c32a2efa9..f30b41fa2 100644 --- a/java/res/values-rm/strings.xml +++ b/java/res/values-rm/strings.xml @@ -140,6 +140,8 @@ - + + + diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml index e714415d0..99c576eb8 100644 --- a/java/res/values-ru/strings.xml +++ b/java/res/values-ru/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml index 4a3f77ba1..28faaa914 100644 --- a/java/res/values-sv/strings.xml +++ b/java/res/values-sv/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml index 486cd2c5e..fee07338d 100644 --- a/java/res/values-tr/strings.xml +++ b/java/res/values-tr/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml index 505807c33..cbf287723 100644 --- a/java/res/values-zh-rCN/strings.xml +++ b/java/res/values-zh-rCN/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml index f8e75786e..78ede4ac3 100644 --- a/java/res/values-zh-rTW/strings.xml +++ b/java/res/values-zh-rTW/strings.xml @@ -138,6 +138,8 @@ - + + + diff --git a/java/res/values/colors.xml b/java/res/values/colors.xml index 343a9405d..245648df2 100644 --- a/java/res/values/colors.xml +++ b/java/res/values/colors.xml @@ -18,15 +18,15 @@ */ --> - #FF000000 - #FFE35900 - #ff808080 + #FFFFFFFF + #FFF07020 + #ffD06015 #00000000 #80000000 #80FFFFFF - #FF808080 + #FFC0C0C0 #A0000000 - #FF000000 + #FFFFFFFF #FFFFFFFF #FF000000 diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml index b7bfd9c3a..97b645c4a 100644 --- a/java/res/values/donottranslate.xml +++ b/java/res/values/donottranslate.xml @@ -24,16 +24,22 @@ .,!?) !?,\u0022\u0027:()-/@_ + + 1 + + 2 - + 4 - + 5 + + 0 diff --git a/java/res/values/keycodes.xml b/java/res/values/keycodes.xml index 8156c0e07..3f03dd665 100644 --- a/java/res/values/keycodes.xml +++ b/java/res/values/keycodes.xml @@ -20,5 +20,6 @@ + -100 -103 diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 083a35410..2a3851fdf 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -320,7 +320,10 @@ Input method - + + + Select input method + Input languages @@ -332,22 +335,25 @@ Dictionary available - + Enable user feedback - + Help improve this input method editor by automatically sending usage statistics and crash reports to Google. + Keyboard Theme Basic Basic (High Contrast) - Default (bold) - Default (normal) + Stone (bold) + Stone (normal) + Gingerbread @string/layout_basic @string/layout_high_contrast @string/layout_stone_normal @string/layout_stone_bold + @string/layout_gingerbread @@ -355,10 +361,9 @@ 1 2 3 + 4 - Debug (Temporary) - keyboard voice diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml index 24fee02d8..16478c883 100644 --- a/java/res/values/styles.xml +++ b/java/res/values/styles.xml @@ -22,7 +22,7 @@ @dimen/key_text_size #FFFFFFFF @layout/keyboard_key_preview - -12dip + 5dip 80dip 14sp @layout/keyboard_popup_keyboard diff --git a/java/res/xml-da/kbd_qwerty.xml b/java/res/xml-da/kbd_qwerty.xml index 472f8be55..fb8d062ee 100644 --- a/java/res/xml-da/kbd_qwerty.xml +++ b/java/res/xml-da/kbd_qwerty.xml @@ -112,102 +112,99 @@ + android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="10%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="20%p" android:isRepeatable="true" android:isModifier="true"/> - + android:keyWidth="15%p" android:isModifier="true"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right" android:isModifier="true"/> - diff --git a/java/res/xml-da/kbd_qwerty_black.xml b/java/res/xml-da/kbd_qwerty_black.xml index 2b41cf1fb..b9d1d1796 100644 --- a/java/res/xml-da/kbd_qwerty_black.xml +++ b/java/res/xml-da/kbd_qwerty_black.xml @@ -114,87 +114,83 @@ android:iconPreview="@drawable/sym_keyboard_feedback_delete" android:isRepeatable="true"/> - + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="10%p" android:keyEdgeFlags="left"/> + @@ -203,11 +199,11 @@ android:keyWidth="20%p" android:isRepeatable="true"/> - + android:keyWidth="15%p"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right"/> - diff --git a/java/res/xml-de/kbd_qwerty.xml b/java/res/xml-de/kbd_qwerty.xml index da833b2c4..763627a34 100755 --- a/java/res/xml-de/kbd_qwerty.xml +++ b/java/res/xml-de/kbd_qwerty.xml @@ -1,19 +1,19 @@ @@ -49,9 +49,9 @@ /> - + - @@ -67,7 +67,7 @@ - + + android:isRepeatable="true" android:isModifier="true"/> - + - - + + + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> - + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> - + android:keyWidth="10%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + + android:keyWidth="20%p" android:isRepeatable="true" android:isModifier="true"/> - + android:keyWidth="15%p" android:isModifier="true"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right" android:isModifier="true"/> diff --git a/java/res/xml-de/kbd_qwerty_black.xml b/java/res/xml-de/kbd_qwerty_black.xml index 366f87134..b0b6c238f 100755 --- a/java/res/xml-de/kbd_qwerty_black.xml +++ b/java/res/xml-de/kbd_qwerty_black.xml @@ -97,93 +97,94 @@ - + + + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> - + + + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> - + + - + android:keyWidth="15%p"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right"/> diff --git a/java/res/xml-fr/kbd_qwerty.xml b/java/res/xml-fr/kbd_qwerty.xml index 77076fd2f..0f08c26c2 100644 --- a/java/res/xml-fr/kbd_qwerty.xml +++ b/java/res/xml-fr/kbd_qwerty.xml @@ -1,19 +1,19 @@ @@ -26,7 +26,7 @@ > - @@ -55,7 +55,7 @@ /> - + - @@ -91,103 +91,102 @@ /> - + android:isRepeatable="true" android:isModifier="true"/> - + - - + + + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> - + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> - + android:keyWidth="10%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + + android:keyWidth="20%p" android:isRepeatable="true" android:isModifier="true"/> - + android:keyWidth="15%p" android:isModifier="true"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right" android:isModifier="true"/> - - diff --git a/java/res/xml-fr/kbd_qwerty_black.xml b/java/res/xml-fr/kbd_qwerty_black.xml index 1b799a51d..6d3aeb829 100644 --- a/java/res/xml-fr/kbd_qwerty_black.xml +++ b/java/res/xml-fr/kbd_qwerty_black.xml @@ -99,94 +99,94 @@ - + + + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> - + + + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> - + + - + android:keyWidth="15%p"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right"/> - diff --git a/java/res/xml-iw/kbd_qwerty.xml b/java/res/xml-iw/kbd_qwerty.xml index b893f1a62..208ba92b4 100755 --- a/java/res/xml-iw/kbd_qwerty.xml +++ b/java/res/xml-iw/kbd_qwerty.xml @@ -41,7 +41,7 @@ android:keyIcon="@drawable/sym_keyboard_delete" android:keyWidth="13.75%p" android:keyEdgeFlags="right" android:iconPreview="@drawable/sym_keyboard_feedback_delete" - android:isRepeatable="true"/> + android:isRepeatable="true" android:isModifier="true"/> @@ -71,94 +71,95 @@ - + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> - + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> - + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> - + android:keyWidth="10%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + + android:keyWidth="20%p" android:isRepeatable="true" android:isModifier="true"/> - + android:keyWidth="15%p" android:isModifier="true"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right" android:isModifier="true"/> diff --git a/java/res/xml-iw/kbd_qwerty_black.xml b/java/res/xml-iw/kbd_qwerty_black.xml index 0dcf513e3..981ad37c3 100755 --- a/java/res/xml-iw/kbd_qwerty_black.xml +++ b/java/res/xml-iw/kbd_qwerty_black.xml @@ -71,94 +71,95 @@ - + + + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> - + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> - + + + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> - + + - + android:keyWidth="15%p"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right"/> diff --git a/java/res/xml-nb/kbd_qwerty.xml b/java/res/xml-nb/kbd_qwerty.xml index d2f0258c1..d033bb02c 100644 --- a/java/res/xml-nb/kbd_qwerty.xml +++ b/java/res/xml-nb/kbd_qwerty.xml @@ -110,102 +110,99 @@ + android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="10%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="20%p" android:isRepeatable="true" android:isModifier="true"/> - + android:keyWidth="15%p" android:isModifier="true"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right" android:isModifier="true"/> - diff --git a/java/res/xml-nb/kbd_qwerty_black.xml b/java/res/xml-nb/kbd_qwerty_black.xml index 150ff7fc7..14456e6b6 100644 --- a/java/res/xml-nb/kbd_qwerty_black.xml +++ b/java/res/xml-nb/kbd_qwerty_black.xml @@ -115,84 +115,81 @@ + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="10%p" android:keyEdgeFlags="left"/> + @@ -201,11 +198,11 @@ android:keyWidth="20%p" android:isRepeatable="true"/> - + android:keyWidth="15%p"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right"/> - diff --git a/java/res/xml-ru/kbd_qwerty.xml b/java/res/xml-ru/kbd_qwerty.xml index 9773a305f..e512c0b84 100755 --- a/java/res/xml-ru/kbd_qwerty.xml +++ b/java/res/xml-ru/kbd_qwerty.xml @@ -78,99 +78,100 @@ + android:isRepeatable="true" android:isModifier="true"/> - + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> - + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> - + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> - + android:keyWidth="10%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + + android:keyWidth="20%p" android:isRepeatable="true" android:isModifier="true"/> - + android:keyWidth="15%p" android:isModifier="true"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right" android:isModifier="true"/> diff --git a/java/res/xml-ru/kbd_qwerty_black.xml b/java/res/xml-ru/kbd_qwerty_black.xml index 4923be01a..00c399273 100755 --- a/java/res/xml-ru/kbd_qwerty_black.xml +++ b/java/res/xml-ru/kbd_qwerty_black.xml @@ -83,93 +83,94 @@ - + + + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> - + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> - + + + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> - + + - + android:keyWidth="15%p"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right"/> diff --git a/java/res/xml-sr/kbd_qwerty.xml b/java/res/xml-sr/kbd_qwerty.xml index e4884a8a6..cab846004 100644 --- a/java/res/xml-sr/kbd_qwerty.xml +++ b/java/res/xml-sr/kbd_qwerty.xml @@ -74,98 +74,99 @@ + android:isRepeatable="true" android:isModifier="true"/> - + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> - + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> - + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> - + android:keyWidth="10%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + + android:keyWidth="20%p" android:isRepeatable="true" android:isModifier="true"/> - + android:keyWidth="15%p" android:isModifier="true"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right" android:isModifier="true"/> diff --git a/java/res/xml-sr/kbd_qwerty_black.xml b/java/res/xml-sr/kbd_qwerty_black.xml index 30d094a88..00a289449 100644 --- a/java/res/xml-sr/kbd_qwerty_black.xml +++ b/java/res/xml-sr/kbd_qwerty_black.xml @@ -79,93 +79,94 @@ - + + + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> - + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> - + + + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> - + + - + android:keyWidth="15%p"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right"/> diff --git a/java/res/xml-sv/kbd_qwerty.xml b/java/res/xml-sv/kbd_qwerty.xml index d4ffa4d52..514a44154 100644 --- a/java/res/xml-sv/kbd_qwerty.xml +++ b/java/res/xml-sv/kbd_qwerty.xml @@ -119,97 +119,94 @@ + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="10%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="20%p" android:isRepeatable="true" android:isModifier="true"/> - + android:keyWidth="15%p" android:isModifier="true"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right" android:isModifier="true"/> - diff --git a/java/res/xml-sv/kbd_qwerty_black.xml b/java/res/xml-sv/kbd_qwerty_black.xml index 6604bc87c..4cc37cec8 100644 --- a/java/res/xml-sv/kbd_qwerty_black.xml +++ b/java/res/xml-sv/kbd_qwerty_black.xml @@ -119,84 +119,81 @@ + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="10%p" android:keyEdgeFlags="left"/> + @@ -205,11 +202,11 @@ android:keyWidth="20%p" android:isRepeatable="true"/> - + android:keyWidth="15%p"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right"/> - diff --git a/java/res/xml/kbd_alpha.xml b/java/res/xml/kbd_alpha.xml deleted file mode 100644 index 4e8af3399..000000000 --- a/java/res/xml/kbd_alpha.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/java/res/xml/kbd_alpha_black.xml b/java/res/xml/kbd_alpha_black.xml deleted file mode 100644 index 108e466b8..000000000 --- a/java/res/xml/kbd_alpha_black.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/java/res/xml/kbd_extension.xml b/java/res/xml/kbd_extension.xml deleted file mode 100755 index c64f666d0..000000000 --- a/java/res/xml/kbd_extension.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/java/res/xml/kbd_phone.xml b/java/res/xml/kbd_phone.xml index d2bcdac52..73d022fcb 100755 --- a/java/res/xml/kbd_phone.xml +++ b/java/res/xml/kbd_phone.xml @@ -50,8 +50,6 @@ diff --git a/java/res/xml/kbd_phone_black.xml b/java/res/xml/kbd_phone_black.xml index b7f9096bd..3738f2b68 100755 --- a/java/res/xml/kbd_phone_black.xml +++ b/java/res/xml/kbd_phone_black.xml @@ -50,8 +50,6 @@ diff --git a/java/res/xml/kbd_phone_symbols.xml b/java/res/xml/kbd_phone_symbols.xml index 9604664fa..9196df8da 100755 --- a/java/res/xml/kbd_phone_symbols.xml +++ b/java/res/xml/kbd_phone_symbols.xml @@ -55,8 +55,6 @@ + + + - - + + + android:popupCharacters="@string/alternates_for_r" + /> + android:popupCharacters="@string/alternates_for_t" + /> - + - + - @@ -82,9 +96,9 @@ android:popupCharacters="@string/alternates_for_l" android:keyEdgeFlags="right"/> - + - @@ -106,103 +120,99 @@ + android:isRepeatable="true" android:isModifier="true"/> - + + + android:keyWidth="10%p" android:isModifier="true"/> - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + android:keyWidth="10%p" android:isModifier="true"/> - + android:keyWidth="30%p" android:isRepeatable="true" android:isModifier="true"/> + + android:keyWidth="25%p" android:keyEdgeFlags="right" android:isModifier="true"/> + android:keyWidth="10%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + android:keyWidth="10%p" android:isModifier="true"/> + android:keyWidth="20%p" android:isRepeatable="true" android:isModifier="true"/> - + android:keyWidth="15%p" android:isModifier="true"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right" android:isModifier="true"/> - - diff --git a/java/res/xml/kbd_qwerty_black.xml b/java/res/xml/kbd_qwerty_black.xml index d013ae01b..8b68d7500 100755 --- a/java/res/xml/kbd_qwerty_black.xml +++ b/java/res/xml/kbd_qwerty_black.xml @@ -26,18 +26,26 @@ > - - + + + android:popupCharacters="@string/alternates_for_r" + /> + android:popupCharacters="@string/alternates_for_t" + /> - + @@ -110,85 +121,82 @@ - + + - + + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + - + android:keyWidth="30%p" android:isRepeatable="true"/> + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + - + + android:keyWidth="25%p" android:keyEdgeFlags="right"/> + android:keyWidth="10%p" android:keyEdgeFlags="left"/> + @@ -197,11 +205,11 @@ android:keyWidth="20%p" android:isRepeatable="true"/> - + android:keyWidth="15%p"/> + + android:keyWidth="15%p" android:keyEdgeFlags="right"/> - diff --git a/java/res/xml/kbd_symbols.xml b/java/res/xml/kbd_symbols.xml index ab5792fd1..fad3ebc10 100755 --- a/java/res/xml/kbd_symbols.xml +++ b/java/res/xml/kbd_symbols.xml @@ -118,24 +118,25 @@ /> + android:isRepeatable="true" android:isModifier="true"/> - + android:keyWidth="15%p" android:keyEdgeFlags="left" android:isModifier="true"/> + + + android:isRepeatable="true" android:isModifier="true"/> - + + android:isModifier="true"/> diff --git a/java/res/xml/kbd_symbols_black.xml b/java/res/xml/kbd_symbols_black.xml index 5652f7fca..7eae55481 100755 --- a/java/res/xml/kbd_symbols_black.xml +++ b/java/res/xml/kbd_symbols_black.xml @@ -123,18 +123,19 @@ + android:keyWidth="15%p" android:keyEdgeFlags="left"/> + - diff --git a/java/res/xml/kbd_symbols_shift.xml b/java/res/xml/kbd_symbols_shift.xml index ca431fc8c..b0693917e 100755 --- a/java/res/xml/kbd_symbols_shift.xml +++ b/java/res/xml/kbd_symbols_shift.xml @@ -85,23 +85,24 @@ /> + android:isRepeatable="true" android:isModifier="true"/> - - + + + - + android:isRepeatable="true" android:isModifier="true"/> + + android:isModifier="true"/> diff --git a/java/res/xml/kbd_symbols_shift_black.xml b/java/res/xml/kbd_symbols_shift_black.xml index a8acb9d00..250e0854c 100755 --- a/java/res/xml/kbd_symbols_shift_black.xml +++ b/java/res/xml/kbd_symbols_shift_black.xml @@ -89,18 +89,19 @@ - + diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml index 57d139e43..55fe14a4a 100644 --- a/java/res/xml/prefs.xml +++ b/java/res/xml/prefs.xml @@ -61,14 +61,14 @@ android:defaultValue="@string/voice_mode_main" /> - + android:defaultValue="4" + />--> - diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java index 7fcc3d532..bd73c6fb8 100755 --- a/java/src/com/android/inputmethod/latin/CandidateView.java +++ b/java/src/com/android/inputmethod/latin/CandidateView.java @@ -107,7 +107,6 @@ public class CandidateView extends View { } break; } - } }; @@ -238,6 +237,8 @@ public class CandidateView extends View { final boolean typedWordValid = mTypedWordValid; final int y = (int) (height + mPaint.getTextSize() - mDescent) / 2; + boolean existsAutoCompletion = false; + for (int i = 0; i < count; i++) { CharSequence suggestion = mSuggestions.get(i); if (suggestion == null) continue; @@ -246,6 +247,7 @@ public class CandidateView extends View { && ((i == 1 && !typedWordValid) || (i == 0 && typedWordValid))) { paint.setTypeface(Typeface.DEFAULT_BOLD); paint.setColor(mColorRecommended); + existsAutoCompletion = true; } else if (i != 0) { paint.setColor(mColorOther); } @@ -286,6 +288,7 @@ public class CandidateView extends View { paint.setTypeface(Typeface.DEFAULT); x += wordWidth; } + mService.onAutoCompletionStateChanged(existsAutoCompletion); mTotalWidth = x; if (mTargetScrollX != scrollX) { scrollToTarget(); @@ -333,6 +336,10 @@ public class CandidateView extends View { requestLayout(); } + public boolean isShowingAddToDictionaryHint() { + return mShowingAddToDictionary; + } + public void showAddToDictionaryHint(CharSequence word) { ArrayList suggestions = new ArrayList(); suggestions.add(word); diff --git a/java/src/com/android/inputmethod/latin/CandidateViewContainer.java b/java/src/com/android/inputmethod/latin/CandidateViewContainer.java deleted file mode 100644 index e0cb8c3b0..000000000 --- a/java/src/com/android/inputmethod/latin/CandidateViewContainer.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.inputmethod.latin; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnTouchListener; -import android.widget.LinearLayout; - -public class CandidateViewContainer extends LinearLayout implements OnTouchListener { - - private View mButtonLeft; - private View mButtonRight; - private View mButtonLeftLayout; - private View mButtonRightLayout; - private CandidateView mCandidates; - - public CandidateViewContainer(Context screen, AttributeSet attrs) { - super(screen, attrs); - } - - public void initViews() { - if (mCandidates == null) { - mButtonLeftLayout = findViewById(R.id.candidate_left_parent); - mButtonLeft = findViewById(R.id.candidate_left); - if (mButtonLeft != null) { - mButtonLeft.setOnTouchListener(this); - } - mButtonRightLayout = findViewById(R.id.candidate_right_parent); - mButtonRight = findViewById(R.id.candidate_right); - if (mButtonRight != null) { - mButtonRight.setOnTouchListener(this); - } - mCandidates = (CandidateView) findViewById(R.id.candidates); - } - } - - @Override - public void requestLayout() { - if (mCandidates != null) { - int availableWidth = mCandidates.getWidth(); - int neededWidth = mCandidates.computeHorizontalScrollRange(); - int x = mCandidates.getScrollX(); - boolean leftVisible = x > 0; - boolean rightVisible = x + availableWidth < neededWidth; - if (mButtonLeftLayout != null) { - mButtonLeftLayout.setVisibility(leftVisible ? VISIBLE : GONE); - } - if (mButtonRightLayout != null) { - mButtonRightLayout.setVisibility(rightVisible ? VISIBLE : GONE); - } - } - super.requestLayout(); - } - - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - if (v == mButtonRight) { - mCandidates.scrollNext(); - } else if (v == mButtonLeft) { - mCandidates.scrollPrev(); - } - } - return false; - } - -} diff --git a/java/src/com/android/inputmethod/latin/EditingUtil.java b/java/src/com/android/inputmethod/latin/EditingUtil.java index be31cb787..781d7fd4a 100644 --- a/java/src/com/android/inputmethod/latin/EditingUtil.java +++ b/java/src/com/android/inputmethod/latin/EditingUtil.java @@ -16,10 +16,13 @@ package com.android.inputmethod.latin; +import android.text.TextUtils; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.regex.Pattern; /** @@ -31,6 +34,11 @@ public class EditingUtil { */ private static final int LOOKBACK_CHARACTER_NUM = 15; + // Cache Method pointers + private static boolean sMethodsInitialized; + private static Method sMethodGetSelectedText; + private static Method sMethodSetComposingRegion; + private EditingUtil() {}; /** @@ -65,36 +73,16 @@ public class EditingUtil { return extracted.startOffset + extracted.selectionStart; } - private static int getSelectionEnd(InputConnection connection) { - ExtractedText extracted = connection.getExtractedText( - new ExtractedTextRequest(), 0); - if (extracted == null) { - return -1; - } - return extracted.startOffset + extracted.selectionEnd; - } - /** * @param connection connection to the current text field. * @param sep characters which may separate words + * @param range the range object to store the result into * @return the word that surrounds the cursor, including up to one trailing * separator. For example, if the field contains "he|llo world", where | * represents the cursor, then "hello " will be returned. */ public static String getWordAtCursor( - InputConnection connection, String separators) { - return getWordAtCursor(connection, separators, null); - } - - /** - * @param connection connection to the current text field. - * @param sep characters which may separate words - * @return the word that surrounds the cursor, including up to one trailing - * separator. For example, if the field contains "he|llo world", where | - * represents the cursor, then "hello " will be returned. - */ - public static String getWordAtCursor( - InputConnection connection, String separators, Range range) { + InputConnection connection, String separators, Range range) { Range r = getWordRangeAtCursor(connection, separators, range); return (r == null) ? null : r.word; } @@ -204,26 +192,146 @@ public class EditingUtil { } } - /** - * Checks if the cursor is touching/inside a word or the selection is for a whole - * word and no more and no less. - * @param range the Range object that contains the bounds of the word around the cursor - * @param start the start of the selection - * @param end the end of the selection, which could be the same as the start, if text is not - * in selection mode - * @return false if the selection is a partial word or straddling multiple words, true if - * the selection is a full word or there is no selection. - */ - public static boolean isFullWordOrInside(Range range, int start, int end) { - // Is the cursor inside or touching a word? - if (start == end) return true; + public static class SelectedWord { + public int start; + public int end; + public CharSequence word; + } - // Is it a selection? Then is the start of the selection the start of the word and - // the size of the selection the size of the word? Then return true - if (start < end - && (range.charsBefore == 0 && range.charsAfter == end - start)) { - return true; + /** + * Takes a character sequence with a single character and checks if the character occurs + * in a list of word separators or is empty. + * @param singleChar A CharSequence with null, zero or one character + * @param wordSeparators A String containing the word separators + * @return true if the character is at a word boundary, false otherwise + */ + private static boolean isWordBoundary(CharSequence singleChar, String wordSeparators) { + return TextUtils.isEmpty(singleChar) || wordSeparators.contains(singleChar); + } + + /** + * Checks if the cursor is inside a word or the current selection is a whole word. + * @param ic the InputConnection for accessing the text field + * @param selStart the start position of the selection within the text field + * @param selEnd the end position of the selection within the text field. This could be + * the same as selStart, if there's no selection. + * @param wordSeparators the word separator characters for the current language + * @return an object containing the text and coordinates of the selected/touching word, + * null if the selection/cursor is not marking a whole word. + */ + public static SelectedWord getWordAtCursorOrSelection(final InputConnection ic, + int selStart, int selEnd, String wordSeparators) { + if (selStart == selEnd) { + // There is just a cursor, so get the word at the cursor + EditingUtil.Range range = new EditingUtil.Range(); + CharSequence touching = getWordAtCursor(ic, wordSeparators, range); + if (!TextUtils.isEmpty(touching)) { + SelectedWord selWord = new SelectedWord(); + selWord.word = touching; + selWord.start = selStart - range.charsBefore; + selWord.end = selEnd + range.charsAfter; + return selWord; + } + } else { + // Is the previous character empty or a word separator? If not, return null. + CharSequence charsBefore = ic.getTextBeforeCursor(1, 0); + if (!isWordBoundary(charsBefore, wordSeparators)) { + return null; + } + + // Is the next character empty or a word separator? If not, return null. + CharSequence charsAfter = ic.getTextAfterCursor(1, 0); + if (!isWordBoundary(charsAfter, wordSeparators)) { + return null; + } + + // Extract the selection alone + CharSequence touching = getSelectedText(ic, selStart, selEnd); + if (TextUtils.isEmpty(touching)) return null; + // Is any part of the selection a separator? If so, return null. + final int length = touching.length(); + for (int i = 0; i < length; i++) { + if (wordSeparators.contains(touching.subSequence(i, i + 1))) { + return null; + } + } + // Prepare the selected word + SelectedWord selWord = new SelectedWord(); + selWord.start = selStart; + selWord.end = selEnd; + selWord.word = touching; + return selWord; + } + return null; + } + + /** + * Cache method pointers for performance + */ + private static void initializeMethodsForReflection() { + try { + // These will either both exist or not, so no need for separate try/catch blocks. + // If other methods are added later, use separate try/catch blocks. + sMethodGetSelectedText = InputConnection.class.getMethod("getSelectedText", int.class); + sMethodSetComposingRegion = InputConnection.class.getMethod("setComposingRegion", + int.class, int.class); + } catch (NoSuchMethodException exc) { + // Ignore + } + sMethodsInitialized = true; + } + + /** + * Returns the selected text between the selStart and selEnd positions. + */ + private static CharSequence getSelectedText(InputConnection ic, int selStart, int selEnd) { + // Use reflection, for backward compatibility + CharSequence result = null; + if (!sMethodsInitialized) { + initializeMethodsForReflection(); + } + if (sMethodGetSelectedText != null) { + try { + result = (CharSequence) sMethodGetSelectedText.invoke(ic, 0); + return result; + } catch (InvocationTargetException exc) { + // Ignore + } catch (IllegalArgumentException e) { + // Ignore + } catch (IllegalAccessException e) { + // Ignore + } + } + // Reflection didn't work, try it the poor way, by moving the cursor to the start, + // getting the text after the cursor and moving the text back to selected mode. + // TODO: Verify that this works properly in conjunction with + // LatinIME#onUpdateSelection + ic.setSelection(selStart, selEnd); + result = ic.getTextAfterCursor(selEnd - selStart, 0); + ic.setSelection(selStart, selEnd); + return result; + } + + /** + * Tries to set the text into composition mode if there is support for it in the framework. + */ + public static void underlineWord(InputConnection ic, SelectedWord word) { + // Use reflection, for backward compatibility + // If method not found, there's nothing we can do. It still works but just wont underline + // the word. + if (!sMethodsInitialized) { + initializeMethodsForReflection(); + } + if (sMethodSetComposingRegion != null) { + try { + sMethodSetComposingRegion.invoke(ic, word.start, word.end); + } catch (InvocationTargetException exc) { + // Ignore + } catch (IllegalArgumentException e) { + // Ignore + } catch (IllegalAccessException e) { + // Ignore + } } - return false; } } diff --git a/java/src/com/android/inputmethod/latin/KeyDetector.java b/java/src/com/android/inputmethod/latin/KeyDetector.java new file mode 100644 index 000000000..76fe1200e --- /dev/null +++ b/java/src/com/android/inputmethod/latin/KeyDetector.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF 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.inputmethodservice.Keyboard; +import android.inputmethodservice.Keyboard.Key; + +import java.util.Arrays; +import java.util.List; + +abstract class KeyDetector { + protected Keyboard mKeyboard; + + private Key[] mKeys; + + protected int mCorrectionX; + + protected int mCorrectionY; + + protected boolean mProximityCorrectOn; + + protected int mProximityThresholdSquare; + + public Key[] setKeyboard(Keyboard keyboard, float correctionX, float correctionY) { + if (keyboard == null) + throw new NullPointerException(); + mCorrectionX = (int)correctionX; + mCorrectionY = (int)correctionY; + mKeyboard = keyboard; + List keys = mKeyboard.getKeys(); + Key[] array = keys.toArray(new Key[keys.size()]); + mKeys = array; + return array; + } + + protected int getTouchX(int x) { + return x + mCorrectionX; + } + + protected int getTouchY(int y) { + return y + mCorrectionY; + } + + protected Key[] getKeys() { + if (mKeys == null) + throw new IllegalStateException("keyboard isn't set"); + // mKeyboard is guaranteed not to be null at setKeybaord() method if mKeys is not null + return mKeys; + } + + public void setProximityCorrectionEnabled(boolean enabled) { + mProximityCorrectOn = enabled; + } + + public boolean isProximityCorrectionEnabled() { + return mProximityCorrectOn; + } + + public void setProximityThreshold(int threshold) { + mProximityThresholdSquare = threshold * threshold; + } + + /** + * Allocates array that can hold all key indices returned by {@link #getKeyIndexAndNearbyCodes} + * method. The maximum size of the array should be computed by {@link #getMaxNearbyKeys}. + * + * @return Allocates and returns an array that can hold all key indices returned by + * {@link #getKeyIndexAndNearbyCodes} method. All elements in the returned array are + * initialized by {@link com.android.inputmethod.latin.LatinKeyboardView.NOT_A_KEY} + * value. + */ + public int[] newCodeArray() { + int[] codes = new int[getMaxNearbyKeys()]; + Arrays.fill(codes, LatinKeyboardBaseView.NOT_A_KEY); + return codes; + } + + /** + * Computes maximum size of the array that can contain all nearby key indices returned by + * {@link #getKeyIndexAndNearbyCodes}. + * + * @return Returns maximum size of the array that can contain all nearby key indices returned + * by {@link #getKeyIndexAndNearbyCodes}. + */ + abstract protected int getMaxNearbyKeys(); + + /** + * Finds all possible nearby key indices around a touch event point and returns the nearest key + * index. The algorithm to determine the nearby keys depends on the threshold set by + * {@link #setProximityThreshold(int)} and the mode set by + * {@link #setProximityCorrectionEnabled(boolean)}. + * + * @param x The x-coordinate of a touch point + * @param y The y-coordinate of a touch point + * @param allKeys All nearby key indices are returned in this array + * @return The nearest key index + */ + abstract public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys); +} diff --git a/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java b/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java index dec29b7cb..2919e9b56 100644 --- a/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java @@ -37,29 +37,24 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha public static final int MODE_EMAIL = 5; public static final int MODE_IM = 6; public static final int MODE_WEB = 7; - - public static final int MODE_TEXT_QWERTY = 0; - public static final int MODE_TEXT_ALPHA = 1; - public static final int MODE_TEXT_COUNT = 2; - + public static final int KEYBOARDMODE_NORMAL = R.id.mode_normal; public static final int KEYBOARDMODE_URL = R.id.mode_url; public static final int KEYBOARDMODE_EMAIL = R.id.mode_email; public static final int KEYBOARDMODE_IM = R.id.mode_im; public static final int KEYBOARDMODE_WEB = R.id.mode_webentry; - public static final String DEFAULT_LAYOUT_ID = "3"; - public static final String PREF_KEYBOARD_LAYOUT = "keyboard_layout"; + public static final String DEFAULT_LAYOUT_ID = "4"; + public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20100902"; private static final int[] THEMES = new int [] { R.layout.input_basic, R.layout.input_basic_highcontrast, R.layout.input_stone_normal, - R.layout.input_stone_bold}; + R.layout.input_stone_bold, R.layout.input_gingerbread}; // Ids for each characters' color in the keyboard private static final int CHAR_THEME_COLOR_WHITE = 0; private static final int CHAR_THEME_COLOR_BLACK = 1; // Tables which contains resource ids for each character theme color - private static final int[] KBD_ALPHA = new int[] {R.xml.kbd_alpha, R.xml.kbd_alpha_black}; private static final int[] KBD_PHONE = new int[] {R.xml.kbd_phone, R.xml.kbd_phone_black}; private static final int[] KBD_PHONE_SYMBOLS = new int[] { R.xml.kbd_phone_symbols, R.xml.kbd_phone_symbols_black}; @@ -83,7 +78,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha Context mContext; LatinIME mInputMethodService; - + private KeyboardId mSymbolsId; private KeyboardId mSymbolsShiftedId; @@ -92,8 +87,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha private int mMode = MODE_NONE; /** One of the MODE_XXX values */ private int mImeOptions; - private int mTextMode = MODE_TEXT_QWERTY; private boolean mIsSymbols; + /** mIsAutoCompletionActive indicates that auto completed word will be input instead of + * what user actually typed. */ + private boolean mIsAutoCompletionActive; private boolean mHasVoice; private boolean mVoiceOnPrimary; private boolean mPreferSymbols; @@ -245,7 +242,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha keyboard.setShifted(false); keyboard.setShiftLocked(keyboard.isShiftLocked()); keyboard.setImeOptions(mContext.getResources(), mMode, imeOptions); - keyboard.setBlackFlag(isBlackSym()); + keyboard.setColorOfSymbolIcons(mIsAutoCompletionActive, isBlackSym()); } private LatinKeyboard getKeyboard(KeyboardId id) { @@ -255,20 +252,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha Locale saveLocale = conf.locale; conf.locale = mInputLocale; orig.updateConfiguration(conf, null); - LatinKeyboard keyboard = new LatinKeyboard( - mContext, id.mXml, id.mKeyboardMode); + LatinKeyboard keyboard = new LatinKeyboard(mContext, id.mXml, id.mKeyboardMode); keyboard.setVoiceMode(hasVoiceButton(id.mXml == R.xml.kbd_symbols || id.mXml == R.xml.kbd_symbols_black), mHasVoice); - keyboard.setLanguageSwitcher(mLanguageSwitcher); - keyboard.setBlackFlag(isBlackSym()); - if (id.mKeyboardMode == KEYBOARDMODE_NORMAL - || id.mKeyboardMode == KEYBOARDMODE_URL - || id.mKeyboardMode == KEYBOARDMODE_IM - || id.mKeyboardMode == KEYBOARDMODE_EMAIL - || id.mKeyboardMode == KEYBOARDMODE_WEB - ) { - keyboard.setExtension(R.xml.kbd_extension); - } + keyboard.setLanguageSwitcher(mLanguageSwitcher, mIsAutoCompletionActive, isBlackSym()); if (id.mEnableShiftLock) { keyboard.enableShiftLock(); @@ -299,11 +286,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha "getKeyboardId:" + mode + "," + imeOptions + "," + isSymbols); /* fall through */ case MODE_TEXT: - if (mTextMode == MODE_TEXT_ALPHA) { - return new KeyboardId( - KBD_ALPHA[charColorId], KEYBOARDMODE_NORMAL, true, hasVoice); - } - // Normally mTextMode should be MODE_TEXT_QWERTY. return new KeyboardId(keyboardRowsResId, KEYBOARDMODE_NORMAL, true, hasVoice); case MODE_SYMBOLS: return new KeyboardId(KBD_SYMBOLS[charColorId], hasVoice); @@ -328,10 +310,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha boolean isTextMode() { return mMode == MODE_TEXT; } - - int getTextModeCount() { - return MODE_TEXT_COUNT; - } boolean isAlphabetMode() { if (mCurrentId == null) { @@ -439,7 +417,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha mLayoutId + "," + newLayout, e); } } - mInputView.setExtentionLayoutResId(THEMES[newLayout]); mInputView.setOnKeyboardActionListener(mInputMethodService); mLayoutId = newLayout; } @@ -474,4 +451,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha } } + public void onAutoCompletionStateChanged(boolean isAutoCompletion) { + if (isAutoCompletion != mIsAutoCompletionActive) { + LatinKeyboardView keyboardView = getInputView(); + mIsAutoCompletionActive = isAutoCompletion; + keyboardView.invalidateKey(((LatinKeyboard) keyboardView.getKeyboard()) + .onAutoCompletionStateChanged(isAutoCompletion)); + } + } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 763e5e53c..e4776f888 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -61,6 +61,7 @@ import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; +import android.widget.LinearLayout; import java.io.FileDescriptor; import java.io.IOException; @@ -85,7 +86,6 @@ public class LatinIME extends InputMethodService static final boolean TRACE = false; static final boolean VOICE_INSTALLED = true; static final boolean ENABLE_VOICE_BUTTON = true; - private static final boolean MODIFY_TEXT_FOR_CORRECTION = false; private static final String PREF_VIBRATE_ON = "vibrate_on"; private static final String PREF_SOUND_ON = "sound_on"; @@ -153,7 +153,7 @@ public class LatinIME extends InputMethodService private static final int POS_METHOD = 1; //private LatinKeyboardView mInputView; - private CandidateViewContainer mCandidateViewContainer; + private LinearLayout mCandidateViewContainer; private CandidateView mCandidateView; private Suggest mSuggest; private CompletionInfo[] mCompletions; @@ -226,6 +226,9 @@ public class LatinIME extends InputMethodService private int mDeleteCount; private long mLastKeyTime; + // Shift modifier key state + private ModifierKeyState mShiftKeyState = new ModifierKeyState(); + private Tutorial mTutorial; private AudioManager mAudioManager; @@ -537,9 +540,8 @@ public class LatinIME extends InputMethodService @Override public View onCreateCandidatesView() { mKeyboardSwitcher.makeKeyboards(true); - mCandidateViewContainer = (CandidateViewContainer) getLayoutInflater().inflate( + mCandidateViewContainer = (LinearLayout) getLayoutInflater().inflate( R.layout.candidates, null); - mCandidateViewContainer.initViews(); mCandidateView = (CandidateView) mCandidateViewContainer.findViewById(R.id.candidates); mCandidateView.setService(this); setCandidatesViewShown(true); @@ -646,16 +648,14 @@ public class LatinIME extends InputMethodService (attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) == 0) { mInputTypeNoAutoCorrect = true; } - if ((attribute.inputType&EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) { + if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) { mPredictionOn = false; - mCompletionOn = true && isFullscreenMode(); + mCompletionOn = isFullscreenMode(); } - updateShiftKeyState(attribute); break; default: mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_TEXT, attribute.imeOptions, enableVoiceButton); - updateShiftKeyState(attribute); } inputView.closing(); mComposing.setLength(0); @@ -665,8 +665,9 @@ public class LatinIME extends InputMethodService loadSettings(); updateShiftKeyState(attribute); - setCandidatesViewShown(false); - setSuggestions(null, false, false, false); + setCandidatesViewShownInternal(isCandidateStripVisible() || mCompletionOn, + false /* needsInputViewShown */ ); + updateSuggestions(); // If the dictionary is not big enough, don't auto correct mHasDictionary = mSuggest.hasMainDictionary(); @@ -685,6 +686,7 @@ public class LatinIME extends InputMethodService super.onFinishInput(); LatinImeLogger.commit(); + onAutoCompletionStateChanged(false); if (VOICE_INSTALLED && !mConfigurationChanging) { if (mAfterVoiceInput) { @@ -767,27 +769,29 @@ public class LatinIME extends InputMethodService mLastSelectionEnd = newSelEnd; - // Check if we should go in or out of correction mode. - // TODO: Uncomment this block when we enable re-editing feature - // If a word is selected - /* - if (isPredictionOn() && mJustRevertedSeparator == null - && (candidatesStart == candidatesEnd || newSelStart != oldSelStart - || TextEntryState.isCorrecting()) - && (newSelStart < newSelEnd - 1 || (!mPredicting)) - && !mVoiceInputHighlighted) { - if (isCursorTouchingWord() || mLastSelectionStart < mLastSelectionEnd) { - postUpdateOldSuggestions(); - } else { - abortCorrection(false); + // Don't look for corrections if the keyboard is not visible + if (mKeyboardSwitcher != null && mKeyboardSwitcher.getInputView() != null + && mKeyboardSwitcher.getInputView().isShown()) { + // Check if we should go in or out of correction mode. + if (isPredictionOn() + && mJustRevertedSeparator == null + && (candidatesStart == candidatesEnd || newSelStart != oldSelStart + || TextEntryState.isCorrecting()) + && (newSelStart < newSelEnd - 1 || (!mPredicting)) + && !mVoiceInputHighlighted) { + if (isCursorTouchingWord() || mLastSelectionStart < mLastSelectionEnd) { + postUpdateOldSuggestions(); + } else { + abortCorrection(false); + } } } - */ } @Override public void hideWindow() { LatinImeLogger.commit(); + onAutoCompletionStateChanged(false); if (TRACE) Debug.stopMethodTracing(); if (mOptionsDialog != null && mOptionsDialog.isShowing()) { @@ -822,7 +826,7 @@ public class LatinIME extends InputMethodService if (mCompletionOn) { mCompletions = completions; if (completions == null) { - setSuggestions(null, false, false, false); + clearSuggestions(); return; } @@ -834,18 +838,21 @@ public class LatinIME extends InputMethodService // When in fullscreen mode, show completions generated by the application setSuggestions(stringList, true, true, true); mBestWord = null; - setCandidatesViewShown(isCandidateStripVisible() || mCompletionOn); + setCandidatesViewShown(true); + } + } + + private void setCandidatesViewShownInternal(boolean shown, boolean needsInputViewShown) { + // TODO: Remove this if we support candidates with hard keyboard + if (onEvaluateInputViewShown()) { + super.setCandidatesViewShown(shown && mKeyboardSwitcher.getInputView() != null + && (needsInputViewShown ? mKeyboardSwitcher.getInputView().isShown() : true)); } } @Override public void setCandidatesViewShown(boolean shown) { - // TODO: Remove this if we support candidates with hard keyboard - if (onEvaluateInputViewShown()) { - // Show the candidates view only if input view is showing - super.setCandidatesViewShown(shown && mKeyboardSwitcher.getInputView() != null - && mKeyboardSwitcher.getInputView().isShown()); - } + setCandidatesViewShownInternal(shown, true /* needsInputViewShown */ ); } @Override @@ -966,13 +973,15 @@ public class LatinIME extends InputMethodService private void postUpdateShiftKeyState() { mHandler.removeMessages(MSG_UPDATE_SHIFT_STATE); + // TODO: Should remove this 300ms delay? mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_SHIFT_STATE), 300); } public void updateShiftKeyState(EditorInfo attr) { InputConnection ic = getCurrentInputConnection(); if (ic != null && attr != null && mKeyboardSwitcher.isAlphabetMode()) { - mKeyboardSwitcher.setShifted(mCapsLock || getCursorCapsMode(ic, attr) != 0); + mKeyboardSwitcher.setShifted(mShiftKeyState.isMomentary() || mCapsLock + || getCursorCapsMode(ic, attr) != 0); } } @@ -1075,6 +1084,40 @@ public class LatinIME extends InputMethodService } } + private boolean hasMultipleEnabledIMEs() { + return ((InputMethodManager) getSystemService( + INPUT_METHOD_SERVICE)).getEnabledInputMethodList().size() > 1; + } + + private void showInputMethodPicker() { + ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)) + .showInputMethodPicker(); + } + + private void onOptionKeyPressed() { + if (!isShowingOptionDialog()) { + if (hasMultipleEnabledIMEs()) { + showOptionsMenu(); + } else { + launchSettings(); + } + } + } + + private void onOptionKeyLongPressed() { + if (!isShowingOptionDialog()) { + if (hasMultipleEnabledIMEs()) { + showInputMethodPicker(); + } else { + launchSettings(); + } + } + } + + private boolean isShowingOptionDialog() { + return mOptionsDialog != null && mOptionsDialog.isShowing(); + } + // Implementation of KeyboardViewListener public void onKey(int primaryCode, int[] keyCodes, int x, int y) { @@ -1091,15 +1134,18 @@ public class LatinIME extends InputMethodService LatinImeLogger.logOnDelete(); break; case Keyboard.KEYCODE_SHIFT: - handleShift(); + // Shift key is handled in onPress(). break; case Keyboard.KEYCODE_CANCEL: - if (mOptionsDialog == null || !mOptionsDialog.isShowing()) { + if (!isShowingOptionDialog()) { handleClose(); } break; case LatinKeyboardView.KEYCODE_OPTIONS: - showOptionsMenu(); + onOptionKeyPressed(); + break; + case LatinKeyboardView.KEYCODE_OPTIONS_LONGPRESS: + onOptionKeyLongPressed(); break; case LatinKeyboardView.KEYCODE_NEXT_LANGUAGE: toggleLanguage(false, true); @@ -1107,10 +1153,8 @@ public class LatinIME extends InputMethodService case LatinKeyboardView.KEYCODE_PREV_LANGUAGE: toggleLanguage(false, false); break; - case LatinKeyboardView.KEYCODE_SHIFT_LONGPRESS: - handleCapsLock(); - break; case Keyboard.KEYCODE_MODE_CHANGE: + // TODO: Mode change (symbol key) should be handled in onPress(). changeKeyboardMode(); break; case LatinKeyboardView.KEYCODE_VOICE: @@ -1231,12 +1275,20 @@ public class LatinIME extends InputMethodService ic.endBatchEdit(); } + private void resetShift() { + handleShiftInternal(true); + } + private void handleShift() { + handleShiftInternal(false); + } + + private void handleShiftInternal(boolean forceNormal) { mHandler.removeMessages(MSG_UPDATE_SHIFT_STATE); KeyboardSwitcher switcher = mKeyboardSwitcher; LatinKeyboardView inputView = switcher.getInputView(); if (switcher.isAlphabetMode()) { - if (mCapsLock) { + if (mCapsLock || forceNormal) { mCapsLock = false; switcher.setShifted(false); } else if (inputView != null) { @@ -1252,23 +1304,10 @@ public class LatinIME extends InputMethodService } } - private void handleCapsLock() { - mHandler.removeMessages(MSG_UPDATE_SHIFT_STATE); - KeyboardSwitcher switcher = mKeyboardSwitcher; - if (switcher.isAlphabetMode()) { - mCapsLock = !mCapsLock; - if (mCapsLock) { - switcher.setShiftLocked(true); - } else { - switcher.setShifted(false); - } - } - } - private void abortCorrection(boolean force) { if (force || TextEntryState.isCorrecting()) { getCurrentInputConnection().finishComposingText(); - setSuggestions(null, false, false, false); + clearSuggestions(); } } @@ -1281,7 +1320,9 @@ public class LatinIME extends InputMethodService // Assume input length is 1. This assumption fails for smiley face insertions. mVoiceInput.incrementTextModificationInsertCount(1); } - abortCorrection(false); + if (mLastSelectionStart == mLastSelectionEnd && TextEntryState.isCorrecting()) { + abortCorrection(false); + } if (isAlphabet(primaryCode) && isPredictionOn() && !isCursorTouchingWord()) { if (!mPredicting) { @@ -1436,8 +1477,7 @@ public class LatinIME extends InputMethodService } private boolean isPredictionOn() { - boolean predictionOn = mPredictionOn; - return predictionOn; + return mPredictionOn; } private boolean isCandidateStripVisible() { @@ -1511,7 +1551,7 @@ public class LatinIME extends InputMethodService } // Clear N-best suggestions - setSuggestions(null, false, false, true); + clearSuggestions(); FieldContext context = new FieldContext( getCurrentInputConnection(), @@ -1618,13 +1658,15 @@ public class LatinIME extends InputMethodService mVoiceInputHighlighted = true; mWordToSuggestions.putAll(mVoiceResults.alternatives); + } + private void clearSuggestions() { + setSuggestions(null, false, false, false); } private void setSuggestions( List suggestions, boolean completions, - boolean typedWordValid, boolean haveMinimalSuggestion) { @@ -1668,14 +1710,14 @@ public class LatinIME extends InputMethodService } private void showSuggestions(WordComposer word) { - //long startTime = System.currentTimeMillis(); // TIME MEASUREMENT! + // long startTime = System.currentTimeMillis(); // TIME MEASUREMENT! // TODO Maybe need better way of retrieving previous word CharSequence prevWord = EditingUtil.getPreviousWord(getCurrentInputConnection(), mWordSeparators); List stringList = mSuggest.getSuggestions( - mKeyboardSwitcher.getInputView(), word, false, prevWord); - //long stopTime = System.currentTimeMillis(); // TIME MEASUREMENT! - //Log.d("LatinIME","Suggest Total Time - " + (stopTime - startTime)); + mKeyboardSwitcher.getInputView(), word, false, prevWord); + // long stopTime = System.currentTimeMillis(); // TIME MEASUREMENT! + // Log.d("LatinIME","Suggest Total Time - " + (stopTime - startTime)); int[] nextLettersFrequencies = mSuggest.getNextLettersFrequencies(); @@ -1734,13 +1776,13 @@ public class LatinIME extends InputMethodService } public void pickSuggestionManually(int index, CharSequence suggestion) { - if (mAfterVoiceInput && mShowingVoiceSuggestions) mVoiceInput.logNBestChoose(index); List suggestions = mCandidateView.getSuggestions(); - - if (mAfterVoiceInput && !mShowingVoiceSuggestions) { + if (mAfterVoiceInput && mShowingVoiceSuggestions) { mVoiceInput.flushAllTextModificationCounters(); // send this intent AFTER logging any prior aggregated edits. - mVoiceInput.logTextModifiedByChooseSuggestion(suggestion.length()); + mVoiceInput.logTextModifiedByChooseSuggestion(suggestion.toString(), index, + mWordSeparators, + getCurrentInputConnection()); } final boolean correcting = TextEntryState.isCorrecting(); @@ -1796,18 +1838,23 @@ public class LatinIME extends InputMethodService mJustAddedAutoSpace = true; } - // Fool the state watcher so that a subsequent backspace will not do a revert, unless - // we just did a correction, in which case we need to stay in - // TextEntryState.State.PICKED_SUGGESTION state. + final boolean showingAddToDictionaryHint = index == 0 && mCorrectionMode > 0 + && !mSuggest.isValidWord(suggestion) + && !mSuggest.isValidWord(suggestion.toString().toLowerCase()); + if (!correcting) { + // Fool the state watcher so that a subsequent backspace will not do a revert, unless + // we just did a correction, in which case we need to stay in + // TextEntryState.State.PICKED_SUGGESTION state. TextEntryState.typedCharacter((char) KEYCODE_SPACE, true); setNextSuggestions(); - } else { + } else if (!showingAddToDictionaryHint) { + // If we're not showing the "Tap again to save hint", then show corrections again. // In case the cursor position doesn't change, make sure we show the suggestions again. + clearSuggestions(); postUpdateOldSuggestions(); } - if (index == 0 && mCorrectionMode > 0 && !mSuggest.isValidWord(suggestion) - && !mSuggest.isValidWord(suggestion.toString().toLowerCase())) { + if (showingAddToDictionaryHint) { mCandidateView.showAddToDictionaryHint(suggestion); } if (ic != null) { @@ -1857,16 +1904,6 @@ public class LatinIME extends InputMethodService InputConnection ic = getCurrentInputConnection(); if (ic != null) { rememberReplacedWord(suggestion); - // If text is in correction mode and we're not using composing - // text to underline, then the word at the cursor position needs - // to be removed before committing the correction - if (correcting && !MODIFY_TEXT_FOR_CORRECTION) { - if (mLastSelectionStart < mLastSelectionEnd) { - ic.setSelection(mLastSelectionStart, mLastSelectionStart); - } - EditingUtil.deleteWordAtCursor(ic, getWordSeparators()); - } - ic.commitText(suggestion, 1); } saveWordInHistory(suggestion); @@ -1880,96 +1917,108 @@ public class LatinIME extends InputMethodService updateShiftKeyState(getCurrentInputEditorInfo()); } + /** + * Tries to apply any voice alternatives for the word if this was a spoken word and + * there are voice alternatives. + * @param touching The word that the cursor is touching, with position information + * @return true if an alternative was found, false otherwise. + */ + private boolean applyVoiceAlternatives(EditingUtil.SelectedWord touching) { + // Search for result in spoken word alternatives + String selectedWord = touching.word.toString().trim(); + if (!mWordToSuggestions.containsKey(selectedWord)) { + selectedWord = selectedWord.toLowerCase(); + } + if (mWordToSuggestions.containsKey(selectedWord)) { + mShowingVoiceSuggestions = true; + List suggestions = mWordToSuggestions.get(selectedWord); + // If the first letter of touching is capitalized, make all the suggestions + // start with a capital letter. + if (Character.isUpperCase((char) touching.word.charAt(0))) { + for (int i = 0; i < suggestions.size(); i++) { + String origSugg = (String) suggestions.get(i); + String capsSugg = origSugg.toUpperCase().charAt(0) + + origSugg.subSequence(1, origSugg.length()).toString(); + suggestions.set(i, capsSugg); + } + } + setSuggestions(suggestions, false, true, true); + setCandidatesViewShown(true); + return true; + } + return false; + } + + /** + * Tries to apply any typed alternatives for the word if we have any cached alternatives, + * otherwise tries to find new corrections and completions for the word. + * @param touching The word that the cursor is touching, with position information + * @return true if an alternative was found, false otherwise. + */ + private boolean applyTypedAlternatives(EditingUtil.SelectedWord touching) { + // If we didn't find a match, search for result in typed word history + WordComposer foundWord = null; + WordAlternatives alternatives = null; + for (WordAlternatives entry : mWordHistory) { + if (TextUtils.equals(entry.getChosenWord(), touching.word)) { + if (entry instanceof TypedWordAlternatives) { + foundWord = ((TypedWordAlternatives) entry).word; + } + alternatives = entry; + break; + } + } + // If we didn't find a match, at least suggest completions + if (foundWord == null + && (mSuggest.isValidWord(touching.word) + || mSuggest.isValidWord(touching.word.toString().toLowerCase()))) { + foundWord = new WordComposer(); + for (int i = 0; i < touching.word.length(); i++) { + foundWord.add(touching.word.charAt(i), new int[] { + touching.word.charAt(i) + }); + } + foundWord.setCapitalized(Character.isUpperCase(touching.word.charAt(0))); + } + // Found a match, show suggestions + if (foundWord != null || alternatives != null) { + if (alternatives == null) { + alternatives = new TypedWordAlternatives(touching.word, foundWord); + } + showCorrections(alternatives); + if (foundWord != null) { + mWord = new WordComposer(foundWord); + } else { + mWord.reset(); + } + return true; + } + return false; + } + private void setOldSuggestions() { - // TODO: Inefficient to check if touching word and then get the touching word. Do it - // in one go. mShowingVoiceSuggestions = false; + if (mCandidateView != null && mCandidateView.isShowingAddToDictionaryHint()) { + return; + } InputConnection ic = getCurrentInputConnection(); if (ic == null) return; - ic.beginBatchEdit(); - // If there is a selection, then undo the selection first. Unfortunately this causes - // a flicker. TODO: Add getSelectionText() to InputConnection API. - if (mLastSelectionStart < mLastSelectionEnd) { - ic.setSelection(mLastSelectionStart, mLastSelectionStart); - } - if (!mPredicting && isCursorTouchingWord()) { - EditingUtil.Range range = new EditingUtil.Range(); - CharSequence touching = EditingUtil.getWordAtCursor(getCurrentInputConnection(), - mWordSeparators, range); - // If it's a selection, check if it's an entire word and no more, no less. - boolean fullword = EditingUtil.isFullWordOrInside(range, mLastSelectionStart, - mLastSelectionEnd); - if (fullword && touching != null && touching.length() > 1) { - // Strip out any trailing word separator - if (mWordSeparators.indexOf(touching.charAt(touching.length() - 1)) > 0) { - touching = touching.toString().substring(0, touching.length() - 1); + if (!mPredicting) { + // Extract the selected or touching text + EditingUtil.SelectedWord touching = EditingUtil.getWordAtCursorOrSelection(ic, + mLastSelectionStart, mLastSelectionEnd, mWordSeparators); + + if (touching != null && touching.word.length() > 1) { + ic.beginBatchEdit(); + + if (!applyVoiceAlternatives(touching) && !applyTypedAlternatives(touching)) { + abortCorrection(true); + } else { + TextEntryState.selectedForCorrection(); + EditingUtil.underlineWord(ic, touching); } - // Search for result in spoken word alternatives - String selectedWord = touching.toString().trim(); - if (!mWordToSuggestions.containsKey(selectedWord)){ - selectedWord = selectedWord.toLowerCase(); - } - if (mWordToSuggestions.containsKey(selectedWord)){ - mShowingVoiceSuggestions = true; - underlineWord(touching, range.charsBefore, range.charsAfter); - List suggestions = mWordToSuggestions.get(selectedWord); - // If the first letter of touching is capitalized, make all the suggestions - // start with a capital letter. - if (Character.isUpperCase((char) touching.charAt(0))) { - for (int i=0; i< suggestions.size(); i++) { - String origSugg = (String) suggestions.get(i); - String capsSugg = origSugg.toUpperCase().charAt(0) - + origSugg.subSequence(1, origSugg.length()).toString(); - suggestions.set(i,capsSugg); - } - } - setSuggestions(suggestions, false, true, true); - setCandidatesViewShown(true); - TextEntryState.selectedForCorrection(); - ic.endBatchEdit(); - return; - } - - // If we didn't find a match, search for result in typed word history - WordComposer foundWord = null; - WordAlternatives alternatives = null; - for (WordAlternatives entry : mWordHistory) { - if (TextUtils.equals(entry.getChosenWord(), touching)) { - if (entry instanceof TypedWordAlternatives) { - foundWord = ((TypedWordAlternatives)entry).word; - } - alternatives = entry; - break; - } - } - // If we didn't find a match, at least suggest completions - if (foundWord == null && mSuggest.isValidWord(touching)) { - foundWord = new WordComposer(); - for (int i = 0; i < touching.length(); i++) { - foundWord.add(touching.charAt(i), new int[] { touching.charAt(i) }); - } - } - // Found a match, show suggestions - if (foundWord != null || alternatives != null) { - underlineWord(touching, range.charsBefore, range.charsAfter); - TextEntryState.selectedForCorrection(); - if (alternatives == null) alternatives = new TypedWordAlternatives(touching, - foundWord); - showCorrections(alternatives); - if (foundWord != null) { - mWord = new WordComposer(foundWord); - } else { - mWord.reset(); - } - // Revert the selection - if (mLastSelectionStart < mLastSelectionEnd) { - ic.setSelection(mLastSelectionStart, mLastSelectionEnd); - } - ic.endBatchEdit(); - return; - } - abortCorrection(true); + ic.endBatchEdit(); } else { abortCorrection(true); setNextSuggestions(); @@ -1977,28 +2026,12 @@ public class LatinIME extends InputMethodService } else { abortCorrection(true); } - // Revert the selection - if (mLastSelectionStart < mLastSelectionEnd) { - ic.setSelection(mLastSelectionStart, mLastSelectionEnd); - } - ic.endBatchEdit(); } private void setNextSuggestions() { setSuggestions(mSuggestPuncList, false, false, false); } - private void underlineWord(CharSequence word, int left, int right) { - InputConnection ic = getCurrentInputConnection(); - if (ic == null) return; - if (MODIFY_TEXT_FOR_CORRECTION) { - ic.finishComposingText(); - ic.deleteSurroundingText(left, right); - ic.setComposingText(word, 1); - } - ic.setSelection(mLastSelectionStart, mLastSelectionStart); - } - private void addToDictionaries(CharSequence suggestion, int frequencyDelta) { checkAddToDictionary(suggestion, frequencyDelta, false); } @@ -2162,12 +2195,27 @@ public class LatinIME extends InputMethodService public void onPress(int primaryCode) { vibrate(); playKeyClick(primaryCode); + if (primaryCode == Keyboard.KEYCODE_SHIFT) { + mShiftKeyState.onPress(); + handleShift(); + } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE) { + // TODO: We should handle KEYCODE_MODE_CHANGE (symbol) here as well. + } else { + mShiftKeyState.onOtherKeyPressed(); + } } public void onRelease(int primaryCode) { // Reset any drag flags in the keyboard ((LatinKeyboard) mKeyboardSwitcher.getInputView().getKeyboard()).keyReleased(); //vibrate(); + if (primaryCode == Keyboard.KEYCODE_SHIFT) { + if (mShiftKeyState.isMomentary()) + resetShift(); + mShiftKeyState.onRelease(); + } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE) { + // TODO: We should handle KEYCODE_MODE_CHANGE (symbol) here as well. + } } private FieldContext makeFieldContext() { @@ -2389,7 +2437,7 @@ public class LatinIME extends InputMethodService builder.setIcon(R.drawable.ic_dialog_keyboard); builder.setNegativeButton(android.R.string.cancel, null); CharSequence itemSettings = getString(R.string.english_ime_settings); - CharSequence itemInputMethod = getString(R.string.inputMethod); + CharSequence itemInputMethod = getString(R.string.selectInputMethod); builder.setItems(new CharSequence[] { itemSettings, itemInputMethod}, new DialogInterface.OnClickListener() { @@ -2472,4 +2520,7 @@ public class LatinIME extends InputMethodService System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total)); } + public void onAutoCompletionStateChanged(boolean isAutoCompletion) { + mKeyboardSwitcher.onAutoCompletionStateChanged(isAutoCompletion); + } } diff --git a/java/src/com/android/inputmethod/latin/LatinIMESettings.java b/java/src/com/android/inputmethod/latin/LatinIMESettings.java index 806ef00af..565c1e6e8 100644 --- a/java/src/com/android/inputmethod/latin/LatinIMESettings.java +++ b/java/src/com/android/inputmethod/latin/LatinIMESettings.java @@ -76,7 +76,7 @@ public class LatinIMESettings extends PreferenceActivity mLogger = VoiceInputLogger.getLogger(this); mDebugMode = (CheckBoxPreference) findPreference(DEBUG_MODE_KEY); - updateDebugMode(mDebugMode.isChecked()); + updateDebugMode(); } @Override @@ -111,16 +111,20 @@ public class LatinIMESettings extends PreferenceActivity showVoiceConfirmation(); } } else if (key.equals(DEBUG_MODE_KEY)) { - updateDebugMode(prefs.getBoolean(DEBUG_MODE_KEY, false)); + if (mDebugMode != null) { + mDebugMode.setChecked(prefs.getBoolean(DEBUG_MODE_KEY, false)); + updateDebugMode(); + } } mVoiceOn = !(prefs.getString(VOICE_SETTINGS_KEY, mVoiceModeOff).equals(mVoiceModeOff)); updateVoiceModeSummary(); } - private void updateDebugMode(boolean isDebugMode) { + private void updateDebugMode() { if (mDebugMode == null) { return; } + boolean isDebugMode = mDebugMode.isChecked(); String version = ""; try { PackageInfo info = getPackageManager().getPackageInfo(getPackageName(), 0); @@ -134,8 +138,8 @@ public class LatinIMESettings extends PreferenceActivity mDebugMode.setSummary(""); } else { mDebugMode.setEnabled(true); - mDebugMode.setTitle(getResources().getString(R.string.prefs_debug_mode)); mDebugMode.setSummary(version); + mDebugMode.setSummary(""); } } diff --git a/java/src/com/android/inputmethod/latin/LatinIMEUtil.java b/java/src/com/android/inputmethod/latin/LatinIMEUtil.java index 838b4fe10..93ad4072d 100644 --- a/java/src/com/android/inputmethod/latin/LatinIMEUtil.java +++ b/java/src/com/android/inputmethod/latin/LatinIMEUtil.java @@ -54,9 +54,6 @@ public class LatinIMEUtil { } public boolean tryGCOrWait(String metaData, Throwable t) { - if (LatinImeLogger.sDBG) { - Log.d(TAG, "Encountered Exception or Error. Try GC."); - } if (mGCTryCount == 0) { System.gc(); } diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java index 716f7207f..007d0ccdd 100644 --- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java +++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java @@ -20,907 +20,52 @@ import com.android.inputmethod.latin.Dictionary.DataType; import android.content.Context; import android.content.SharedPreferences; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager.NameNotFoundException; import android.inputmethodservice.Keyboard; -import android.os.AsyncTask; -import android.os.DropBoxManager; -import android.preference.PreferenceManager; -import android.text.TextUtils; -import android.text.format.DateUtils; -import android.util.Log; -import android.util.Pair; - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; import java.util.List; public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChangeListener { - private static final String TAG = "LatinIMELogs"; - public static boolean sDBG = false; - private static boolean sPRINTLOGGING = false; - // SUPPRESS_EXCEPTION should be true when released to public. - private static final boolean SUPPRESS_EXCEPTION = true; - // DEFAULT_LOG_ENABLED should be false when released to public. - private static final boolean DEFAULT_LOG_ENABLED = false; - - private static final long MINIMUMSENDINTERVAL = 300 * DateUtils.SECOND_IN_MILLIS; // 300 sec - private static final long MINIMUMCOUNTINTERVAL = 20 * DateUtils.SECOND_IN_MILLIS; // 20 sec - private static final long MINIMUMSENDSIZE = 40; - private static final char SEPARATER = ';'; - private static final char NULL_CHAR = '\uFFFC'; - private static final int EXCEPTION_MAX_LENGTH = 400; - private static final int INVALID_COORDINATE = -2; - - // ID_MANUALSUGGESTION has been replaced by ID_MANUALSUGGESTION_WITH_DATATYPE - // private static final int ID_MANUALSUGGESTION = 0; - // private static final int ID_AUTOSUGGESTIONCANCELLED = 1; - // private static final int ID_AUTOSUGGESTION = 2; - private static final int ID_INPUT_COUNT = 3; - private static final int ID_DELETE_COUNT = 4; - private static final int ID_WORD_COUNT = 5; - private static final int ID_ACTUAL_CHAR_COUNT = 6; - private static final int ID_THEME_ID = 7; - private static final int ID_SETTING_AUTO_COMPLETE = 8; - private static final int ID_VERSION = 9; - private static final int ID_EXCEPTION = 10; - private static final int ID_MANUALSUGGESTIONCOUNT = 11; - private static final int ID_AUTOSUGGESTIONCANCELLEDCOUNT = 12; - private static final int ID_AUTOSUGGESTIONCOUNT = 13; - private static final int ID_LANGUAGES = 14; - private static final int ID_MANUALSUGGESTION_WITH_DATATYPE = 15; - private static final int ID_AUTOSUGGESTIONCANCELLED_WITH_COORDINATES = 16; - private static final int ID_AUTOSUGGESTION_WITH_COORDINATES = 17; - - private static final String PREF_ENABLE_LOG = "enable_logging"; - private static final String PREF_DEBUG_MODE = "debug_mode"; - private static final String PREF_AUTO_COMPLETE = "auto_complete"; - - public static boolean sLogEnabled = true; - /* package */ static LatinImeLogger sLatinImeLogger = new LatinImeLogger(); - // Store the last auto suggested word. - // This is required for a cancellation log of auto suggestion of that word. - /* package */ static String sLastAutoSuggestBefore; - /* package */ static String sLastAutoSuggestAfter; - /* package */ static String sLastAutoSuggestSeparator; - private static int[] sLastAutoSuggestXCoordinates; - private static int[] sLastAutoSuggestYCoordinates; - // This value holds MAIN, USER, AUTO, etc... - private static int sLastAutoSuggestDicTypeId; - // This value holds 0 (= unigram), 1 (= bigram) etc... - private static int sLastAutoSuggestDataType; - private static HashMap> sSuggestDicMap - = new HashMap>(); - private static String[] sPreviousWords; - private static DebugKeyEnabler sDebugKeyEnabler = new DebugKeyEnabler(); - private static int sKeyboardWidth = 0; - private static int sKeyboardHeight = 0; - - private ArrayList mLogBuffer = null; - private ArrayList mPrivacyLogBuffer = null; - /* package */ RingCharBuffer mRingCharBuffer = null; - - private Context mContext = null; - private DropBoxManager mDropBox = null; - private AddTextToDropBoxTask mAddTextToDropBoxTask; - private long mLastTimeActive; - private long mLastTimeSend; - private long mLastTimeCountEntry; - - private String mThemeId; - private String mSelectedLanguages; - private String mCurrentLanguage; - private int mDeleteCount; - private int mInputCount; - private int mWordCount; - private int[] mAutoSuggestCountPerDic = new int[Suggest.DIC_TYPE_LAST_ID + 1]; - private int[] mManualSuggestCountPerDic = new int[Suggest.DIC_TYPE_LAST_ID + 1]; - private int[] mAutoCancelledCountPerDic = new int[Suggest.DIC_TYPE_LAST_ID + 1]; - private int mActualCharCount; - - private static class LogEntry implements Comparable { - public final int mTag; - public final String[] mData; - public long mTime; - - public LogEntry (long time, int tag, String[] data) { - mTag = tag; - mTime = time; - mData = data; - } - - public int compareTo(LogEntry log2) { - if (mData.length == 0 && log2.mData.length == 0) { - return 0; - } else if (mData.length == 0) { - return 1; - } else if (log2.mData.length == 0) { - return -1; - } - return log2.mData[0].compareTo(mData[0]); - } - } - - private class AddTextToDropBoxTask extends AsyncTask { - private final DropBoxManager mDropBox; - private final long mTime; - private final String mData; - public AddTextToDropBoxTask(DropBoxManager db, long time, String data) { - mDropBox = db; - mTime = time; - mData = data; - } - @Override - protected Void doInBackground(Void... params) { - if (sPRINTLOGGING) { - Log.d(TAG, "Commit log: " + mData); - } - mDropBox.addText(TAG, mData); - return null; - } - @Override - protected void onPostExecute(Void v) { - mLastTimeSend = mTime; - } - } - - private void initInternal(Context context) { - mContext = context; - mDropBox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE); - mLastTimeSend = System.currentTimeMillis(); - mLastTimeActive = mLastTimeSend; - mLastTimeCountEntry = mLastTimeSend; - mDeleteCount = 0; - mInputCount = 0; - mWordCount = 0; - mActualCharCount = 0; - Arrays.fill(mAutoSuggestCountPerDic, 0); - Arrays.fill(mManualSuggestCountPerDic, 0); - Arrays.fill(mAutoCancelledCountPerDic, 0); - mLogBuffer = new ArrayList(); - mPrivacyLogBuffer = new ArrayList(); - mRingCharBuffer = new RingCharBuffer(context); - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - sLogEnabled = prefs.getBoolean(PREF_ENABLE_LOG, DEFAULT_LOG_ENABLED); - mThemeId = prefs.getString(KeyboardSwitcher.PREF_KEYBOARD_LAYOUT, - KeyboardSwitcher.DEFAULT_LAYOUT_ID); - mSelectedLanguages = prefs.getString(LatinIME.PREF_SELECTED_LANGUAGES, ""); - mCurrentLanguage = prefs.getString(LatinIME.PREF_INPUT_LANGUAGE, ""); - sPRINTLOGGING = prefs.getBoolean(PREF_DEBUG_MODE, sPRINTLOGGING); - sDBG = sPRINTLOGGING; - prefs.registerOnSharedPreferenceChangeListener(this); - } - - /** - * Clear all logged data - */ - private void reset() { - mDeleteCount = 0; - mInputCount = 0; - mWordCount = 0; - mActualCharCount = 0; - Arrays.fill(mAutoSuggestCountPerDic, 0); - Arrays.fill(mManualSuggestCountPerDic, 0); - Arrays.fill(mAutoCancelledCountPerDic, 0); - mLogBuffer.clear(); - mPrivacyLogBuffer.clear(); - } - - public void destroy() { - LatinIMEUtil.cancelTask(mAddTextToDropBoxTask, false); - } - - /** - * Check if the input string is safe as an entry or not. - */ - private static boolean checkStringDataSafe(String s) { - if (sDBG) { - Log.d(TAG, "Check String safety: " + s); - } - for (int i = 0; i < s.length(); ++i) { - if (Character.isDigit(s.charAt(i))) { - return false; - } - } - return true; - } - - private void addCountEntry(long time) { - if (sPRINTLOGGING) { - Log.d(TAG, "Log counts. (4)"); - } - mLogBuffer.add(new LogEntry (time, ID_DELETE_COUNT, - new String[] {String.valueOf(mDeleteCount)})); - mLogBuffer.add(new LogEntry (time, ID_INPUT_COUNT, - new String[] {String.valueOf(mInputCount)})); - mLogBuffer.add(new LogEntry (time, ID_WORD_COUNT, - new String[] {String.valueOf(mWordCount)})); - mLogBuffer.add(new LogEntry (time, ID_ACTUAL_CHAR_COUNT, - new String[] {String.valueOf(mActualCharCount)})); - mDeleteCount = 0; - mInputCount = 0; - mWordCount = 0; - mActualCharCount = 0; - mLastTimeCountEntry = time; - } - - private void addSuggestionCountEntry(long time) { - if (sPRINTLOGGING) { - Log.d(TAG, "log suggest counts. (1)"); - } - String[] s = new String[mAutoSuggestCountPerDic.length]; - for (int i = 0; i < s.length; ++i) { - s[i] = String.valueOf(mAutoSuggestCountPerDic[i]); - } - mLogBuffer.add(new LogEntry(time, ID_AUTOSUGGESTIONCOUNT, s)); - - s = new String[mAutoCancelledCountPerDic.length]; - for (int i = 0; i < s.length; ++i) { - s[i] = String.valueOf(mAutoCancelledCountPerDic[i]); - } - mLogBuffer.add(new LogEntry(time, ID_AUTOSUGGESTIONCANCELLEDCOUNT, s)); - - s = new String[mManualSuggestCountPerDic.length]; - for (int i = 0; i < s.length; ++i) { - s[i] = String.valueOf(mManualSuggestCountPerDic[i]); - } - mLogBuffer.add(new LogEntry(time, ID_MANUALSUGGESTIONCOUNT, s)); - - Arrays.fill(mAutoSuggestCountPerDic, 0); - Arrays.fill(mManualSuggestCountPerDic, 0); - Arrays.fill(mAutoCancelledCountPerDic, 0); - } - - private void addThemeIdEntry(long time) { - if (sPRINTLOGGING) { - Log.d(TAG, "Log theme Id. (1)"); - } - // TODO: Not to convert theme ID here. Currently "2" is treated as "6" in a log server. - if (mThemeId.equals("2")) { - mThemeId = "6"; - } else if (mThemeId.equals("3")) { - mThemeId = "7"; - } - mLogBuffer.add(new LogEntry (time, ID_THEME_ID, - new String[] {mThemeId})); - } - - private void addLanguagesEntry(long time) { - if (sPRINTLOGGING) { - Log.d(TAG, "Log language settings. (1)"); - } - // CurrentLanguage and SelectedLanguages will be blank if user doesn't use multi-language - // switching. - if (TextUtils.isEmpty(mCurrentLanguage)) { - mCurrentLanguage = mContext.getResources().getConfiguration().locale.toString(); - } - mLogBuffer.add(new LogEntry (time, ID_LANGUAGES, - new String[] {mCurrentLanguage , mSelectedLanguages})); - } - - private void addSettingsEntry(long time) { - if (sPRINTLOGGING) { - Log.d(TAG, "Log settings. (1)"); - } - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); - mLogBuffer.add(new LogEntry (time, ID_SETTING_AUTO_COMPLETE, - new String[] {String.valueOf(prefs.getBoolean(PREF_AUTO_COMPLETE, - mContext.getResources().getBoolean(R.bool.enable_autocorrect)))})); - } - - private void addVersionNameEntry(long time) { - if (sPRINTLOGGING) { - Log.d(TAG, "Log Version. (1)"); - } - try { - PackageInfo info = mContext.getPackageManager().getPackageInfo( - mContext.getPackageName(), 0); - mLogBuffer.add(new LogEntry (time, ID_VERSION, - new String[] {String.valueOf(info.versionCode), info.versionName})); - } catch (NameNotFoundException e) { - Log.e(TAG, "Could not find version name."); - } - } - - private void addExceptionEntry(long time, String[] data) { - if (sPRINTLOGGING) { - Log.d(TAG, "Log Exception. (1)"); - } - mLogBuffer.add(new LogEntry(time, ID_EXCEPTION, data)); - } - - private void flushPrivacyLogSafely() { - if (sPRINTLOGGING) { - Log.d(TAG, "Log obfuscated data. (" + mPrivacyLogBuffer.size() + ")"); - } - long now = System.currentTimeMillis(); - Collections.sort(mPrivacyLogBuffer); - for (LogEntry l: mPrivacyLogBuffer) { - l.mTime = now; - mLogBuffer.add(l); - } - mPrivacyLogBuffer.clear(); - } - - /** - * Add an entry - * @param tag - * @param data - */ - private void addData(int tag, Object data) { - switch (tag) { - case ID_DELETE_COUNT: - if (((mLastTimeActive - mLastTimeCountEntry) > MINIMUMCOUNTINTERVAL) - || (mDeleteCount == 0 && mInputCount == 0)) { - addCountEntry(mLastTimeActive); - } - mDeleteCount += (Integer)data; - break; - case ID_INPUT_COUNT: - if (((mLastTimeActive - mLastTimeCountEntry) > MINIMUMCOUNTINTERVAL) - || (mDeleteCount == 0 && mInputCount == 0)) { - addCountEntry(mLastTimeActive); - } - mInputCount += (Integer)data; - break; - case ID_MANUALSUGGESTION_WITH_DATATYPE: - case ID_AUTOSUGGESTION_WITH_COORDINATES: - ++mWordCount; - String[] dataStrings = (String[]) data; - if (dataStrings.length < 2) { - if (sDBG) { - Log.e(TAG, "The length of logged string array is invalid."); - } - break; - } - mActualCharCount += dataStrings[1].length(); - if (checkStringDataSafe(dataStrings[0]) && checkStringDataSafe(dataStrings[1])) { - mPrivacyLogBuffer.add( - new LogEntry (System.currentTimeMillis(), tag, dataStrings)); - } else { - if (sDBG) { - Log.d(TAG, "Skipped to add an entry because data is unsafe."); - } - } - break; - case ID_AUTOSUGGESTIONCANCELLED_WITH_COORDINATES: - --mWordCount; - dataStrings = (String[]) data; - if (dataStrings.length < 2) { - if (sDBG) { - Log.e(TAG, "The length of logged string array is invalid."); - } - break; - } - mActualCharCount -= dataStrings[1].length(); - if (checkStringDataSafe(dataStrings[0]) && checkStringDataSafe(dataStrings[1])) { - mPrivacyLogBuffer.add( - new LogEntry (System.currentTimeMillis(), tag, dataStrings)); - } else { - if (sDBG) { - Log.d(TAG, "Skipped to add an entry because data is unsafe."); - } - } - break; - case ID_EXCEPTION: - dataStrings = (String[]) data; - if (dataStrings.length < 2) { - if (sDBG) { - Log.e(TAG, "The length of logged string array is invalid."); - } - break; - } - addExceptionEntry(System.currentTimeMillis(), dataStrings); - break; - default: - if (sDBG) { - Log.e(TAG, "Log Tag is not entried."); - } - break; - } - } - - private void commitInternal() { - // if there is no log entry in mLogBuffer, will not send logs to DropBox. - if (!mLogBuffer.isEmpty() && (mAddTextToDropBoxTask == null - || mAddTextToDropBoxTask.getStatus() == AsyncTask.Status.FINISHED)) { - if (sPRINTLOGGING) { - Log.d(TAG, "Commit (" + mLogBuffer.size() + ")"); - } - flushPrivacyLogSafely(); - long now = System.currentTimeMillis(); - addCountEntry(now); - addThemeIdEntry(now); - addLanguagesEntry(now); - addSettingsEntry(now); - addVersionNameEntry(now); - addSuggestionCountEntry(now); - String s = LogSerializer.createStringFromEntries(mLogBuffer); - reset(); - mAddTextToDropBoxTask = (AddTextToDropBoxTask) new AddTextToDropBoxTask( - mDropBox, now, s).execute(); - } - } - - private void commitInternalAndStopSelf() { - if (sDBG) { - Log.e(TAG, "Exception was thrown and let's die."); - } - commitInternal(); - LatinIME ime = ((LatinIME) mContext); - ime.hideWindow(); - ime.stopSelf(); - } - - private synchronized void sendLogToDropBox(int tag, Object s) { - long now = System.currentTimeMillis(); - if (sDBG) { - String out = ""; - if (s instanceof String[]) { - for (String str: ((String[]) s)) { - out += str + ","; - } - } else if (s instanceof Integer) { - out += (Integer) s; - } - Log.d(TAG, "SendLog: " + tag + ";" + out + " -> will be sent after " - + (- (now - mLastTimeSend - MINIMUMSENDINTERVAL) / 1000) + " sec."); - } - if (now - mLastTimeActive > MINIMUMSENDINTERVAL) { - // Send a log before adding an log entry if the last data is too old. - commitInternal(); - addData(tag, s); - } else if (now - mLastTimeSend > MINIMUMSENDINTERVAL) { - // Send a log after adding an log entry. - addData(tag, s); - commitInternal(); - } else { - addData(tag, s); - } - mLastTimeActive = now; - } public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (PREF_ENABLE_LOG.equals(key)) { - if (sharedPreferences.getBoolean(key, DEFAULT_LOG_ENABLED)) { - sLogEnabled = (mContext != null); - } else { - sLogEnabled = false; - } - if (sDebugKeyEnabler.check()) { - sharedPreferences.edit().putBoolean(PREF_DEBUG_MODE, true).commit(); - } - } else if (KeyboardSwitcher.PREF_KEYBOARD_LAYOUT.equals(key)) { - mThemeId = sharedPreferences.getString(KeyboardSwitcher.PREF_KEYBOARD_LAYOUT, - KeyboardSwitcher.DEFAULT_LAYOUT_ID); - addThemeIdEntry(mLastTimeActive); - } else if (PREF_DEBUG_MODE.equals(key)) { - sPRINTLOGGING = sharedPreferences.getBoolean(PREF_DEBUG_MODE, sPRINTLOGGING); - sDBG = sPRINTLOGGING; - } else if (LatinIME.PREF_INPUT_LANGUAGE.equals(key)) { - mCurrentLanguage = sharedPreferences.getString(LatinIME.PREF_INPUT_LANGUAGE, ""); - addLanguagesEntry(mLastTimeActive); - } else if (LatinIME.PREF_INPUT_LANGUAGE.equals(key)) { - mSelectedLanguages = sharedPreferences.getString(LatinIME.PREF_SELECTED_LANGUAGES, ""); - } } public static void init(Context context) { - sLatinImeLogger.initInternal(context); } public static void commit() { - if (sLogEnabled) { - if (System.currentTimeMillis() - sLatinImeLogger.mLastTimeActive > MINIMUMCOUNTINTERVAL - || (sLatinImeLogger.mLogBuffer.size() - + sLatinImeLogger.mPrivacyLogBuffer.size() > MINIMUMSENDSIZE)) { - sLatinImeLogger.commitInternal(); - } - } } public static void onDestroy() { - sLatinImeLogger.commitInternal(); - sLatinImeLogger.destroy(); } - // TODO: Handle CharSequence instead of String public static void logOnManualSuggestion(String before, String after, int position , List suggestions) { - if (sLogEnabled) { - // log punctuation - if (before.length() == 0 && after.length() == 1) { - sLatinImeLogger.sendLogToDropBox(ID_MANUALSUGGESTION_WITH_DATATYPE, new String[] { - before, after, String.valueOf(position), ""}); - } else if (!sSuggestDicMap.containsKey(after)) { - if (sDBG) { - Log.e(TAG, "logOnManualSuggestion was cancelled: from unknown dic."); - } - } else { - int dicTypeId = sSuggestDicMap.get(after).first; - sLatinImeLogger.mManualSuggestCountPerDic[dicTypeId]++; - if (dicTypeId != Suggest.DIC_MAIN) { - if (sDBG) { - Log.d(TAG, "logOnManualSuggestion was cancelled: not from main dic."); - } - before = ""; - after = ""; - sPreviousWords = null; - } - // TODO: Don't send a log if this doesn't come from Main Dictionary. - { - if (before.equals(after)) { - before = ""; - after = ""; - } - - /* Example: - * When user typed "Illegal imm" and picked "immigrants", - * the suggestion list has "immigrants, immediate, immigrant". - * At this time, the log strings will be something like below: - * strings[0 = COLUMN_BEFORE_ID] = imm - * strings[1 = COLUMN_AFTER_ID] = immigrants - * strings[2 = COLUMN_PICKED_POSITION_ID] = 0 - * strings[3 = COLUMN_SUGGESTION_LENGTH_ID] = 3 - * strings[4 = COLUMN_PREVIOUS_WORDS_COUNT_ID] = 1 - * strings[5] = immigrants - * strings[6] = immediate - * strings[7] = immigrant - * strings[8] = 1 (= bigram) - * strings[9] = 0 (= unigram) - * strings[10] = 1 (= bigram) - * strings[11] = Illegal - */ - - // 0 for unigram, 1 for bigram, 2 for trigram... - int previousWordsLength = (sPreviousWords == null) ? 0 : sPreviousWords.length; - int suggestionLength = suggestions.size(); - - final int COLUMN_BEFORE_ID = 0; - final int COLUMN_AFTER_ID = 1; - final int COLUMN_PICKED_POSITION_ID = 2; - final int COLUMN_SUGGESTION_LENGTH_ID = 3; - final int COLUMN_PREVIOUS_WORDS_COUNT_ID = 4; - final int BASE_COLUMN_SIZE = 5; - - String[] strings = - new String[BASE_COLUMN_SIZE + suggestionLength * 2 + previousWordsLength]; - strings[COLUMN_BEFORE_ID] = before; - strings[COLUMN_AFTER_ID] = after; - strings[COLUMN_PICKED_POSITION_ID] = String.valueOf(position); - strings[COLUMN_SUGGESTION_LENGTH_ID] = String.valueOf(suggestionLength); - strings[COLUMN_PREVIOUS_WORDS_COUNT_ID] = String.valueOf(previousWordsLength); - - for (int i = 0; i < suggestionLength; ++i) { - String s = suggestions.get(i).toString(); - if (sSuggestDicMap.containsKey(s)) { - strings[BASE_COLUMN_SIZE + i] = s; - strings[BASE_COLUMN_SIZE + suggestionLength + i] - = sSuggestDicMap.get(s).second.toString(); - } else { - strings[BASE_COLUMN_SIZE + i] = ""; - strings[BASE_COLUMN_SIZE + suggestionLength + i] = ""; - } - } - - for (int i = 0; i < previousWordsLength; ++i) { - strings[BASE_COLUMN_SIZE + suggestionLength * 2 + i] = sPreviousWords[i]; - } - - sLatinImeLogger.sendLogToDropBox(ID_MANUALSUGGESTION_WITH_DATATYPE, strings); - } - } - sSuggestDicMap.clear(); - } - } + } public static void logOnAutoSuggestion(String before, String after) { - if (sLogEnabled) { - if (!sSuggestDicMap.containsKey(after)) { - if (sDBG) { - Log.e(TAG, "logOnAutoSuggestion was cancelled: from unknown dic."); - } - } else { - String separator = String.valueOf(sLatinImeLogger.mRingCharBuffer.getLastChar()); - sLastAutoSuggestDicTypeId = sSuggestDicMap.get(after).first; - sLastAutoSuggestDataType = sSuggestDicMap.get(after).second; - sLatinImeLogger.mAutoSuggestCountPerDic[sLastAutoSuggestDicTypeId]++; - if (sLastAutoSuggestDicTypeId != Suggest.DIC_MAIN) { - if (sDBG) { - Log.d(TAG, "logOnAutoSuggestion was cancelled: not from main dic.:" - + sLastAutoSuggestDicTypeId); - } - before = ""; - after = ""; - sPreviousWords = null; - } - // TODO: Not to send a log if this doesn't come from Main Dictionary. - { - if (before.equals(after)) { - before = ""; - after = ""; - } - - final int COLUMN_BEFORE_ID = 0; - final int COLUMN_AFTER_ID = 1; - final int COLUMN_SEPARATOR_ID = 2; - final int COLUMN_DATA_TYPE_ID = 3; - final int COLUMN_KEYBOARD_SIZE_WIDTH = 4; - final int COLUMN_KEYBOARD_SIZE_HEIGHT = 5; - final int BASE_COLUMN_SIZE = 6; - - final int userTypedWordLength = before.length(); - final int previousWordsLength = (sPreviousWords == null) ? 0 - : sPreviousWords.length; - String[] strings = new String[BASE_COLUMN_SIZE + userTypedWordLength * 2 - + previousWordsLength]; - sLastAutoSuggestXCoordinates = new int[userTypedWordLength]; - sLastAutoSuggestXCoordinates = new int[userTypedWordLength]; - - strings[COLUMN_BEFORE_ID] = before; - strings[COLUMN_AFTER_ID] = after; - strings[COLUMN_SEPARATOR_ID] = separator; - strings[COLUMN_DATA_TYPE_ID] = String.valueOf(sLastAutoSuggestDataType); - strings[COLUMN_KEYBOARD_SIZE_WIDTH] = String.valueOf(sKeyboardWidth); - strings[COLUMN_KEYBOARD_SIZE_HEIGHT] = String.valueOf(sKeyboardHeight); - - for (int i = 0; i < userTypedWordLength; ++i) { - int x = sLatinImeLogger.mRingCharBuffer.getPreviousX(before.charAt(i), - userTypedWordLength - i - 1); - int y = sLatinImeLogger.mRingCharBuffer.getPreviousY(before.charAt(i), - userTypedWordLength - i - 1); - strings[BASE_COLUMN_SIZE + i * 2] = String.valueOf(x); - strings[BASE_COLUMN_SIZE + i * 2 + 1] = String.valueOf(y); - sLastAutoSuggestXCoordinates[i] = x; - sLastAutoSuggestXCoordinates[i] = y; - } - - for (int i = 0; i < previousWordsLength; ++i) { - strings[BASE_COLUMN_SIZE + userTypedWordLength * 2 + i] = sPreviousWords[i]; - } - - sLatinImeLogger.sendLogToDropBox(ID_AUTOSUGGESTION_WITH_COORDINATES, strings); - } - synchronized (LatinImeLogger.class) { - sLastAutoSuggestBefore = before; - sLastAutoSuggestAfter = after; - sLastAutoSuggestSeparator = separator; - } - } - sSuggestDicMap.clear(); - } } public static void logOnAutoSuggestionCanceled() { - if (sLogEnabled) { - sLatinImeLogger.mAutoCancelledCountPerDic[sLastAutoSuggestDicTypeId]++; - if (sLastAutoSuggestBefore != null && sLastAutoSuggestAfter != null) { - final int COLUMN_BEFORE_ID = 0; - final int COLUMN_AFTER_ID = 1; - final int COLUMN_SEPARATOR_ID = 2; - final int COLUMN_KEYBOARD_SIZE_WIDTH = 3; - final int COLUMN_KEYBOARD_SIZE_HEIGHT = 4; - final int BASE_COLUMN_SIZE = 5; - - final int userTypedWordLength = sLastAutoSuggestBefore.length(); - - String[] strings = new String[BASE_COLUMN_SIZE + userTypedWordLength * 2]; - strings[COLUMN_BEFORE_ID] = sLastAutoSuggestBefore; - strings[COLUMN_AFTER_ID] = sLastAutoSuggestAfter; - strings[COLUMN_SEPARATOR_ID] = sLastAutoSuggestSeparator; - strings[COLUMN_KEYBOARD_SIZE_WIDTH] = String.valueOf(sKeyboardWidth); - strings[COLUMN_KEYBOARD_SIZE_HEIGHT] = String.valueOf(sKeyboardHeight); - for (int i = 0; i < userTypedWordLength; ++i) { - strings[BASE_COLUMN_SIZE + i * 2] = String.valueOf( - sLastAutoSuggestXCoordinates); - strings[BASE_COLUMN_SIZE + i * 2 + 1] = String.valueOf( - sLastAutoSuggestYCoordinates); - } - sLatinImeLogger.sendLogToDropBox( - ID_AUTOSUGGESTIONCANCELLED_WITH_COORDINATES, strings); - } - synchronized (LatinImeLogger.class) { - sLastAutoSuggestBefore = ""; - sLastAutoSuggestAfter = ""; - sLastAutoSuggestSeparator = ""; - } - } } public static void logOnDelete() { - if (sLogEnabled) { - String mLastWord = sLatinImeLogger.mRingCharBuffer.getLastString(); - if (!TextUtils.isEmpty(mLastWord) - && mLastWord.equalsIgnoreCase(sLastAutoSuggestBefore)) { - logOnAutoSuggestionCanceled(); - } - sLatinImeLogger.mRingCharBuffer.pop(); - sLatinImeLogger.sendLogToDropBox(ID_DELETE_COUNT, 1); - } } public static void logOnInputChar(char c, int x, int y) { - if (sLogEnabled) { - sLatinImeLogger.mRingCharBuffer.push(c, x, y); - sLatinImeLogger.sendLogToDropBox(ID_INPUT_COUNT, 1); - } } public static void logOnException(String metaData, Throwable e) { - if (sLogEnabled) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); - e.printStackTrace(ps); - String exceptionString = URLEncoder.encode(new String(baos.toByteArray(), 0, - Math.min(EXCEPTION_MAX_LENGTH, baos.size()))); - sLatinImeLogger.sendLogToDropBox( - ID_EXCEPTION, new String[] {metaData, exceptionString}); - if (sDBG) { - Log.e(TAG, "Exception: " + new String(baos.toByteArray())+ ":" + exceptionString); - } - if (SUPPRESS_EXCEPTION) { - sLatinImeLogger.commitInternalAndStopSelf(); - } else { - sLatinImeLogger.commitInternal(); - if (e instanceof RuntimeException) { - throw (RuntimeException) e; - } else if (e instanceof Error) { - throw (Error) e; - } - } - } } public static void logOnWarning(String warning) { - if (sLogEnabled) { - sLatinImeLogger.sendLogToDropBox( - ID_EXCEPTION, new String[] {warning, ""}); - } } - // TODO: This code supports only Bigram. public static void onStartSuggestion(CharSequence previousWords) { - if (sLogEnabled) { - sSuggestDicMap.clear(); - sPreviousWords = new String[] { - (previousWords == null) ? "" : previousWords.toString()}; - } } public static void onAddSuggestedWord(String word, int typeId, DataType dataType) { - if (sLogEnabled) { - sSuggestDicMap.put(word, new Pair(typeId, dataType.ordinal())); - } } public static void onSetKeyboard(Keyboard kb) { - if (sLogEnabled) { - sKeyboardWidth = kb.getMinWidth(); - sKeyboardHeight = kb.getHeight(); - } } - private static class LogSerializer { - private static void appendWithLength(StringBuffer sb, String data) { - sb.append(data.length()); - sb.append(SEPARATER); - sb.append(data); - sb.append(SEPARATER); - } - - private static void appendLogEntry(StringBuffer sb, String time, String tag, - String[] data) { - if (data.length > 0) { - appendWithLength(sb, String.valueOf(data.length + 2)); - appendWithLength(sb, time); - appendWithLength(sb, tag); - for (String s: data) { - appendWithLength(sb, s); - } - } - } - - public static String createStringFromEntries(ArrayList logs) { - StringBuffer sb = new StringBuffer(); - for (LogEntry log: logs) { - appendLogEntry(sb, String.valueOf(log.mTime), String.valueOf(log.mTag), log.mData); - } - return sb.toString(); - } - } - - /* package */ static class RingCharBuffer { - final int BUFSIZE = 20; - private Context mContext; - private int mEnd = 0; - /* package */ int mLength = 0; - private char[] mCharBuf = new char[BUFSIZE]; - private int[] mXBuf = new int[BUFSIZE]; - private int[] mYBuf = new int[BUFSIZE]; - - public RingCharBuffer(Context context) { - mContext = context; - } - private int normalize(int in) { - int ret = in % BUFSIZE; - return ret < 0 ? ret + BUFSIZE : ret; - } - public void push(char c, int x, int y) { - mCharBuf[mEnd] = c; - mXBuf[mEnd] = x; - mYBuf[mEnd] = y; - mEnd = normalize(mEnd + 1); - if (mLength < BUFSIZE) { - ++mLength; - } - } - public char pop() { - if (mLength < 1) { - return NULL_CHAR; - } else { - mEnd = normalize(mEnd - 1); - --mLength; - return mCharBuf[mEnd]; - } - } - public char getLastChar() { - if (mLength < 1) { - return NULL_CHAR; - } else { - return mCharBuf[normalize(mEnd - 1)]; - } - } - public int getPreviousX(char c, int back) { - int index = normalize(mEnd - 2 - back); - if (mLength <= back - || Character.toLowerCase(c) != Character.toLowerCase(mCharBuf[index])) { - return INVALID_COORDINATE; - } else { - return mXBuf[index]; - } - } - public int getPreviousY(char c, int back) { - int index = normalize(mEnd - 2 - back); - if (mLength <= back - || Character.toLowerCase(c) != Character.toLowerCase(mCharBuf[index])) { - return INVALID_COORDINATE; - } else { - return mYBuf[index]; - } - } - public String getLastString() { - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < mLength; ++i) { - char c = mCharBuf[normalize(mEnd - 1 - i)]; - if (!((LatinIME)mContext).isWordSeparator(c)) { - sb.append(c); - } else { - break; - } - } - return sb.reverse().toString(); - } - public void reset() { - mLength = 0; - } - } - - private static class DebugKeyEnabler { - private int mCounter = 0; - private long mLastTime = 0; - public boolean check() { - if (System.currentTimeMillis() - mLastTime > 10 * 1000) { - mCounter = 0; - mLastTime = System.currentTimeMillis(); - } else if (++mCounter >= 10) { - return true; - } - return false; - } - } } diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboard.java b/java/src/com/android/inputmethod/latin/LatinKeyboard.java index db4d167d4..c7ca67727 100644 --- a/java/src/com/android/inputmethod/latin/LatinKeyboard.java +++ b/java/src/com/android/inputmethod/latin/LatinKeyboard.java @@ -43,11 +43,14 @@ public class LatinKeyboard extends Keyboard { private static final boolean DEBUG_PREFERRED_LETTER = false; private static final String TAG = "LatinKeyboard"; + private static final int OPACITY_FULLY_OPAQUE = 255; + private static final int SPACE_LED_LENGTH_PERCENT = 80; private Drawable mShiftLockIcon; private Drawable mShiftLockPreviewIcon; private Drawable mOldShiftIcon; private Drawable mSpaceIcon; + private Drawable mSpaceAutoCompletionIndicator; private Drawable mSpacePreviewIcon; private Drawable mMicIcon; private Drawable mMicPreviewIcon; @@ -81,7 +84,6 @@ public class LatinKeyboard extends Keyboard { private int mPrefLetterY; private int mPrefDistance; - private int mExtensionResId; // TODO: generalize for any keyboardId private boolean mIsBlackSym; @@ -112,6 +114,7 @@ public class LatinKeyboard extends Keyboard { mShiftLockPreviewIcon.getIntrinsicWidth(), mShiftLockPreviewIcon.getIntrinsicHeight()); mSpaceIcon = res.getDrawable(R.drawable.sym_keyboard_space); + mSpaceAutoCompletionIndicator = res.getDrawable(R.drawable.sym_keyboard_space_led); mSpacePreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_space); mMicIcon = res.getDrawable(R.drawable.sym_keyboard_mic); mMicPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_mic); @@ -278,17 +281,9 @@ public class LatinKeyboard extends Keyboard { return mIsAlphaKeyboard; } - public void setExtension(int resId) { - mExtensionResId = resId; - } - - public int getExtension() { - return mExtensionResId; - } - - public void setBlackFlag(boolean f) { - mIsBlackSym = f; - if (f) { + public void setColorOfSymbolIcons(boolean isAutoCompletion, boolean isBlack) { + mIsBlackSym = isBlack; + if (isBlack) { mShiftLockIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_shift_locked); mSpaceIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_space); mMicIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_mic); @@ -301,8 +296,7 @@ public class LatinKeyboard extends Keyboard { } updateF1Key(); if (mSpaceKey != null) { - mSpaceKey.icon = mSpaceIcon; - updateSpaceBarForLocale(f); + updateSpaceBarForLocale(isAutoCompletion, isBlack); } } @@ -343,57 +337,87 @@ public class LatinKeyboard extends Keyboard { } } - private void updateSpaceBarForLocale(boolean isBlack) { + /** + * @return a key which should be invalidated. + */ + public Key onAutoCompletionStateChanged(boolean isAutoCompletion) { + updateSpaceBarForLocale(isAutoCompletion, mIsBlackSym); + return mSpaceKey; + } + + private void updateSpaceBarForLocale(boolean isAutoCompletion, boolean isBlack) { + // If application locales are explicitly selected. if (mLocale != null) { - // Create the graphic for spacebar - Bitmap buffer = Bitmap.createBitmap(mSpaceKey.width, mSpaceIcon.getIntrinsicHeight(), - Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(buffer); - drawSpaceBar(canvas, buffer.getWidth(), buffer.getHeight(), 255, isBlack); - mSpaceKey.icon = new BitmapDrawable(mRes, buffer); + mSpaceKey.icon = new BitmapDrawable(mRes, + drawSpaceBar(OPACITY_FULLY_OPAQUE, isAutoCompletion, isBlack)); mSpaceKey.repeatable = mLanguageSwitcher.getLocaleCount() < 2; } else { - mSpaceKey.icon = isBlack ? mRes.getDrawable(R.drawable.sym_bkeyboard_space) - : mRes.getDrawable(R.drawable.sym_keyboard_space); + // sym_keyboard_space_led can be shared with Black and White symbol themes. + if (isAutoCompletion) { + mSpaceKey.icon = new BitmapDrawable(mRes, + drawSpaceBar(OPACITY_FULLY_OPAQUE, isAutoCompletion, isBlack)); + } else { + mSpaceKey.icon = isBlack ? mRes.getDrawable(R.drawable.sym_bkeyboard_space) + : mRes.getDrawable(R.drawable.sym_keyboard_space); + } mSpaceKey.repeatable = true; } } - private void drawSpaceBar(Canvas canvas, int width, int height, int opacity, boolean isBlack) { + private Bitmap drawSpaceBar(int opacity, boolean isAutoCompletion, boolean isBlack) { + int width = mSpaceKey.width; + int height = mSpaceIcon.getIntrinsicHeight(); + Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(buffer); canvas.drawColor(mRes.getColor(R.color.latinkeyboard_transparent), PorterDuff.Mode.CLEAR); - Paint paint = new Paint(); - paint.setAntiAlias(true); - paint.setAlpha(opacity); - // Get the text size from the theme - paint.setTextSize(getTextSizeFromTheme(android.R.style.TextAppearance_Small, 14)); - paint.setTextAlign(Align.CENTER); - final String language = getInputLanguage(mSpaceKey.width, paint); - final int ascent = (int) -paint.ascent(); + // If application locales are explicitly selected. + if (mLocale != null) { + Paint paint = new Paint(); + paint.setAntiAlias(true); + paint.setAlpha(opacity); + // Get the text size from the theme + paint.setTextSize(getTextSizeFromTheme(android.R.style.TextAppearance_Small, 14)); + paint.setTextAlign(Align.CENTER); + final String language = getInputLanguage(mSpaceKey.width, paint); + final int ascent = (int) -paint.ascent(); - int shadowColor = isBlack ? mRes.getColor(R.color.latinkeyboard_bar_language_shadow_black) - : mRes.getColor(R.color.latinkeyboard_bar_language_shadow_white); + int shadowColor = isBlack ? + mRes.getColor(R.color.latinkeyboard_bar_language_shadow_black) + : mRes.getColor(R.color.latinkeyboard_bar_language_shadow_white); - paint.setColor(shadowColor); - canvas.drawText(language, width / 2, ascent - 1, paint); - paint.setColor(mRes.getColor(R.color.latinkeyboard_bar_language_text)); - canvas.drawText(language, width / 2, ascent, paint); - // Put arrows on either side of the text - if (mLanguageSwitcher.getLocaleCount() > 1) { - Rect bounds = new Rect(); - paint.getTextBounds(language, 0, language.length(), bounds); - drawButtonArrow(mButtonArrowLeftIcon, canvas, - (mSpaceKey.width - bounds.right) / 2 - - mButtonArrowLeftIcon.getIntrinsicWidth(), - (int) paint.getTextSize()); - drawButtonArrow(mButtonArrowRightIcon, canvas, - (mSpaceKey.width + bounds.right) / 2, (int) paint.getTextSize()); + paint.setColor(shadowColor); + canvas.drawText(language, width / 2, ascent - 1, paint); + paint.setColor(mRes.getColor(R.color.latinkeyboard_bar_language_text)); + canvas.drawText(language, width / 2, ascent, paint); + // Put arrows on either side of the text + if (mLanguageSwitcher.getLocaleCount() > 1) { + Rect bounds = new Rect(); + paint.getTextBounds(language, 0, language.length(), bounds); + drawButtonArrow(mButtonArrowLeftIcon, canvas, + (mSpaceKey.width - bounds.right) / 2 + - mButtonArrowLeftIcon.getIntrinsicWidth(), + (int) paint.getTextSize()); + drawButtonArrow(mButtonArrowRightIcon, canvas, + (mSpaceKey.width + bounds.right) / 2, (int) paint.getTextSize()); + } } // Draw the spacebar icon at the bottom - int x = (width - mSpaceIcon.getIntrinsicWidth()) / 2; - int y = height - mSpaceIcon.getIntrinsicHeight(); - mSpaceIcon.setBounds(x, y, - x + mSpaceIcon.getIntrinsicWidth(), y + mSpaceIcon.getIntrinsicHeight()); - mSpaceIcon.draw(canvas); + if (isAutoCompletion) { + final int iconWidth = width * SPACE_LED_LENGTH_PERCENT / 100; + final int iconHeight = mSpaceAutoCompletionIndicator.getIntrinsicHeight(); + int x = (width - iconWidth) / 2; + int y = height - iconHeight; + mSpaceAutoCompletionIndicator.setBounds(x, y, x + iconWidth, y + iconHeight); + mSpaceAutoCompletionIndicator.draw(canvas); + } else { + final int iconWidth = mSpaceIcon.getIntrinsicWidth(); + final int iconHeight = mSpaceIcon.getIntrinsicHeight(); + int x = (width - iconWidth) / 2; + int y = height - iconHeight; + mSpaceIcon.setBounds(x, y, x + iconWidth, y + iconHeight); + mSpaceIcon.draw(canvas); + } + return buffer; } private void drawButtonArrow(Drawable arrow, Canvas canvas, int x, int bottomY) { @@ -447,7 +471,8 @@ public class LatinKeyboard extends Keyboard { return mSpaceDragLastDiff > 0 ? 1 : -1; } - public void setLanguageSwitcher(LanguageSwitcher switcher) { + public void setLanguageSwitcher(LanguageSwitcher switcher, boolean isAutoCompletion, + boolean isBlackSym) { mLanguageSwitcher = switcher; Locale locale = mLanguageSwitcher.getLocaleCount() > 0 ? mLanguageSwitcher.getInputLocale() @@ -459,9 +484,9 @@ public class LatinKeyboard extends Keyboard { .equalsIgnoreCase(locale.getLanguage())) { locale = null; } + setColorOfSymbolIcons(isAutoCompletion, isBlackSym); if (mLocale != null && mLocale.equals(locale)) return; mLocale = locale; - updateSpaceBarForLocale(mIsBlackSym); } boolean isCurrentlyInSpace() { @@ -637,9 +662,20 @@ public class LatinKeyboard extends Keyboard { } class LatinKey extends Keyboard.Key { - + + // functional normal state (with properties) + private final int[] KEY_STATE_FUNCTIONAL_NORMAL = { + android.R.attr.state_single + }; + + // functional pressed state (with properties) + private final int[] KEY_STATE_FUNCTIONAL_PRESSED = { + android.R.attr.state_single, + android.R.attr.state_pressed + }; + private boolean mShiftLockEnabled; - + public LatinKey(Resources res, Keyboard.Row parent, int x, int y, XmlResourceParser parser) { super(res, parent, x, y, parser); @@ -648,11 +684,17 @@ public class LatinKeyboard extends Keyboard { popupResId = 0; } } - - void enableShiftLock() { + + private void enableShiftLock() { mShiftLockEnabled = true; } + // sticky is used for shift key. If a key is not sticky and is modifier, + // the key will be treated as functional. + private boolean isFunctionalKey() { + return !sticky && modifier; + } + @Override public void onReleased(boolean inside) { if (!mShiftLockEnabled) { @@ -674,6 +716,18 @@ public class LatinKeyboard extends Keyboard { boolean isInsideSuper(int x, int y) { return super.isInside(x, y); } + + @Override + public int[] getCurrentDrawableState() { + if (isFunctionalKey()) { + if (pressed) { + return KEY_STATE_FUNCTIONAL_PRESSED; + } else { + return KEY_STATE_FUNCTIONAL_NORMAL; + } + } + return super.getCurrentDrawableState(); + } } /** @@ -709,7 +763,7 @@ public class LatinKeyboard extends Keyboard { mTextPaint.setTextSize(textSize); mTextPaint.setColor(R.color.latinkeyboard_transparent); mTextPaint.setTextAlign(Align.CENTER); - mTextPaint.setAlpha(255); + mTextPaint.setAlpha(OPACITY_FULLY_OPAQUE); mTextPaint.setAntiAlias(true); mAscent = (int) mTextPaint.ascent(); mMiddleX = (mWidth - mBackground.getIntrinsicWidth()) / 2; @@ -741,7 +795,7 @@ public class LatinKeyboard extends Keyboard { public void draw(Canvas canvas) { canvas.save(); if (mHitThreshold) { - mTextPaint.setColor(mRes.getColor(R.color.latinkeyboard_text_color)); + mTextPaint.setColor(mRes.getColor(R.color.latinkeyboard_feedback_language_text)); canvas.clipRect(0, 0, mWidth, mHeight); if (mCurrentLanguage == null) { mCurrentLanguage = getInputLanguage(mWidth, mTextPaint); diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java index 4007c2b55..c449b36e7 100644 --- a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java +++ b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java @@ -17,6 +17,7 @@ package com.android.inputmethod.latin; import android.content.Context; +import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -32,19 +33,20 @@ import android.inputmethodservice.Keyboard.Key; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; +import android.util.Log; import android.util.TypedValue; import android.view.GestureDetector; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; -import android.view.ViewConfiguration; import android.view.ViewGroup.LayoutParams; import android.widget.PopupWindow; import android.widget.TextView; +import java.util.ArrayList; import java.util.HashMap; -import java.util.List; +import java.util.LinkedList; import java.util.Map; /** @@ -60,7 +62,11 @@ import java.util.Map; * @attr ref R.styleable#LatinKeyboardBaseView_verticalCorrection * @attr ref R.styleable#LatinKeyboardBaseView_popupLayout */ -public class LatinKeyboardBaseView extends View implements View.OnClickListener { +public class LatinKeyboardBaseView extends View implements PointerTracker.UIProxy { + private static final String TAG = "LatinKeyboardBaseView"; + private static final boolean DEBUG = false; + + public static final int NOT_A_TOUCH_COORDINATE = -1; public interface OnKeyboardActionListener { @@ -139,116 +145,97 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener void swipeUp(); } - public static final int NOT_A_TOUCH_COORDINATE = -1; + // Timing constants + private static final int DELAY_BEFORE_PREVIEW = 0; + private static final int DELAY_AFTER_PREVIEW = 70; + private static final int REPEAT_INTERVAL = PointerTracker.REPEAT_INTERVAL; - private static final boolean DEBUG = false; - static final int NOT_A_KEY = -1; - private static final int[] KEY_DELETE = { Keyboard.KEYCODE_DELETE }; + // Miscellaneous constants + /* package */ static final int NOT_A_KEY = -1; private static final int[] LONG_PRESSABLE_STATE_SET = { android.R.attr.state_long_pressable }; - private Keyboard mKeyboard; - private int mCurrentKeyIndex = NOT_A_KEY; - private int mLabelTextSize; + // XML attribute private int mKeyTextSize; private int mKeyTextColor; - private float mShadowRadius; + private Typeface mKeyTextStyle = Typeface.DEFAULT; + private int mLabelTextSize; + private int mSymbolColorScheme = 0; private int mShadowColor; + private float mShadowRadius; + private Drawable mKeyBackground; private float mBackgroundDimAmount; + private float mVerticalCorrection; + private int mPreviewOffset; + private int mPreviewHeight; + private int mPopupLayout; + // Main keyboard + private Keyboard mKeyboard; + private Key[] mKeys; + + // Key preview popup + private final static boolean PREVIEW_CENTERED = false; private TextView mPreviewText; private PopupWindow mPreviewPopup; private int mPreviewTextSizeLarge; - private int mPreviewOffset; - private int mPreviewHeight; private int[] mOffsetInWindow; - - private PopupWindow mPopupKeyboard; - private View mMiniKeyboardContainer; - private LatinKeyboardBaseView mMiniKeyboard; - private boolean mMiniKeyboardOnScreen; - private View mPopupParent; - private int mMiniKeyboardOffsetX; - private int mMiniKeyboardOffsetY; - private Map mMiniKeyboardCache; - private int[] mWindowOffset; - private Key[] mKeys; - private Typeface mKeyTextStyle = Typeface.DEFAULT; - private int mSymbolColorScheme = 0; - - /** Listener for {@link OnKeyboardActionListener}. */ - private OnKeyboardActionListener mKeyboardActionListener; - - private static final int DELAY_BEFORE_PREVIEW = 0; - private static final int DELAY_AFTER_PREVIEW = 70; - private static final int DEBOUNCE_TIME = 70; - - private int mVerticalCorrection; - private ProximityKeyDetector mProximityKeyDetector = new ProximityKeyDetector(); - - private boolean mPreviewCentered = false; + private int mOldPreviewKeyIndex = NOT_A_KEY; private boolean mShowPreview = true; private boolean mShowTouchPoints = true; private int mPopupPreviewX; private int mPopupPreviewY; + private int mPopupPreviewOffsetX; + private int mPopupPreviewOffsetY; private int mWindowY; - private Paint mPaint; - private Rect mPadding; + // Popup mini keyboard + private PopupWindow mMiniKeyboardPopup; + private LatinKeyboardBaseView mMiniKeyboard; + private View mMiniKeyboardParent; + private Map mMiniKeyboardCache; + private int mMiniKeyboardOriginX; + private int mMiniKeyboardOriginY; + private long mMiniKeyboardPopupTime; + private int[] mWindowOffset; - private int mCurrentKey = NOT_A_KEY; - private int mStartX; - private int mStartY; + /** Listener for {@link OnKeyboardActionListener}. */ + private OnKeyboardActionListener mKeyboardActionListener; - private KeyDebouncer mDebouncer; + private final ArrayList mPointerTrackers = new ArrayList(); + private final PointerQueue mPointerQueue = new PointerQueue(); + private final float mDebounceHysteresis; - private GestureDetector mGestureDetector; - private int mPopupX; - private int mPopupY; - private int mPopupLayout; - private boolean mAbortKey; - private Key mInvalidatedKey; - private Rect mClipRegion = new Rect(0, 0, 0, 0); - private SwipeTracker mSwipeTracker = new SwipeTracker(); - private int mSwipeThreshold; - private boolean mDisambiguateSwipe; + protected KeyDetector mKeyDetector = new ProximityKeyDetector(); - // Variables for dealing with multiple pointers - private int mOldPointerCount = 1; - private int mOldPointerX; - private int mOldPointerY; - - private Drawable mKeyBackground; - - private static final int REPEAT_INTERVAL = 50; // ~20 keys per second - private static final int REPEAT_START_DELAY = 400; - private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout(); - - // For multi-tap - private int mLastSentIndex; - private int mTapCount; - private long mLastTapTime; - private boolean mInMultiTap; - private static final int MULTITAP_INTERVAL = 800; // milliseconds - private StringBuilder mPreviewLabel = new StringBuilder(1); + // Swipe gesture detector + private final GestureDetector mGestureDetector; + private final SwipeTracker mSwipeTracker = new SwipeTracker(); + private final int mSwipeThreshold; + private final boolean mDisambiguateSwipe; + // Drawing /** Whether the keyboard bitmap needs to be redrawn before it's blitted. **/ private boolean mDrawPending; /** The dirty region in the keyboard bitmap */ - private Rect mDirtyRect = new Rect(); + private final Rect mDirtyRect = new Rect(); /** The keyboard bitmap for faster updates */ private Bitmap mBuffer; /** Notes if the keyboard just changed, so that we could possibly reallocate the mBuffer. */ private boolean mKeyboardChanged; + private Key mInvalidatedKey; /** The canvas for the above mutable keyboard bitmap */ private Canvas mCanvas; + private final Paint mPaint; + private final Rect mPadding; + private final Rect mClipRegion = new Rect(0, 0, 0, 0); - UIHandler mHandler = new UIHandler(); + private final UIHandler mHandler = new UIHandler(); class UIHandler extends Handler { private static final int MSG_POPUP_PREVIEW = 1; private static final int MSG_DISMISS_PREVIEW = 2; private static final int MSG_REPEAT_KEY = 3; - private static final int MSG_LOGPRESS_KEY = 4; + private static final int MSG_LONGPRESS_KEY = 4; private boolean mInKeyRepeat; @@ -256,24 +243,34 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener public void handleMessage(Message msg) { switch (msg.what) { case MSG_POPUP_PREVIEW: - showKey(msg.arg1); + showKey(msg.arg1, (PointerTracker)msg.obj); break; case MSG_DISMISS_PREVIEW: mPreviewText.setVisibility(INVISIBLE); break; - case MSG_REPEAT_KEY: - repeatKey(msg.arg1); - startKeyRepeatTimer(REPEAT_INTERVAL, msg.arg1); + case MSG_REPEAT_KEY: { + final PointerTracker tracker = (PointerTracker)msg.obj; + tracker.repeatKey(msg.arg1); + startKeyRepeatTimer(REPEAT_INTERVAL, msg.arg1, tracker); break; - case MSG_LOGPRESS_KEY: - openPopupIfRequired(msg.arg1); + } + case MSG_LONGPRESS_KEY: { + final PointerTracker tracker = (PointerTracker)msg.obj; + openPopupIfRequired(msg.arg1, tracker); break; + } } } - public void popupPreview(int keyIndex, long delay) { + public void popupPreview(long delay, int keyIndex, PointerTracker tracker) { removeMessages(MSG_POPUP_PREVIEW); - sendMessageDelayed(obtainMessage(MSG_POPUP_PREVIEW, keyIndex, 0), delay); + if (mPreviewPopup.isShowing() && mPreviewText.getVisibility() == VISIBLE) { + // Show right away, if it's already visible and finger is moving around + showKey(keyIndex, tracker); + } else { + sendMessageDelayed(obtainMessage(MSG_POPUP_PREVIEW, keyIndex, 0, tracker), + delay); + } } public void cancelPopupPreview() { @@ -281,16 +278,18 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener } public void dismissPreview(long delay) { - sendMessageDelayed(obtainMessage(MSG_DISMISS_PREVIEW), delay); + if (mPreviewPopup.isShowing()) { + sendMessageDelayed(obtainMessage(MSG_DISMISS_PREVIEW), delay); + } } public void cancelDismissPreview() { removeMessages(MSG_DISMISS_PREVIEW); } - public void startKeyRepeatTimer(long delay, int keyIndex) { + public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) { mInKeyRepeat = true; - sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, keyIndex, 0), delay); + sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, keyIndex, 0, tracker), delay); } public void cancelKeyRepeatTimer() { @@ -302,13 +301,13 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener return mInKeyRepeat; } - public void startLongPressTimer(int keyIndex, long delay) { - removeMessages(MSG_LOGPRESS_KEY); - sendMessageDelayed(obtainMessage(MSG_LOGPRESS_KEY, keyIndex, 0), delay); + public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) { + removeMessages(MSG_LONGPRESS_KEY); + sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, keyIndex, 0, tracker), delay); } public void cancelLongPressTimer() { - removeMessages(MSG_LOGPRESS_KEY); + removeMessages(MSG_LONGPRESS_KEY); } public void cancelKeyTimers() { @@ -323,109 +322,38 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener } }; - static class KeyDebouncer { - private final Key[] mKeys; - private final int mKeyDebounceThresholdSquared; + static class PointerQueue { + private LinkedList mQueue = new LinkedList(); - // for move de-bouncing - private int mLastCodeX; - private int mLastCodeY; - private int mLastX; - private int mLastY; - - // for time de-bouncing - private int mLastKey; - private long mLastKeyTime; - private long mLastMoveTime; - private long mCurrentKeyTime; - - KeyDebouncer(Key[] keys, float hysteresisPixel) { - if (keys == null || hysteresisPixel < 1.0f) - throw new IllegalArgumentException(); - mKeys = keys; - mKeyDebounceThresholdSquared = (int)(hysteresisPixel * hysteresisPixel); + public void add(PointerTracker tracker) { + mQueue.add(tracker); } - public int getLastCodeX() { - return mLastCodeX; + public int lastIndexOf(PointerTracker tracker) { + LinkedList queue = mQueue; + for (int index = queue.size() - 1; index >= 0; index--) { + PointerTracker t = queue.get(index); + if (t == tracker) + return index; + } + return -1; } - public int getLastCodeY() { - return mLastCodeY; - } - - public int getLastX() { - return mLastX; - } - - public int getLastY() { - return mLastY; - } - - public int getLastKey() { - return mLastKey; - } - - public void startMoveDebouncing(int x, int y) { - mLastCodeX = x; - mLastCodeY = y; - } - - public void updateMoveDebouncing(int x, int y) { - mLastX = x; - mLastY = y; - } - - public void resetMoveDebouncing() { - mLastCodeX = mLastX; - mLastCodeY = mLastY; - } - - public boolean isMinorMoveBounce(int x, int y, int newKey, int curKey) { - if (newKey == curKey) { - return true; - } else if (curKey >= 0 && curKey < mKeys.length) { - return getSquareDistanceToKeyEdge(x, y, mKeys[curKey]) - < mKeyDebounceThresholdSquared; - } else { - return false; + public void releasePointersOlderThan(PointerTracker tracker, long eventTime) { + LinkedList queue = mQueue; + int oldestPos = 0; + for (PointerTracker t = queue.get(oldestPos); t != tracker; t = queue.get(oldestPos)) { + if (t.isModifier()) { + oldestPos++; + } else { + t.onUpEvent(t.getLastX(), t.getLastY(), eventTime); + queue.remove(oldestPos); + } } } - private static int getSquareDistanceToKeyEdge(int x, int y, Key key) { - final int left = key.x; - final int right = key.x + key.width; - final int top = key.y; - final int bottom = key.y + key.height; - final int edgeX = x < left ? left : (x > right ? right : x); - final int edgeY = y < top ? top : (y > bottom ? bottom : y); - final int dx = x - edgeX; - final int dy = y - edgeY; - return dx * dx + dy * dy; - } - - public void startTimeDebouncing(long eventTime) { - mLastKey = NOT_A_KEY; - mLastKeyTime = 0; - mCurrentKeyTime = 0; - mLastMoveTime = eventTime; - } - - public void updateTimeDebouncing(long eventTime) { - mCurrentKeyTime += eventTime - mLastMoveTime; - mLastMoveTime = eventTime; - } - - public void resetTimeDebouncing(long eventTime, int currentKey) { - mLastKey = currentKey; - mLastKeyTime = mCurrentKeyTime + eventTime - mLastMoveTime; - mCurrentKeyTime = 0; - mLastMoveTime = eventTime; - } - - public boolean isMinorTimeBounce() { - return mCurrentKeyTime < mLastKeyTime && mCurrentKeyTime < DEBOUNCE_TIME - && mLastKey != NOT_A_KEY; + public void remove(PointerTracker tracker) { + mQueue.remove(tracker); } } @@ -516,15 +444,11 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener } else { mShowPreview = false; } - mPreviewPopup.setTouchable(false); + mMiniKeyboardParent = this; - mPopupKeyboard = new PopupWindow(context); - mPopupKeyboard.setBackgroundDrawable(null); - //mPopupKeyboard.setClippingEnabled(false); - - mPopupParent = this; - //mPredicting = true; + mMiniKeyboardPopup = new PopupWindow(context); + mMiniKeyboardPopup.setBackgroundDrawable(null); mPaint = new Paint(); mPaint.setAntiAlias(true); @@ -536,19 +460,17 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener mMiniKeyboardCache = new HashMap(); mKeyBackground.getPadding(mPadding); - mSwipeThreshold = (int) (500 * getResources().getDisplayMetrics().density); + final Resources res = getResources(); + mSwipeThreshold = (int) (500 * res.getDisplayMetrics().density); // TODO: Refer frameworks/base/core/res/res/values/config.xml - mDisambiguateSwipe = getResources().getBoolean(R.bool.config_swipeDisambiguation); - resetMultiTap(); - initGestureDetector(); - } + mDisambiguateSwipe = res.getBoolean(R.bool.config_swipeDisambiguation); + mDebounceHysteresis = res.getDimension(R.dimen.key_debounce_hysteresis_distance); - private void initGestureDetector() { GestureDetector.SimpleOnGestureListener listener = new GestureDetector.SimpleOnGestureListener() { @Override - public boolean onFling(MotionEvent me1, MotionEvent me2, - float velocityX, float velocityY) { + public boolean onFling(MotionEvent me1, MotionEvent me2, float velocityX, + float velocityY) { final float absX = Math.abs(velocityX); final float absY = Math.abs(velocityY); float deltaX = me2.getX() - me1.getX(); @@ -590,6 +512,9 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener public void setOnKeyboardActionListener(OnKeyboardActionListener listener) { mKeyboardActionListener = listener; + for (PointerTracker tracker : mPointerTrackers) { + tracker.setOnKeyboardActionListener(listener); + } } /** @@ -609,26 +534,24 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener */ public void setKeyboard(Keyboard keyboard) { if (mKeyboard != null) { - showPreview(NOT_A_KEY); + dismissKeyPreview(); } // Remove any pending messages, except dismissing preview mHandler.cancelKeyTimers(); mHandler.cancelPopupPreview(); mKeyboard = keyboard; - LatinImeLogger.onSetKeyboard(mKeyboard); - List keys = mKeyboard.getKeys(); - mKeys = keys.toArray(new Key[keys.size()]); - mProximityKeyDetector.setKeyboard(keyboard, mKeys); + LatinImeLogger.onSetKeyboard(keyboard); + mKeys = mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), + -getPaddingTop() + mVerticalCorrection); + for (PointerTracker tracker : mPointerTrackers) { + tracker.setKeyboard(mKeys, mDebounceHysteresis); + } requestLayout(); // Hint to reallocate the buffer if the size changed mKeyboardChanged = true; invalidateAllKeys(); computeProximityThreshold(keyboard); mMiniKeyboardCache.clear(); - // Not really necessary to do every time, but will free up views - // Switching to a different keyboard should abort any pending keys so that the key up - // doesn't get delivered to the old or new keyboard - mAbortKey = true; // Until the next ACTION_DOWN } /** @@ -691,16 +614,13 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener return mSymbolColorScheme; } - public void setVerticalCorrection(int verticalOffset) { - } - public void setPopupParent(View v) { - mPopupParent = v; + mMiniKeyboardParent = v; } public void setPopupOffset(int x, int y) { - mMiniKeyboardOffsetX = x; - mMiniKeyboardOffsetY = y; + mPopupPreviewOffsetX = x; + mPopupPreviewOffsetY = y; if (mPreviewPopup.isShowing()) { mPreviewPopup.dismiss(); } @@ -713,22 +633,14 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener * @param enabled whether or not the proximity correction is enabled */ public void setProximityCorrectionEnabled(boolean enabled) { - mProximityKeyDetector.setProximityCorrectionEnabled(enabled); + mKeyDetector.setProximityCorrectionEnabled(enabled); } /** * Returns true if proximity correction is enabled. */ public boolean isProximityCorrectionEnabled() { - return mProximityKeyDetector.isProximityCorrectionEnabled(); - } - - /** - * Popup keyboard close button clicked. - * @hide - */ - public void onClick(View v) { - dismissPopupKeyboard(); + return mKeyDetector.isProximityCorrectionEnabled(); } protected CharSequence adjustCase(CharSequence label) { @@ -772,11 +684,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener dimensionSum += Math.min(key.width, key.height) + key.gap; } if (dimensionSum < 0 || length == 0) return; - mProximityKeyDetector.setProximityThreshold((int) (dimensionSum * 1.4f / length)); - - final float hysteresisPixel = getContext().getResources() - .getDimension(R.dimen.key_debounce_hysteresis_distance); - mDebouncer = new KeyDebouncer(keys, hysteresisPixel); + mKeyDetector.setProximityThreshold((int) (dimensionSum * 1.4f / length)); } @Override @@ -889,23 +797,27 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener } mInvalidatedKey = null; // Overlay a dark rectangle to dim the keyboard - if (mMiniKeyboardOnScreen) { + if (mMiniKeyboard != null) { paint.setColor((int) (mBackgroundDimAmount * 0xFF) << 24); canvas.drawRect(0, 0, getWidth(), getHeight(), paint); } if (DEBUG) { if (mShowTouchPoints) { - int lastX = mDebouncer.getLastX(); - int lastY = mDebouncer.getLastY(); - paint.setAlpha(128); - paint.setColor(0xFFFF0000); - canvas.drawCircle(mStartX, mStartY, 3, paint); - canvas.drawLine(mStartX, mStartY, lastX, lastY, paint); - paint.setColor(0xFF0000FF); - canvas.drawCircle(lastX, lastY, 3, paint); - paint.setColor(0xFF00FF00); - canvas.drawCircle((mStartX + lastX) / 2, (mStartY + lastY) / 2, 2, paint); + for (PointerTracker tracker : mPointerTrackers) { + int startX = tracker.getStartX(); + int startY = tracker.getStartY(); + int lastX = tracker.getLastX(); + int lastY = tracker.getLastY(); + paint.setAlpha(128); + paint.setColor(0xFFFF0000); + canvas.drawCircle(startX, startY, 3, paint); + canvas.drawLine(startX, startY, lastX, lastY, paint); + paint.setColor(0xFF0000FF); + canvas.drawCircle(lastX, lastY, 3, paint); + paint.setColor(0xFF00FF00); + canvas.drawCircle((startX + lastX) / 2, (startY + lastY) / 2, 2, paint); + } } } @@ -913,105 +825,39 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener mDirtyRect.setEmpty(); } - - private void detectAndSendKey(int index, int x, int y, long eventTime) { - if (index != NOT_A_KEY && index < mKeys.length) { - final Key key = mKeys[index]; - if (key.text != null) { - mKeyboardActionListener.onText(key.text); - mKeyboardActionListener.onRelease(NOT_A_KEY); - } else { - int code = key.codes[0]; - //TextEntryState.keyPressedAt(key, x, y); - int[] codes = mProximityKeyDetector.newCodeArray(); - mProximityKeyDetector.getKeyIndexAndNearbyCodes(x, y, codes); - // Multi-tap - if (mInMultiTap) { - if (mTapCount != -1) { - mKeyboardActionListener.onKey(Keyboard.KEYCODE_DELETE, KEY_DELETE, x, y); - } else { - mTapCount = 0; - } - code = key.codes[mTapCount]; - } - /* - * Swap the first and second values in the codes array if the primary code is not - * the first value but the second value in the array. This happens when key - * debouncing is in effect. - */ - if (codes.length >= 2 && codes[0] != code && codes[1] == code) { - codes[1] = codes[0]; - codes[0] = code; - } - mKeyboardActionListener.onKey(code, codes, x, y); - mKeyboardActionListener.onRelease(code); - } - mLastSentIndex = index; - mLastTapTime = eventTime; - } + // TODO: clean up this method. + private void dismissKeyPreview() { + for (PointerTracker tracker : mPointerTrackers) + tracker.updateKey(NOT_A_KEY); + showPreview(NOT_A_KEY, null); } - /** - * Handle multi-tap keys by producing the key label for the current multi-tap state. - */ - private CharSequence getPreviewText(Key key) { - if (mInMultiTap) { - // Multi-tap - mPreviewLabel.setLength(0); - mPreviewLabel.append((char) key.codes[mTapCount < 0 ? 0 : mTapCount]); - return adjustCase(mPreviewLabel); - } else { - return adjustCase(key.label); - } - } - - private void showPreview(int keyIndex) { - int oldKeyIndex = mCurrentKeyIndex; - final PopupWindow previewPopup = mPreviewPopup; - - mCurrentKeyIndex = keyIndex; - // Release the old key and press the new key - final Key[] keys = mKeys; - if (oldKeyIndex != mCurrentKeyIndex) { - if (oldKeyIndex != NOT_A_KEY && keys.length > oldKeyIndex) { - keys[oldKeyIndex].onReleased(mCurrentKeyIndex == NOT_A_KEY); - invalidateKey(oldKeyIndex); - } - if (mCurrentKeyIndex != NOT_A_KEY && keys.length > mCurrentKeyIndex) { - keys[mCurrentKeyIndex].onPressed(); - invalidateKey(mCurrentKeyIndex); - } - } + public void showPreview(int keyIndex, PointerTracker tracker) { + int oldKeyIndex = mOldPreviewKeyIndex; + mOldPreviewKeyIndex = keyIndex; // If key changed and preview is on ... - if (oldKeyIndex != mCurrentKeyIndex && mShowPreview) { + if (oldKeyIndex != keyIndex && mShowPreview) { if (keyIndex == NOT_A_KEY) { mHandler.cancelPopupPreview(); - if (previewPopup.isShowing()) { - mHandler.dismissPreview(DELAY_AFTER_PREVIEW); - } - } else { - if (previewPopup.isShowing() && mPreviewText.getVisibility() == VISIBLE) { - // Show right away, if it's already visible and finger is moving around - showKey(keyIndex); - } else { - mHandler.popupPreview(keyIndex, DELAY_BEFORE_PREVIEW); - } + mHandler.dismissPreview(DELAY_AFTER_PREVIEW); + } else if (tracker != null) { + mHandler.popupPreview(DELAY_BEFORE_PREVIEW, keyIndex, tracker); } } } - private void showKey(final int keyIndex) { + private void showKey(final int keyIndex, PointerTracker tracker) { + Key key = tracker.getKey(keyIndex); + if (key == null) + return; final PopupWindow previewPopup = mPreviewPopup; - final Key[] keys = mKeys; - if (keyIndex < 0 || keyIndex >= mKeys.length) return; - Key key = keys[keyIndex]; if (key.icon != null) { mPreviewText.setCompoundDrawables(null, null, null, key.iconPreview != null ? key.iconPreview : key.icon); mPreviewText.setText(null); } else { mPreviewText.setCompoundDrawables(null, null, null, null); - mPreviewText.setText(getPreviewText(key)); + mPreviewText.setText(adjustCase(tracker.getPreviewText(key))); if (key.label.length() > 1 && key.codes.length < 2) { mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mKeyTextSize); mPreviewText.setTypeface(Typeface.DEFAULT_BOLD); @@ -1030,20 +876,20 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener lp.width = popupWidth; lp.height = popupHeight; } - if (!mPreviewCentered) { - mPopupPreviewX = key.x - mPreviewText.getPaddingLeft() + getPaddingLeft(); - mPopupPreviewY = key.y - popupHeight + mPreviewOffset; - } else { + if (PREVIEW_CENTERED) { // TODO: Fix this if centering is brought back mPopupPreviewX = 160 - mPreviewText.getMeasuredWidth() / 2; mPopupPreviewY = - mPreviewText.getMeasuredHeight(); + } else { + mPopupPreviewX = key.x - mPreviewText.getPaddingLeft() + getPaddingLeft(); + mPopupPreviewY = key.y - popupHeight + mPreviewOffset; } mHandler.cancelDismissPreview(); if (mOffsetInWindow == null) { mOffsetInWindow = new int[2]; getLocationInWindow(mOffsetInWindow); - mOffsetInWindow[0] += mMiniKeyboardOffsetX; // Offset may be zero - mOffsetInWindow[1] += mMiniKeyboardOffsetY; // Offset may be zero + mOffsetInWindow[0] += mPopupPreviewOffsetX; // Offset may be zero + mOffsetInWindow[1] += mPopupPreviewOffsetY; // Offset may be zero int[] mWindowLocation = new int[2]; getLocationOnScreen(mWindowLocation); mWindowY = mWindowLocation[1]; @@ -1072,7 +918,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener } else { previewPopup.setWidth(popupWidth); previewPopup.setHeight(popupHeight); - previewPopup.showAtLocation(mPopupParent, Gravity.NO_GRAVITY, + previewPopup.showAtLocation(mMiniKeyboardParent, Gravity.NO_GRAVITY, mPopupPreviewX, mPopupPreviewY); } mPreviewText.setVisibility(VISIBLE); @@ -1082,7 +928,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener * Requests a redraw of the entire keyboard. Calling {@link #invalidate} is not sufficient * because the keyboard renders the keys to an off-screen buffer and an invalidate() only * draws the cached buffer. - * @see #invalidateKey(int) + * @see #invalidateKey(Key) */ public void invalidateAllKeys() { mDirtyRect.union(0, 0, getWidth(), getHeight()); @@ -1094,15 +940,12 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener * Invalidates a key so that it will be redrawn on the next repaint. Use this method if only * one key is changing it's content. Any changes that affect the position or size of the key * may not be honored. - * @param keyIndex the index of the key in the attached {@link Keyboard}. + * @param key key in the attached {@link Keyboard}. * @see #invalidateAllKeys */ - public void invalidateKey(int keyIndex) { - if (mKeys == null) return; - if (keyIndex < 0 || keyIndex >= mKeys.length) { + public void invalidateKey(Key key) { + if (key == null) return; - } - final Key key = mKeys[keyIndex]; mInvalidatedKey = key; mDirtyRect.union(key.x + getPaddingLeft(), key.y + getPaddingTop(), key.x + key.width + getPaddingLeft(), key.y + key.height + getPaddingTop()); @@ -1111,24 +954,75 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener key.x + key.width + getPaddingLeft(), key.y + key.height + getPaddingTop()); } - private boolean openPopupIfRequired(int keyIndex) { + private boolean openPopupIfRequired(int keyIndex, PointerTracker tracker) { // Check if we have a popup layout specified first. if (mPopupLayout == 0) { return false; } - if (keyIndex < 0 || keyIndex >= mKeys.length) { - return false; - } - Key popupKey = mKeys[keyIndex]; + Key popupKey = tracker.getKey(keyIndex); + if (popupKey == null) + return false; boolean result = onLongPress(popupKey); if (result) { - mAbortKey = true; - showPreview(NOT_A_KEY); + dismissKeyPreview(); + tracker.setAlreadyProcessed(); } return result; } + private View inflateMiniKeyboardContainer(Key popupKey) { + int popupKeyboardId = popupKey.popupResId; + LayoutInflater inflater = (LayoutInflater)getContext().getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + View container = inflater.inflate(mPopupLayout, null); + if (container == null) + throw new NullPointerException(); + + mMiniKeyboard = (LatinKeyboardBaseView)container.findViewById(R.id.LatinKeyboardBaseView); + mMiniKeyboard.setOnKeyboardActionListener(new OnKeyboardActionListener() { + public void onKey(int primaryCode, int[] keyCodes, int x, int y) { + mKeyboardActionListener.onKey(primaryCode, keyCodes, x, y); + dismissPopupKeyboard(); + } + + public void onText(CharSequence text) { + mKeyboardActionListener.onText(text); + dismissPopupKeyboard(); + } + + public void swipeLeft() { + } + public void swipeRight() { + } + public void swipeUp() { + } + public void swipeDown() { + } + public void onPress(int primaryCode) { + mKeyboardActionListener.onPress(primaryCode); + } + public void onRelease(int primaryCode) { + mKeyboardActionListener.onRelease(primaryCode); + } + }); + + Keyboard keyboard; + if (popupKey.popupCharacters != null) { + keyboard = new Keyboard(getContext(), popupKeyboardId, popupKey.popupCharacters, + -1, getPaddingLeft() + getPaddingRight()); + } else { + keyboard = new Keyboard(getContext(), popupKeyboardId); + } + mMiniKeyboard.setKeyboard(keyboard); + mMiniKeyboard.setPopupParent(this); + + container.measure(MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), + MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST)); + + return container; + } + /** * Called when a key is long pressed. By default this will open any popup keyboard associated * with this key through the attributes popupLayout and popupCharacters. @@ -1137,123 +1031,99 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener * method on the base class if the subclass doesn't wish to handle the call. */ protected boolean onLongPress(Key popupKey) { - int popupKeyboardId = popupKey.popupResId; + // TODO if popupKey.popupCharacters has only one letter, send it as key without opening + // mini keyboard. - if (popupKeyboardId != 0) { - mMiniKeyboardContainer = mMiniKeyboardCache.get(popupKey); - if (mMiniKeyboardContainer == null) { - LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - mMiniKeyboardContainer = inflater.inflate(mPopupLayout, null); - mMiniKeyboard = (LatinKeyboardBaseView) mMiniKeyboardContainer.findViewById( - R.id.LatinKeyboardBaseView); - View closeButton = mMiniKeyboardContainer.findViewById( - R.id.closeButton); - if (closeButton != null) closeButton.setOnClickListener(this); - mMiniKeyboard.setOnKeyboardActionListener(new OnKeyboardActionListener() { - public void onKey(int primaryCode, int[] keyCodes, int x, int y) { - mKeyboardActionListener.onKey(primaryCode, keyCodes, x, y); - dismissPopupKeyboard(); - } + if (popupKey.popupResId == 0) + return false; - public void onText(CharSequence text) { - mKeyboardActionListener.onText(text); - dismissPopupKeyboard(); - } - - public void swipeLeft() { } - public void swipeRight() { } - public void swipeUp() { } - public void swipeDown() { } - public void onPress(int primaryCode) { - mKeyboardActionListener.onPress(primaryCode); - } - public void onRelease(int primaryCode) { - mKeyboardActionListener.onRelease(primaryCode); - } - }); - //mInputView.setSuggest(mSuggest); - Keyboard keyboard; - if (popupKey.popupCharacters != null) { - keyboard = new Keyboard(getContext(), popupKeyboardId, - popupKey.popupCharacters, -1, getPaddingLeft() + getPaddingRight()); - } else { - keyboard = new Keyboard(getContext(), popupKeyboardId); - } - mMiniKeyboard.setKeyboard(keyboard); - mMiniKeyboard.setPopupParent(this); - mMiniKeyboardContainer.measure( - MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST), - MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST)); - - mMiniKeyboardCache.put(popupKey, mMiniKeyboardContainer); - } else { - mMiniKeyboard = (LatinKeyboardBaseView) mMiniKeyboardContainer.findViewById( - R.id.LatinKeyboardBaseView); - } - if (mWindowOffset == null) { - mWindowOffset = new int[2]; - getLocationInWindow(mWindowOffset); - } - mPopupX = popupKey.x + getPaddingLeft(); - mPopupY = popupKey.y + getPaddingTop(); - mPopupX = mPopupX + popupKey.width - mMiniKeyboardContainer.getMeasuredWidth(); - mPopupY = mPopupY - mMiniKeyboardContainer.getMeasuredHeight(); - final int x = mPopupX + mMiniKeyboardContainer.getPaddingRight() + mWindowOffset[0]; - final int y = mPopupY + mMiniKeyboardContainer.getPaddingBottom() + mWindowOffset[1]; - mMiniKeyboard.setPopupOffset(x < 0 ? 0 : x, y); - mMiniKeyboard.setShifted(isShifted()); - mPopupKeyboard.setContentView(mMiniKeyboardContainer); - mPopupKeyboard.setWidth(mMiniKeyboardContainer.getMeasuredWidth()); - mPopupKeyboard.setHeight(mMiniKeyboardContainer.getMeasuredHeight()); - mPopupKeyboard.showAtLocation(this, Gravity.NO_GRAVITY, x, y); - mMiniKeyboardOnScreen = true; - //mMiniKeyboard.onTouchEvent(getTranslatedEvent(me)); - invalidateAllKeys(); - return true; + View container = mMiniKeyboardCache.get(popupKey); + if (container == null) { + container = inflateMiniKeyboardContainer(popupKey); + mMiniKeyboardCache.put(popupKey, container); } - return false; + mMiniKeyboard = (LatinKeyboardBaseView)container.findViewById(R.id.LatinKeyboardBaseView); + if (mWindowOffset == null) { + mWindowOffset = new int[2]; + getLocationInWindow(mWindowOffset); + } + int popupX = popupKey.x + popupKey.width + getPaddingLeft(); + int popupY = popupKey.y + getPaddingTop(); + popupX -= container.getMeasuredWidth(); + popupY -= container.getMeasuredHeight(); + popupX += mWindowOffset[0]; + popupY += mWindowOffset[1]; + final int x = popupX + container.getPaddingRight(); + final int y = popupY + container.getPaddingBottom(); + mMiniKeyboardOriginX = (x < 0 ? 0 : x) + container.getPaddingLeft(); + mMiniKeyboardOriginY = y + container.getPaddingTop(); + mMiniKeyboard.setPopupOffset((x < 0) ? 0 : x, y); + mMiniKeyboard.setShifted(isShifted()); + mMiniKeyboard.setPreviewEnabled(isPreviewEnabled()); + mMiniKeyboardPopup.setContentView(container); + mMiniKeyboardPopup.setWidth(container.getMeasuredWidth()); + mMiniKeyboardPopup.setHeight(container.getMeasuredHeight()); + mMiniKeyboardPopup.showAtLocation(this, Gravity.NO_GRAVITY, x, y); + + // Inject down event on the key to mini keyboard. + long eventTime = System.currentTimeMillis(); + mMiniKeyboardPopupTime = eventTime; + MotionEvent downEvent = generateMiniKeyboardMotionEvent(MotionEvent.ACTION_DOWN, popupKey.x + + popupKey.width / 2, popupKey.y + popupKey.height / 2, eventTime); + mMiniKeyboard.onTouchEvent(downEvent); + downEvent.recycle(); + + invalidateAllKeys(); + return true; } - private int getTouchX(float x) { - return (int)x - getPaddingLeft(); + private MotionEvent generateMiniKeyboardMotionEvent(int action, int x, int y, long eventTime) { + return MotionEvent.obtain(mMiniKeyboardPopupTime, eventTime, action, + x - mMiniKeyboardOriginX, y - mMiniKeyboardOriginY, 0); } - private int getTouchY(float y) { - return (int)y + mVerticalCorrection - getPaddingTop(); + private PointerTracker getPointerTracker(final int id) { + final ArrayList pointers = mPointerTrackers; + final Key[] keys = mKeys; + final OnKeyboardActionListener listener = mKeyboardActionListener; + + // Create pointer trackers until we can get 'id+1'-th tracker, if needed. + for (int i = pointers.size(); i <= id; i++) { + final PointerTracker tracker = + new PointerTracker(i, mHandler, mKeyDetector, this); + if (keys != null) + tracker.setKeyboard(keys, mDebounceHysteresis); + if (listener != null) + tracker.setOnKeyboardActionListener(listener); + pointers.add(tracker); + } + + return pointers.get(id); } @Override public boolean onTouchEvent(MotionEvent me) { - // Convert multi-pointer up/down events to single up/down events to - // deal with the typical multi-pointer behavior of two-thumb typing final int pointerCount = me.getPointerCount(); - final int action = me.getAction(); + final int action = me.getActionMasked(); final long eventTime = me.getEventTime(); - if (pointerCount > 1 && mOldPointerCount > 1) { - // Don't do anything when 2 or more pointers are down and moving. - return true; - } - // Track the last few movements to look for spurious swipes. mSwipeTracker.addMovement(me); - // Ignore all motion events until a DOWN. - if (mAbortKey - && action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_CANCEL) { - return true; - } - - if (mGestureDetector.onTouchEvent(me)) { - showPreview(NOT_A_KEY); + // We must disable gesture detector while mini-keyboard is on the screen. + if (mMiniKeyboard == null && mGestureDetector.onTouchEvent(me)) { + dismissKeyPreview(); mHandler.cancelKeyTimers(); return true; } // Needs to be called after the gesture detector gets a turn, as it may have // displayed the mini keyboard - if (mMiniKeyboardOnScreen && action != MotionEvent.ACTION_CANCEL) { + if (mMiniKeyboard != null) { + MotionEvent translated = generateMiniKeyboardMotionEvent(action, (int)me.getX(), + (int)me.getY(), eventTime); + mMiniKeyboard.onTouchEvent(translated); + translated.recycle(); return true; } @@ -1268,145 +1138,58 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener // Up event will pass through. } - int touchX = getTouchX(me.getX()); - int touchY = getTouchY(me.getY()); - if (pointerCount != mOldPointerCount) { - if (pointerCount == 1) { - // Send a down event for the latest pointer - onDownEvent(touchX, touchY, eventTime); - // If it's an up action, then deliver the up as well. - if (action == MotionEvent.ACTION_UP) { - onUpEvent(touchX, touchY, eventTime); - } - } else { - // Send an up event for the last pointer - onUpEvent(mOldPointerX, mOldPointerY, eventTime); + if (action == MotionEvent.ACTION_MOVE) { + for (int index = 0; index < pointerCount; index++) { + int x = (int)me.getX(index); + int y = (int)me.getY(index); + int id = me.getPointerId(index); + PointerTracker tracker = getPointerTracker(id); + tracker.onMoveEvent(x, y, eventTime); } - mOldPointerCount = pointerCount; - return true; } else { - if (pointerCount == 1) { - onModifiedTouchEvent(action, touchX, touchY, eventTime); - mOldPointerX = touchX; - mOldPointerY = touchY; - return true; - } - } - - return false; - } - - private void onModifiedTouchEvent(int action, int touchX, int touchY, long eventTime) { - switch (action) { + int index = me.getActionIndex(); + int x = (int)me.getX(index); + int y = (int)me.getY(index); + int id = me.getPointerId(index); + PointerTracker tracker = getPointerTracker(id); + switch (action) { case MotionEvent.ACTION_DOWN: - onDownEvent(touchX, touchY, eventTime); - break; - case MotionEvent.ACTION_MOVE: - onMoveEvent(touchX, touchY, eventTime); + case MotionEvent.ACTION_POINTER_DOWN: + onDownEvent(tracker, x, y, eventTime); break; case MotionEvent.ACTION_UP: - onUpEvent(touchX, touchY, eventTime); + case MotionEvent.ACTION_POINTER_UP: + onUpEvent(tracker, x, y, eventTime); break; case MotionEvent.ACTION_CANCEL: - onCancelEvent(touchX, touchY, eventTime); + onCancelEvent(tracker, x, y, eventTime); break; - } - } - - private void onDownEvent(int touchX, int touchY, long eventTime) { - int keyIndex = mProximityKeyDetector.getKeyIndexAndNearbyCodes(touchX, touchY, null); - mAbortKey = false; - mCurrentKey = keyIndex; - mStartX = touchX; - mStartY = touchY; - mDebouncer.startMoveDebouncing(touchX, touchY); - mDebouncer.startTimeDebouncing(eventTime); - checkMultiTap(eventTime, keyIndex); - mKeyboardActionListener.onPress(keyIndex != NOT_A_KEY ? mKeys[keyIndex].codes[0] : 0); - if (keyIndex >= 0 && mKeys[keyIndex].repeatable) { - repeatKey(keyIndex); - mHandler.startKeyRepeatTimer(REPEAT_START_DELAY, keyIndex); - // Delivering the key could have caused an abort - if (mAbortKey) { - mHandler.cancelKeyRepeatTimer(); - return; } } - if (keyIndex != NOT_A_KEY) { - mHandler.startLongPressTimer(keyIndex, LONGPRESS_TIMEOUT); - } - showPreview(keyIndex); - mDebouncer.updateMoveDebouncing(touchX, touchY); + + return true; } - private void onMoveEvent(int touchX, int touchY, long eventTime) { - int keyIndex = mProximityKeyDetector.getKeyIndexAndNearbyCodes(touchX, touchY, null); - if (keyIndex != NOT_A_KEY) { - if (mCurrentKey == NOT_A_KEY) { - mDebouncer.updateTimeDebouncing(eventTime); - mCurrentKey = keyIndex; - mHandler.startLongPressTimer(keyIndex, LONGPRESS_TIMEOUT); - } else if (mDebouncer.isMinorMoveBounce(touchX, touchY, keyIndex, mCurrentKey)) { - mDebouncer.updateTimeDebouncing(eventTime); - } else { - resetMultiTap(); - mDebouncer.resetTimeDebouncing(eventTime, mCurrentKey); - mDebouncer.resetMoveDebouncing(); - mCurrentKey = keyIndex; - mHandler.startLongPressTimer(keyIndex, LONGPRESS_TIMEOUT); - } + private void onDownEvent(PointerTracker tracker, int x, int y, long eventTime) { + tracker.onDownEvent(x, y, eventTime); + mPointerQueue.add(tracker); + } + + private void onUpEvent(PointerTracker tracker, int x, int y, long eventTime) { + int index = mPointerQueue.lastIndexOf(tracker); + if (index >= 0) { + mPointerQueue.releasePointersOlderThan(tracker, eventTime); } else { - mHandler.cancelLongPressTimer(); + Log.w(TAG, "onUpEvent: corresponding down event not found for pointer " + + tracker.mPointerId); } - /* - * While time debouncing is in effect, mCurrentKey holds the new key and mDebouncer - * holds the last key. At ACTION_UP event if time debouncing will be in effect - * eventually, the last key should be sent as the result. In such case mCurrentKey - * should not be showed as popup preview. - */ - showPreview(mDebouncer.isMinorTimeBounce() ? mDebouncer.getLastKey() : mCurrentKey); - mDebouncer.updateMoveDebouncing(touchX, touchY); + tracker.onUpEvent(x, y, eventTime); + mPointerQueue.remove(tracker); } - private void onUpEvent(int touchX, int touchY, long eventTime) { - int keyIndex = mProximityKeyDetector.getKeyIndexAndNearbyCodes(touchX, touchY, null); - boolean wasInKeyRepeat = mHandler.isInKeyRepeat(); - mHandler.cancelKeyTimers(); - mHandler.cancelPopupPreview(); - if (mDebouncer.isMinorMoveBounce(touchX, touchY, keyIndex, mCurrentKey)) { - mDebouncer.updateTimeDebouncing(eventTime); - } else { - resetMultiTap(); - mDebouncer.resetTimeDebouncing(eventTime, mCurrentKey); - mCurrentKey = keyIndex; - } - if (mDebouncer.isMinorTimeBounce()) { - mCurrentKey = mDebouncer.getLastKey(); - touchX = mDebouncer.getLastCodeX(); - touchY = mDebouncer.getLastCodeY(); - } - showPreview(NOT_A_KEY); - // If we're not on a repeating key (which sends on a DOWN event) - if (!wasInKeyRepeat && !mMiniKeyboardOnScreen && !mAbortKey) { - detectAndSendKey(mCurrentKey, touchX, touchY, eventTime); - } - invalidateKey(keyIndex); - } - - private void onCancelEvent(int touchX, int touchY, long eventTime) { - mHandler.cancelKeyTimers(); - mHandler.cancelPopupPreview(); - dismissPopupKeyboard(); - mAbortKey = true; - showPreview(NOT_A_KEY); - invalidateKey(mCurrentKey); - } - - private void repeatKey(int keyIndex) { - Key key = mKeys[keyIndex]; - // While key is repeating, because there is no need to handle multi-tap key, we can pass - // -1 as eventTime argument. - detectAndSendKey(keyIndex, key.x, key.y, -1); + private void onCancelEvent(PointerTracker tracker, int x, int y, long eventTime) { + tracker.onCancelEvent(x, y, eventTime); + mPointerQueue.remove(tracker); } protected void swipeRight() { @@ -1444,44 +1227,20 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener } private void dismissPopupKeyboard() { - if (mPopupKeyboard.isShowing()) { - mPopupKeyboard.dismiss(); - mMiniKeyboardOnScreen = false; + if (mMiniKeyboardPopup.isShowing()) { + mMiniKeyboardPopup.dismiss(); + mMiniKeyboard = null; + mMiniKeyboardOriginX = 0; + mMiniKeyboardOriginY = 0; invalidateAllKeys(); } } public boolean handleBack() { - if (mPopupKeyboard.isShowing()) { + if (mMiniKeyboardPopup.isShowing()) { dismissPopupKeyboard(); return true; } return false; } - - private void resetMultiTap() { - mLastSentIndex = NOT_A_KEY; - mTapCount = 0; - mLastTapTime = -1; - mInMultiTap = false; - } - - private void checkMultiTap(long eventTime, int keyIndex) { - if (keyIndex == NOT_A_KEY) return; - Key key = mKeys[keyIndex]; - if (key.codes.length > 1) { - mInMultiTap = true; - if (eventTime < mLastTapTime + MULTITAP_INTERVAL - && keyIndex == mLastSentIndex) { - mTapCount = (mTapCount + 1) % key.codes.length; - return; - } else { - mTapCount = -1; - return; - } - } - if (eventTime > mLastTapTime + MULTITAP_INTERVAL || keyIndex != mLastSentIndex) { - resetMultiTap(); - } - } } diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboardView.java b/java/src/com/android/inputmethod/latin/LatinKeyboardView.java index e57abd2c5..71ca8b81a 100644 --- a/java/src/com/android/inputmethod/latin/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/latin/LatinKeyboardView.java @@ -16,8 +16,6 @@ package com.android.inputmethod.latin; -import java.util.List; - import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; @@ -27,14 +25,14 @@ import android.os.Handler; import android.os.Message; import android.os.SystemClock; import android.util.AttributeSet; -import android.view.LayoutInflater; import android.view.MotionEvent; -import android.widget.PopupWindow; + +import java.util.List; public class LatinKeyboardView extends LatinKeyboardBaseView { static final int KEYCODE_OPTIONS = -100; - static final int KEYCODE_SHIFT_LONGPRESS = -101; + static final int KEYCODE_OPTIONS_LONGPRESS = -101; static final int KEYCODE_VOICE = -102; static final int KEYCODE_F1 = -103; static final int KEYCODE_NEXT_LANGUAGE = -104; @@ -42,21 +40,11 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { private Keyboard mPhoneKeyboard; - /** Whether the extension of this keyboard is visible */ - private boolean mExtensionVisible; - /** The view that is shown as an extension of this keyboard view */ - private LatinKeyboardView mExtension; - /** The popup window that contains the extension of this keyboard */ - private PopupWindow mExtensionPopup; - /** Whether this view is an extension of another keyboard */ - private boolean mIsExtensionType; - private boolean mFirstEvent; /** Whether we've started dropping move events because we found a big jump */ private boolean mDroppingEvents; - /** - * Whether multi-touch disambiguation needs to be disabled for any reason. There are 2 reasons - * for this to happen - (1) if a real multi-touch event has occured and (2) we've opened an - * extension keyboard. + /** + * Whether multi-touch disambiguation needs to be disabled if a real multi-touch event has + * occured */ private boolean mDisableDisambiguation; /** The distance threshold at which we start treating the touch session as a multi-touch */ @@ -64,7 +52,8 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { /** The y coordinate of the last row */ private int mLastRowY; - private int mExtensionLayoutResId = 0; + // This is local working variable for onLongPress(). + private int[] mKeyCodes = new int[1]; public LatinKeyboardView(Context context, AttributeSet attrs) { super(context, attrs); @@ -78,10 +67,6 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { mPhoneKeyboard = phoneKeyboard; } - public void setExtentionLayoutResId (int id) { - mExtensionLayoutResId = id; - } - @Override public void setKeyboard(Keyboard k) { super.setKeyboard(k); @@ -93,23 +78,37 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { setKeyboardLocal(k); } + private static boolean hasOneDigitAlternate(Key key) { + final CharSequence alternates = key.popupCharacters; + if (alternates == null) + return false; + final String altChars = alternates.toString(); + if (altChars.codePointCount(0, altChars.length()) != 1) + return false; + final int altCode = altChars.codePointAt(0); + return altCode >= '0' && altCode <= '9'; + } + @Override protected boolean onLongPress(Key key) { - if (key.codes[0] == Keyboard.KEYCODE_MODE_CHANGE) { - getOnKeyboardActionListener().onKey(KEYCODE_OPTIONS, null, + int primaryCode = key.codes[0]; + if (primaryCode == KEYCODE_OPTIONS) { + getOnKeyboardActionListener().onKey(KEYCODE_OPTIONS_LONGPRESS, null, LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE, LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE); return true; - } else if (key.codes[0] == Keyboard.KEYCODE_SHIFT) { - getOnKeyboardActionListener().onKey(KEYCODE_SHIFT_LONGPRESS, null, - LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE, - LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE); - invalidateAllKeys(); - return true; - } else if (key.codes[0] == '0' && getKeyboard() == mPhoneKeyboard) { + } else if (primaryCode == '0' && getKeyboard() == mPhoneKeyboard) { // Long pressing on 0 in phone number keypad gives you a '+'. getOnKeyboardActionListener().onKey( - '+', null, LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE, + '+', null, + LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE, + LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE); + return true; + } else if (hasOneDigitAlternate(key)) { + mKeyCodes[0] = primaryCode = key.popupCharacters.charAt(0); + // when there is only one alternate character, send it as key action. + getOnKeyboardActionListener().onKey(primaryCode, mKeyCodes, + LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE, LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE); return true; } else { @@ -145,10 +144,10 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { * that could be due to a multi-touch being treated as a move by the firmware or hardware. * Once a sudden jump is detected, all subsequent move events are discarded * until an UP is received.

- * When a sudden jump is detected, an UP event is simulated at the last position and when + * When a sudden jump is detected, an UP event is simulated at the last position and when * the sudden moves subside, a DOWN event is simulated for the second key. * @param me the motion event - * @return true if the event was consumed, so that it doesn't continue to be handled by + * @return true if the event was consumed, so that it doesn't continue to be handled by * KeyboardView. */ private boolean handleSuddenJump(MotionEvent me) { @@ -226,11 +225,10 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { invalidate(); } - // If an extension keyboard is visible or this is an extension keyboard, don't look - // for sudden jumps. Otherwise, if there was a sudden jump, return without processing the - // actual motion event. - if (!mExtensionVisible && !mIsExtensionType - && handleSuddenJump(me)) return true; + // If there was a sudden jump, return without processing the actual motion event. + if (handleSuddenJump(me)) + return true; + // Reset any bounding box controls in the keyboard if (me.getAction() == MotionEvent.ACTION_DOWN) { keyboard.keyReleased(); @@ -248,154 +246,7 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { } } - // If we don't have an extension keyboard, don't go any further. - if (keyboard.getExtension() == 0) { - return super.onTouchEvent(me); - } - // If the motion event is above the keyboard and it's not an UP event coming - // even before the first MOVE event into the extension area - if (me.getY() < 0 && (mExtensionVisible || me.getAction() != MotionEvent.ACTION_UP)) { - if (mExtensionVisible) { - int action = me.getAction(); - if (mFirstEvent) action = MotionEvent.ACTION_DOWN; - mFirstEvent = false; - MotionEvent translated = MotionEvent.obtain(me.getEventTime(), me.getEventTime(), - action, - me.getX(), me.getY() + mExtension.getHeight(), me.getMetaState()); - boolean result = mExtension.onTouchEvent(translated); - translated.recycle(); - if (me.getAction() == MotionEvent.ACTION_UP - || me.getAction() == MotionEvent.ACTION_CANCEL) { - closeExtension(); - } - return result; - } else { - if (openExtension()) { - MotionEvent cancel = MotionEvent.obtain(me.getDownTime(), me.getEventTime(), - MotionEvent.ACTION_CANCEL, me.getX() - 100, me.getY() - 100, 0); - super.onTouchEvent(cancel); - cancel.recycle(); - if (mExtension.getHeight() > 0) { - MotionEvent translated = MotionEvent.obtain(me.getEventTime(), - me.getEventTime(), - MotionEvent.ACTION_DOWN, - me.getX(), me.getY() + mExtension.getHeight(), - me.getMetaState()); - mExtension.onTouchEvent(translated); - translated.recycle(); - } else { - mFirstEvent = true; - } - // Stop processing multi-touch errors - mDisableDisambiguation = true; - } - return true; - } - } else if (mExtensionVisible) { - closeExtension(); - // Send a down event into the main keyboard first - MotionEvent down = MotionEvent.obtain(me.getEventTime(), me.getEventTime(), - MotionEvent.ACTION_DOWN, - me.getX(), me.getY(), me.getMetaState()); - super.onTouchEvent(down); - down.recycle(); - // Send the actual event - return super.onTouchEvent(me); - } else { - return super.onTouchEvent(me); - } - } - - private void setExtensionType(boolean isExtensionType) { - mIsExtensionType = isExtensionType; - } - - private boolean openExtension() { - // If the current keyboard is not visible, don't show the popup - if (!isShown()) { - return false; - } - if (((LatinKeyboard) getKeyboard()).getExtension() == 0) return false; - makePopupWindow(); - mExtensionVisible = true; - return true; - } - - private void makePopupWindow() { - if (mExtensionPopup == null) { - int[] windowLocation = new int[2]; - mExtensionPopup = new PopupWindow(getContext()); - mExtensionPopup.setBackgroundDrawable(null); - LayoutInflater li = (LayoutInflater) getContext().getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - mExtension = (LatinKeyboardView) li.inflate(mExtensionLayoutResId == 0 ? - R.layout.input_trans : mExtensionLayoutResId, null); - mExtension.setExtensionType(true); - mExtension.setOnKeyboardActionListener( - new ExtensionKeyboardListener(getOnKeyboardActionListener())); - mExtension.setPopupParent(this); - mExtension.setPopupOffset(0, -windowLocation[1]); - Keyboard keyboard; - mExtension.setKeyboard(keyboard = new LatinKeyboard(getContext(), - ((LatinKeyboard) getKeyboard()).getExtension())); - mExtensionPopup.setContentView(mExtension); - mExtensionPopup.setWidth(getWidth()); - mExtensionPopup.setHeight(keyboard.getHeight()); - mExtensionPopup.setAnimationStyle(-1); - getLocationInWindow(windowLocation); - // TODO: Fix the "- 30". - mExtension.setPopupOffset(0, -windowLocation[1] - 30); - mExtensionPopup.showAtLocation(this, 0, 0, -keyboard.getHeight() - + windowLocation[1]); - } else { - mExtension.setVisibility(VISIBLE); - } - } - - @Override - public void closing() { - super.closing(); - if (mExtensionPopup != null && mExtensionPopup.isShowing()) { - mExtensionPopup.dismiss(); - mExtensionPopup = null; - } - } - - private void closeExtension() { - mExtension.closing(); - mExtension.setVisibility(INVISIBLE); - mExtensionVisible = false; - } - - private static class ExtensionKeyboardListener implements OnKeyboardActionListener { - private OnKeyboardActionListener mTarget; - ExtensionKeyboardListener(OnKeyboardActionListener target) { - mTarget = target; - } - public void onKey(int primaryCode, int[] keyCodes, int x, int y) { - mTarget.onKey(primaryCode, keyCodes, x, y); - } - public void onPress(int primaryCode) { - mTarget.onPress(primaryCode); - } - public void onRelease(int primaryCode) { - mTarget.onRelease(primaryCode); - } - public void onText(CharSequence text) { - mTarget.onText(text); - } - public void swipeDown() { - // Don't pass through - } - public void swipeLeft() { - // Don't pass through - } - public void swipeRight() { - // Don't pass through - } - public void swipeUp() { - // Don't pass through - } + return super.onTouchEvent(me); } /**************************** INSTRUMENTATION *******************************/ @@ -404,9 +255,9 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { static final boolean DEBUG_LINE = false; private static final int MSG_TOUCH_DOWN = 1; private static final int MSG_TOUCH_UP = 2; - + Handler mHandler2; - + private String mStringToPlay; private int mStringIndex; private boolean mDownDelivered; @@ -426,7 +277,7 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { removeMessages(MSG_TOUCH_DOWN); removeMessages(MSG_TOUCH_UP); if (mPlaying == false) return; - + switch (msg.what) { case MSG_TOUCH_DOWN: if (mStringIndex >= mStringToPlay.length()) { @@ -434,7 +285,7 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { return; } char c = mStringToPlay.charAt(mStringIndex); - while (c > 255 || mAsciiKeys[(int) c] == null) { + while (c > 255 || mAsciiKeys[c] == null) { mStringIndex++; if (mStringIndex >= mStringToPlay.length()) { mPlaying = false; @@ -444,8 +295,8 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { } int x = mAsciiKeys[c].x + 10; int y = mAsciiKeys[c].y + 26; - MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(), - SystemClock.uptimeMillis(), + MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(), + SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, x, y, 0); LatinKeyboardView.this.dispatchTouchEvent(me); me.recycle(); @@ -458,9 +309,9 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { int x2 = mAsciiKeys[cUp].x + 10; int y2 = mAsciiKeys[cUp].y + 26; mStringIndex++; - - MotionEvent me2 = MotionEvent.obtain(SystemClock.uptimeMillis(), - SystemClock.uptimeMillis(), + + MotionEvent me2 = MotionEvent.obtain(SystemClock.uptimeMillis(), + SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, x2, y2, 0); LatinKeyboardView.this.dispatchTouchEvent(me2); me2.recycle(); @@ -481,7 +332,7 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { // Get the keys on this keyboard for (int i = 0; i < keys.size(); i++) { int code = keys.get(i).codes[0]; - if (code >= 0 && code <= 255) { + if (code >= 0 && code <= 255) { mAsciiKeys[code] = keys.get(i); } } diff --git a/java/src/com/android/inputmethod/latin/ModifierKeyState.java b/java/src/com/android/inputmethod/latin/ModifierKeyState.java new file mode 100644 index 000000000..097e87abe --- /dev/null +++ b/java/src/com/android/inputmethod/latin/ModifierKeyState.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF 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; + +class ModifierKeyState { + private static final int RELEASING = 0; + private static final int PRESSING = 1; + private static final int MOMENTARY = 2; + + private int mState = RELEASING; + + public void onPress() { + mState = PRESSING; + } + + public void onRelease() { + mState = RELEASING; + } + + public void onOtherKeyPressed() { + if (mState == PRESSING) + mState = MOMENTARY; + } + + public boolean isMomentary() { + return mState == MOMENTARY; + } +} diff --git a/java/src/com/android/inputmethod/latin/PointerTracker.java b/java/src/com/android/inputmethod/latin/PointerTracker.java new file mode 100644 index 000000000..2685e87c6 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/PointerTracker.java @@ -0,0 +1,459 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin; + +import com.android.inputmethod.latin.LatinKeyboardBaseView.OnKeyboardActionListener; +import com.android.inputmethod.latin.LatinKeyboardBaseView.UIHandler; + +import android.inputmethodservice.Keyboard; +import android.inputmethodservice.Keyboard.Key; +import android.util.Log; +import android.view.ViewConfiguration; + +public class PointerTracker { + private static final String TAG = "PointerTracker"; + private static final boolean DEBUG = false; + private static final boolean DEBUG_MOVE = DEBUG && true; + + public interface UIProxy { + public void invalidateKey(Key key); + public void showPreview(int keyIndex, PointerTracker tracker); + } + + public final int mPointerId; + + // Timing constants + private static final int REPEAT_START_DELAY = 400; + /* package */ static final int REPEAT_INTERVAL = 50; // ~20 keys per second + private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout(); + private static final int MULTITAP_INTERVAL = 800; // milliseconds + private static final int KEY_DEBOUNCE_TIME = 70; + + // Miscellaneous constants + private static final int NOT_A_KEY = LatinKeyboardBaseView.NOT_A_KEY; + private static final int[] KEY_DELETE = { Keyboard.KEYCODE_DELETE }; + + private final UIProxy mProxy; + private final UIHandler mHandler; + private final KeyDetector mKeyDetector; + private OnKeyboardActionListener mListener; + + private Key[] mKeys; + private int mKeyDebounceThresholdSquared = -1; + + private int mCurrentKey = NOT_A_KEY; + private int mStartX; + private int mStartY; + private long mDownTime; + + // true if event is already translated to a key action (long press or mini-keyboard) + private boolean mKeyAlreadyProcessed; + + // for move de-bouncing + private int mLastCodeX; + private int mLastCodeY; + private int mLastX; + private int mLastY; + + // for time de-bouncing + private int mLastKey; + private long mLastKeyTime; + private long mLastMoveTime; + private long mCurrentKeyTime; + + // For multi-tap + private int mLastSentIndex; + private int mTapCount; + private long mLastTapTime; + private boolean mInMultiTap; + private final StringBuilder mPreviewLabel = new StringBuilder(1); + + // pressed key + private int mPreviousKey = NOT_A_KEY; + + public PointerTracker(int id, UIHandler handler, KeyDetector keyDetector, UIProxy proxy) { + if (proxy == null || handler == null || keyDetector == null) + throw new NullPointerException(); + mPointerId = id; + mProxy = proxy; + mHandler = handler; + mKeyDetector = keyDetector; + resetMultiTap(); + } + + public void setOnKeyboardActionListener(OnKeyboardActionListener listener) { + mListener = listener; + } + + public void setKeyboard(Key[] keys, float hysteresisPixel) { + if (keys == null || hysteresisPixel < 1.0f) + throw new IllegalArgumentException(); + mKeys = keys; + mKeyDebounceThresholdSquared = (int)(hysteresisPixel * hysteresisPixel); + } + + private boolean isValidKeyIndex(int keyIndex) { + return keyIndex >= 0 && keyIndex < mKeys.length; + } + + public Key getKey(int keyIndex) { + return isValidKeyIndex(keyIndex) ? mKeys[keyIndex] : null; + } + + public boolean isModifier() { + Key key = getKey(mCurrentKey); + if (key == null) + return false; + int primaryCode = key.codes[0]; + // TODO: KEYCODE_MODE_CHANGE (symbol) will be also a modifier key + return primaryCode == Keyboard.KEYCODE_SHIFT; + } + + public void updateKey(int keyIndex) { + if (mKeyAlreadyProcessed) + return; + int oldKeyIndex = mPreviousKey; + mPreviousKey = keyIndex; + if (keyIndex != oldKeyIndex) { + if (isValidKeyIndex(oldKeyIndex)) { + // if new key index is not a key, old key was just released inside of the key. + final boolean inside = (keyIndex == NOT_A_KEY); + mKeys[oldKeyIndex].onReleased(inside); + mProxy.invalidateKey(mKeys[oldKeyIndex]); + } + if (isValidKeyIndex(keyIndex)) { + mKeys[keyIndex].onPressed(); + mProxy.invalidateKey(mKeys[keyIndex]); + } + } + } + + public void setAlreadyProcessed() { + mKeyAlreadyProcessed = true; + } + + public void onDownEvent(int x, int y, long eventTime) { + int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); + mCurrentKey = keyIndex; + mStartX = x; + mStartY = y; + mDownTime = eventTime; + mKeyAlreadyProcessed = false; + startMoveDebouncing(x, y); + startTimeDebouncing(eventTime); + checkMultiTap(eventTime, keyIndex); + if (mListener != null) { + int primaryCode = isValidKeyIndex(keyIndex) ? mKeys[keyIndex].codes[0] : 0; + mListener.onPress(primaryCode); + } + if (isValidKeyIndex(keyIndex)) { + if (mKeys[keyIndex].repeatable) { + repeatKey(keyIndex); + mHandler.startKeyRepeatTimer(REPEAT_START_DELAY, keyIndex, this); + } + mHandler.startLongPressTimer(LONGPRESS_TIMEOUT, keyIndex, this); + } + showKeyPreviewAndUpdateKey(keyIndex); + updateMoveDebouncing(x, y); + if (DEBUG) + debugLog("onDownEvent:", x, y); + } + + public void onMoveEvent(int x, int y, long eventTime) { + if (mKeyAlreadyProcessed) + return; + int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); + if (isValidKeyIndex(keyIndex)) { + if (mCurrentKey == NOT_A_KEY) { + updateTimeDebouncing(eventTime); + mCurrentKey = keyIndex; + mHandler.startLongPressTimer(LONGPRESS_TIMEOUT, keyIndex, this); + } else if (isMinorMoveBounce(x, y, keyIndex, mCurrentKey)) { + updateTimeDebouncing(eventTime); + } else { + resetMultiTap(); + resetTimeDebouncing(eventTime, mCurrentKey); + resetMoveDebouncing(); + mCurrentKey = keyIndex; + mHandler.startLongPressTimer(LONGPRESS_TIMEOUT, keyIndex, this); + } + } else { + if (mCurrentKey != NOT_A_KEY) { + updateTimeDebouncing(eventTime); + mCurrentKey = keyIndex; + mHandler.cancelLongPressTimer(); + } else if (isMinorMoveBounce(x, y, keyIndex, mCurrentKey)) { + updateTimeDebouncing(eventTime); + } else { + resetMultiTap(); + resetTimeDebouncing(eventTime, mCurrentKey); + resetMoveDebouncing(); + mCurrentKey = keyIndex; + mHandler.cancelLongPressTimer(); + } + } + /* + * While time debouncing is in effect, mCurrentKey holds the new key and this tracker + * holds the last key. At ACTION_UP event if time debouncing will be in effect + * eventually, the last key should be sent as the result. In such case mCurrentKey + * should not be showed as popup preview. + */ + showKeyPreviewAndUpdateKey(isMinorTimeBounce() ? mLastKey : mCurrentKey); + updateMoveDebouncing(x, y); + if (DEBUG_MOVE) + debugLog("onMoveEvent:", x, y); + } + + public void onUpEvent(int x, int y, long eventTime) { + if (mKeyAlreadyProcessed) + return; + if (DEBUG) + debugLog("onUpEvent :", x, y); + int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); + boolean wasInKeyRepeat = mHandler.isInKeyRepeat(); + mHandler.cancelKeyTimers(); + mHandler.cancelPopupPreview(); + if (isMinorMoveBounce(x, y, keyIndex, mCurrentKey)) { + updateTimeDebouncing(eventTime); + } else { + resetMultiTap(); + resetTimeDebouncing(eventTime, mCurrentKey); + mCurrentKey = keyIndex; + } + if (isMinorTimeBounce()) { + mCurrentKey = mLastKey; + x = mLastCodeX; + y = mLastCodeY; + } + showKeyPreviewAndUpdateKey(NOT_A_KEY); + // If we're not on a repeating key (which sends on a DOWN event) + if (!wasInKeyRepeat) { + detectAndSendKey(mCurrentKey, (int)x, (int)y, eventTime); + } + if (isValidKeyIndex(keyIndex)) + mProxy.invalidateKey(mKeys[keyIndex]); + } + + public void onCancelEvent(int x, int y, long eventTime) { + if (DEBUG) + debugLog("onCancelEvt:", x, y); + mHandler.cancelKeyTimers(); + mHandler.cancelPopupPreview(); + showKeyPreviewAndUpdateKey(NOT_A_KEY); + int keyIndex = mCurrentKey; + if (isValidKeyIndex(keyIndex)) + mProxy.invalidateKey(mKeys[keyIndex]); + } + + public void repeatKey(int keyIndex) { + Key key = getKey(keyIndex); + if (key != null) { + // While key is repeating, because there is no need to handle multi-tap key, we can + // pass -1 as eventTime argument. + detectAndSendKey(keyIndex, key.x, key.y, -1); + } + } + + public int getLastX() { + return mLastX; + } + + public int getLastY() { + return mLastY; + } + + public long getDownTime() { + return mDownTime; + } + + // These package scope methods are only for debugging purpose. + /* package */ int getStartX() { + return mStartX; + } + + /* package */ int getStartY() { + return mStartY; + } + + private void startMoveDebouncing(int x, int y) { + mLastCodeX = x; + mLastCodeY = y; + } + + private void updateMoveDebouncing(int x, int y) { + mLastX = x; + mLastY = y; + } + + private void resetMoveDebouncing() { + mLastCodeX = mLastX; + mLastCodeY = mLastY; + } + + private boolean isMinorMoveBounce(int x, int y, int newKey, int curKey) { + if (mKeys == null || mKeyDebounceThresholdSquared < 0) + throw new IllegalStateException("keyboard and/or hysteresis not set"); + if (newKey == curKey) { + return true; + } else if (isValidKeyIndex(curKey)) { + return getSquareDistanceToKeyEdge(x, y, mKeys[curKey]) + < mKeyDebounceThresholdSquared; + } else { + return false; + } + } + + private static int getSquareDistanceToKeyEdge(int x, int y, Key key) { + final int left = key.x; + final int right = key.x + key.width; + final int top = key.y; + final int bottom = key.y + key.height; + final int edgeX = x < left ? left : (x > right ? right : x); + final int edgeY = y < top ? top : (y > bottom ? bottom : y); + final int dx = x - edgeX; + final int dy = y - edgeY; + return dx * dx + dy * dy; + } + + private void startTimeDebouncing(long eventTime) { + mLastKey = NOT_A_KEY; + mLastKeyTime = 0; + mCurrentKeyTime = 0; + mLastMoveTime = eventTime; + } + + private void updateTimeDebouncing(long eventTime) { + mCurrentKeyTime += eventTime - mLastMoveTime; + mLastMoveTime = eventTime; + } + + private void resetTimeDebouncing(long eventTime, int currentKey) { + mLastKey = currentKey; + mLastKeyTime = mCurrentKeyTime + eventTime - mLastMoveTime; + mCurrentKeyTime = 0; + mLastMoveTime = eventTime; + } + + private boolean isMinorTimeBounce() { + return mCurrentKeyTime < mLastKeyTime && mCurrentKeyTime < KEY_DEBOUNCE_TIME + && mLastKey != NOT_A_KEY; + } + + private void showKeyPreviewAndUpdateKey(int keyIndex) { + updateKey(keyIndex); + if (!isModifier()) + mProxy.showPreview(keyIndex, this); + } + + private void detectAndSendKey(int index, int x, int y, long eventTime) { + if (isValidKeyIndex(index)) { + final Key key = mKeys[index]; + OnKeyboardActionListener listener = mListener; + if (key.text != null) { + if (listener != null) { + listener.onText(key.text); + listener.onRelease(NOT_A_KEY); + } + } else { + int code = key.codes[0]; + //TextEntryState.keyPressedAt(key, x, y); + int[] codes = mKeyDetector.newCodeArray(); + mKeyDetector.getKeyIndexAndNearbyCodes(x, y, codes); + // Multi-tap + if (mInMultiTap) { + if (mTapCount != -1) { + mListener.onKey(Keyboard.KEYCODE_DELETE, KEY_DELETE, x, y); + } else { + mTapCount = 0; + } + code = key.codes[mTapCount]; + } + /* + * Swap the first and second values in the codes array if the primary code is not + * the first value but the second value in the array. This happens when key + * debouncing is in effect. + */ + if (codes.length >= 2 && codes[0] != code && codes[1] == code) { + codes[1] = codes[0]; + codes[0] = code; + } + if (listener != null) { + listener.onKey(code, codes, x, y); + listener.onRelease(code); + } + } + mLastSentIndex = index; + mLastTapTime = eventTime; + } + } + + /** + * Handle multi-tap keys by producing the key label for the current multi-tap state. + */ + public CharSequence getPreviewText(Key key) { + if (mInMultiTap) { + // Multi-tap + mPreviewLabel.setLength(0); + mPreviewLabel.append((char) key.codes[mTapCount < 0 ? 0 : mTapCount]); + return mPreviewLabel; + } else { + return key.label; + } + } + + private void resetMultiTap() { + mLastSentIndex = NOT_A_KEY; + mTapCount = 0; + mLastTapTime = -1; + mInMultiTap = false; + } + + private void checkMultiTap(long eventTime, int keyIndex) { + Key key = getKey(keyIndex); + if (key == null) + return; + + final boolean isMultiTap = + (eventTime < mLastTapTime + MULTITAP_INTERVAL && keyIndex == mLastSentIndex); + if (key.codes.length > 1) { + mInMultiTap = true; + if (isMultiTap) { + mTapCount = (mTapCount + 1) % key.codes.length; + return; + } else { + mTapCount = -1; + return; + } + } + if (!isMultiTap) { + resetMultiTap(); + } + } + + private void debugLog(String title, int x, int y) { + Key key = getKey(mCurrentKey); + final String code; + if (key == null) { + code = "----"; + } else { + int primaryCode = key.codes[0]; + code = String.format((primaryCode < 0) ? "%4d" : "0x%02x", primaryCode); + } + Log.d(TAG, String.format("%s [%d] %3d,%3d %s %s", title, mPointerId, x, y, code, + isModifier() ? "modifier" : "")); + } +} \ No newline at end of file diff --git a/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java b/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java index eae2d7f08..d17bedb56 100644 --- a/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java +++ b/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java @@ -16,70 +16,43 @@ package com.android.inputmethod.latin; -import android.inputmethodservice.Keyboard; import android.inputmethodservice.Keyboard.Key; import java.util.Arrays; -class ProximityKeyDetector { +class ProximityKeyDetector extends KeyDetector { private static final int MAX_NEARBY_KEYS = 12; - private Keyboard mKeyboard; - private Key[] mKeys; - - private boolean mProximityCorrectOn; - private int mProximityThresholdSquare; - // working area private int[] mDistances = new int[MAX_NEARBY_KEYS]; - public void setKeyboard(Keyboard keyboard, Key[] keys) { - if (keyboard == null || keys == null) - throw new NullPointerException(); - mKeyboard = keyboard; - mKeys = keys; - } - - public void setProximityCorrectionEnabled(boolean enabled) { - mProximityCorrectOn = enabled; - } - - public boolean isProximityCorrectionEnabled() { - return mProximityCorrectOn; - } - - public void setProximityThreshold(int threshold) { - mProximityThresholdSquare = threshold * threshold; - } - - public int[] newCodeArray() { - int[] codes = new int[MAX_NEARBY_KEYS]; - Arrays.fill(codes, LatinKeyboardBaseView.NOT_A_KEY); - return codes; + @Override + protected int getMaxNearbyKeys() { + return MAX_NEARBY_KEYS; } + @Override public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys) { - final Key[] keys = mKeys; - if (keys == null) - throw new IllegalStateException("keyboard isn't set"); - // mKeyboard is guaranteed not null at setKeybaord() method + final Key[] keys = getKeys(); + final int touchX = getTouchX(x); + final int touchY = getTouchY(y); int primaryIndex = LatinKeyboardBaseView.NOT_A_KEY; int closestKey = LatinKeyboardBaseView.NOT_A_KEY; int closestKeyDist = mProximityThresholdSquare + 1; int[] distances = mDistances; Arrays.fill(distances, Integer.MAX_VALUE); - int [] nearestKeyIndices = mKeyboard.getNearestKeys(x, y); + int [] nearestKeyIndices = mKeyboard.getNearestKeys(touchX, touchY); final int keyCount = nearestKeyIndices.length; for (int i = 0; i < keyCount; i++) { final Key key = keys[nearestKeyIndices[i]]; int dist = 0; - boolean isInside = key.isInside(x,y); + boolean isInside = key.isInside(touchX, touchY); if (isInside) { primaryIndex = nearestKeyIndices[i]; } if (((mProximityCorrectOn - && (dist = key.squaredDistanceFrom(x, y)) < mProximityThresholdSquare) + && (dist = key.squaredDistanceFrom(touchX, touchY)) < mProximityThresholdSquare) || isInside) && key.codes[0] > 32) { // Find insertion point diff --git a/java/src/com/android/inputmethod/voice/VoiceInput.java b/java/src/com/android/inputmethod/voice/VoiceInput.java index f24c180d0..4c54dd3c5 100644 --- a/java/src/com/android/inputmethod/voice/VoiceInput.java +++ b/java/src/com/android/inputmethod/voice/VoiceInput.java @@ -16,6 +16,7 @@ package com.android.inputmethod.voice; +import com.android.inputmethod.latin.EditingUtil; import com.android.inputmethod.latin.R; import android.content.ContentResolver; @@ -30,6 +31,7 @@ import android.speech.RecognitionListener; import android.speech.SpeechRecognizer; import android.speech.RecognizerIntent; import android.util.Log; +import android.view.inputmethod.InputConnection; import android.view.View; import android.view.View.OnClickListener; @@ -423,8 +425,14 @@ public class VoiceInput implements OnClickListener { mLogger.textModifiedByTypingDeletion(length); } - public void logTextModifiedByChooseSuggestion(int length) { - mLogger.textModifiedByChooseSuggestion(length); + public void logTextModifiedByChooseSuggestion(String suggestion, int index, + String wordSeparators, InputConnection ic) { + EditingUtil.Range range = new EditingUtil.Range(); + String wordToBeReplaced = EditingUtil.getWordAtCursor(ic, wordSeparators, range); + // If we enable phrase-based alternatives, only send up the first word + // in suggestion and wordToBeReplaced. + mLogger.textModifiedByChooseSuggestion(suggestion.length(), wordToBeReplaced.length(), + index, wordToBeReplaced, suggestion); } public void logKeyboardWarningDialogShown() { @@ -455,10 +463,6 @@ public class VoiceInput implements OnClickListener { mLogger.voiceInputDelivered(length); } - public void logNBestChoose(int index) { - mLogger.nBestChoose(index); - } - public void logInputEnded() { mLogger.inputEnded(); } diff --git a/java/src/com/android/inputmethod/voice/VoiceInputLogger.java b/java/src/com/android/inputmethod/voice/VoiceInputLogger.java index 9d3a92037..4d50f5ee8 100644 --- a/java/src/com/android/inputmethod/voice/VoiceInputLogger.java +++ b/java/src/com/android/inputmethod/voice/VoiceInputLogger.java @@ -178,20 +178,19 @@ public class VoiceInputLogger { mContext.sendBroadcast(i); } - public void textModifiedByChooseSuggestion(int length) { + public void textModifiedByChooseSuggestion(int suggestionLength, int replacedPhraseLength, + int index, String before, String after) { Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.TEXT_MODIFIED); - i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_LENGTH, length); + i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_LENGTH, suggestionLength); + i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_REPLACED_LENGTH, replacedPhraseLength); i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_TYPE, LoggingEvents.VoiceIme.TEXT_MODIFIED_TYPE_CHOOSE_SUGGESTION); + i.putExtra(LoggingEvents.VoiceIme.EXTRA_N_BEST_CHOOSE_INDEX, index); + i.putExtra(LoggingEvents.VoiceIme.EXTRA_BEFORE_N_BEST_CHOOSE, before); + i.putExtra(LoggingEvents.VoiceIme.EXTRA_AFTER_N_BEST_CHOOSE, after); mContext.sendBroadcast(i); } - public void nBestChoose(int index) { - Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.N_BEST_CHOOSE); - i.putExtra(LoggingEvents.VoiceIme.EXTRA_N_BEST_CHOOSE_INDEX, index); - mContext.sendBroadcast(i); - } - public void inputEnded() { mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.INPUT_ENDED)); }