diff options
190 files changed, 5822 insertions, 770 deletions
diff --git a/java/res/color/emoji_tab_label_color_lxx.xml b/java/res/color/emoji_tab_label_color_lxx.xml new file mode 100644 index 000000000..c2710d365 --- /dev/null +++ b/java/res/color/emoji_tab_label_color_lxx.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2014, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:state_focused="true" + android:color="@color/key_text_color_holo" /> + <item + android:state_pressed="true" + android:color="@color/key_text_color_holo" /> + <item + android:state_selected="true" + android:color="@color/key_text_color_holo" /> + <item + android:color="@color/key_text_inactive_color_lxx" /> +</selector> 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 Binary files differdeleted file mode 100644 index bc130cab6..000000000 --- a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off_lxx.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off_lxx.9.png Binary files differnew file mode 100644 index 000000000..44308bfd8 --- /dev/null +++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off_lxx.9.png diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_lmp.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_lmp.9.png Binary files differdeleted file mode 100644 index 814e40235..000000000 --- a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_lxx.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_lxx.9.png Binary files differnew file mode 100644 index 000000000..674783d7d --- /dev/null +++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_lxx.9.png 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 Binary files differdeleted file mode 100644 index af5ea6bd2..000000000 --- a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_lmp.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_lmp.9.png Binary files differdeleted file mode 100644 index 90abe3940..000000000 --- a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png Binary files differdeleted file mode 100644 index 48eeb3f54..000000000 --- a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_lxx.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_lxx.9.png Binary files differnew file mode 100644 index 000000000..96b625bd6 --- /dev/null +++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_lxx.9.png 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 Binary files differdeleted file mode 100644 index fc7ba2aeb..000000000 --- a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png Binary files differdeleted file mode 100644 index 71e0683cd..000000000 --- a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_lxx.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_lxx.9.png Binary files differnew file mode 100644 index 000000000..20e53c2e5 --- /dev/null +++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_lxx.9.png 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 Binary files differdeleted file mode 100644 index 005c4e498..000000000 --- a/java/res/drawable-hdpi/btn_keyboard_key_light_normal.9.png +++ /dev/null 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 Binary files differdeleted file mode 100644 index 9a07acd91..000000000 --- a/java/res/drawable-hdpi/btn_keyboard_key_light_popup_selected.9.png +++ /dev/null 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 Binary files differdeleted file mode 100644 index be420a7af..000000000 --- a/java/res/drawable-hdpi/btn_keyboard_key_light_pressed.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/btn_keyboard_key_light_pressed_lmp.9.png b/java/res/drawable-hdpi/btn_keyboard_key_light_pressed_lmp.9.png Binary files differdeleted file mode 100644 index 6768241a7..000000000 --- a/java/res/drawable-hdpi/btn_keyboard_key_light_pressed_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/btn_keyboard_key_popup_selected_lmp.9.png b/java/res/drawable-hdpi/btn_keyboard_key_popup_selected_lxx.9.png Binary files differindex 10f8e97e4..10f8e97e4 100644 --- a/java/res/drawable-hdpi/btn_keyboard_key_popup_selected_lmp.9.png +++ b/java/res/drawable-hdpi/btn_keyboard_key_popup_selected_lxx.9.png diff --git a/java/res/drawable-hdpi/btn_suggestion_pressed.9.png b/java/res/drawable-hdpi/btn_suggestion_pressed.9.png Binary files differdeleted file mode 100644 index 7acceaee7..000000000 --- a/java/res/drawable-hdpi/btn_suggestion_pressed.9.png +++ /dev/null diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_background_lmp.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_background_lxx.9.png Binary files differindex be394151a..be394151a 100644 --- a/java/res/drawable-hdpi/keyboard_key_feedback_background_lmp.9.png +++ b/java/res/drawable-hdpi/keyboard_key_feedback_background_lxx.9.png diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_left_background_lmp.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_left_background_lxx.9.png Binary files differindex 9fa6d0003..9fa6d0003 100644 --- a/java/res/drawable-hdpi/keyboard_key_feedback_left_background_lmp.9.png +++ b/java/res/drawable-hdpi/keyboard_key_feedback_left_background_lxx.9.png diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_left_more_background_lmp.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_left_more_background_lxx.9.png Binary files differindex c73269b7e..c73269b7e 100644 --- a/java/res/drawable-hdpi/keyboard_key_feedback_left_more_background_lmp.9.png +++ b/java/res/drawable-hdpi/keyboard_key_feedback_left_more_background_lxx.9.png diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_more_background_lmp.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_more_background_lxx.9.png Binary files differindex fffd4021e..fffd4021e 100644 --- a/java/res/drawable-hdpi/keyboard_key_feedback_more_background_lmp.9.png +++ b/java/res/drawable-hdpi/keyboard_key_feedback_more_background_lxx.9.png diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_right_background_lmp.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_right_background_lxx.9.png Binary files differindex 61c23c19b..61c23c19b 100644 --- a/java/res/drawable-hdpi/keyboard_key_feedback_right_background_lmp.9.png +++ b/java/res/drawable-hdpi/keyboard_key_feedback_right_background_lxx.9.png diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_right_more_background_lmp.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_right_more_background_lxx.9.png Binary files differindex 827d74363..827d74363 100644 --- a/java/res/drawable-hdpi/keyboard_key_feedback_right_more_background_lmp.9.png +++ b/java/res/drawable-hdpi/keyboard_key_feedback_right_more_background_lxx.9.png diff --git a/java/res/drawable-hdpi/keyboard_popup_panel_background_lmp.9.png b/java/res/drawable-hdpi/keyboard_popup_panel_background_lxx.9.png Binary files differindex f9dd3b8b1..f9dd3b8b1 100644 --- a/java/res/drawable-hdpi/keyboard_popup_panel_background_lmp.9.png +++ b/java/res/drawable-hdpi/keyboard_popup_panel_background_lxx.9.png diff --git a/java/res/drawable-hdpi/sym_keyboard_mic_holo_dark.png b/java/res/drawable-hdpi/sym_keyboard_mic_holo_dark.png Binary files differdeleted file mode 100644 index 3c5469403..000000000 --- a/java/res/drawable-hdpi/sym_keyboard_mic_holo_dark.png +++ /dev/null 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 Binary files differdeleted file mode 100644 index 49329f094..000000000 --- a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off_lxx.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off_lxx.9.png Binary files differnew file mode 100644 index 000000000..837df83ce --- /dev/null +++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off_lxx.9.png diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_lmp.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_lmp.9.png Binary files differdeleted file mode 100644 index b7b2dca43..000000000 --- a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_lxx.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_lxx.9.png Binary files differnew file mode 100644 index 000000000..977265214 --- /dev/null +++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_lxx.9.png 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 Binary files differdeleted file mode 100644 index c6876f76e..000000000 --- a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_lmp.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_lmp.9.png Binary files differdeleted file mode 100644 index 4a92b80dd..000000000 --- a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png Binary files differdeleted file mode 100644 index 72125a065..000000000 --- a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_lxx.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_lxx.9.png Binary files differnew file mode 100644 index 000000000..d21363316 --- /dev/null +++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_lxx.9.png 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 Binary files differdeleted file mode 100644 index 2bb7b64f4..000000000 --- a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png Binary files differdeleted file mode 100644 index 82413d4cc..000000000 --- a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_lxx.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_lxx.9.png Binary files differnew file mode 100644 index 000000000..6d20c540b --- /dev/null +++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_lxx.9.png 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 Binary files differdeleted file mode 100644 index f5ce40cf6..000000000 --- a/java/res/drawable-mdpi/btn_keyboard_key_light_normal.9.png +++ /dev/null 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 Binary files differdeleted file mode 100644 index ca73b9249..000000000 --- a/java/res/drawable-mdpi/btn_keyboard_key_light_popup_selected.9.png +++ /dev/null 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 Binary files differdeleted file mode 100644 index 73f2006d4..000000000 --- a/java/res/drawable-mdpi/btn_keyboard_key_light_pressed.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/btn_keyboard_key_light_pressed_lmp.9.png b/java/res/drawable-mdpi/btn_keyboard_key_light_pressed_lmp.9.png Binary files differdeleted file mode 100644 index 049385984..000000000 --- a/java/res/drawable-mdpi/btn_keyboard_key_light_pressed_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/btn_keyboard_key_popup_selected_lmp.9.png b/java/res/drawable-mdpi/btn_keyboard_key_popup_selected_lxx.9.png Binary files differindex ee0aae28b..ee0aae28b 100644 --- a/java/res/drawable-mdpi/btn_keyboard_key_popup_selected_lmp.9.png +++ b/java/res/drawable-mdpi/btn_keyboard_key_popup_selected_lxx.9.png diff --git a/java/res/drawable-mdpi/btn_suggestion_pressed.9.png b/java/res/drawable-mdpi/btn_suggestion_pressed.9.png Binary files differdeleted file mode 100644 index 02b4e9a53..000000000 --- a/java/res/drawable-mdpi/btn_suggestion_pressed.9.png +++ /dev/null diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_background_lmp.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_background_lxx.9.png Binary files differindex 625490b1f..625490b1f 100644 --- a/java/res/drawable-mdpi/keyboard_key_feedback_background_lmp.9.png +++ b/java/res/drawable-mdpi/keyboard_key_feedback_background_lxx.9.png diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_left_background_lmp.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_left_background_lxx.9.png Binary files differindex 427c87061..427c87061 100644 --- a/java/res/drawable-mdpi/keyboard_key_feedback_left_background_lmp.9.png +++ b/java/res/drawable-mdpi/keyboard_key_feedback_left_background_lxx.9.png diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_left_more_background_lmp.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_left_more_background_lxx.9.png Binary files differindex ea757296d..ea757296d 100644 --- a/java/res/drawable-mdpi/keyboard_key_feedback_left_more_background_lmp.9.png +++ b/java/res/drawable-mdpi/keyboard_key_feedback_left_more_background_lxx.9.png diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_more_background_lmp.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_more_background_lxx.9.png Binary files differindex 1911c429f..1911c429f 100644 --- a/java/res/drawable-mdpi/keyboard_key_feedback_more_background_lmp.9.png +++ b/java/res/drawable-mdpi/keyboard_key_feedback_more_background_lxx.9.png diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_right_background_lmp.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_right_background_lxx.9.png Binary files differindex cdef116d2..cdef116d2 100644 --- a/java/res/drawable-mdpi/keyboard_key_feedback_right_background_lmp.9.png +++ b/java/res/drawable-mdpi/keyboard_key_feedback_right_background_lxx.9.png diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_right_more_background_lmp.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_right_more_background_lxx.9.png Binary files differindex dea5d076c..dea5d076c 100644 --- a/java/res/drawable-mdpi/keyboard_key_feedback_right_more_background_lmp.9.png +++ b/java/res/drawable-mdpi/keyboard_key_feedback_right_more_background_lxx.9.png diff --git a/java/res/drawable-mdpi/keyboard_popup_panel_background_lmp.9.png b/java/res/drawable-mdpi/keyboard_popup_panel_background_lxx.9.png Binary files differindex 896505518..896505518 100644 --- a/java/res/drawable-mdpi/keyboard_popup_panel_background_lmp.9.png +++ b/java/res/drawable-mdpi/keyboard_popup_panel_background_lxx.9.png diff --git a/java/res/drawable-mdpi/sym_keyboard_mic_holo_dark.png b/java/res/drawable-mdpi/sym_keyboard_mic_holo_dark.png Binary files differdeleted file mode 100644 index 5e58866a7..000000000 --- a/java/res/drawable-mdpi/sym_keyboard_mic_holo_dark.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal.9.png Binary files differdeleted file mode 100644 index d0090a305..000000000 --- a/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_off_lxx.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_off_lxx.9.png Binary files differnew file mode 100644 index 000000000..eeb447cc3 --- /dev/null +++ b/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_off_lxx.9.png diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_on_lmp.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_on_lmp.9.png Binary files differdeleted file mode 100644 index 20251a000..000000000 --- a/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_on_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_on_lxx.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_on_lxx.9.png Binary files differnew file mode 100644 index 000000000..624ba8c27 --- /dev/null +++ b/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_on_lxx.9.png diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed.9.png Binary files differdeleted file mode 100644 index a932249a8..000000000 --- a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_lmp.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_lmp.9.png Binary files differdeleted file mode 100644 index 84d173967..000000000 --- a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png Binary files differdeleted file mode 100644 index ee4490eac..000000000 --- a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_off_lxx.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_off_lxx.9.png Binary files differnew file mode 100644 index 000000000..2bc16cfeb --- /dev/null +++ b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_off_lxx.9.png diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on.9.png Binary files differdeleted file mode 100644 index 3ca93fdb3..000000000 --- a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png Binary files differdeleted file mode 100644 index e8124776c..000000000 --- a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on_lxx.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on_lxx.9.png Binary files differnew file mode 100644 index 000000000..80dedd228 --- /dev/null +++ b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on_lxx.9.png diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_light_normal.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_light_normal.9.png Binary files differdeleted file mode 100644 index aa4f44fdd..000000000 --- a/java/res/drawable-xhdpi/btn_keyboard_key_light_normal.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_light_popup_selected.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_light_popup_selected.9.png Binary files differdeleted file mode 100644 index 4539255c2..000000000 --- a/java/res/drawable-xhdpi/btn_keyboard_key_light_popup_selected.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_light_pressed.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_light_pressed.9.png Binary files differdeleted file mode 100644 index 568392444..000000000 --- a/java/res/drawable-xhdpi/btn_keyboard_key_light_pressed.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_light_pressed_lmp.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_light_pressed_lmp.9.png Binary files differdeleted file mode 100644 index f770962c3..000000000 --- a/java/res/drawable-xhdpi/btn_keyboard_key_light_pressed_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_popup_selected_lmp.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_popup_selected_lxx.9.png Binary files differindex 891d00024..891d00024 100644 --- a/java/res/drawable-xhdpi/btn_keyboard_key_popup_selected_lmp.9.png +++ b/java/res/drawable-xhdpi/btn_keyboard_key_popup_selected_lxx.9.png diff --git a/java/res/drawable-xhdpi/btn_suggestion_pressed.9.png b/java/res/drawable-xhdpi/btn_suggestion_pressed.9.png Binary files differdeleted file mode 100644 index 41e126a73..000000000 --- a/java/res/drawable-xhdpi/btn_suggestion_pressed.9.png +++ /dev/null diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_background_lmp.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_background_lxx.9.png Binary files differindex c211d89c8..c211d89c8 100644 --- a/java/res/drawable-xhdpi/keyboard_key_feedback_background_lmp.9.png +++ b/java/res/drawable-xhdpi/keyboard_key_feedback_background_lxx.9.png diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_left_background_lmp.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_left_background_lxx.9.png Binary files differindex 543bc763e..543bc763e 100644 --- a/java/res/drawable-xhdpi/keyboard_key_feedback_left_background_lmp.9.png +++ b/java/res/drawable-xhdpi/keyboard_key_feedback_left_background_lxx.9.png diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_left_more_background_lmp.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_left_more_background_lxx.9.png Binary files differindex ec42aadb6..ec42aadb6 100644 --- a/java/res/drawable-xhdpi/keyboard_key_feedback_left_more_background_lmp.9.png +++ b/java/res/drawable-xhdpi/keyboard_key_feedback_left_more_background_lxx.9.png diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_lmp.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_lxx.9.png Binary files differindex 319e9d7cf..319e9d7cf 100644 --- a/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_lmp.9.png +++ b/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_lxx.9.png diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_right_background_lmp.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_right_background_lxx.9.png Binary files differindex 052032be7..052032be7 100644 --- a/java/res/drawable-xhdpi/keyboard_key_feedback_right_background_lmp.9.png +++ b/java/res/drawable-xhdpi/keyboard_key_feedback_right_background_lxx.9.png diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_right_more_background_lmp.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_right_more_background_lxx.9.png Binary files differindex c7e9d1c9e..c7e9d1c9e 100644 --- a/java/res/drawable-xhdpi/keyboard_key_feedback_right_more_background_lmp.9.png +++ b/java/res/drawable-xhdpi/keyboard_key_feedback_right_more_background_lxx.9.png diff --git a/java/res/drawable-xhdpi/keyboard_popup_panel_background_lmp.9.png b/java/res/drawable-xhdpi/keyboard_popup_panel_background_lxx.9.png Binary files differindex 36df715b6..36df715b6 100644 --- a/java/res/drawable-xhdpi/keyboard_popup_panel_background_lmp.9.png +++ b/java/res/drawable-xhdpi/keyboard_popup_panel_background_lxx.9.png diff --git a/java/res/drawable-xhdpi/sym_keyboard_mic_holo_dark.png b/java/res/drawable-xhdpi/sym_keyboard_mic_holo_dark.png Binary files differdeleted file mode 100644 index 566ba1fcd..000000000 --- a/java/res/drawable-xhdpi/sym_keyboard_mic_holo_dark.png +++ /dev/null diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_off_lxx.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_off_lxx.9.png Binary files differnew file mode 100644 index 000000000..97b049eb0 --- /dev/null +++ b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_off_lxx.9.png diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_on_lmp.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_on_lmp.9.png Binary files differdeleted file mode 100644 index 97f96258e..000000000 --- a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_on_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_on_lxx.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_on_lxx.9.png Binary files differnew file mode 100644 index 000000000..2e8149709 --- /dev/null +++ b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_on_lxx.9.png diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_lmp.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_lmp.9.png Binary files differdeleted file mode 100644 index dfb16a76b..000000000 --- a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png Binary files differdeleted file mode 100644 index bf1d34686..000000000 --- a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_off_lxx.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_off_lxx.9.png Binary files differnew file mode 100644 index 000000000..d844b1713 --- /dev/null +++ b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_off_lxx.9.png diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png Binary files differdeleted file mode 100644 index 962277165..000000000 --- a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_on_lxx.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_on_lxx.9.png Binary files differnew file mode 100644 index 000000000..9661f4a6e --- /dev/null +++ b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_on_lxx.9.png diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_light_pressed_lmp.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_light_pressed_lmp.9.png Binary files differdeleted file mode 100644 index 17144b673..000000000 --- a/java/res/drawable-xxhdpi/btn_keyboard_key_light_pressed_lmp.9.png +++ /dev/null diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_popup_selected_lmp.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_popup_selected_lxx.9.png Binary files differindex 0cbb2ec84..0cbb2ec84 100644 --- a/java/res/drawable-xxhdpi/btn_keyboard_key_popup_selected_lmp.9.png +++ b/java/res/drawable-xxhdpi/btn_keyboard_key_popup_selected_lxx.9.png diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_background_lmp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_background_lxx.9.png Binary files differindex fd2f9e514..fd2f9e514 100644 --- a/java/res/drawable-xxhdpi/keyboard_key_feedback_background_lmp.9.png +++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_background_lxx.9.png diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_lmp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_lxx.9.png Binary files differindex 3ab79007e..3ab79007e 100644 --- a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_lmp.9.png +++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_lxx.9.png diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_lmp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_lxx.9.png Binary files differindex 99543a1e0..99543a1e0 100644 --- a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_lmp.9.png +++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_lxx.9.png diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_lmp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_lxx.9.png Binary files differindex 121411a06..121411a06 100644 --- a/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_lmp.9.png +++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_lxx.9.png diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_lmp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_lxx.9.png Binary files differindex e9e379287..e9e379287 100644 --- a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_lmp.9.png +++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_lxx.9.png diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_lmp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_lxx.9.png Binary files differindex 6c1143aeb..6c1143aeb 100644 --- a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_lmp.9.png +++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_lxx.9.png diff --git a/java/res/drawable-xxhdpi/keyboard_popup_panel_background_lmp.9.png b/java/res/drawable-xxhdpi/keyboard_popup_panel_background_lxx.9.png Binary files differindex 91d5d7f90..91d5d7f90 100644 --- a/java/res/drawable-xxhdpi/keyboard_popup_panel_background_lmp.9.png +++ b/java/res/drawable-xxhdpi/keyboard_popup_panel_background_lxx.9.png diff --git a/java/res/drawable-xxhdpi/sym_keyboard_mic_holo_dark.png b/java/res/drawable-xxhdpi/sym_keyboard_mic_holo_dark.png Binary files differdeleted file mode 100644 index f55af308c..000000000 --- a/java/res/drawable-xxhdpi/sym_keyboard_mic_holo_dark.png +++ /dev/null diff --git a/java/res/drawable/btn_keyboard_key_functional_lmp.xml b/java/res/drawable/btn_keyboard_key_functional_lxx.xml index 427b8d568..fc6f98d01 100644 --- a/java/res/drawable/btn_keyboard_key_functional_lmp.xml +++ b/java/res/drawable/btn_keyboard_key_functional_lxx.xml @@ -17,6 +17,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- Functional keys. --> <item android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_dark_pressed_lmp" /> - <item android:drawable="@android:color/transparent" /> + android:drawable="@color/key_background_pressed_lxx" /> + <item android:drawable="@color/key_background_lxx" /> </selector> diff --git a/java/res/drawable/btn_keyboard_key_ics.xml b/java/res/drawable/btn_keyboard_key_ics.xml index 9db0eeef4..af14cd51c 100644 --- a/java/res/drawable/btn_keyboard_key_ics.xml +++ b/java/res/drawable/btn_keyboard_key_ics.xml @@ -15,12 +15,6 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <!-- Functional keys. --> - <item android:state_single="true" android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_dark_pressed_ics" /> - <item android:state_single="true" - android:drawable="@drawable/btn_keyboard_key_dark_normal_holo" /> - <!-- Action keys. --> <item android:state_active="true" android:state_pressed="true" android:drawable="@drawable/btn_keyboard_key_dark_pressed_ics" /> diff --git a/java/res/drawable/btn_keyboard_key_klp.xml b/java/res/drawable/btn_keyboard_key_klp.xml index 500e3ea75..56c295f14 100644 --- a/java/res/drawable/btn_keyboard_key_klp.xml +++ b/java/res/drawable/btn_keyboard_key_klp.xml @@ -15,12 +15,6 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <!-- Functional keys. --> - <item android:state_single="true" android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_dark_pressed_klp" /> - <item android:state_single="true" - android:drawable="@drawable/btn_keyboard_key_dark_normal_holo" /> - <!-- Action keys. --> <item android:state_active="true" android:state_pressed="true" android:drawable="@drawable/btn_keyboard_key_dark_pressed_klp" /> diff --git a/java/res/drawable/btn_keyboard_key_lmp.xml b/java/res/drawable/btn_keyboard_key_lxx.xml index fdd19df68..fc19a0bbd 100644 --- a/java/res/drawable/btn_keyboard_key_lmp.xml +++ b/java/res/drawable/btn_keyboard_key_lxx.xml @@ -15,34 +15,28 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <!-- Functional keys. --> - <item android:state_single="true" android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_dark_pressed_lmp" /> - <item android:state_single="true" - android:drawable="@android:color/transparent" /> - <!-- Action keys. --> <item android:state_active="true" android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_dark_pressed_lmp" /> + android:drawable="@color/key_background_pressed_lxx" /> <item android:state_active="true" - android:drawable="@android:color/transparent" /> + android:drawable="@color/key_background_lxx" /> <!-- Toggle keys. Use checkable/checked state. --> <item android:state_checkable="true" android:state_checked="true" android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_dark_pressed_on_lmp" /> + android:drawable="@drawable/btn_keyboard_key_dark_pressed_on_lxx" /> <item android:state_checkable="true" android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_dark_pressed_lmp" /> + android:drawable="@drawable/btn_keyboard_key_dark_pressed_off_lxx" /> <item android:state_checkable="true" android:state_checked="true" - android:drawable="@drawable/btn_keyboard_key_dark_normal_on_lmp" /> + android:drawable="@drawable/btn_keyboard_key_dark_normal_on_lxx" /> <item android:state_checkable="true" - android:drawable="@android:color/transparent" /> + android:drawable="@drawable/btn_keyboard_key_dark_normal_off_lxx" /> <!-- Empty background keys. --> <item android:state_empty="true" - android:drawable="@android:color/transparent" /> + android:drawable="@color/key_background_lxx" /> <!-- Normal keys. --> <item android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_light_pressed_lmp" /> - <item android:drawable="@android:color/transparent" /> + android:drawable="@color/key_background_pressed_lxx" /> + <item android:drawable="@color/key_background_lxx" /> </selector> diff --git a/java/res/drawable/btn_keyboard_key_popup_lmp.xml b/java/res/drawable/btn_keyboard_key_popup_lxx.xml index ebedaea3a..7daebc8d3 100644 --- a/java/res/drawable/btn_keyboard_key_popup_lmp.xml +++ b/java/res/drawable/btn_keyboard_key_popup_lxx.xml @@ -16,6 +16,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_popup_selected_lmp" /> + android:drawable="@drawable/btn_keyboard_key_popup_selected_lxx" /> <item android:drawable="@android:color/transparent" /> </selector> diff --git a/java/res/drawable/btn_keyboard_spacebar_lmp.xml b/java/res/drawable/btn_keyboard_spacebar_lxx.xml index 516cb0731..10d04a8cc 100644 --- a/java/res/drawable/btn_keyboard_spacebar_lmp.xml +++ b/java/res/drawable/btn_keyboard_spacebar_lxx.xml @@ -16,6 +16,6 @@ <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_light_pressed_lmp" /> - <item android:drawable="@android:color/transparent" /> + android:drawable="@color/key_background_pressed_lxx" /> + <item android:drawable="@color/key_background_lxx" /> </selector> diff --git a/java/res/drawable/btn_suggestion_lmp.xml b/java/res/drawable/btn_suggestion_lxx.xml index c778e236f..c73e1f772 100644 --- a/java/res/drawable/btn_suggestion_lmp.xml +++ b/java/res/drawable/btn_suggestion_lxx.xml @@ -23,5 +23,5 @@ > <item android:state_pressed="true" - android:drawable="@drawable/btn_keyboard_key_popup_selected_lmp" /> + android:drawable="@color/suggested_word_background_selected_lxx" /> </selector> diff --git a/java/res/drawable/keyboard_key_feedback_lmp.xml b/java/res/drawable/keyboard_key_feedback_lxx.xml index cdbe64c38..2abbc909d 100644 --- a/java/res/drawable/keyboard_key_feedback_lmp.xml +++ b/java/res/drawable/keyboard_key_feedback_lxx.xml @@ -20,17 +20,17 @@ > <!-- Left edge --> <item latin:state_left_edge="true" latin:state_has_morekeys="true" - android:drawable="@drawable/keyboard_key_feedback_left_more_background_lmp" /> + android:drawable="@drawable/keyboard_key_feedback_left_more_background_lxx" /> <item latin:state_left_edge="true" - android:drawable="@drawable/keyboard_key_feedback_left_background_lmp" /> + android:drawable="@drawable/keyboard_key_feedback_left_background_lxx" /> <!-- Right edge --> <item latin:state_right_edge="true" latin:state_has_morekeys="true" - android:drawable="@drawable/keyboard_key_feedback_right_more_background_lmp" /> + android:drawable="@drawable/keyboard_key_feedback_right_more_background_lxx" /> <item latin:state_right_edge="true" - android:drawable="@drawable/keyboard_key_feedback_right_background_lmp" /> + android:drawable="@drawable/keyboard_key_feedback_right_background_lxx" /> <item latin:state_has_morekeys="true" - android:drawable="@drawable/keyboard_key_feedback_more_background_lmp" /> - <item android:drawable="@drawable/keyboard_key_feedback_background_lmp" /> + android:drawable="@drawable/keyboard_key_feedback_more_background_lxx" /> + <item android:drawable="@drawable/keyboard_key_feedback_background_lxx" /> </selector> diff --git a/java/res/layout/emoji_keyboard_page.xml b/java/res/layout/emoji_keyboard_page.xml index 9afad366a..0d1086171 100644 --- a/java/res/layout/emoji_keyboard_page.xml +++ b/java/res/layout/emoji_keyboard_page.xml @@ -18,7 +18,7 @@ */ --> -<com.android.inputmethod.keyboard.internal.EmojiPageKeyboardView +<com.android.inputmethod.keyboard.emoji.EmojiPageKeyboardView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/emoji_keyboard_page" android:layoutDirection="ltr" diff --git a/java/res/layout/emoji_palettes_view.xml b/java/res/layout/emoji_palettes_view.xml index 552a474b4..761887168 100644 --- a/java/res/layout/emoji_palettes_view.xml +++ b/java/res/layout/emoji_palettes_view.xml @@ -18,7 +18,7 @@ */ --> -<com.android.inputmethod.keyboard.EmojiPalettesView +<com.android.inputmethod.keyboard.emoji.EmojiPalettesView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/emoji_keyboard_view" android:orientation="vertical" @@ -78,7 +78,7 @@ android:id="@+id/emoji_keyboard_pager" android:layout_width="match_parent" android:layout_height="wrap_content" /> - <com.android.inputmethod.keyboard.EmojiCategoryPageIndicatorView + <com.android.inputmethod.keyboard.emoji.EmojiCategoryPageIndicatorView android:id="@+id/emoji_category_page_id_view" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -109,4 +109,4 @@ android:gravity="center" android:layout_height="match_parent" /> </LinearLayout> -</com.android.inputmethod.keyboard.EmojiPalettesView> +</com.android.inputmethod.keyboard.emoji.EmojiPalettesView> diff --git a/java/res/values-km-rKH/strings.xml b/java/res/values-km-rKH/strings.xml index 519aa44d0..4d7de93c8 100644 --- a/java/res/values-km-rKH/strings.xml +++ b/java/res/values-km-rKH/strings.xml @@ -29,7 +29,7 @@ <string name="popup_on_keypress" msgid="123894815723512944">"លេចឡើងនៅពេលចុចគ្រាប់ចុច"</string> <string name="general_category" msgid="1859088467017573195">"ទូទៅ"</string> <string name="correction_category" msgid="2236750915056607613">"ការកែអត្ថបទ"</string> - <string name="gesture_typing_category" msgid="497263612130532630">"បញ្ចូលដោយប្រើកាយវិការ"</string> + <string name="gesture_typing_category" msgid="497263612130532630">"បញ្ចូលដោយប្រើកាយវិការ"</string> <string name="misc_category" msgid="6894192814868233453">"ជម្រើសផ្សេងទៀត"</string> <string name="advanced_settings" msgid="362895144495591463">"ការកំណត់កម្រិតខ្ពស់"</string> <string name="advanced_settings_summary" msgid="4487980456152830271">"ជម្រើសសម្រាប់អ្នកជំនាញ"</string> @@ -39,7 +39,7 @@ <string name="show_language_switch_key_summary" msgid="7343403647474265713">"បង្ហាញនៅពេលដែលបើកភាសាបញ្ចូលច្រើន"</string> <string name="sliding_key_input_preview" msgid="6604262359510068370">"បង្ហាញទ្រនិចបង្ហាញស្លាយ"</string> <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"បង្ហាញសញ្ញាមើលឃើញខណៈពេលដែលរុញពីឆ្វេង ឬគ្រាប់ចុចនិមិត្តសញ្ញា"</string> - <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"សោលេចឡើងបោះបង់ការពន្យារពេល"</string> + <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"សោលេចឡើងបោះបង់ការពន្យារពេល"</string> <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"គ្មានការពន្យារពេល"</string> <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"លំនាំដើម"</string> <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> មិល្លីវិនាទី"</string> @@ -49,7 +49,7 @@ <string name="use_personalized_dicts" msgid="5167396352105467626">"ការស្នើផ្ទាល់ខ្លួន"</string> <string name="use_double_space_period" msgid="8781529969425082860">"រយៈពេលចុចដកឃ្លាពីរដង"</string> <string name="use_double_space_period_summary" msgid="6532892187247952799">"ប៉ះដកឃ្លាពីរដងបញ្ចូលរយៈពេលដែលអនុវត្តតាមដកឃ្លា"</string> - <string name="auto_cap" msgid="1719746674854628252">"ការសរសេរជាអក្សរធំស្វ័យប្រវត្តិ"</string> + <string name="auto_cap" msgid="1719746674854628252">"ការសរសេរជាអក្សរធំស្វ័យប្រវត្តិ"</string> <string name="auto_cap_summary" msgid="7934452761022946874">"សរសេរពាក្យដំបូងជាអក្សរធំនៃប្រយោគនីមួយៗ"</string> <string name="edit_personal_dictionary" msgid="3996910038952940420">"វចនានុក្រមផ្ទាល់ខ្លួន"</string> <string name="configure_dictionaries_title" msgid="4238652338556902049">"ផ្នែកបន្ថែមវចនានុក្រម"</string> @@ -60,7 +60,7 @@ <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3859783767435239118">"បង្ហាញនៅក្នុងរបៀបបញ្ឈរ"</string> <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"លាក់ជានិច្ច"</string> <string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"ទប់ស្កាត់ពាក្យបំពាន"</string> - <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"កុំស្នើឲ្យពាក្យបំពានមានសក្ដានុពល"</string> + <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"កុំស្នើឲ្យពាក្យបំពានមានសក្ដានុពល"</string> <string name="auto_correction" msgid="7630720885194996950">"ការកែស្វ័យប្រវត្តិ"</string> <string name="auto_correction_summary" msgid="5625751551134658006">"ចន្លោះមិនឃើញ និងសញ្ញាវណ្ណយុត្តកែពាក្យដែលបានវាយខុសស្វ័យប្រវត្តិ"</string> <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"បិទ"</string> @@ -123,7 +123,7 @@ <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"ថិរវេលាញ័រពេលចុចគ្រាប់ចុច"</string> <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"កម្រិតសំឡេងពេលចុចគ្រាប់ចុច"</string> <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"អានឯកសារវចនានុក្រមខាងក្រៅ"</string> - <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"គ្មានឯកសារវចនានុក្រមនៅក្នុងថតទាញយក"</string> + <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"គ្មានឯកសារវចនានុក្រមនៅក្នុងថតទាញយក"</string> <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"ជ្រើសឯកសារវចនានុក្រម ដើម្បីដំឡើង"</string> <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"ពិតជាដំឡើងឯកសារនេះសម្រាប់ <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string> <string name="error" msgid="8940763624668513648">"មានកំហុស"</string> @@ -154,7 +154,7 @@ <string name="dictionary_provider_name" msgid="3027315045397363079">"កម្មវិធីផ្ដល់វចនានុក្រម"</string> <string name="dictionary_service_name" msgid="6237472350693511448">"សេវាកម្មវចនានុក្រម"</string> <string name="download_description" msgid="6014835283119198591">"ព័ត៌មានបច្ចុប្បន្នភាពវចនានុក្រម"</string> - <string name="dictionary_settings_title" msgid="8091417676045693313">"ផ្នែកបន្ថែមវចនានុក្រម"</string> + <string name="dictionary_settings_title" msgid="8091417676045693313">"ផ្នែកបន្ថែមវចនានុក្រម"</string> <string name="dictionary_install_over_metered_network_prompt" msgid="3587517870006332980">"វចនានុក្រមអាចប្រើបាន"</string> <string name="dictionary_settings_summary" msgid="5305694987799824349">"ការកំណត់សម្រាប់វចនានុក្រម"</string> <string name="user_dictionaries" msgid="3582332055892252845">"វចនានុក្រមអ្នកប្រើ"</string> @@ -170,10 +170,10 @@ <string name="message_updating" msgid="4457761393932375219">"ពិនិត្យមើលបច្ចុប្បន្នភាព"</string> <string name="message_loading" msgid="5638680861387748936">"កំពុងផ្ទុក..."</string> <string name="main_dict_description" msgid="3072821352793492143">"វចនានុក្រមចម្បង"</string> - <string name="cancel" msgid="6830980399865683324">"បោះបង់"</string> + <string name="cancel" msgid="6830980399865683324">"បោះបង់"</string> <string name="go_to_settings" msgid="3876892339342569259">"ការកំណត់"</string> <string name="install_dict" msgid="180852772562189365">"ដំឡើង"</string> - <string name="cancel_download_dict" msgid="7843340278507019303">"បោះបង់"</string> + <string name="cancel_download_dict" msgid="7843340278507019303">"បោះបង់"</string> <string name="delete_dict" msgid="756853268088330054">"លុប"</string> <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"ភាសាដែលបានជ្រើសនៅលើឧបករណ៍ចល័តមានវចនានុក្រមអាចប្រើបាន។<br/> យើងផ្ដល់អនុសាសន៍ឲ្យ <b>ទាញយក</b> វចនានុក្រមភាសា <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ដើម្បីបង្កើនបទពិសោធន៍វាយបញ្ចូលរបស់អ្នក។<br/> <br/> ការទាញយកអាចចំណាយពេលប្រហែលពីរនាទីនៅតាម 3G។ ការគិតថ្លៃអាចអនុវត្តប្រសិនបើអ្នកមិនប្រើ <b>ផែនការទិន្នន័យគ្មានដែនកំណត់</b>.<br/> បើអ្នកមិនប្រាកដថាផែនការណាមួយដែលអ្នកមាន យើងផ្ដល់អនុសាសន៍ឲ្យភ្ជាប់វ៉ាយហ្វាយ ដើម្បីចាប់ផ្ដើមទាញយកដោយស្វ័យប្រវត្តិ។<br/> <br/> ជំនួយ៖ អ្នកអាចទាញយក និងលុបវចនានុក្រមដោយចូលទៅ <b>ភាសា & ការបញ្ចូល</b> នៅក្នុងម៉ឺនុយ <b>ការកំណត់</b> សម្រាប់ឧបករណ៍ចល័ត។"</string> <string name="download_over_metered" msgid="1643065851159409546">"ទាញយកឥឡូវនេះ (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> មេកាបៃ)"</string> @@ -191,7 +191,7 @@ <string name="user_dict_settings_add_word_option_name" msgid="6665558053408962865">"ពាក្យ៖"</string> <string name="user_dict_settings_add_shortcut_option_name" msgid="3094731590655523777">"ផ្លូវកាត់៖"</string> <string name="user_dict_settings_add_locale_option_name" msgid="4738643440987277705">"ភាសា៖"</string> - <string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"វាយបញ្ចូលពាក្យ"</string> + <string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"វាយបញ្ចូលពាក្យ"</string> <string name="user_dict_settings_add_shortcut_hint" msgid="2265453012555060178">"ផ្លូវកាត់ជាជម្រើស"</string> <string name="user_dict_settings_edit_dialog_title" msgid="3765774633869590352">"កែពាក្យ"</string> <string name="user_dict_settings_context_menu_edit_title" msgid="6812255903472456302">"កែ"</string> diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index 769a1d986..79cc139a2 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -41,13 +41,16 @@ </declare-styleable> <declare-styleable name="KeyboardView"> - <!-- Image for the key. This image needs to be a {@link StateListDrawable}, with the - following possible states: normal, pressed, checkable, checkable+pressed, + <!-- Background image for the key. This image needs to be a {@link StateListDrawable}, + with the following possible states: normal, pressed, checkable, checkable+pressed, checkable+checked, checkable+checked+pressed. --> <attr name="keyBackground" format="reference" /> - <!-- Image for the functional key used in Emoji layout. --> - <attr name="keyBackgroundEmojiFunctional" format="reference" /> - + <!-- Background image for the functional key. This image needs to be a + {@link StateListDrawable}, with the following possible states: normal, pressed. --> + <attr name="functionalKeyBackground" format="reference" /> + <!-- Background image for the spacebar. This image needs to be a + {@link StateListDrawable}, with the following possible states: normal, pressed. --> + <attr name="spacebarBackground" format="reference" /> <!-- Horizontal padding of left/right aligned key label to the edge of the key. --> <attr name="keyLabelHorizontalPadding" format="dimension" /> <!-- Right padding of hint letter to the edge of the key.--> @@ -76,8 +79,6 @@ <attr name="languageOnSpacebarTextColor" format="color" /> <attr name="languageOnSpacebarTextShadowRadius" format="float" /> <attr name="languageOnSpacebarTextShadowColor" format="color" /> - <!-- Background image for the spacebar. --> - <attr name="spacebarBackground" format="reference" /> <!-- Fadeout animator for spacebar language label. --> <attr name="languageOnSpacebarFinalAlpha" format="integer" /> <attr name="languageOnSpacebarFadeoutAnimator" format="reference" /> diff --git a/java/res/values/colors.xml b/java/res/values/colors.xml index baa0887bc..60b5cdfae 100644 --- a/java/res/values/colors.xml +++ b/java/res/values/colors.xml @@ -39,12 +39,18 @@ <color name="typed_word_color_klp">#D8F0F0F0</color> <color name="suggested_word_color_klp">#B2F0F0F0</color> <color name="highlight_translucent_color_klp">#99E0E0E0</color> - <!-- Color resources for LMP theme. Base color = F0F0F0 --> - <color name="key_hint_letter_color_lmp">@android:color/white</color> - <color name="highlight_color_lmp">#FFF0F0F0</color> - <color name="typed_word_color_lmp">#D8F0F0F0</color> - <color name="suggested_word_color_lmp">#B2F0F0F0</color> - <color name="highlight_translucent_color_lmp">#99E0E0E0</color> + <!-- Color resources for LXX theme. Base color = F0F0F0 --> + <color name="key_text_inactive_color_lxx">#808184</color> + <color name="key_hint_letter_color_lxx">#808184</color> + <color name="highlight_color_lxx">#7FCAC3</color> + <color name="typed_word_color_lxx">#D87FCAC3</color> + <color name="suggested_word_color_lxx">#B27FCAC3</color> + <color name="highlight_translucent_color_lxx">#997FCAC3</color> + <color name="keyboard_background_lxx">#384248</color> + <color name="key_background_lxx">#384248</color> + <color name="key_background_pressed_lxx">#546872</color> + <color name="suggestions_strip_background_lxx">#263238</color> + <color name="suggested_word_background_selected_lxx">#384248</color> <!-- Color resources for setup wizard and tutorial --> <color name="setup_background">#FFEBEBEB</color> <color name="setup_text_dark">#FF707070</color> diff --git a/java/res/values/config-common.xml b/java/res/values/config-common.xml index 1962c0d45..ad27ab427 100644 --- a/java/res/values/config-common.xml +++ b/java/res/values/config-common.xml @@ -133,7 +133,7 @@ <integer name="config_gesture_trail_shadow_ratio">-1</integer> <!-- Common configuration of Emoji keyboard --> - <dimen name="config_emoji_category_page_id_height">3dp</dimen> + <dimen name="config_emoji_category_page_id_height">2dp</dimen> <!-- Inset used in Accessibility mode to avoid accidental key presses when a finger slides off the screen. --> <dimen name="config_accessibility_edge_slop">8dp</dimen> diff --git a/java/res/values/keyboard-icons-lmp.xml b/java/res/values/keyboard-icons-lxx.xml index 39e0fe306..ea4b6e65c 100644 --- a/java/res/values/keyboard-icons-lmp.xml +++ b/java/res/values/keyboard-icons-lxx.xml @@ -19,7 +19,7 @@ --> <resources xmlns:android="http://schemas.android.com/apk/res/android"> - <style name="KeyboardIcons.LMP"> + <style name="KeyboardIcons.LXX"> <!-- Keyboard icons --> <item name="iconShiftKey">@drawable/sym_keyboard_shift_holo_dark</item> <item name="iconDeleteKey">@drawable/sym_keyboard_delete_holo_dark</item> diff --git a/java/res/values/themes-common.xml b/java/res/values/themes-common.xml index 76abb10fb..df26fb3b4 100644 --- a/java/res/values/themes-common.xml +++ b/java/res/values/themes-common.xml @@ -109,12 +109,7 @@ <style name="KeyPreviewTextView" /> <!-- Though {@link EmojiPalettesView} doesn't extend {@link KeyboardView}, some views inside it, for instance delete button, need themed {@link KeyboardView} attributes. --> - <style - name="EmojiPalettesView" - parent="KeyboardView" - > - <item name="emojiTabLabelColor">@color/emoji_tab_label_color_holo</item> - </style> + <style name="EmojiPalettesView" /> <style name="MoreKeysKeyboard" /> <style name="MoreKeysKeyboardView" diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml index d7943eeaf..560cfc505 100644 --- a/java/res/values/themes-ics.xml +++ b/java/res/values/themes-ics.xml @@ -48,6 +48,8 @@ > <item name="android:background">@drawable/keyboard_background_holo</item> <item name="keyBackground">@drawable/btn_keyboard_key_ics</item> + <item name="functionalKeyBackground">@drawable/btn_keyboard_key_functional_ics</item> + <item name="spacebarBackground">@drawable/btn_keyboard_spacebar_ics</item> <item name="keyTypeface">bold</item> <item name="keyTextColor">@color/key_text_color_holo</item> <item name="keyTextInactivatedColor">@color/key_text_inactivated_color_holo</item> @@ -73,7 +75,6 @@ <item name="languageOnSpacebarTextColor">@color/spacebar_text_color_holo</item> <item name="languageOnSpacebarTextShadowRadius">1.0</item> <item name="languageOnSpacebarTextShadowColor">@color/spacebar_text_shadow_color_holo</item> - <item name="spacebarBackground">@drawable/btn_keyboard_spacebar_ics</item> </style> <style name="KeyPreviewTextView.ICS" @@ -85,9 +86,8 @@ for instance delete button, need themed {@link KeyboardView} attributes. --> <style name="EmojiPalettesView.ICS" - parent="KeyboardView.ICS" + parent="MainKeyboardView.ICS" > - <item name="keyBackgroundEmojiFunctional">@drawable/btn_keyboard_key_functional_ics</item> <item name="emojiTabLabelColor">@color/emoji_tab_label_color_holo</item> </style> <style diff --git a/java/res/values/themes-klp.xml b/java/res/values/themes-klp.xml index 13500fef2..453e5cbce 100644 --- a/java/res/values/themes-klp.xml +++ b/java/res/values/themes-klp.xml @@ -48,6 +48,8 @@ > <item name="android:background">@drawable/keyboard_background_holo</item> <item name="keyBackground">@drawable/btn_keyboard_key_klp</item> + <item name="functionalKeyBackground">@drawable/btn_keyboard_key_functional_klp</item> + <item name="spacebarBackground">@drawable/btn_keyboard_spacebar_klp</item> <item name="keyTypeface">bold</item> <item name="keyTextColor">@color/key_text_color_holo</item> <item name="keyTextInactivatedColor">@color/key_text_inactivated_color_holo</item> @@ -73,7 +75,6 @@ <item name="languageOnSpacebarTextColor">@color/spacebar_text_color_holo</item> <item name="languageOnSpacebarTextShadowRadius">1.0</item> <item name="languageOnSpacebarTextShadowColor">@color/spacebar_text_shadow_color_holo</item> - <item name="spacebarBackground">@drawable/btn_keyboard_spacebar_klp</item> </style> <style name="KeyPreviewTextView.KLP" @@ -85,9 +86,8 @@ for instance delete button, need themed {@link KeyboardView} attributes. --> <style name="EmojiPalettesView.KLP" - parent="KeyboardView.KLP" + parent="MainKeyboardView.KLP" > - <item name="keyBackgroundEmojiFunctional">@drawable/btn_keyboard_key_functional_klp</item> <item name="emojiTabLabelColor">@color/emoji_tab_label_color_holo</item> </style> <style diff --git a/java/res/values/themes-lmp.xml b/java/res/values/themes-lxx.xml index 41c4d09d5..4f3ee80c9 100644 --- a/java/res/values/themes-lmp.xml +++ b/java/res/values/themes-lxx.xml @@ -19,23 +19,23 @@ --> <resources xmlns:android="http://schemas.android.com/apk/res/android"> - <style name="KeyboardTheme.LMP" parent="KeyboardIcons.LMP"> - <item name="keyboardStyle">@style/Keyboard.LMP</item> - <item name="keyboardViewStyle">@style/KeyboardView.LMP</item> - <item name="mainKeyboardViewStyle">@style/MainKeyboardView.LMP</item> - <item name="keyPreviewTextViewStyle">@style/KeyPreviewTextView.LMP</item> - <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.LMP</item> - <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.LMP</item> - <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.LMP</item> - <item name="suggestionStripViewStyle">@style/SuggestionStripView.LMP</item> - <item name="suggestionWordStyle">@style/SuggestionWord.LMP</item> + <style name="KeyboardTheme.LXX" parent="KeyboardIcons.LXX"> + <item name="keyboardStyle">@style/Keyboard.LXX</item> + <item name="keyboardViewStyle">@style/KeyboardView.LXX</item> + <item name="mainKeyboardViewStyle">@style/MainKeyboardView.LXX</item> + <item name="keyPreviewTextViewStyle">@style/KeyPreviewTextView.LXX</item> + <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.LXX</item> + <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.LXX</item> + <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.LXX</item> + <item name="suggestionStripViewStyle">@style/SuggestionStripView.LXX</item> + <item name="suggestionWordStyle">@style/SuggestionWord.LXX</item> </style> <style - name="Keyboard.LMP" + name="Keyboard.LXX" parent="Keyboard" > <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] --> - <item name="themeId">0</item> + <item name="themeId">3</item> <item name="keyboardTopPadding">@fraction/config_keyboard_top_padding_holo</item> <item name="keyboardBottomPadding">@fraction/config_keyboard_bottom_padding_holo</item> <item name="horizontalGap">@fraction/config_key_horizontal_gap_holo</item> @@ -43,56 +43,56 @@ <item name="touchPositionCorrectionData">@array/touch_position_correction_data_holo</item> </style> <style - name="KeyboardView.LMP" + name="KeyboardView.LXX" parent="KeyboardView" > - <item name="android:background">@drawable/keyboard_background_holo</item> - <item name="keyBackground">@drawable/btn_keyboard_key_lmp</item> + <item name="android:background">@color/keyboard_background_lxx</item> + <item name="keyBackground">@drawable/btn_keyboard_key_lxx</item> + <item name="functionalKeyBackground">@drawable/btn_keyboard_key_functional_lxx</item> + <item name="spacebarBackground">@drawable/btn_keyboard_spacebar_lxx</item> <item name="keyTypeface">bold</item> <item name="keyTextColor">@color/key_text_color_holo</item> - <item name="keyTextInactivatedColor">@color/key_text_inactivated_color_holo</item> - <item name="keyHintLetterColor">@color/key_hint_letter_color_lmp</item> - <item name="keyHintLabelColor">@color/key_hint_label_color_holo</item> - <item name="keyShiftedLetterHintInactivatedColor">@color/key_shifted_letter_hint_inactivated_color_holo</item> - <item name="keyShiftedLetterHintActivatedColor">@color/key_shifted_letter_hint_activated_color_holo</item> + <item name="keyTextInactivatedColor">@color/key_text_inactive_color_lxx</item> + <item name="keyHintLetterColor">@color/key_hint_letter_color_lxx</item> + <item name="keyHintLabelColor">@color/key_text_inactive_color_lxx</item> + <item name="keyShiftedLetterHintInactivatedColor">@color/key_text_inactive_color_lxx</item> + <item name="keyShiftedLetterHintActivatedColor">@color/key_text_color_holo</item> <item name="keyPreviewTextColor">@color/key_text_color_holo</item> <!-- A negative value to disable key text shadow layer. --> <item name="keyTextShadowRadius">-1.0</item> </style> <style - name="MainKeyboardView.LMP" - parent="KeyboardView.LMP" + name="MainKeyboardView.LXX" + parent="KeyboardView.LXX" > <item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item> - <item name="gestureFloatingPreviewTextColor">@color/highlight_color_lmp</item> + <item name="gestureFloatingPreviewTextColor">@color/highlight_color_lxx</item> <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_holo</item> - <item name="gestureTrailColor">@color/highlight_color_lmp</item> - <item name="slidingKeyInputPreviewColor">@color/highlight_translucent_color_lmp</item> + <item name="gestureTrailColor">@color/highlight_color_lxx</item> + <item name="slidingKeyInputPreviewColor">@color/highlight_translucent_color_lxx</item> <item name="autoCorrectionSpacebarLedEnabled">false</item> <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led_holo</item> - <item name="languageOnSpacebarTextColor">@color/spacebar_text_color_holo</item> - <item name="languageOnSpacebarTextShadowRadius">1.0</item> - <item name="languageOnSpacebarTextShadowColor">@color/spacebar_text_shadow_color_holo</item> - <item name="spacebarBackground">@drawable/btn_keyboard_spacebar_lmp</item> + <item name="languageOnSpacebarTextColor">@color/key_text_inactive_color_lxx</item> + <!-- A negative value to disable text shadow layer. --> + <item name="languageOnSpacebarTextShadowRadius">-1.0</item> </style> <style - name="KeyPreviewTextView.LMP" + name="KeyPreviewTextView.LXX" parent="KeyPreviewTextView" > - <item name="android:background">@drawable/keyboard_key_feedback_lmp</item> + <item name="android:background">@drawable/keyboard_key_feedback_lxx</item> </style> <!-- Though {@link EmojiPalettesView} doesn't extend {@link KeyboardView}, some views inside it, for instance delete button, need themed {@link KeyboardView} attributes. --> <style - name="EmojiPalettesView.LMP" - parent="KeyboardView.LMP" + name="EmojiPalettesView.LXX" + parent="MainKeyboardView.LXX" > - <item name="keyBackgroundEmojiFunctional">@drawable/btn_keyboard_key_functional_lmp</item> - <item name="emojiTabLabelColor">@color/emoji_tab_label_color_holo</item> + <item name="emojiTabLabelColor">@color/emoji_tab_label_color_lxx</item> </style> <style - name="MoreKeysKeyboard.LMP" - parent="Keyboard.LMP" + name="MoreKeysKeyboard.LXX" + parent="Keyboard.LXX" > <item name="keyboardTopPadding">0%p</item> <item name="keyboardBottomPadding">0%p</item> @@ -100,17 +100,17 @@ <item name="touchPositionCorrectionData">@null</item> </style> <style - name="MoreKeysKeyboardView.LMP" - parent="KeyboardView.LMP" + name="MoreKeysKeyboardView.LXX" + parent="KeyboardView.LXX" > - <item name="android:background">@drawable/keyboard_popup_panel_background_lmp</item> - <item name="keyBackground">@drawable/btn_keyboard_key_popup_lmp</item> + <item name="android:background">@drawable/keyboard_popup_panel_background_lxx</item> + <item name="keyBackground">@drawable/btn_keyboard_key_popup_lxx</item> <item name="keyTypeface">normal</item> <item name="verticalCorrection">@dimen/config_more_keys_keyboard_vertical_correction_holo</item> </style> <style - name="SuggestionStripView.LMP" - parent="KeyboardView.LMP" + name="SuggestionStripView.LXX" + parent="KeyboardView.LXX" > <item name="suggestionsCountInStrip">@integer/config_suggestions_count_in_strip</item> <item name="centerSuggestionPercentile">@fraction/config_center_suggestion_percentile</item> @@ -118,17 +118,17 @@ <item name="minMoreSuggestionsWidth">@fraction/config_min_more_suggestions_width</item> <item name="android:background">@drawable/keyboard_suggest_strip_holo</item> <item name="suggestionStripOptions">autoCorrectBold|validTypedWordBold</item> - <item name="colorValidTypedWord">@color/typed_word_color_lmp</item> - <item name="colorTypedWord">@color/typed_word_color_lmp</item> - <item name="colorAutoCorrect">@color/highlight_color_lmp</item> - <item name="colorSuggested">@color/suggested_word_color_lmp</item> + <item name="colorValidTypedWord">@color/typed_word_color_lxx</item> + <item name="colorTypedWord">@color/typed_word_color_lxx</item> + <item name="colorAutoCorrect">@color/highlight_color_lxx</item> + <item name="colorSuggested">@color/suggested_word_color_lxx</item> <item name="alphaObsoleted">70%</item> </style> <style - name="SuggestionWord.LMP" + name="SuggestionWord.LXX" parent="SuggestionWord" > - <item name="android:background">@drawable/btn_suggestion_lmp</item> - <item name="android:textColor">@color/highlight_color_lmp</item> + <item name="android:background">@drawable/btn_suggestion_lxx</item> + <item name="android:textColor">@color/highlight_color_lxx</item> </style> </resources> diff --git a/java/src/com/android/inputmethod/event/CombinerChain.java b/java/src/com/android/inputmethod/event/CombinerChain.java index 990f7deea..9e7f04d4f 100644 --- a/java/src/com/android/inputmethod/event/CombinerChain.java +++ b/java/src/com/android/inputmethod/event/CombinerChain.java @@ -56,18 +56,20 @@ public class CombinerChain { * * The combiner chain takes events as inputs and outputs code points and combining state. * For example, if the input language is Japanese, the combining chain will typically perform - * kana conversion. + * kana conversion. This takes a string for initial text, taken to be present before the + * cursor: we'll start after this. * + * @param initialText The text that has already been combined so far. * @param combinerList A list of combiners to be applied in order. */ - public CombinerChain(final Combiner... combinerList) { + public CombinerChain(final String initialText, final Combiner... combinerList) { mCombiners = CollectionUtils.newArrayList(); // The dead key combiner is always active, and always first mCombiners.add(new DeadKeyCombiner()); for (final Combiner combiner : combinerList) { mCombiners.add(combiner); } - mCombinedText = new StringBuilder(); + mCombinedText = new StringBuilder(initialText); mStateFeedback = new SpannableStringBuilder(); } diff --git a/java/src/com/android/inputmethod/event/MyanmarReordering.java b/java/src/com/android/inputmethod/event/MyanmarReordering.java index 27b8c14bb..da0228bd2 100644 --- a/java/src/com/android/inputmethod/event/MyanmarReordering.java +++ b/java/src/com/android/inputmethod/event/MyanmarReordering.java @@ -207,9 +207,33 @@ public class MyanmarReordering implements Combiner { return clearAndGetResultingEvent(newEvent); } } else if (Constants.CODE_DELETE == newEvent.mKeyCode) { - if (mCurrentEvents.size() > 0) { - mCurrentEvents.remove(mCurrentEvents.size() - 1); - return null; + final Event lastEvent = getLastEvent(); + final int eventSize = mCurrentEvents.size(); + if (null != lastEvent) { + if (VOWEL_E == lastEvent.mCodePoint) { + // We have a VOWEL_E at the end. There are four cases. + // - The vowel is the only code point in the buffer. Remove it. + // - The vowel is preceded by a ZWNJ. Remove both vowel E and ZWNJ. + // - The vowel is preceded by a consonant/medial, remove the consonant/medial. + // - In all other cases, it's strange, so just remove the last code point. + if (eventSize <= 1) { + mCurrentEvents.clear(); + } else { // eventSize >= 2 + final int previousCodePoint = mCurrentEvents.get(eventSize - 2).mCodePoint; + if (previousCodePoint == ZERO_WIDTH_NON_JOINER) { + mCurrentEvents.remove(eventSize - 1); + mCurrentEvents.remove(eventSize - 2); + } else if (isConsonantOrMedial(previousCodePoint)) { + mCurrentEvents.remove(eventSize - 2); + } else { + mCurrentEvents.remove(eventSize - 1); + } + } + return null; + } else if (eventSize > 0) { + mCurrentEvents.remove(eventSize - 1); + return null; + } } } // This character is not part of the combining scheme, so we should reset everything. diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index 816a94300..4c2250740 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -218,7 +218,7 @@ public class Key implements Comparable<Key> { * * @param keySpec the key specification. * @param keyAttr the Key XML attributes array. - * @param keyStyle the {@link KeyStyle} of this key. + * @param style the {@link KeyStyle} of this key. * @param params the keyboard building parameters. * @param row the row that this key belongs to. row's x-coordinate will be the right edge of * this key. @@ -857,17 +857,6 @@ public class Key implements Comparable<Key> { android.R.attr.state_empty }; - // functional normal state (with properties) - private static final int[] KEY_STATE_FUNCTIONAL_NORMAL = { - android.R.attr.state_single - }; - - // functional pressed state (with properties) - private static final int[] KEY_STATE_FUNCTIONAL_PRESSED = { - android.R.attr.state_single, - android.R.attr.state_pressed - }; - // action normal state (with properties) private static final int[] KEY_STATE_ACTIVE_NORMAL = { android.R.attr.state_active @@ -880,25 +869,43 @@ public class Key implements Comparable<Key> { }; /** - * Returns the drawable state for the key, based on the current state and type of the key. - * @return the drawable state of the key. + * Returns the background drawable for the key, based on the current state and type of the key. + * @return the background drawable of the key. * @see android.graphics.drawable.StateListDrawable#setState(int[]) */ - public final int[] getCurrentDrawableState() { + public final Drawable selectBackgroundDrawable(final Drawable keyBackground, + final Drawable functionalKeyBackground, final Drawable spacebarBackground) { + final Drawable background; + if (mBackgroundType == BACKGROUND_TYPE_FUNCTIONAL) { + background = functionalKeyBackground; + } else if (getCode() == Constants.CODE_SPACE) { + background = spacebarBackground; + } else { + background = keyBackground; + } + final int[] stateSet; switch (mBackgroundType) { - case BACKGROUND_TYPE_FUNCTIONAL: - return mPressed ? KEY_STATE_FUNCTIONAL_PRESSED : KEY_STATE_FUNCTIONAL_NORMAL; case BACKGROUND_TYPE_ACTION: - return mPressed ? KEY_STATE_ACTIVE_PRESSED : KEY_STATE_ACTIVE_NORMAL; + stateSet = mPressed ? KEY_STATE_ACTIVE_PRESSED : KEY_STATE_ACTIVE_NORMAL; + break; case BACKGROUND_TYPE_STICKY_OFF: - return mPressed ? KEY_STATE_PRESSED_HIGHLIGHT_OFF : KEY_STATE_NORMAL_HIGHLIGHT_OFF; + stateSet = mPressed ? KEY_STATE_PRESSED_HIGHLIGHT_OFF : KEY_STATE_NORMAL_HIGHLIGHT_OFF; + break; case BACKGROUND_TYPE_STICKY_ON: - return mPressed ? KEY_STATE_PRESSED_HIGHLIGHT_ON : KEY_STATE_NORMAL_HIGHLIGHT_ON; + stateSet = mPressed ? KEY_STATE_PRESSED_HIGHLIGHT_ON : KEY_STATE_NORMAL_HIGHLIGHT_ON; + break; case BACKGROUND_TYPE_EMPTY: - return mPressed ? KEY_STATE_PRESSED : KEY_STATE_EMPTY; + stateSet = mPressed ? KEY_STATE_PRESSED : KEY_STATE_EMPTY; + break; + case BACKGROUND_TYPE_FUNCTIONAL: + stateSet = mPressed ? KEY_STATE_PRESSED : KEY_STATE_NORMAL; + break; default: /* BACKGROUND_TYPE_NORMAL */ - return mPressed ? KEY_STATE_PRESSED : KEY_STATE_NORMAL; + stateSet = mPressed ? KEY_STATE_PRESSED : KEY_STATE_NORMAL; + break; } + background.setState(stateSet); + return background; } public static class Spacer extends Key { diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 4a46a4a46..fc9faa6e3 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -28,6 +28,7 @@ import android.view.inputmethod.EditorInfo; import com.android.inputmethod.compat.InputMethodServiceCompatUtils; import com.android.inputmethod.keyboard.KeyboardLayoutSet.KeyboardLayoutSetException; +import com.android.inputmethod.keyboard.emoji.EmojiPalettesView; import com.android.inputmethod.keyboard.internal.KeyboardState; import com.android.inputmethod.keyboard.internal.KeyboardTextsSet; import com.android.inputmethod.latin.InputView; @@ -253,10 +254,11 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { // Implements {@link KeyboardState.SwitchActions}. @Override public void setEmojiKeyboard() { + final Keyboard keyboard = mKeyboardView.getKeyboard(); mMainKeyboardFrame.setVisibility(View.GONE); mEmojiPalettesView.startEmojiPalettes( mKeyboardTextsSet.getText(KeyboardTextsSet.SWITCH_TO_ALPHA_KEY_LABEL), - mKeyboardView.getKeyVisualAttribute()); + mKeyboardView.getKeyVisualAttribute(), keyboard.mIconsSet); mEmojiPalettesView.setVisibility(View.VISIBLE); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java index 429c7ddd7..e0b74fa14 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java @@ -34,7 +34,7 @@ public final class KeyboardTheme { static final int THEME_ID_ICS = 0; static final int THEME_ID_KLP = 2; - static final int THEME_ID_LMP = 3; + static final int THEME_ID_LXX = 3; static final int DEFAULT_THEME_ID = THEME_ID_KLP; private static final KeyboardTheme[] KEYBOARD_THEMES = { @@ -42,7 +42,7 @@ public final class KeyboardTheme { VERSION_CODES.ICE_CREAM_SANDWICH), new KeyboardTheme(THEME_ID_KLP, R.style.KeyboardTheme_KLP, VERSION_CODES.KITKAT), - new KeyboardTheme(THEME_ID_LMP, R.style.KeyboardTheme_LMP, + new KeyboardTheme(THEME_ID_LXX, R.style.KeyboardTheme_LXX, // TODO: Update this constant once the *next* version becomes available. VERSION_CODES.CUR_DEVELOPMENT), }; @@ -88,7 +88,7 @@ public final class KeyboardTheme { return 5; case THEME_ID_KLP: return 9; - case THEME_ID_LMP: + case THEME_ID_LXX: return 10; default: // Invalid theme return -1; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 4450a4474..a6eac4cd7 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -47,6 +47,8 @@ import java.util.HashSet; * A view that renders a virtual {@link Keyboard}. * * @attr ref R.styleable#KeyboardView_keyBackground + * @attr ref R.styleable#KeyboardView_functionalKeyBackground + * @attr ref R.styleable#KeyboardView_spacebarBackground * @attr ref R.styleable#KeyboardView_keyLabelHorizontalPadding * @attr ref R.styleable#KeyboardView_keyHintLetterPadding * @attr ref R.styleable#KeyboardView_keyPopupHintLetterPadding @@ -81,6 +83,8 @@ public class KeyboardView extends View { private final float mKeyTextShadowRadius; private final float mVerticalCorrection; private final Drawable mKeyBackground; + private final Drawable mFunctionalKeyBackground; + private final Drawable mSpacebarBackground; private final Rect mKeyBackgroundPadding = new Rect(); private static final float KET_TEXT_SHADOW_RADIUS_DISABLED = -1.0f; @@ -125,6 +129,14 @@ public class KeyboardView extends View { R.styleable.KeyboardView, defStyle, R.style.KeyboardView); mKeyBackground = keyboardViewAttr.getDrawable(R.styleable.KeyboardView_keyBackground); mKeyBackground.getPadding(mKeyBackgroundPadding); + final Drawable functionalKeyBackground = keyboardViewAttr.getDrawable( + R.styleable.KeyboardView_functionalKeyBackground); + mFunctionalKeyBackground = (functionalKeyBackground != null) ? functionalKeyBackground + : mKeyBackground; + final Drawable spacebarBackground = keyboardViewAttr.getDrawable( + R.styleable.KeyboardView_spacebarBackground); + mSpacebarBackground = (spacebarBackground != null) ? spacebarBackground + : mKeyBackground; mKeyLabelHorizontalPadding = keyboardViewAttr.getDimensionPixelOffset( R.styleable.KeyboardView_keyLabelHorizontalPadding, 0); mKeyHintLetterPadding = keyboardViewAttr.getDimension( @@ -324,7 +336,9 @@ public class KeyboardView extends View { params.mAnimAlpha = Constants.Color.ALPHA_OPAQUE; if (!key.isSpacer()) { - onDrawKeyBackground(key, canvas, mKeyBackground); + final Drawable background = key.selectBackgroundDrawable( + mKeyBackground, mFunctionalKeyBackground, mSpacebarBackground); + onDrawKeyBackground(key, canvas, background); } onDrawKeyTopVisuals(key, canvas, paint, params); @@ -339,8 +353,6 @@ public class KeyboardView extends View { final int bgHeight = key.getHeight() + padding.top + padding.bottom; final int bgX = -padding.left; final int bgY = -padding.top; - final int[] drawableState = key.getCurrentDrawableState(); - background.setState(drawableState); final Rect bounds = background.getBounds(); if (bgWidth != bounds.right || bgHeight != bounds.bottom) { background.setBounds(0, 0, bgWidth, bgHeight); diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 1a8e4b7e9..4a0976845 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -76,7 +76,6 @@ import java.util.WeakHashMap; * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextColor * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextShadowRadius * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextShadowColor - * @attr ref R.styleable#MainKeyboardView_spacebarBackground * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarFinalAlpha * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarFadeoutAnimator * @attr ref R.styleable#MainKeyboardView_altCodeKeyWhileTypingFadeoutAnimator @@ -120,7 +119,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack /* Space key and its icon and background. */ private Key mSpaceKey; private Drawable mSpacebarIcon; - private final Drawable mSpacebarBackground; // Stuff to draw language name on spacebar. private final int mLanguageOnSpacebarFinalAlpha; private ObjectAnimator mLanguageOnSpacebarFadeoutAnimator; @@ -154,7 +152,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack private final SlidingKeyInputDrawingPreview mSlidingKeyInputDrawingPreview; // Key preview - private static final boolean FADE_OUT_KEY_TOP_LETTER_WHEN_KEY_IS_PRESSED = false; private final KeyPreviewDrawParams mKeyPreviewDrawParams; private final KeyPreviewChoreographer mKeyPreviewChoreographer; @@ -224,8 +221,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack R.styleable.MainKeyboardView_backgroundDimAlpha, 0); mBackgroundDimAlphaPaint.setColor(Color.BLACK); mBackgroundDimAlphaPaint.setAlpha(backgroundDimAlpha); - mSpacebarBackground = mainKeyboardViewAttr.getDrawable( - R.styleable.MainKeyboardView_spacebarBackground); mAutoCorrectionSpacebarLedEnabled = mainKeyboardViewAttr.getBoolean( R.styleable.MainKeyboardView_autoCorrectionSpacebarLedEnabled, false); mAutoCorrectionSpacebarLedIcon = mainKeyboardViewAttr.getDrawable( @@ -557,6 +552,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } // Note that this method is called from a non-UI thread. + @SuppressWarnings("static-method") public void setMainDictionaryAvailability(final boolean mainDictionaryAvailable) { PointerTracker.setMainDictionaryAvailability(mainDictionaryAvailable); } @@ -864,30 +860,12 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } } - // Draw key background. - @Override - protected void onDrawKeyBackground(final Key key, final Canvas canvas, - final Drawable background) { - if (key.getCode() == Constants.CODE_SPACE) { - super.onDrawKeyBackground(key, canvas, mSpacebarBackground); - return; - } - super.onDrawKeyBackground(key, canvas, background); - } - @Override protected void onDrawKeyTopVisuals(final Key key, final Canvas canvas, final Paint paint, final KeyDrawParams params) { if (key.altCodeWhileTyping() && key.isEnabled()) { params.mAnimAlpha = mAltCodeKeyWhileTypingAnimAlpha; } - // Don't draw key top letter when key preview is showing. - if (FADE_OUT_KEY_TOP_LETTER_WHEN_KEY_IS_PRESSED - && mKeyPreviewChoreographer.isShowingKeyPreview(key)) { - // TODO: Fade out animation for the key top letter, and fade in animation for the key - // background color when the user presses the key. - return; - } final int code = key.getCode(); if (code == Constants.CODE_SPACE) { drawSpacebar(key, canvas, paint); diff --git a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java b/java/src/com/android/inputmethod/keyboard/emoji/DynamicGridKeyboard.java index 67a222732..c7a9025c0 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/emoji/DynamicGridKeyboard.java @@ -14,13 +14,12 @@ * limitations under the License. */ -package com.android.inputmethod.keyboard.internal; +package com.android.inputmethod.keyboard.emoji; import android.content.SharedPreferences; import android.text.TextUtils; import android.util.Log; -import com.android.inputmethod.keyboard.EmojiPalettesView; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.settings.Settings; @@ -36,7 +35,7 @@ import java.util.List; /** * This is a Keyboard class where you can add keys dynamically shown in a grid layout */ -public class DynamicGridKeyboard extends Keyboard { +final class DynamicGridKeyboard extends Keyboard { private static final String TAG = DynamicGridKeyboard.class.getSimpleName(); private static final int TEMPLATE_KEY_CODE_0 = 0x30; private static final int TEMPLATE_KEY_CODE_1 = 0x31; @@ -62,7 +61,7 @@ public class DynamicGridKeyboard extends Keyboard { mVerticalStep = key0.getHeight() + mVerticalGap; mColumnsNum = mBaseWidth / mHorizontalStep; mMaxKeyCount = maxKeyCount; - mIsRecents = categoryId == EmojiPalettesView.CATEGORY_ID_RECENTS; + mIsRecents = categoryId == EmojiCategory.ID_RECENTS; mPrefs = prefs; } diff --git a/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java new file mode 100644 index 000000000..dd0e3e838 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.keyboard.emoji; + +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.graphics.Rect; +import android.os.Build; +import android.util.Log; +import android.util.Pair; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.KeyboardLayoutSet; +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.settings.Settings; +import com.android.inputmethod.latin.utils.CollectionUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +final class EmojiCategory { + private final String TAG = EmojiCategory.class.getSimpleName(); + + private static final int ID_UNSPECIFIED = -1; + public static final int ID_RECENTS = 0; + private static final int ID_PEOPLE = 1; + private static final int ID_OBJECTS = 2; + private static final int ID_NATURE = 3; + private static final int ID_PLACES = 4; + private static final int ID_SYMBOLS = 5; + private static final int ID_EMOTICONS = 6; + + public final class CategoryProperties { + public final int mCategoryId; + public final int mPageCount; + public CategoryProperties(final int categoryId, final int pageCount) { + mCategoryId = categoryId; + mPageCount = pageCount; + } + } + + private static final String[] sCategoryName = { + "recents", + "people", + "objects", + "nature", + "places", + "symbols", + "emoticons" }; + + private static final int[] sCategoryIcon = { + R.drawable.ic_emoji_recent_light, + R.drawable.ic_emoji_people_light, + R.drawable.ic_emoji_objects_light, + R.drawable.ic_emoji_nature_light, + R.drawable.ic_emoji_places_light, + R.drawable.ic_emoji_symbols_light, + 0 }; + + private static final String[] sCategoryLabel = + { null, null, null, null, null, null, ":-)" }; + + private static final int[] sAccessibilityDescriptionResourceIdsForCategories = { + R.string.spoken_descrption_emoji_category_recents, + R.string.spoken_descrption_emoji_category_people, + R.string.spoken_descrption_emoji_category_objects, + R.string.spoken_descrption_emoji_category_nature, + R.string.spoken_descrption_emoji_category_places, + R.string.spoken_descrption_emoji_category_symbols, + R.string.spoken_descrption_emoji_category_emoticons }; + + private static final int[] sCategoryElementId = { + KeyboardId.ELEMENT_EMOJI_RECENTS, + KeyboardId.ELEMENT_EMOJI_CATEGORY1, + KeyboardId.ELEMENT_EMOJI_CATEGORY2, + KeyboardId.ELEMENT_EMOJI_CATEGORY3, + KeyboardId.ELEMENT_EMOJI_CATEGORY4, + KeyboardId.ELEMENT_EMOJI_CATEGORY5, + KeyboardId.ELEMENT_EMOJI_CATEGORY6 }; + + private final SharedPreferences mPrefs; + private final Resources mRes; + private final int mMaxPageKeyCount; + private final KeyboardLayoutSet mLayoutSet; + private final HashMap<String, Integer> mCategoryNameToIdMap = CollectionUtils.newHashMap(); + private final ArrayList<CategoryProperties> mShownCategories = + CollectionUtils.newArrayList(); + private final ConcurrentHashMap<Long, DynamicGridKeyboard> + mCategoryKeyboardMap = new ConcurrentHashMap<Long, DynamicGridKeyboard>(); + + private int mCurrentCategoryId = EmojiCategory.ID_UNSPECIFIED; + private int mCurrentCategoryPageId = 0; + + public EmojiCategory(final SharedPreferences prefs, final Resources res, + final KeyboardLayoutSet layoutSet) { + mPrefs = prefs; + mRes = res; + mMaxPageKeyCount = res.getInteger(R.integer.config_emoji_keyboard_max_page_key_count); + mLayoutSet = layoutSet; + for (int i = 0; i < sCategoryName.length; ++i) { + mCategoryNameToIdMap.put(sCategoryName[i], i); + } + addShownCategoryId(EmojiCategory.ID_RECENTS); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2 + || android.os.Build.VERSION.CODENAME.equalsIgnoreCase("KeyLimePie") + || android.os.Build.VERSION.CODENAME.equalsIgnoreCase("KitKat")) { + addShownCategoryId(EmojiCategory.ID_PEOPLE); + addShownCategoryId(EmojiCategory.ID_OBJECTS); + addShownCategoryId(EmojiCategory.ID_NATURE); + addShownCategoryId(EmojiCategory.ID_PLACES); + mCurrentCategoryId = + Settings.readLastShownEmojiCategoryId(mPrefs, EmojiCategory.ID_PEOPLE); + } else { + mCurrentCategoryId = + Settings.readLastShownEmojiCategoryId(mPrefs, EmojiCategory.ID_SYMBOLS); + } + addShownCategoryId(EmojiCategory.ID_SYMBOLS); + addShownCategoryId(EmojiCategory.ID_EMOTICONS); + getKeyboard(EmojiCategory.ID_RECENTS, 0 /* cagetoryPageId */) + .loadRecentKeys(mCategoryKeyboardMap.values()); + } + + private void addShownCategoryId(final int categoryId) { + // Load a keyboard of categoryId + getKeyboard(categoryId, 0 /* cagetoryPageId */); + final CategoryProperties properties = + new CategoryProperties(categoryId, getCategoryPageCount(categoryId)); + mShownCategories.add(properties); + } + + public String getCategoryName(final int categoryId, final int categoryPageId) { + return sCategoryName[categoryId] + "-" + categoryPageId; + } + + public int getCategoryId(final String name) { + final String[] strings = name.split("-"); + return mCategoryNameToIdMap.get(strings[0]); + } + + public int getCategoryIcon(final int categoryId) { + return sCategoryIcon[categoryId]; + } + + public String getCategoryLabel(final int categoryId) { + return sCategoryLabel[categoryId]; + } + + public String getAccessibilityDescription(final int categoryId) { + return mRes.getString(sAccessibilityDescriptionResourceIdsForCategories[categoryId]); + } + + public ArrayList<CategoryProperties> getShownCategories() { + return mShownCategories; + } + + public int getCurrentCategoryId() { + return mCurrentCategoryId; + } + + public int getCurrentCategoryPageSize() { + return getCategoryPageSize(mCurrentCategoryId); + } + + public int getCategoryPageSize(final int categoryId) { + for (final CategoryProperties prop : mShownCategories) { + if (prop.mCategoryId == categoryId) { + return prop.mPageCount; + } + } + Log.w(TAG, "Invalid category id: " + categoryId); + // Should not reach here. + return 0; + } + + public void setCurrentCategoryId(final int categoryId) { + mCurrentCategoryId = categoryId; + Settings.writeLastShownEmojiCategoryId(mPrefs, categoryId); + } + + public void setCurrentCategoryPageId(final int id) { + mCurrentCategoryPageId = id; + } + + public int getCurrentCategoryPageId() { + return mCurrentCategoryPageId; + } + + public void saveLastTypedCategoryPage() { + Settings.writeLastTypedEmojiCategoryPageId( + mPrefs, mCurrentCategoryId, mCurrentCategoryPageId); + } + + public boolean isInRecentTab() { + return mCurrentCategoryId == EmojiCategory.ID_RECENTS; + } + + public int getTabIdFromCategoryId(final int categoryId) { + for (int i = 0; i < mShownCategories.size(); ++i) { + if (mShownCategories.get(i).mCategoryId == categoryId) { + return i; + } + } + Log.w(TAG, "categoryId not found: " + categoryId); + return 0; + } + + // Returns the view pager's page position for the categoryId + public int getPageIdFromCategoryId(final int categoryId) { + final int lastSavedCategoryPageId = + Settings.readLastTypedEmojiCategoryPageId(mPrefs, categoryId); + int sum = 0; + for (int i = 0; i < mShownCategories.size(); ++i) { + final CategoryProperties props = mShownCategories.get(i); + if (props.mCategoryId == categoryId) { + return sum + lastSavedCategoryPageId; + } + sum += props.mPageCount; + } + Log.w(TAG, "categoryId not found: " + categoryId); + return 0; + } + + public int getRecentTabId() { + return getTabIdFromCategoryId(EmojiCategory.ID_RECENTS); + } + + private int getCategoryPageCount(final int categoryId) { + final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]); + return (keyboard.getSortedKeys().size() - 1) / mMaxPageKeyCount + 1; + } + + // Returns a pair of the category id and the category page id from the view pager's page + // position. The category page id is numbered in each category. And the view page position + // is the position of the current shown page in the view pager which contains all pages of + // all categories. + public Pair<Integer, Integer> getCategoryIdAndPageIdFromPagePosition(final int position) { + int sum = 0; + for (final CategoryProperties properties : mShownCategories) { + final int temp = sum; + sum += properties.mPageCount; + if (sum > position) { + return new Pair<Integer, Integer>(properties.mCategoryId, position - temp); + } + } + return null; + } + + // Returns a keyboard from the view pager's page position. + public DynamicGridKeyboard getKeyboardFromPagePosition(final int position) { + final Pair<Integer, Integer> categoryAndId = + getCategoryIdAndPageIdFromPagePosition(position); + if (categoryAndId != null) { + return getKeyboard(categoryAndId.first, categoryAndId.second); + } + return null; + } + + private static final Long getCategoryKeyboardMapKey(final int categoryId, final int id) { + return (((long) categoryId) << Constants.MAX_INT_BIT_COUNT) | id; + } + + public DynamicGridKeyboard getKeyboard(final int categoryId, final int id) { + synchronized (mCategoryKeyboardMap) { + final Long categotyKeyboardMapKey = getCategoryKeyboardMapKey(categoryId, id); + if (mCategoryKeyboardMap.containsKey(categotyKeyboardMapKey)) { + return mCategoryKeyboardMap.get(categotyKeyboardMapKey); + } + + if (categoryId == EmojiCategory.ID_RECENTS) { + final DynamicGridKeyboard kbd = new DynamicGridKeyboard(mPrefs, + mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), + mMaxPageKeyCount, categoryId); + mCategoryKeyboardMap.put(categotyKeyboardMapKey, kbd); + return kbd; + } + + final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]); + final Key[][] sortedKeys = sortKeysIntoPages( + keyboard.getSortedKeys(), mMaxPageKeyCount); + for (int pageId = 0; pageId < sortedKeys.length; ++pageId) { + final DynamicGridKeyboard tempKeyboard = new DynamicGridKeyboard(mPrefs, + mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), + mMaxPageKeyCount, categoryId); + for (final Key emojiKey : sortedKeys[pageId]) { + if (emojiKey == null) { + break; + } + tempKeyboard.addKeyLast(emojiKey); + } + mCategoryKeyboardMap.put( + getCategoryKeyboardMapKey(categoryId, pageId), tempKeyboard); + } + return mCategoryKeyboardMap.get(categotyKeyboardMapKey); + } + } + + public int getTotalPageCountOfAllCategories() { + int sum = 0; + for (CategoryProperties properties : mShownCategories) { + sum += properties.mPageCount; + } + return sum; + } + + private static Comparator<Key> EMOJI_KEY_COMPARATOR = new Comparator<Key>() { + @Override + public int compare(final Key lhs, final Key rhs) { + final Rect lHitBox = lhs.getHitBox(); + final Rect rHitBox = rhs.getHitBox(); + if (lHitBox.top < rHitBox.top) { + return -1; + } else if (lHitBox.top > rHitBox.top) { + return 1; + } + if (lHitBox.left < rHitBox.left) { + return -1; + } else if (lHitBox.left > rHitBox.left) { + return 1; + } + if (lhs.getCode() == rhs.getCode()) { + return 0; + } + return lhs.getCode() < rhs.getCode() ? -1 : 1; + } + }; + + private static Key[][] sortKeysIntoPages(final List<Key> inKeys, final int maxPageCount) { + final ArrayList<Key> keys = CollectionUtils.newArrayList(inKeys); + Collections.sort(keys, EMOJI_KEY_COMPARATOR); + final int pageCount = (keys.size() - 1) / maxPageCount + 1; + final Key[][] retval = new Key[pageCount][maxPageCount]; + for (int i = 0; i < keys.size(); ++i) { + retval[i / maxPageCount][i % maxPageCount] = keys.get(i); + } + return retval; + } +} diff --git a/java/src/com/android/inputmethod/keyboard/EmojiCategoryPageIndicatorView.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategoryPageIndicatorView.java index d56a3cf25..74cfd9b4b 100644 --- a/java/src/com/android/inputmethod/keyboard/EmojiCategoryPageIndicatorView.java +++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategoryPageIndicatorView.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.inputmethod.keyboard; +package com.android.inputmethod.keyboard.emoji; import com.android.inputmethod.latin.R; @@ -24,8 +24,8 @@ import android.graphics.Paint; import android.util.AttributeSet; import android.widget.LinearLayout; -public class EmojiCategoryPageIndicatorView extends LinearLayout { - private static final float BOTTOM_MARGIN_RATIO = 0.66f; +public final class EmojiCategoryPageIndicatorView extends LinearLayout { + private static final float BOTTOM_MARGIN_RATIO = 1.0f; private final Paint mPaint = new Paint(); private int mCategoryPageSize = 0; private int mCurrentCategoryPageId = 0; diff --git a/java/src/com/android/inputmethod/keyboard/internal/EmojiLayoutParams.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiLayoutParams.java index d57ea5a94..77c183a99 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/EmojiLayoutParams.java +++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiLayoutParams.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.inputmethod.keyboard.internal; +package com.android.inputmethod.keyboard.emoji; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.utils.ResourceUtils; @@ -24,7 +24,7 @@ import android.support.v4.view.ViewPager; import android.widget.ImageView; import android.widget.LinearLayout; -public class EmojiLayoutParams { +final class EmojiLayoutParams { private static final int DEFAULT_KEYBOARD_ROWS = 4; public final int mEmojiPagerHeight; diff --git a/java/src/com/android/inputmethod/keyboard/internal/EmojiPageKeyboardView.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java index e175a051e..d14ffeef9 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/EmojiPageKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.inputmethod.keyboard.internal; +package com.android.inputmethod.keyboard.emoji; import android.content.Context; import android.os.Handler; @@ -26,15 +26,14 @@ import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardView; -import com.android.inputmethod.keyboard.PointerTracker; import com.android.inputmethod.latin.R; /** * This is an extended {@link KeyboardView} class that hosts an emoji page keyboard. - * Multi-touch unsupported. No {@link PointerTracker}s. No gesture support. + * Multi-touch unsupported. No gesture support. */ // TODO: Implement key popup preview. -public final class EmojiPageKeyboardView extends KeyboardView implements +final class EmojiPageKeyboardView extends KeyboardView implements GestureDetector.OnGestureListener { private static final long KEY_PRESS_DELAY_TIME = 250; // msec private static final long KEY_RELEASE_DELAY_TIME = 30; // msec diff --git a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesAdapter.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesAdapter.java new file mode 100644 index 000000000..52a4dde97 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesAdapter.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.keyboard.emoji; + +import android.support.v4.view.PagerAdapter; +import android.util.Log; +import android.util.SparseArray; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.KeyboardView; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.utils.CollectionUtils; + +final class EmojiPalettesAdapter extends PagerAdapter { + private static final String TAG = EmojiPalettesAdapter.class.getSimpleName(); + private static final boolean DEBUG_PAGER = false; + + private final EmojiPageKeyboardView.OnKeyEventListener mListener; + private final DynamicGridKeyboard mRecentsKeyboard; + private final SparseArray<EmojiPageKeyboardView> mActiveKeyboardViews = + CollectionUtils.newSparseArray(); + private final EmojiCategory mEmojiCategory; + private int mActivePosition = 0; + + public EmojiPalettesAdapter(final EmojiCategory emojiCategory, + final EmojiPageKeyboardView.OnKeyEventListener listener) { + mEmojiCategory = emojiCategory; + mListener = listener; + mRecentsKeyboard = mEmojiCategory.getKeyboard(EmojiCategory.ID_RECENTS, 0); + } + + public void flushPendingRecentKeys() { + mRecentsKeyboard.flushPendingRecentKeys(); + final KeyboardView recentKeyboardView = + mActiveKeyboardViews.get(mEmojiCategory.getRecentTabId()); + if (recentKeyboardView != null) { + recentKeyboardView.invalidateAllKeys(); + } + } + + public void addRecentKey(final Key key) { + if (mEmojiCategory.isInRecentTab()) { + mRecentsKeyboard.addPendingKey(key); + return; + } + mRecentsKeyboard.addKeyFirst(key); + final KeyboardView recentKeyboardView = + mActiveKeyboardViews.get(mEmojiCategory.getRecentTabId()); + if (recentKeyboardView != null) { + recentKeyboardView.invalidateAllKeys(); + } + } + + public void onPageScrolled() { + // Make sure the delayed key-down event (highlight effect and haptic feedback) will be + // canceled. + final EmojiPageKeyboardView currentKeyboardView = + mActiveKeyboardViews.get(mActivePosition); + if (currentKeyboardView != null) { + currentKeyboardView.releaseCurrentKey(); + } + } + + @Override + public int getCount() { + return mEmojiCategory.getTotalPageCountOfAllCategories(); + } + + @Override + public void setPrimaryItem(final ViewGroup container, final int position, + final Object object) { + if (mActivePosition == position) { + return; + } + final EmojiPageKeyboardView oldKeyboardView = mActiveKeyboardViews.get(mActivePosition); + if (oldKeyboardView != null) { + oldKeyboardView.releaseCurrentKey(); + oldKeyboardView.deallocateMemory(); + } + mActivePosition = position; + } + + @Override + public Object instantiateItem(final ViewGroup container, final int position) { + if (DEBUG_PAGER) { + Log.d(TAG, "instantiate item: " + position); + } + final EmojiPageKeyboardView oldKeyboardView = mActiveKeyboardViews.get(position); + if (oldKeyboardView != null) { + oldKeyboardView.deallocateMemory(); + // This may be redundant but wanted to be safer.. + mActiveKeyboardViews.remove(position); + } + final Keyboard keyboard = + mEmojiCategory.getKeyboardFromPagePosition(position); + final LayoutInflater inflater = LayoutInflater.from(container.getContext()); + final EmojiPageKeyboardView keyboardView = (EmojiPageKeyboardView)inflater.inflate( + R.layout.emoji_keyboard_page, container, false /* attachToRoot */); + keyboardView.setKeyboard(keyboard); + keyboardView.setOnKeyEventListener(mListener); + container.addView(keyboardView); + mActiveKeyboardViews.put(position, keyboardView); + return keyboardView; + } + + @Override + public boolean isViewFromObject(final View view, final Object object) { + return view == object; + } + + @Override + public void destroyItem(final ViewGroup container, final int position, + final Object object) { + if (DEBUG_PAGER) { + Log.d(TAG, "destroy item: " + position + ", " + object.getClass().getSimpleName()); + } + final EmojiPageKeyboardView keyboardView = mActiveKeyboardViews.get(position); + if (keyboardView != null) { + keyboardView.deallocateMemory(); + mActiveKeyboardViews.remove(position); + } + if (object instanceof View) { + container.removeView((View)object); + } else { + Log.w(TAG, "Warning!!! Emoji palette may be leaking. " + object); + } + } +} diff --git a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java index d8b5758a6..3813c578a 100644 --- a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java +++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java @@ -14,55 +14,44 @@ * limitations under the License. */ -package com.android.inputmethod.keyboard; +package com.android.inputmethod.keyboard.emoji; import static com.android.inputmethod.latin.Constants.NOT_A_COORDINATE; import android.content.Context; -import android.content.SharedPreferences; import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Color; -import android.graphics.Rect; -import android.os.Build; +import android.graphics.Typeface; import android.os.CountDownTimer; import android.preference.PreferenceManager; -import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.util.AttributeSet; -import android.util.Log; import android.util.Pair; -import android.util.SparseArray; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; -import android.view.ViewGroup; +import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TabHost; import android.widget.TabHost.OnTabChangeListener; import android.widget.TextView; -import com.android.inputmethod.keyboard.internal.DynamicGridKeyboard; -import com.android.inputmethod.keyboard.internal.EmojiLayoutParams; -import com.android.inputmethod.keyboard.internal.EmojiPageKeyboardView; +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.KeyboardActionListener; +import com.android.inputmethod.keyboard.KeyboardLayoutSet; +import com.android.inputmethod.keyboard.KeyboardView; import com.android.inputmethod.keyboard.internal.KeyDrawParams; import com.android.inputmethod.keyboard.internal.KeyVisualAttributes; +import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SubtypeSwitcher; -import com.android.inputmethod.latin.settings.Settings; -import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.ResourceUtils; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; /** @@ -79,17 +68,17 @@ import java.util.concurrent.TimeUnit; public final class EmojiPalettesView extends LinearLayout implements OnTabChangeListener, ViewPager.OnPageChangeListener, View.OnClickListener, View.OnTouchListener, EmojiPageKeyboardView.OnKeyEventListener { - static final String TAG = EmojiPalettesView.class.getSimpleName(); - private static final boolean DEBUG_PAGER = false; - private final int mKeyBackgroundId; - private final int mEmojiFunctionalKeyBackgroundId; + private final int mFunctionalKeyBackgroundId; + private final int mSpacebarBackgroundId; private final ColorStateList mTabLabelColor; private final DeleteKeyOnTouchListener mDeleteKeyOnTouchListener; private EmojiPalettesAdapter mEmojiPalettesAdapter; private final EmojiLayoutParams mEmojiLayoutParams; + private ImageButton mDeleteKey; private TextView mAlphabetKeyLeft; private TextView mAlphabetKeyRight; + private ImageButton mSpacebar; private TabHost mTabHost; private ViewPager mEmojiPager; private int mCurrentPagerPosition = 0; @@ -97,317 +86,6 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange private KeyboardActionListener mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER; - private static final int CATEGORY_ID_UNSPECIFIED = -1; - public static final int CATEGORY_ID_RECENTS = 0; - public static final int CATEGORY_ID_PEOPLE = 1; - public static final int CATEGORY_ID_OBJECTS = 2; - public static final int CATEGORY_ID_NATURE = 3; - public static final int CATEGORY_ID_PLACES = 4; - public static final int CATEGORY_ID_SYMBOLS = 5; - public static final int CATEGORY_ID_EMOTICONS = 6; - - private static class CategoryProperties { - public int mCategoryId; - public int mPageCount; - public CategoryProperties(final int categoryId, final int pageCount) { - mCategoryId = categoryId; - mPageCount = pageCount; - } - } - - private static class EmojiCategory { - private static final String[] sCategoryName = { - "recents", - "people", - "objects", - "nature", - "places", - "symbols", - "emoticons" }; - private static final int[] sCategoryIcon = { - R.drawable.ic_emoji_recent_light, - R.drawable.ic_emoji_people_light, - R.drawable.ic_emoji_objects_light, - R.drawable.ic_emoji_nature_light, - R.drawable.ic_emoji_places_light, - R.drawable.ic_emoji_symbols_light, - 0 }; - private static final String[] sCategoryLabel = - { null, null, null, null, null, null, ":-)" }; - private static final int[] sAccessibilityDescriptionResourceIdsForCategories = { - R.string.spoken_descrption_emoji_category_recents, - R.string.spoken_descrption_emoji_category_people, - R.string.spoken_descrption_emoji_category_objects, - R.string.spoken_descrption_emoji_category_nature, - R.string.spoken_descrption_emoji_category_places, - R.string.spoken_descrption_emoji_category_symbols, - R.string.spoken_descrption_emoji_category_emoticons }; - private static final int[] sCategoryElementId = { - KeyboardId.ELEMENT_EMOJI_RECENTS, - KeyboardId.ELEMENT_EMOJI_CATEGORY1, - KeyboardId.ELEMENT_EMOJI_CATEGORY2, - KeyboardId.ELEMENT_EMOJI_CATEGORY3, - KeyboardId.ELEMENT_EMOJI_CATEGORY4, - KeyboardId.ELEMENT_EMOJI_CATEGORY5, - KeyboardId.ELEMENT_EMOJI_CATEGORY6 }; - private final SharedPreferences mPrefs; - private final Resources mRes; - private final int mMaxPageKeyCount; - private final KeyboardLayoutSet mLayoutSet; - private final HashMap<String, Integer> mCategoryNameToIdMap = CollectionUtils.newHashMap(); - private final ArrayList<CategoryProperties> mShownCategories = - CollectionUtils.newArrayList(); - private final ConcurrentHashMap<Long, DynamicGridKeyboard> - mCategoryKeyboardMap = new ConcurrentHashMap<Long, DynamicGridKeyboard>(); - - private int mCurrentCategoryId = CATEGORY_ID_UNSPECIFIED; - private int mCurrentCategoryPageId = 0; - - public EmojiCategory(final SharedPreferences prefs, final Resources res, - final KeyboardLayoutSet layoutSet) { - mPrefs = prefs; - mRes = res; - mMaxPageKeyCount = res.getInteger(R.integer.config_emoji_keyboard_max_page_key_count); - mLayoutSet = layoutSet; - for (int i = 0; i < sCategoryName.length; ++i) { - mCategoryNameToIdMap.put(sCategoryName[i], i); - } - addShownCategoryId(CATEGORY_ID_RECENTS); - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2 - || android.os.Build.VERSION.CODENAME.equalsIgnoreCase("KeyLimePie") - || android.os.Build.VERSION.CODENAME.equalsIgnoreCase("KitKat")) { - addShownCategoryId(CATEGORY_ID_PEOPLE); - addShownCategoryId(CATEGORY_ID_OBJECTS); - addShownCategoryId(CATEGORY_ID_NATURE); - addShownCategoryId(CATEGORY_ID_PLACES); - mCurrentCategoryId = - Settings.readLastShownEmojiCategoryId(mPrefs, CATEGORY_ID_PEOPLE); - } else { - mCurrentCategoryId = - Settings.readLastShownEmojiCategoryId(mPrefs, CATEGORY_ID_SYMBOLS); - } - addShownCategoryId(CATEGORY_ID_SYMBOLS); - addShownCategoryId(CATEGORY_ID_EMOTICONS); - getKeyboard(CATEGORY_ID_RECENTS, 0 /* cagetoryPageId */) - .loadRecentKeys(mCategoryKeyboardMap.values()); - } - - private void addShownCategoryId(final int categoryId) { - // Load a keyboard of categoryId - getKeyboard(categoryId, 0 /* cagetoryPageId */); - final CategoryProperties properties = - new CategoryProperties(categoryId, getCategoryPageCount(categoryId)); - mShownCategories.add(properties); - } - - public String getCategoryName(final int categoryId, final int categoryPageId) { - return sCategoryName[categoryId] + "-" + categoryPageId; - } - - public int getCategoryId(final String name) { - final String[] strings = name.split("-"); - return mCategoryNameToIdMap.get(strings[0]); - } - - public int getCategoryIcon(final int categoryId) { - return sCategoryIcon[categoryId]; - } - - public String getCategoryLabel(final int categoryId) { - return sCategoryLabel[categoryId]; - } - - public String getAccessibilityDescription(final int categoryId) { - return mRes.getString(sAccessibilityDescriptionResourceIdsForCategories[categoryId]); - } - - public ArrayList<CategoryProperties> getShownCategories() { - return mShownCategories; - } - - public int getCurrentCategoryId() { - return mCurrentCategoryId; - } - - public int getCurrentCategoryPageSize() { - return getCategoryPageSize(mCurrentCategoryId); - } - - public int getCategoryPageSize(final int categoryId) { - for (final CategoryProperties prop : mShownCategories) { - if (prop.mCategoryId == categoryId) { - return prop.mPageCount; - } - } - Log.w(TAG, "Invalid category id: " + categoryId); - // Should not reach here. - return 0; - } - - public void setCurrentCategoryId(final int categoryId) { - mCurrentCategoryId = categoryId; - Settings.writeLastShownEmojiCategoryId(mPrefs, categoryId); - } - - public void setCurrentCategoryPageId(final int id) { - mCurrentCategoryPageId = id; - } - - public int getCurrentCategoryPageId() { - return mCurrentCategoryPageId; - } - - public void saveLastTypedCategoryPage() { - Settings.writeLastTypedEmojiCategoryPageId( - mPrefs, mCurrentCategoryId, mCurrentCategoryPageId); - } - - public boolean isInRecentTab() { - return mCurrentCategoryId == CATEGORY_ID_RECENTS; - } - - public int getTabIdFromCategoryId(final int categoryId) { - for (int i = 0; i < mShownCategories.size(); ++i) { - if (mShownCategories.get(i).mCategoryId == categoryId) { - return i; - } - } - Log.w(TAG, "categoryId not found: " + categoryId); - return 0; - } - - // Returns the view pager's page position for the categoryId - public int getPageIdFromCategoryId(final int categoryId) { - final int lastSavedCategoryPageId = - Settings.readLastTypedEmojiCategoryPageId(mPrefs, categoryId); - int sum = 0; - for (int i = 0; i < mShownCategories.size(); ++i) { - final CategoryProperties props = mShownCategories.get(i); - if (props.mCategoryId == categoryId) { - return sum + lastSavedCategoryPageId; - } - sum += props.mPageCount; - } - Log.w(TAG, "categoryId not found: " + categoryId); - return 0; - } - - public int getRecentTabId() { - return getTabIdFromCategoryId(CATEGORY_ID_RECENTS); - } - - private int getCategoryPageCount(final int categoryId) { - final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]); - return (keyboard.getSortedKeys().size() - 1) / mMaxPageKeyCount + 1; - } - - // Returns a pair of the category id and the category page id from the view pager's page - // position. The category page id is numbered in each category. And the view page position - // is the position of the current shown page in the view pager which contains all pages of - // all categories. - public Pair<Integer, Integer> getCategoryIdAndPageIdFromPagePosition(final int position) { - int sum = 0; - for (final CategoryProperties properties : mShownCategories) { - final int temp = sum; - sum += properties.mPageCount; - if (sum > position) { - return new Pair<Integer, Integer>(properties.mCategoryId, position - temp); - } - } - return null; - } - - // Returns a keyboard from the view pager's page position. - public DynamicGridKeyboard getKeyboardFromPagePosition(final int position) { - final Pair<Integer, Integer> categoryAndId = - getCategoryIdAndPageIdFromPagePosition(position); - if (categoryAndId != null) { - return getKeyboard(categoryAndId.first, categoryAndId.second); - } - return null; - } - - private static final Long getCategoryKeyboardMapKey(final int categoryId, final int id) { - return (((long) categoryId) << Constants.MAX_INT_BIT_COUNT) | id; - } - - public DynamicGridKeyboard getKeyboard(final int categoryId, final int id) { - synchronized (mCategoryKeyboardMap) { - final Long categotyKeyboardMapKey = getCategoryKeyboardMapKey(categoryId, id); - if (mCategoryKeyboardMap.containsKey(categotyKeyboardMapKey)) { - return mCategoryKeyboardMap.get(categotyKeyboardMapKey); - } - - if (categoryId == CATEGORY_ID_RECENTS) { - final DynamicGridKeyboard kbd = new DynamicGridKeyboard(mPrefs, - mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), - mMaxPageKeyCount, categoryId); - mCategoryKeyboardMap.put(categotyKeyboardMapKey, kbd); - return kbd; - } - - final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]); - final Key[][] sortedKeys = sortKeysIntoPages( - keyboard.getSortedKeys(), mMaxPageKeyCount); - for (int pageId = 0; pageId < sortedKeys.length; ++pageId) { - final DynamicGridKeyboard tempKeyboard = new DynamicGridKeyboard(mPrefs, - mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), - mMaxPageKeyCount, categoryId); - for (final Key emojiKey : sortedKeys[pageId]) { - if (emojiKey == null) { - break; - } - tempKeyboard.addKeyLast(emojiKey); - } - mCategoryKeyboardMap.put( - getCategoryKeyboardMapKey(categoryId, pageId), tempKeyboard); - } - return mCategoryKeyboardMap.get(categotyKeyboardMapKey); - } - } - - public int getTotalPageCountOfAllCategories() { - int sum = 0; - for (CategoryProperties properties : mShownCategories) { - sum += properties.mPageCount; - } - return sum; - } - - private static Comparator<Key> EMOJI_KEY_COMPARATOR = new Comparator<Key>() { - @Override - public int compare(final Key lhs, final Key rhs) { - final Rect lHitBox = lhs.getHitBox(); - final Rect rHitBox = rhs.getHitBox(); - if (lHitBox.top < rHitBox.top) { - return -1; - } else if (lHitBox.top > rHitBox.top) { - return 1; - } - if (lHitBox.left < rHitBox.left) { - return -1; - } else if (lHitBox.left > rHitBox.left) { - return 1; - } - if (lhs.getCode() == rhs.getCode()) { - return 0; - } - return lhs.getCode() < rhs.getCode() ? -1 : 1; - } - }; - - private static Key[][] sortKeysIntoPages(final List<Key> inKeys, final int maxPageCount) { - final ArrayList<Key> keys = CollectionUtils.newArrayList(inKeys); - Collections.sort(keys, EMOJI_KEY_COMPARATOR); - final int pageCount = (keys.size() - 1) / maxPageCount + 1; - final Key[][] retval = new Key[pageCount][maxPageCount]; - for (int i = 0; i < keys.size(); ++i) { - retval[i / maxPageCount][i % maxPageCount] = keys.get(i); - } - return retval; - } - } - private final EmojiCategory mEmojiCategory; public EmojiPalettesView(final Context context, final AttributeSet attrs) { @@ -418,10 +96,12 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange super(context, attrs, defStyle); final TypedArray keyboardViewAttr = context.obtainStyledAttributes(attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView); - mKeyBackgroundId = keyboardViewAttr.getResourceId( + final int keyBackgroundId = keyboardViewAttr.getResourceId( R.styleable.KeyboardView_keyBackground, 0); - mEmojiFunctionalKeyBackgroundId = keyboardViewAttr.getResourceId( - R.styleable.KeyboardView_keyBackgroundEmojiFunctional, 0); + mFunctionalKeyBackgroundId = keyboardViewAttr.getResourceId( + R.styleable.KeyboardView_functionalKeyBackground, keyBackgroundId); + mSpacebarBackgroundId = keyboardViewAttr.getResourceId( + R.styleable.KeyboardView_spacebarBackground, keyBackgroundId); keyboardViewAttr.recycle(); final TypedArray emojiPalettesViewAttr = context.obtainStyledAttributes(attrs, R.styleable.EmojiPalettesView, defStyle, R.style.EmojiPalettesView); @@ -470,8 +150,11 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange final TextView textView = (TextView)LayoutInflater.from(getContext()).inflate( R.layout.emoji_keyboard_tab_label, null); textView.setText(mEmojiCategory.getCategoryLabel(categoryId)); + textView.setTypeface(Typeface.DEFAULT_BOLD); textView.setContentDescription(mEmojiCategory.getAccessibilityDescription(categoryId)); - textView.setTextColor(mTabLabelColor); + if (mTabLabelColor != null) { + textView.setTextColor(mTabLabelColor); + } tspec.setIndicator(textView); } host.addTab(tspec); @@ -481,7 +164,8 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange protected void onFinishInflate() { mTabHost = (TabHost)findViewById(R.id.emoji_category_tabhost); mTabHost.setup(); - for (final CategoryProperties properties : mEmojiCategory.getShownCategories()) { + for (final EmojiCategory.CategoryProperties properties + : mEmojiCategory.getShownCategories()) { addTab(mTabHost, properties.mCategoryId); } mTabHost.setOnTabChangedListener(this); @@ -506,9 +190,10 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange mEmojiLayoutParams.setActionBarProperties(actionBar); // deleteKey depends only on OnTouchListener. - final ImageView deleteKey = (ImageView)findViewById(R.id.emoji_keyboard_delete); - deleteKey.setTag(Constants.CODE_DELETE); - deleteKey.setOnTouchListener(mDeleteKeyOnTouchListener); + mDeleteKey = (ImageButton)findViewById(R.id.emoji_keyboard_delete); + mDeleteKey.setBackgroundResource(mFunctionalKeyBackgroundId); + mDeleteKey.setTag(Constants.CODE_DELETE); + mDeleteKey.setOnTouchListener(mDeleteKeyOnTouchListener); // {@link #mAlphabetKeyLeft}, {@link #mAlphabetKeyRight, and spaceKey depend on // {@link View.OnClickListener} as well as {@link View.OnTouchListener}. @@ -518,21 +203,21 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange // The text on alphabet keys are set at // {@link #startEmojiPalettes(String,int,float,Typeface)}. mAlphabetKeyLeft = (TextView)findViewById(R.id.emoji_keyboard_alphabet_left); - mAlphabetKeyLeft.setBackgroundResource(mEmojiFunctionalKeyBackgroundId); + mAlphabetKeyLeft.setBackgroundResource(mFunctionalKeyBackgroundId); mAlphabetKeyLeft.setTag(Constants.CODE_ALPHA_FROM_EMOJI); mAlphabetKeyLeft.setOnTouchListener(this); mAlphabetKeyLeft.setOnClickListener(this); mAlphabetKeyRight = (TextView)findViewById(R.id.emoji_keyboard_alphabet_right); - mAlphabetKeyRight.setBackgroundResource(mEmojiFunctionalKeyBackgroundId); + mAlphabetKeyRight.setBackgroundResource(mFunctionalKeyBackgroundId); mAlphabetKeyRight.setTag(Constants.CODE_ALPHA_FROM_EMOJI); mAlphabetKeyRight.setOnTouchListener(this); mAlphabetKeyRight.setOnClickListener(this); - final ImageView spaceKey = (ImageView)findViewById(R.id.emoji_keyboard_space); - spaceKey.setBackgroundResource(mKeyBackgroundId); - spaceKey.setTag(Constants.CODE_SPACE); - spaceKey.setOnTouchListener(this); - spaceKey.setOnClickListener(this); - mEmojiLayoutParams.setKeyProperties(spaceKey); + mSpacebar = (ImageButton)findViewById(R.id.emoji_keyboard_space); + mSpacebar.setBackgroundResource(mSpacebarBackgroundId); + mSpacebar.setTag(Constants.CODE_SPACE); + mSpacebar.setOnTouchListener(this); + mSpacebar.setOnClickListener(this); + mEmojiLayoutParams.setKeyProperties(mSpacebar); } @Override @@ -631,7 +316,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange /** * Called from {@link EmojiPageKeyboardView} through - * {@link com.android.inputmethod.keyboard.internal.EmojiPageKeyboardView.OnKeyEventListener} + * {@link com.android.inputmethod.keyboard.emoji.EmojiPageKeyboardView.OnKeyEventListener} * interface to handle touch events from non-View-based elements such as Emoji buttons. */ @Override @@ -642,7 +327,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange /** * Called from {@link EmojiPageKeyboardView} through - * {@link com.android.inputmethod.keyboard.internal.EmojiPageKeyboardView.OnKeyEventListener} + * {@link com.android.inputmethod.keyboard.emoji.EmojiPageKeyboardView.OnKeyEventListener} * interface to handle touch events from non-View-based elements such as Emoji buttons. */ @Override @@ -674,10 +359,9 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange } public void startEmojiPalettes(final String switchToAlphaLabel, - final KeyVisualAttributes keyVisualAttr) { - if (DEBUG_PAGER) { - Log.d(TAG, "allocate emoji palettes memory " + mCurrentPagerPosition); - } + final KeyVisualAttributes keyVisualAttr, final KeyboardIconsSet iconSet) { + mDeleteKey.setImageDrawable(iconSet.getIconDrawable(KeyboardIconsSet.NAME_DELETE_KEY)); + mSpacebar.setImageDrawable(iconSet.getIconDrawable(KeyboardIconsSet.NAME_SPACE_KEY)); final KeyDrawParams params = new KeyDrawParams(); params.updateParams(mEmojiLayoutParams.getActionBarHeight(), keyVisualAttr); setupAlphabetKey(mAlphabetKeyLeft, switchToAlphaLabel, params); @@ -687,9 +371,6 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange } public void stopEmojiPalettes() { - if (DEBUG_PAGER) { - Log.d(TAG, "deallocate emoji palettes memory"); - } mEmojiPalettesAdapter.flushPendingRecentKeys(); mEmojiPager.setAdapter(null); } @@ -714,7 +395,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange return; } - if (oldCategoryId == CATEGORY_ID_RECENTS) { + if (oldCategoryId == EmojiCategory.ID_RECENTS) { // Needs to save pending updates for recent keys when we get out of the recents // category because we don't want to move the recent emojis around while the user // is in the recents category. @@ -733,124 +414,11 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange } } - private static class EmojiPalettesAdapter extends PagerAdapter { - private final EmojiPageKeyboardView.OnKeyEventListener mListener; - private final DynamicGridKeyboard mRecentsKeyboard; - private final SparseArray<EmojiPageKeyboardView> mActiveKeyboardViews = - CollectionUtils.newSparseArray(); - private final EmojiCategory mEmojiCategory; - private int mActivePosition = 0; - - public EmojiPalettesAdapter(final EmojiCategory emojiCategory, - final EmojiPageKeyboardView.OnKeyEventListener listener) { - mEmojiCategory = emojiCategory; - mListener = listener; - mRecentsKeyboard = mEmojiCategory.getKeyboard(CATEGORY_ID_RECENTS, 0); - } - - public void flushPendingRecentKeys() { - mRecentsKeyboard.flushPendingRecentKeys(); - final KeyboardView recentKeyboardView = - mActiveKeyboardViews.get(mEmojiCategory.getRecentTabId()); - if (recentKeyboardView != null) { - recentKeyboardView.invalidateAllKeys(); - } - } - - public void addRecentKey(final Key key) { - if (mEmojiCategory.isInRecentTab()) { - mRecentsKeyboard.addPendingKey(key); - return; - } - mRecentsKeyboard.addKeyFirst(key); - final KeyboardView recentKeyboardView = - mActiveKeyboardViews.get(mEmojiCategory.getRecentTabId()); - if (recentKeyboardView != null) { - recentKeyboardView.invalidateAllKeys(); - } - } - - public void onPageScrolled() { - // Make sure the delayed key-down event (highlight effect and haptic feedback) will be - // canceled. - final EmojiPageKeyboardView currentKeyboardView = - mActiveKeyboardViews.get(mActivePosition); - if (currentKeyboardView != null) { - currentKeyboardView.releaseCurrentKey(); - } - } - - @Override - public int getCount() { - return mEmojiCategory.getTotalPageCountOfAllCategories(); - } - - @Override - public void setPrimaryItem(final ViewGroup container, final int position, - final Object object) { - if (mActivePosition == position) { - return; - } - final EmojiPageKeyboardView oldKeyboardView = mActiveKeyboardViews.get(mActivePosition); - if (oldKeyboardView != null) { - oldKeyboardView.releaseCurrentKey(); - oldKeyboardView.deallocateMemory(); - } - mActivePosition = position; - } - - @Override - public Object instantiateItem(final ViewGroup container, final int position) { - if (DEBUG_PAGER) { - Log.d(TAG, "instantiate item: " + position); - } - final EmojiPageKeyboardView oldKeyboardView = mActiveKeyboardViews.get(position); - if (oldKeyboardView != null) { - oldKeyboardView.deallocateMemory(); - // This may be redundant but wanted to be safer.. - mActiveKeyboardViews.remove(position); - } - final Keyboard keyboard = - mEmojiCategory.getKeyboardFromPagePosition(position); - final LayoutInflater inflater = LayoutInflater.from(container.getContext()); - final EmojiPageKeyboardView keyboardView = (EmojiPageKeyboardView)inflater.inflate( - R.layout.emoji_keyboard_page, container, false /* attachToRoot */); - keyboardView.setKeyboard(keyboard); - keyboardView.setOnKeyEventListener(mListener); - container.addView(keyboardView); - mActiveKeyboardViews.put(position, keyboardView); - return keyboardView; - } - - @Override - public boolean isViewFromObject(final View view, final Object object) { - return view == object; - } - - @Override - public void destroyItem(final ViewGroup container, final int position, - final Object object) { - if (DEBUG_PAGER) { - Log.d(TAG, "destroy item: " + position + ", " + object.getClass().getSimpleName()); - } - final EmojiPageKeyboardView keyboardView = mActiveKeyboardViews.get(position); - if (keyboardView != null) { - keyboardView.deallocateMemory(); - mActiveKeyboardViews.remove(position); - } - if (object instanceof View) { - container.removeView((View)object); - } else { - Log.w(TAG, "Warning!!! Emoji palette may be leaking. " + object); - } - } - } - private static class DeleteKeyOnTouchListener implements OnTouchListener { - private static final long MAX_REPEAT_COUNT_TIME = TimeUnit.SECONDS.toMillis(30); - private final int mDeleteKeyPressedBackgroundColor; - private final long mKeyRepeatStartTimeout; - private final long mKeyRepeatInterval; + static final long MAX_REPEAT_COUNT_TIME = TimeUnit.SECONDS.toMillis(30); + final int mDeleteKeyPressedBackgroundColor; + final long mKeyRepeatStartTimeout; + final long mKeyRepeatInterval; public DeleteKeyOnTouchListener(Context context) { final Resources res = context.getResources(); @@ -953,7 +521,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange } // Called by {@link #mTimer} in the UI thread as an auto key-repeat signal. - private void onKeyRepeat() { + void onKeyRepeat() { switch (mState) { case KEY_REPEAT_STATE_INITIALIZED: // Basically this should not happen. diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java index 65d6a5633..b5a94807e 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java @@ -138,6 +138,10 @@ public final class KeyboardIconsSet { throw new RuntimeException("unknown icon name: " + name); } + public Drawable getIconDrawable(final String name) { + return getIconDrawable(getIconId(name)); + } + public Drawable getIconDrawable(final int iconId) { if (isValidIconId(iconId)) { return mIcons[iconId]; diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 6818c156e..e323f0ab2 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -607,6 +607,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { Log.d(TAG, "Dump dictionary: " + mDictName); try { final DictionaryHeader header = mBinaryDictionary.getHeader(); + Log.d(TAG, "Format version: " + mBinaryDictionary.getFormatVersion()); Log.d(TAG, CombinedFormatUtils.formatAttributeMap( header.mDictionaryOptions.mAttributes)); } catch (final UnsupportedFormatException e) { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 7dc566a14..8a2ed1088 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -540,18 +540,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen refreshPersonalizationDictionarySession(); } - private DistracterFilter createDistracterFilter() { - final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); - // TODO: Create Keyboard when mainKeyboardView is null. - // TODO: Figure out the most reasonable keyboard for the filter. Refer to the - // spellchecker's logic. - final Keyboard keyboard = (mainKeyboardView != null) ? - mainKeyboardView.getKeyboard() : null; - final DistracterFilter distracterFilter = new DistracterFilter(mInputLogic.mSuggest, - keyboard); - return distracterFilter; - } - private void refreshPersonalizationDictionarySession() { final DictionaryFacilitatorForSuggest dictionaryFacilitator = mInputLogic.mSuggest.mDictionaryFacilitator; @@ -1755,6 +1743,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mInputLogic.mSuggest.mDictionaryFacilitator.clearPersonalizationDictionary(); } + @UsedForTesting + /* package for test */ DistracterFilter createDistracterFilter() { + return DistracterFilter.createDistracterFilter(mInputLogic.mSuggest, mKeyboardSwitcher); + } + public void dumpDictionaryForDebug(final String dictName) { final DictionaryFacilitatorForSuggest dictionaryFacilitator = mInputLogic.mSuggest.mDictionaryFacilitator; diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index cdee496a8..ac6972928 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -80,7 +80,7 @@ public final class WordComposer { private boolean mIsFirstCharCapitalized; public WordComposer() { - mCombinerChain = new CombinerChain(); + mCombinerChain = new CombinerChain(""); mEvents = CollectionUtils.newArrayList(); mAutoCorrection = null; mIsResumed = false; @@ -92,18 +92,17 @@ public final class WordComposer { } /** - * Restart input with a new combining spec. + * Restart the combiners, possibly with a new spec. * @param combiningSpec The spec string for combining. This is found in the extra value. */ - public void restart(final String combiningSpec) { + public void restartCombining(final String combiningSpec) { final String nonNullCombiningSpec = null == combiningSpec ? "" : combiningSpec; - if (nonNullCombiningSpec.equals(mCombiningSpec)) { - mCombinerChain.reset(); - } else { - mCombinerChain = new CombinerChain(CombinerChain.createCombiners(nonNullCombiningSpec)); + if (!nonNullCombiningSpec.equals(mCombiningSpec)) { + mCombinerChain = new CombinerChain( + mCombinerChain.getComposingWordWithCombiningFeedback().toString(), + CombinerChain.createCombiners(nonNullCombiningSpec)); mCombiningSpec = nonNullCombiningSpec; } - reset(); } /** diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 8b795b82f..ea58abc14 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -127,7 +127,7 @@ public final class InputLogic { public void startInput(final boolean restarting, final EditorInfo editorInfo, final String combiningSpec) { mEnteredText = null; - mWordComposer.restart(combiningSpec); + mWordComposer.restartCombining(combiningSpec); resetComposingState(true /* alsoResetLastComposedWord */); mDeleteCount = 0; mSpaceState = SpaceState.NONE; @@ -150,7 +150,7 @@ public final class InputLogic { * @param combiningSpec the spec string for the combining rules */ public void onSubtypeChanged(final String combiningSpec) { - mWordComposer.restart(combiningSpec); + mWordComposer.restartCombining(combiningSpec); } /** @@ -936,7 +936,11 @@ public final class InputLogic { } else { mWordComposer.processEvent(inputTransaction.mEvent); } - mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); + if (mWordComposer.isComposingWord()) { + mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); + } else { + mConnection.commitText("", 1); + } inputTransaction.setRequiresUpdateSuggestions(); } else { if (mLastComposedWord.canRevertCommit()) { diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java index d4f7f36da..619804afa 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java @@ -124,9 +124,9 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick mImportantNoticeStrip.setVisibility(INVISIBLE); } - public void showImportantNoticeStrip() { + public void showImportantNoticeStrip(final boolean enableVoiceKey) { mSuggestionsStrip.setVisibility(INVISIBLE); - mVoiceKey.setVisibility(INVISIBLE); + mVoiceKey.setVisibility(enableVoiceKey ? VISIBLE : INVISIBLE); mAddToDictionaryStrip.setVisibility(INVISIBLE); mImportantNoticeStrip.setVisibility(VISIBLE); } @@ -274,7 +274,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick dismissMoreSuggestionsPanel(); } mLayoutHelper.layoutImportantNotice(mImportantNoticeStrip, importantNoticeTitle); - mStripVisibilityGroup.showImportantNoticeStrip(); + mStripVisibilityGroup.showImportantNoticeStrip(isVoiceKeyEnabled()); mImportantNoticeStrip.setOnClickListener(this); return true; } diff --git a/java/src/com/android/inputmethod/latin/utils/DistracterFilter.java b/java/src/com/android/inputmethod/latin/utils/DistracterFilter.java index 48e43d6ef..55cbf79b3 100644 --- a/java/src/com/android/inputmethod/latin/utils/DistracterFilter.java +++ b/java/src/com/android/inputmethod/latin/utils/DistracterFilter.java @@ -17,21 +17,35 @@ package com.android.inputmethod.latin.utils; import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.KeyboardSwitcher; +import com.android.inputmethod.keyboard.MainKeyboardView; +import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.Suggest; +import com.android.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback; +import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.WordComposer; /** - * This class is used to prevent distracters/misspellings being added to personalization + * This class is used to prevent distracters being added to personalization * or user history dictionaries */ public class DistracterFilter { private final Suggest mSuggest; private final Keyboard mKeyboard; + // If the score of the top suggestion exceeds this value, the tested word (e.g., + // an OOV, a misspelling, or an in-vocabulary word) would be considered as a distracter to + // words in dictionary. The greater the threshold is, the less likely the tested word would + // become a distracter, which means the tested word will be more likely to be added to + // the dictionary. + private static final float DISTRACTER_WORD_SCORE_THRESHOLD = 2.0f; + /** * Create a DistracterFilter instance. * * @param suggest an instance of Suggest which will be used to obtain a list of suggestions - * for a potential distracter/misspelling + * for a potential distracter * @param keyboard the keyboard that is currently being used. This information is needed * when calling mSuggest.getSuggestedWords(...) to obtain a list of suggestions. */ @@ -40,9 +54,79 @@ public class DistracterFilter { mKeyboard = keyboard; } - public boolean isDistracterToWordsInDictionaries(final String prevWord, - final String targetWord) { - // TODO: to be implemented + public static DistracterFilter createDistracterFilter(final Suggest suggest, + final KeyboardSwitcher keyboardSwitcher) { + final MainKeyboardView mainKeyboardView = keyboardSwitcher.getMainKeyboardView(); + // TODO: Create Keyboard when mainKeyboardView is null. + // TODO: Figure out the most reasonable keyboard for the filter. Refer to the + // spellchecker's logic. + final Keyboard keyboard = (mainKeyboardView != null) ? + mainKeyboardView.getKeyboard() : null; + final DistracterFilter distracterFilter = new DistracterFilter(suggest, keyboard); + return distracterFilter; + } + + private static boolean suggestionExceedsDistracterThreshold( + final SuggestedWordInfo suggestion, final String consideredWord, + final float distracterThreshold) { + if (null != suggestion) { + final int suggestionScore = suggestion.mScore; + final float normalizedScore = BinaryDictionaryUtils.calcNormalizedScore( + consideredWord, suggestion.mWord, suggestionScore); + if (normalizedScore > distracterThreshold) { + return true; + } + } return false; } + + /** + * Determine whether a word is a distracter to words in dictionaries. + * + * @param prevWord the previous word, or null if none. + * @param testedWord the word that will be tested to see whether it is a distracter to words + * in dictionaries. + * @return true if testedWord is a distracter, otherwise false. + */ + public boolean isDistracterToWordsInDictionaries(final String prevWord, + final String testedWord) { + if (mSuggest == null) { + return false; + } + + final WordComposer composer = new WordComposer(); + final int[] codePoints = StringUtils.toCodePointArray(testedWord); + final int[] coordinates; + if (null == mKeyboard) { + coordinates = CoordinateUtils.newCoordinateArray(codePoints.length, + Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); + } else { + coordinates = mKeyboard.getCoordinates(codePoints); + } + composer.setComposingWord(codePoints, coordinates, prevWord); + + final int trailingSingleQuotesCount = composer.trailingSingleQuotesCount(); + final String consideredWord = trailingSingleQuotesCount > 0 ? testedWord.substring(0, + testedWord.length() - trailingSingleQuotesCount) : testedWord; + final AsyncResultHolder<Boolean> holder = new AsyncResultHolder<Boolean>(); + final OnGetSuggestedWordsCallback callback = new OnGetSuggestedWordsCallback() { + @Override + public void onGetSuggestedWords(final SuggestedWords suggestedWords) { + if (suggestedWords != null && suggestedWords.size() > 1) { + // The suggestedWordInfo at 0 is the typed word. The 1st suggestion from + // the decoder is at index 1. + final SuggestedWordInfo firstSuggestion = suggestedWords.getInfo(1); + final boolean hasStrongDistractor = suggestionExceedsDistracterThreshold( + firstSuggestion, consideredWord, DISTRACTER_WORD_SCORE_THRESHOLD); + holder.set(hasStrongDistractor); + } + } + }; + mSuggest.getSuggestedWords(composer, prevWord, mKeyboard.getProximityInfo(), + true /* blockOffensiveWords */, true /* isCorrectionEnbaled */, + null /* additionalFeaturesOptions */, 0 /* sessionId */, + SuggestedWords.NOT_A_SEQUENCE_NUMBER, callback); + + return holder.get(false /* defaultValue */, Constants.GET_SUGGESTED_WORDS_TIMEOUT); + } } diff --git a/java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java b/java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java index 55061f45f..74e7db901 100644 --- a/java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java +++ b/java/src/com/android/inputmethod/latin/utils/LanguageModelParam.java @@ -129,6 +129,9 @@ public final class LanguageModelParam { if (locale == null) { return null; } + // TODO: Though targetWord is an IV (in-vocabulary) word, we should still apply + // distracterFilter in the following code. If targetWord is a distracter, + // it should be filtered out. if (dictionaryFacilitator.isValidWord(targetWord, false /* ignoreCase */)) { return createAndGetLanguageModelParamOfWord(prevWord, targetWord, timestamp, true /* isValidWord */, locale); diff --git a/native/jni/CleanupNativeFileList.mk b/native/jni/CleanupNativeFileList.mk index 1738f8c58..eed6f1e63 100644 --- a/native/jni/CleanupNativeFileList.mk +++ b/native/jni/CleanupNativeFileList.mk @@ -13,6 +13,7 @@ # limitations under the License. LATIN_IME_CORE_SRC_FILES := +LATIN_IME_CORE_SRC_FILES_BACKWARD_V401 := LATIN_IME_CORE_TEST_FILES := LATIN_IME_JNI_SRC_FILES := LATIN_IME_SRC_DIR := diff --git a/native/jni/NativeFileList.mk b/native/jni/NativeFileList.mk index 6ccfec911..cb337e65c 100644 --- a/native/jni/NativeFileList.mk +++ b/native/jni/NativeFileList.mk @@ -95,9 +95,31 @@ LATIN_IME_CORE_SRC_FILES := \ $(addprefix utils/, \ autocorrection_threshold_utils.cpp \ char_utils.cpp \ + jni_data_utils.cpp \ log_utils.cpp \ time_keeper.cpp) +LATIN_IME_CORE_SRC_FILES_BACKWARD_V401 := \ + $(addprefix suggest/policyimpl/dictionary/structure/backward/v401/, \ + ver4_dict_buffers.cpp \ + ver4_dict_constants.cpp \ + ver4_patricia_trie_node_reader.cpp \ + ver4_patricia_trie_node_writer.cpp \ + ver4_patricia_trie_policy.cpp \ + ver4_patricia_trie_reading_utils.cpp \ + ver4_patricia_trie_writing_helper.cpp \ + ver4_pt_node_array_reader.cpp) \ + $(addprefix suggest/policyimpl/dictionary/structure/backward/v401/content/, \ + bigram_dict_content.cpp \ + probability_dict_content.cpp \ + shortcut_dict_content.cpp \ + sparse_table_dict_content.cpp \ + terminal_position_lookup_table.cpp) \ + $(addprefix suggest/policyimpl/dictionary/structure/backward/v401/bigram/, \ + ver4_bigram_list_policy.cpp) + +LATIN_IME_CORE_SRC_FILES += $(LATIN_IME_CORE_SRC_FILES_BACKWARD_V401) + LATIN_IME_CORE_TEST_FILES := \ defines_test.cpp \ suggest/core/layout/normal_distribution_2d_test.cpp \ diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index a55b2da96..18b78c4df 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -136,10 +136,9 @@ static void latinime_BinaryDictionary_getHeaderInfo(JNIEnv *env, jclass clazz, j if (!dictionary) return; const DictionaryHeaderStructurePolicy *const headerPolicy = dictionary->getDictionaryStructurePolicy()->getHeaderStructurePolicy(); - const int headerSize = headerPolicy->getSize(); - env->SetIntArrayRegion(outHeaderSize, 0 /* start */, 1 /* len */, &headerSize); - const int formatVersion = headerPolicy->getFormatVersionNumber(); - env->SetIntArrayRegion(outFormatVersion, 0 /* start */, 1 /* len */, &formatVersion); + JniDataUtils::putIntToArray(env, outHeaderSize, 0 /* index */, headerPolicy->getSize()); + JniDataUtils::putIntToArray(env, outFormatVersion, 0 /* index */, + headerPolicy->getFormatVersionNumber()); // Output attribute map jclass arrayListClass = env->FindClass("java/util/ArrayList"); jmethodID addMethodId = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z"); @@ -149,14 +148,16 @@ static void latinime_BinaryDictionary_getHeaderInfo(JNIEnv *env, jclass clazz, j it != attributeMap->end(); ++it) { // Output key jintArray keyCodePointArray = env->NewIntArray(it->first.size()); - env->SetIntArrayRegion( - keyCodePointArray, 0 /* start */, it->first.size(), &it->first.at(0)); + JniDataUtils::outputCodePoints(env, keyCodePointArray, 0 /* start */, + it->first.size(), it->first.data(), it->first.size(), + false /* needsNullTermination */); env->CallBooleanMethod(outAttributeKeys, addMethodId, keyCodePointArray); env->DeleteLocalRef(keyCodePointArray); // Output value jintArray valueCodePointArray = env->NewIntArray(it->second.size()); - env->SetIntArrayRegion( - valueCodePointArray, 0 /* start */, it->second.size(), &it->second.at(0)); + JniDataUtils::outputCodePoints(env, valueCodePointArray, 0 /* start */, + it->second.size(), it->second.data(), it->second.size(), + false /* needsNullTermination */); env->CallBooleanMethod(outAttributeValues, addMethodId, valueCodePointArray); env->DeleteLocalRef(valueCodePointArray); } @@ -182,8 +183,7 @@ static void latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, jfloatArray inOutLanguageWeight) { Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict); // Assign 0 to outSuggestionCount here in case of returning earlier in this method. - int count = 0; - env->SetIntArrayRegion(outSuggestionCount, 0, 1 /* len */, &count); + JniDataUtils::putIntToArray(env, outSuggestionCount, 0 /* index */, 0); if (!dictionary) { return; } @@ -300,7 +300,9 @@ static jint latinime_BinaryDictionary_getNextWord(JNIEnv *env, jclass clazz, int wordCodePoints[outCodePointsLength]; memset(wordCodePoints, 0, sizeof(wordCodePoints)); const int nextToken = dictionary->getNextWordAndNextToken(token, wordCodePoints); - env->SetIntArrayRegion(outCodePoints, 0, outCodePointsLength, wordCodePoints); + JniDataUtils::outputCodePoints(env, outCodePoints, 0 /* start */, + MAX_WORD_LENGTH /* maxLength */, wordCodePoints, outCodePointsLength, + false /* needsNullTermination */); return nextToken; } diff --git a/native/jni/src/suggest/core/dictionary/property/word_property.cpp b/native/jni/src/suggest/core/dictionary/property/word_property.cpp index 95608dcf8..6f5f808f8 100644 --- a/native/jni/src/suggest/core/dictionary/property/word_property.cpp +++ b/native/jni/src/suggest/core/dictionary/property/word_property.cpp @@ -16,14 +16,17 @@ #include "suggest/core/dictionary/property/word_property.h" +#include "utils/jni_data_utils.h" + namespace latinime { void WordProperty::outputProperties(JNIEnv *const env, jintArray outCodePoints, jbooleanArray outFlags, jintArray outProbabilityInfo, jobject outBigramTargets, jobject outBigramProbabilities, jobject outShortcutTargets, jobject outShortcutProbabilities) const { - env->SetIntArrayRegion(outCodePoints, 0 /* start */, mCodePoints.size(), &mCodePoints[0]); - + JniDataUtils::outputCodePoints(env, outCodePoints, 0 /* start */, + MAX_WORD_LENGTH /* maxLength */, mCodePoints.data(), mCodePoints.size(), + false /* needsNullTermination */); jboolean flags[] = {mUnigramProperty.isNotAWord(), mUnigramProperty.isBlacklisted(), !mBigrams.empty(), mUnigramProperty.hasShortcuts()}; env->SetBooleanArrayRegion(outFlags, 0 /* start */, NELEMS(flags), flags); @@ -41,8 +44,9 @@ void WordProperty::outputProperties(JNIEnv *const env, jintArray outCodePoints, for (const auto &bigramProperty : mBigrams) { const std::vector<int> *const word1CodePoints = bigramProperty.getTargetCodePoints(); jintArray bigramWord1CodePointArray = env->NewIntArray(word1CodePoints->size()); - env->SetIntArrayRegion(bigramWord1CodePointArray, 0 /* start */, - word1CodePoints->size(), word1CodePoints->data()); + JniDataUtils::outputCodePoints(env, bigramWord1CodePointArray, 0 /* start */, + word1CodePoints->size(), word1CodePoints->data(), word1CodePoints->size(), + false /* needsNullTermination */); env->CallBooleanMethod(outBigramTargets, addMethodId, bigramWord1CodePointArray); env->DeleteLocalRef(bigramWord1CodePointArray); @@ -62,6 +66,9 @@ void WordProperty::outputProperties(JNIEnv *const env, jintArray outCodePoints, jintArray shortcutTargetCodePointArray = env->NewIntArray(targetCodePoints->size()); env->SetIntArrayRegion(shortcutTargetCodePointArray, 0 /* start */, targetCodePoints->size(), targetCodePoints->data()); + JniDataUtils::outputCodePoints(env, shortcutTargetCodePointArray, 0 /* start */, + targetCodePoints->size(), targetCodePoints->data(), targetCodePoints->size(), + false /* needsNullTermination */); env->CallBooleanMethod(outShortcutTargets, addMethodId, shortcutTargetCodePointArray); env->DeleteLocalRef(shortcutTargetCodePointArray); jobject integerProbability = env->NewObject(integerClass, intToIntegerConstructorId, diff --git a/native/jni/src/suggest/core/result/suggestion_results.cpp b/native/jni/src/suggest/core/result/suggestion_results.cpp index 088a55f6f..4c10bd08a 100644 --- a/native/jni/src/suggest/core/result/suggestion_results.cpp +++ b/native/jni/src/suggest/core/result/suggestion_results.cpp @@ -16,6 +16,8 @@ #include "suggest/core/result/suggestion_results.h" +#include "utils/jni_data_utils.h" + namespace latinime { void SuggestionResults::outputSuggestions(JNIEnv *env, jintArray outSuggestionCount, @@ -27,31 +29,22 @@ void SuggestionResults::outputSuggestions(JNIEnv *env, jintArray outSuggestionCo const SuggestedWord &suggestedWord = mSuggestedWords.top(); suggestedWord.getCodePointCount(); const int start = outputIndex * MAX_WORD_LENGTH; - env->SetIntArrayRegion(outputCodePointsArray, start, suggestedWord.getCodePointCount(), - suggestedWord.getCodePoint()); - if (suggestedWord.getCodePointCount() < MAX_WORD_LENGTH) { - const int terminal = 0; - env->SetIntArrayRegion(outputCodePointsArray, start + suggestedWord.getCodePointCount(), - 1 /* len */, &terminal); - } - const int score = suggestedWord.getScore(); - env->SetIntArrayRegion(outScoresArray, outputIndex, 1 /* len */, &score); - const int indexToPartialCommit = suggestedWord.getIndexToPartialCommit(); - env->SetIntArrayRegion(outSpaceIndicesArray, outputIndex, 1 /* len */, - &indexToPartialCommit); - const int type = suggestedWord.getType(); - env->SetIntArrayRegion(outTypesArray, outputIndex, 1 /* len */, &type); + JniDataUtils::outputCodePoints(env, outputCodePointsArray, start, + MAX_WORD_LENGTH /* maxLength */, suggestedWord.getCodePoint(), + suggestedWord.getCodePointCount(), true /* needsNullTermination */); + JniDataUtils::putIntToArray(env, outScoresArray, outputIndex, suggestedWord.getScore()); + JniDataUtils::putIntToArray(env, outSpaceIndicesArray, outputIndex, + suggestedWord.getIndexToPartialCommit()); + JniDataUtils::putIntToArray(env, outTypesArray, outputIndex, suggestedWord.getType()); if (mSuggestedWords.size() == 1) { - const int autoCommitFirstWordConfidence = - suggestedWord.getAutoCommitFirstWordConfidence(); - env->SetIntArrayRegion(outAutoCommitFirstWordConfidenceArray, 0 /* start */, - 1 /* len */, &autoCommitFirstWordConfidence); + JniDataUtils::putIntToArray(env, outAutoCommitFirstWordConfidenceArray, 0 /* index */, + suggestedWord.getAutoCommitFirstWordConfidence()); } ++outputIndex; mSuggestedWords.pop(); } - env->SetIntArrayRegion(outSuggestionCount, 0 /* start */, 1 /* len */, &outputIndex); - env->SetFloatArrayRegion(outLanguageWeight, 0 /* start */, 1 /* len */, &mLanguageWeight); + JniDataUtils::putIntToArray(env, outSuggestionCount, 0 /* index */, outputIndex); + JniDataUtils::putFloatToArray(env, outLanguageWeight, 0 /* index */, mLanguageWeight); } void SuggestionResults::addPrediction(const int *const codePoints, const int codePointCount, diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/Readme.txt b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/Readme.txt new file mode 100644 index 000000000..9e29e836c --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/Readme.txt @@ -0,0 +1 @@ +Files under this directory have been auto generated. diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.cpp new file mode 100644 index 000000000..7ad072f09 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.cpp @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT CHANGE THE LOGIC IN THIS FILE !!!!! + * Do not edit this file other than updating policy's interface. + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/bigram/ver4_bigram_list_policy.cpp + */ + +#include "suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.h" + +#include "suggest/core/dictionary/property/bigram_property.h" +#include "suggest/policyimpl/dictionary/header/header_policy.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h" + +namespace latinime { +namespace backward { +namespace v401 { + +void Ver4BigramListPolicy::getNextBigram(int *const outBigramPos, int *const outProbability, + bool *const outHasNext, int *const bigramEntryPos) const { + const BigramEntry bigramEntry = + mBigramDictContent->getBigramEntryAndAdvancePosition(bigramEntryPos); + if (outBigramPos) { + // Lookup target PtNode position. + *outBigramPos = mTerminalPositionLookupTable->getTerminalPtNodePosition( + bigramEntry.getTargetTerminalId()); + } + if (outProbability) { + if (bigramEntry.hasHistoricalInfo()) { + *outProbability = + ForgettingCurveUtils::decodeProbability(bigramEntry.getHistoricalInfo(), + mHeaderPolicy); + } else { + *outProbability = bigramEntry.getProbability(); + } + } + if (outHasNext) { + *outHasNext = bigramEntry.hasNext(); + } +} + +bool Ver4BigramListPolicy::addNewEntry(const int terminalId, const int newTargetTerminalId, + const BigramProperty *const bigramProperty, bool *const outAddedNewEntry) { + // 1. The word has no bigrams yet. + // 2. The word has bigrams, and there is the target in the list. + // 3. The word has bigrams, and there is an invalid entry that can be reclaimed. + // 4. The word has bigrams. We have to append new bigram entry to the list. + // 5. Same as 4, but the list is the last entry of the content file. + if (outAddedNewEntry) { + *outAddedNewEntry = false; + } + const int bigramListPos = mBigramDictContent->getBigramListHeadPos(terminalId); + if (bigramListPos == NOT_A_DICT_POS) { + // Case 1. PtNode that doesn't have a bigram list. + // Create new bigram list. + if (!mBigramDictContent->createNewBigramList(terminalId)) { + return false; + } + const BigramEntry newBigramEntry(false /* hasNext */, NOT_A_PROBABILITY, + newTargetTerminalId); + const BigramEntry bigramEntryToWrite = createUpdatedBigramEntryFrom(&newBigramEntry, + bigramProperty); + // Write an entry. + const int writingPos = mBigramDictContent->getBigramListHeadPos(terminalId); + if (!mBigramDictContent->writeBigramEntry(&bigramEntryToWrite, writingPos)) { + return false; + } + if (outAddedNewEntry) { + *outAddedNewEntry = true; + } + return true; + } + + int tailEntryPos = NOT_A_DICT_POS; + const int entryPosToUpdate = getEntryPosToUpdate(newTargetTerminalId, bigramListPos, + &tailEntryPos); + if (tailEntryPos != NOT_A_DICT_POS || entryPosToUpdate == NOT_A_DICT_POS) { + // Case 4, 5. + // Add new entry to the bigram list. + if (tailEntryPos == NOT_A_DICT_POS) { + // Case 4. Create new bigram list. + if (!mBigramDictContent->createNewBigramList(terminalId)) { + return false; + } + const int destPos = mBigramDictContent->getBigramListHeadPos(terminalId); + // Copy existing bigram list. + if (!mBigramDictContent->copyBigramList(bigramListPos, destPos, &tailEntryPos)) { + return false; + } + } + // Write new entry at the tail position of the bigram content. + const BigramEntry newBigramEntry(false /* hasNext */, NOT_A_PROBABILITY, + newTargetTerminalId); + const BigramEntry bigramEntryToWrite = createUpdatedBigramEntryFrom( + &newBigramEntry, bigramProperty); + if (!mBigramDictContent->writeBigramEntryAtTail(&bigramEntryToWrite)) { + return false; + } + // Update has next flag of the tail entry. + if (!updateHasNextFlag(true /* hasNext */, tailEntryPos)) { + return false; + } + if (outAddedNewEntry) { + *outAddedNewEntry = true; + } + return true; + } + + // Case 2. Overwrite the existing entry. Case 3. Reclaim and reuse the existing invalid entry. + const BigramEntry originalBigramEntry = mBigramDictContent->getBigramEntry(entryPosToUpdate); + if (!originalBigramEntry.isValid()) { + // Case 3. Reuse the existing invalid entry. outAddedNewEntry is false when an existing + // entry is updated. + if (outAddedNewEntry) { + *outAddedNewEntry = true; + } + } + const BigramEntry updatedBigramEntry = + originalBigramEntry.updateTargetTerminalIdAndGetEntry(newTargetTerminalId); + const BigramEntry bigramEntryToWrite = createUpdatedBigramEntryFrom( + &updatedBigramEntry, bigramProperty); + return mBigramDictContent->writeBigramEntry(&bigramEntryToWrite, entryPosToUpdate); +} + +bool Ver4BigramListPolicy::removeEntry(const int terminalId, const int targetTerminalId) { + const int bigramListPos = mBigramDictContent->getBigramListHeadPos(terminalId); + if (bigramListPos == NOT_A_DICT_POS) { + // Bigram list doesn't exist. + return false; + } + const int entryPosToUpdate = getEntryPosToUpdate(targetTerminalId, bigramListPos, + nullptr /* outTailEntryPos */); + if (entryPosToUpdate == NOT_A_DICT_POS) { + // Bigram entry doesn't exist. + return false; + } + const BigramEntry bigramEntry = mBigramDictContent->getBigramEntry(entryPosToUpdate); + if (targetTerminalId != bigramEntry.getTargetTerminalId()) { + // Bigram entry doesn't exist. + return false; + } + // Remove bigram entry by marking it as invalid entry and overwriting the original entry. + const BigramEntry updatedBigramEntry = bigramEntry.getInvalidatedEntry(); + return mBigramDictContent->writeBigramEntry(&updatedBigramEntry, entryPosToUpdate); +} + +bool Ver4BigramListPolicy::updateAllBigramEntriesAndDeleteUselessEntries(const int terminalId, + int *const outBigramCount) { + const int bigramListPos = mBigramDictContent->getBigramListHeadPos(terminalId); + if (bigramListPos == NOT_A_DICT_POS) { + // Bigram list doesn't exist. + return true; + } + bool hasNext = true; + int readingPos = bigramListPos; + while (hasNext) { + const int entryPos = readingPos; + const BigramEntry bigramEntry = + mBigramDictContent->getBigramEntryAndAdvancePosition(&readingPos); + hasNext = bigramEntry.hasNext(); + if (!bigramEntry.isValid()) { + continue; + } + const int targetPtNodePos = mTerminalPositionLookupTable->getTerminalPtNodePosition( + bigramEntry.getTargetTerminalId()); + if (targetPtNodePos == NOT_A_DICT_POS) { + // Invalidate bigram entry. + const BigramEntry updatedBigramEntry = bigramEntry.getInvalidatedEntry(); + if (!mBigramDictContent->writeBigramEntry(&updatedBigramEntry, entryPos)) { + return false; + } + } else if (bigramEntry.hasHistoricalInfo()) { + const HistoricalInfo historicalInfo = ForgettingCurveUtils::createHistoricalInfoToSave( + bigramEntry.getHistoricalInfo(), mHeaderPolicy); + if (ForgettingCurveUtils::needsToKeep(&historicalInfo, mHeaderPolicy)) { + const BigramEntry updatedBigramEntry = + bigramEntry.updateHistoricalInfoAndGetEntry(&historicalInfo); + if (!mBigramDictContent->writeBigramEntry(&updatedBigramEntry, entryPos)) { + return false; + } + *outBigramCount += 1; + } else { + // Remove entry. + const BigramEntry updatedBigramEntry = bigramEntry.getInvalidatedEntry(); + if (!mBigramDictContent->writeBigramEntry(&updatedBigramEntry, entryPos)) { + return false; + } + } + } else { + *outBigramCount += 1; + } + } + return true; +} + +int Ver4BigramListPolicy::getBigramEntryConut(const int terminalId) { + const int bigramListPos = mBigramDictContent->getBigramListHeadPos(terminalId); + if (bigramListPos == NOT_A_DICT_POS) { + // Bigram list doesn't exist. + return 0; + } + int bigramCount = 0; + bool hasNext = true; + int readingPos = bigramListPos; + while (hasNext) { + const BigramEntry bigramEntry = + mBigramDictContent->getBigramEntryAndAdvancePosition(&readingPos); + hasNext = bigramEntry.hasNext(); + if (bigramEntry.isValid()) { + bigramCount++; + } + } + return bigramCount; +} + +int Ver4BigramListPolicy::getEntryPosToUpdate(const int targetTerminalIdToFind, + const int bigramListPos, int *const outTailEntryPos) const { + if (outTailEntryPos) { + *outTailEntryPos = NOT_A_DICT_POS; + } + bool hasNext = true; + int invalidEntryPos = NOT_A_DICT_POS; + int readingPos = bigramListPos; + while (hasNext) { + const int entryPos = readingPos; + const BigramEntry bigramEntry = + mBigramDictContent->getBigramEntryAndAdvancePosition(&readingPos); + hasNext = bigramEntry.hasNext(); + if (bigramEntry.getTargetTerminalId() == targetTerminalIdToFind) { + // Entry with same target is found. + return entryPos; + } else if (!bigramEntry.isValid()) { + // Invalid entry that can be reused is found. + invalidEntryPos = entryPos; + } + if (!hasNext && mBigramDictContent->isContentTailPos(readingPos)) { + if (outTailEntryPos) { + *outTailEntryPos = entryPos; + } + } + } + return invalidEntryPos; +} + +const BigramEntry Ver4BigramListPolicy::createUpdatedBigramEntryFrom( + const BigramEntry *const originalBigramEntry, + const BigramProperty *const bigramProperty) const { + // TODO: Consolidate historical info and probability. + if (mHeaderPolicy->hasHistoricalInfoOfWords()) { + const HistoricalInfo historicalInfoForUpdate(bigramProperty->getTimestamp(), + bigramProperty->getLevel(), bigramProperty->getCount()); + const HistoricalInfo updatedHistoricalInfo = + ForgettingCurveUtils::createUpdatedHistoricalInfo( + originalBigramEntry->getHistoricalInfo(), bigramProperty->getProbability(), + &historicalInfoForUpdate, mHeaderPolicy); + return originalBigramEntry->updateHistoricalInfoAndGetEntry(&updatedHistoricalInfo); + } else { + return originalBigramEntry->updateProbabilityAndGetEntry(bigramProperty->getProbability()); + } +} + +bool Ver4BigramListPolicy::updateHasNextFlag(const bool hasNext, const int bigramEntryPos) { + const BigramEntry bigramEntry = mBigramDictContent->getBigramEntry(bigramEntryPos); + const BigramEntry updatedBigramEntry = bigramEntry.updateHasNextAndGetEntry(hasNext); + return mBigramDictContent->writeBigramEntry(&updatedBigramEntry, bigramEntryPos); +} + +} // namespace v401 +} // namespace backward +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.h new file mode 100644 index 000000000..adf687bac --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT CHANGE THE LOGIC IN THIS FILE !!!!! + * Do not edit this file other than updating policy's interface. + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/bigram/ver4_bigram_list_policy.h + */ + +#ifndef LATINIME_BACKWARD_V401_VER4_BIGRAM_LIST_POLICY_H +#define LATINIME_BACKWARD_V401_VER4_BIGRAM_LIST_POLICY_H + +#include "defines.h" +#include "suggest/core/policy/dictionary_bigrams_structure_policy.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_entry.h" + +namespace latinime { +namespace backward { +namespace v401 { + +class BigramDictContent; +} // namespace v401 +} // namespace backward +class BigramProperty; +namespace backward { +namespace v401 { +} // namespace v401 +} // namespace backward +class HeaderPolicy; +namespace backward { +namespace v401 { +class TerminalPositionLookupTable; + +class Ver4BigramListPolicy : public DictionaryBigramsStructurePolicy { + public: + Ver4BigramListPolicy(BigramDictContent *const bigramDictContent, + const TerminalPositionLookupTable *const terminalPositionLookupTable, + const HeaderPolicy *const headerPolicy) + : mBigramDictContent(bigramDictContent), + mTerminalPositionLookupTable(terminalPositionLookupTable), + mHeaderPolicy(headerPolicy) {} + + void getNextBigram(int *const outBigramPos, int *const outProbability, + bool *const outHasNext, int *const bigramEntryPos) const; + + void skipAllBigrams(int *const pos) const { + // Do nothing because we don't need to skip bigram lists in ver4 dictionaries. + } + + bool addNewEntry(const int terminalId, const int newTargetTerminalId, + const BigramProperty *const bigramProperty, bool *const outAddedNewEntry); + + bool removeEntry(const int terminalId, const int targetTerminalId); + + bool updateAllBigramEntriesAndDeleteUselessEntries(const int terminalId, + int *const outBigramCount); + + int getBigramEntryConut(const int terminalId); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4BigramListPolicy); + + int getEntryPosToUpdate(const int targetTerminalIdToFind, const int bigramListPos, + int *const outTailEntryPos) const; + + const BigramEntry createUpdatedBigramEntryFrom(const BigramEntry *const originalBigramEntry, + const BigramProperty *const bigramProperty) const; + + bool updateHasNextFlag(const bool hasNext, const int bigramEntryPos); + + BigramDictContent *const mBigramDictContent; + const TerminalPositionLookupTable *const mTerminalPositionLookupTable; + const HeaderPolicy *const mHeaderPolicy; +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif /* LATINIME_BACKWARD_V401_VER4_BIGRAM_LIST_POLICY_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.cpp new file mode 100644 index 000000000..1e53ff94a --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.cpp @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.cpp + */ + +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.h" + +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" + +namespace latinime { +namespace backward { +namespace v401 { + +const BigramEntry BigramDictContent::getBigramEntryAndAdvancePosition( + int *const bigramEntryPos) const { + const BufferWithExtendableBuffer *const bigramListBuffer = getContentBuffer(); + if (*bigramEntryPos < 0 || *bigramEntryPos >= bigramListBuffer->getTailPosition()) { + AKLOGE("Invalid bigram entry position. bigramEntryPos: %d, bufSize: %d", + *bigramEntryPos, bigramListBuffer->getTailPosition()); + ASSERT(false); + return BigramEntry(false /* hasNext */, NOT_A_PROBABILITY, + Ver4DictConstants::NOT_A_TERMINAL_ID); + } + const int bigramFlags = bigramListBuffer->readUintAndAdvancePosition( + Ver4DictConstants::BIGRAM_FLAGS_FIELD_SIZE, bigramEntryPos); + const bool hasNext = (bigramFlags & Ver4DictConstants::BIGRAM_HAS_NEXT_MASK) != 0; + int probability = NOT_A_PROBABILITY; + int timestamp = NOT_A_TIMESTAMP; + int level = 0; + int count = 0; + if (mHasHistoricalInfo) { + probability = bigramListBuffer->readUintAndAdvancePosition( + Ver4DictConstants::PROBABILITY_SIZE, bigramEntryPos); + timestamp = bigramListBuffer->readUintAndAdvancePosition( + Ver4DictConstants::TIME_STAMP_FIELD_SIZE, bigramEntryPos); + level = bigramListBuffer->readUintAndAdvancePosition( + Ver4DictConstants::WORD_LEVEL_FIELD_SIZE, bigramEntryPos); + count = bigramListBuffer->readUintAndAdvancePosition( + Ver4DictConstants::WORD_COUNT_FIELD_SIZE, bigramEntryPos); + } else { + probability = bigramFlags & Ver4DictConstants::BIGRAM_PROBABILITY_MASK; + } + const int encodedTargetTerminalId = bigramListBuffer->readUintAndAdvancePosition( + Ver4DictConstants::BIGRAM_TARGET_TERMINAL_ID_FIELD_SIZE, bigramEntryPos); + const int targetTerminalId = + (encodedTargetTerminalId == Ver4DictConstants::INVALID_BIGRAM_TARGET_TERMINAL_ID) ? + Ver4DictConstants::NOT_A_TERMINAL_ID : encodedTargetTerminalId; + if (mHasHistoricalInfo) { + const HistoricalInfo historicalInfo(timestamp, level, count); + return BigramEntry(hasNext, probability, &historicalInfo, targetTerminalId); + } else { + return BigramEntry(hasNext, probability, targetTerminalId); + } +} + +bool BigramDictContent::writeBigramEntryAndAdvancePosition( + const BigramEntry *const bigramEntryToWrite, int *const entryWritingPos) { + BufferWithExtendableBuffer *const bigramListBuffer = getWritableContentBuffer(); + const int bigramFlags = createAndGetBigramFlags( + mHasHistoricalInfo ? 0 : bigramEntryToWrite->getProbability(), + bigramEntryToWrite->hasNext()); + if (!bigramListBuffer->writeUintAndAdvancePosition(bigramFlags, + Ver4DictConstants::BIGRAM_FLAGS_FIELD_SIZE, entryWritingPos)) { + AKLOGE("Cannot write bigram flags. pos: %d, flags: %x", *entryWritingPos, bigramFlags); + return false; + } + if (mHasHistoricalInfo) { + if (!bigramListBuffer->writeUintAndAdvancePosition(bigramEntryToWrite->getProbability(), + Ver4DictConstants::PROBABILITY_SIZE, entryWritingPos)) { + AKLOGE("Cannot write bigram probability. pos: %d, probability: %d", *entryWritingPos, + bigramEntryToWrite->getProbability()); + return false; + } + const HistoricalInfo *const historicalInfo = bigramEntryToWrite->getHistoricalInfo(); + if (!bigramListBuffer->writeUintAndAdvancePosition(historicalInfo->getTimeStamp(), + Ver4DictConstants::TIME_STAMP_FIELD_SIZE, entryWritingPos)) { + AKLOGE("Cannot write bigram timestamps. pos: %d, timestamp: %d", *entryWritingPos, + historicalInfo->getTimeStamp()); + return false; + } + if (!bigramListBuffer->writeUintAndAdvancePosition(historicalInfo->getLevel(), + Ver4DictConstants::WORD_LEVEL_FIELD_SIZE, entryWritingPos)) { + AKLOGE("Cannot write bigram level. pos: %d, level: %d", *entryWritingPos, + historicalInfo->getLevel()); + return false; + } + if (!bigramListBuffer->writeUintAndAdvancePosition(historicalInfo->getCount(), + Ver4DictConstants::WORD_COUNT_FIELD_SIZE, entryWritingPos)) { + AKLOGE("Cannot write bigram count. pos: %d, count: %d", *entryWritingPos, + historicalInfo->getCount()); + return false; + } + } + const int targetTerminalIdToWrite = + (bigramEntryToWrite->getTargetTerminalId() == Ver4DictConstants::NOT_A_TERMINAL_ID) ? + Ver4DictConstants::INVALID_BIGRAM_TARGET_TERMINAL_ID : + bigramEntryToWrite->getTargetTerminalId(); + if (!bigramListBuffer->writeUintAndAdvancePosition(targetTerminalIdToWrite, + Ver4DictConstants::BIGRAM_TARGET_TERMINAL_ID_FIELD_SIZE, entryWritingPos)) { + AKLOGE("Cannot write bigram target terminal id. pos: %d, target terminal id: %d", + *entryWritingPos, bigramEntryToWrite->getTargetTerminalId()); + return false; + } + return true; +} + +bool BigramDictContent::copyBigramList(const int bigramListPos, const int toPos, + int *const outTailEntryPos) { + int readingPos = bigramListPos; + int writingPos = toPos; + bool hasNext = true; + while (hasNext) { + const BigramEntry bigramEntry = getBigramEntryAndAdvancePosition(&readingPos); + hasNext = bigramEntry.hasNext(); + if (!hasNext) { + *outTailEntryPos = writingPos; + } + if (!writeBigramEntryAndAdvancePosition(&bigramEntry, &writingPos)) { + AKLOGE("Cannot write bigram entry to copy. pos: %d", writingPos); + return false; + } + } + return true; +} + +bool BigramDictContent::runGC(const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, + const BigramDictContent *const originalBigramDictContent, + int *const outBigramEntryCount) { + for (TerminalPositionLookupTable::TerminalIdMap::const_iterator it = terminalIdMap->begin(); + it != terminalIdMap->end(); ++it) { + const int originalBigramListPos = + originalBigramDictContent->getBigramListHeadPos(it->first); + if (originalBigramListPos == NOT_A_DICT_POS) { + // This terminal does not have a bigram list. + continue; + } + const int bigramListPos = getContentBuffer()->getTailPosition(); + int bigramEntryCount = 0; + // Copy bigram list with GC from original content. + if (!runGCBigramList(originalBigramListPos, originalBigramDictContent, bigramListPos, + terminalIdMap, &bigramEntryCount)) { + AKLOGE("Cannot complete GC for the bigram list. original pos: %d, pos: %d", + originalBigramListPos, bigramListPos); + return false; + } + if (bigramEntryCount == 0) { + // All bigram entries are useless. This terminal does not have a bigram list. + continue; + } + *outBigramEntryCount += bigramEntryCount; + // Set bigram list position to the lookup table. + if (!getUpdatableAddressLookupTable()->set(it->second, bigramListPos)) { + AKLOGE("Cannot set bigram list position. terminal id: %d, pos: %d", + it->second, bigramListPos); + return false; + } + } + return true; +} + +// Returns whether GC for the bigram list was succeeded or not. +bool BigramDictContent::runGCBigramList(const int bigramListPos, + const BigramDictContent *const sourceBigramDictContent, const int toPos, + const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, + int *const outEntrycount) { + bool hasNext = true; + int readingPos = bigramListPos; + int writingPos = toPos; + int lastEntryPos = NOT_A_DICT_POS; + while (hasNext) { + const BigramEntry originalBigramEntry = + sourceBigramDictContent->getBigramEntryAndAdvancePosition(&readingPos); + hasNext = originalBigramEntry.hasNext(); + if (originalBigramEntry.getTargetTerminalId() == Ver4DictConstants::NOT_A_TERMINAL_ID) { + continue; + } + TerminalPositionLookupTable::TerminalIdMap::const_iterator it = + terminalIdMap->find(originalBigramEntry.getTargetTerminalId()); + if (it == terminalIdMap->end()) { + // Target word has been removed. + continue; + } + lastEntryPos = hasNext ? writingPos : NOT_A_DICT_POS; + const BigramEntry updatedBigramEntry = + originalBigramEntry.updateTargetTerminalIdAndGetEntry(it->second); + if (!writeBigramEntryAndAdvancePosition(&updatedBigramEntry, &writingPos)) { + AKLOGE("Cannot write bigram entry to run GC. pos: %d", writingPos); + return false; + } + *outEntrycount += 1; + } + if (lastEntryPos != NOT_A_DICT_POS) { + // Update has next flag in the last written entry. + const BigramEntry bigramEntry = getBigramEntry(lastEntryPos).updateHasNextAndGetEntry( + false /* hasNext */); + if (!writeBigramEntry(&bigramEntry, lastEntryPos)) { + AKLOGE("Cannot write bigram entry to set hasNext flag after GC. pos: %d", writingPos); + return false; + } + } + return true; +} + +} // namespace v401 +} // namespace backward +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.h new file mode 100644 index 000000000..f9c474b4a --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.h + */ + +#ifndef LATINIME_BACKWARD_V401_BIGRAM_DICT_CONTENT_H +#define LATINIME_BACKWARD_V401_BIGRAM_DICT_CONTENT_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_entry.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h" + +namespace latinime { +namespace backward { +namespace v401 { + +class BigramDictContent : public SparseTableDictContent { + public: + BigramDictContent(const char *const dictPath, const bool hasHistoricalInfo, + const bool isUpdatable) + : SparseTableDictContent(dictPath, + Ver4DictConstants::BIGRAM_LOOKUP_TABLE_FILE_EXTENSION, + Ver4DictConstants::BIGRAM_CONTENT_TABLE_FILE_EXTENSION, + Ver4DictConstants::BIGRAM_FILE_EXTENSION, isUpdatable, + Ver4DictConstants::BIGRAM_ADDRESS_TABLE_BLOCK_SIZE, + Ver4DictConstants::BIGRAM_ADDRESS_TABLE_DATA_SIZE), + mHasHistoricalInfo(hasHistoricalInfo) {} + + BigramDictContent(const bool hasHistoricalInfo) + : SparseTableDictContent(Ver4DictConstants::BIGRAM_ADDRESS_TABLE_BLOCK_SIZE, + Ver4DictConstants::BIGRAM_ADDRESS_TABLE_DATA_SIZE), + mHasHistoricalInfo(hasHistoricalInfo) {} + + const BigramEntry getBigramEntry(const int bigramEntryPos) const { + int readingPos = bigramEntryPos; + return getBigramEntryAndAdvancePosition(&readingPos); + } + + const BigramEntry getBigramEntryAndAdvancePosition(int *const bigramEntryPos) const; + + // Returns head position of bigram list for a PtNode specified by terminalId. + int getBigramListHeadPos(const int terminalId) const { + const SparseTable *const addressLookupTable = getAddressLookupTable(); + if (!addressLookupTable->contains(terminalId)) { + return NOT_A_DICT_POS; + } + return addressLookupTable->get(terminalId); + } + + bool writeBigramEntryAtTail(const BigramEntry *const bigramEntryToWrite) { + int writingPos = getContentBuffer()->getTailPosition(); + return writeBigramEntryAndAdvancePosition(bigramEntryToWrite, &writingPos); + } + + bool writeBigramEntry(const BigramEntry *const bigramEntryToWrite, const int entryWritingPos) { + int writingPos = entryWritingPos; + return writeBigramEntryAndAdvancePosition(bigramEntryToWrite, &writingPos); + } + + bool writeBigramEntryAndAdvancePosition(const BigramEntry *const bigramEntryToWrite, + int *const entryWritingPos); + + bool createNewBigramList(const int terminalId) { + const int bigramListPos = getContentBuffer()->getTailPosition(); + return getUpdatableAddressLookupTable()->set(terminalId, bigramListPos); + } + + bool copyBigramList(const int bigramListPos, const int toPos, int *const outTailEntryPos); + + bool flushToFile(const char *const dictPath) const { + return flush(dictPath, Ver4DictConstants::BIGRAM_LOOKUP_TABLE_FILE_EXTENSION, + Ver4DictConstants::BIGRAM_CONTENT_TABLE_FILE_EXTENSION, + Ver4DictConstants::BIGRAM_FILE_EXTENSION); + } + + bool runGC(const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, + const BigramDictContent *const originalBigramDictContent, + int *const outBigramEntryCount); + + bool isContentTailPos(const int pos) const { + return pos == getContentBuffer()->getTailPosition(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(BigramDictContent); + + int createAndGetBigramFlags(const int probability, const bool hasNext) const { + return (probability & Ver4DictConstants::BIGRAM_PROBABILITY_MASK) + | (hasNext ? Ver4DictConstants::BIGRAM_HAS_NEXT_MASK : 0); + } + + bool runGCBigramList(const int bigramListPos, + const BigramDictContent *const sourceBigramDictContent, const int toPos, + const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, + int *const outEntryCount); + + bool mHasHistoricalInfo; +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif /* LATINIME_BACKWARD_V401_BIGRAM_DICT_CONTENT_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_entry.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_entry.h new file mode 100644 index 000000000..82c4b53a8 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_entry.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/content/bigram_entry.h + */ + +#ifndef LATINIME_BACKWARD_V401_BIGRAM_ENTRY_H +#define LATINIME_BACKWARD_V401_BIGRAM_ENTRY_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/utils/historical_info.h" + +namespace latinime { +namespace backward { +namespace v401 { + +class BigramEntry { + public: + BigramEntry(const BigramEntry& bigramEntry) + : mHasNext(bigramEntry.mHasNext), mProbability(bigramEntry.mProbability), + mHistoricalInfo(), mTargetTerminalId(bigramEntry.mTargetTerminalId) {} + + // Entry with historical information. + BigramEntry(const bool hasNext, const int probability, const int targetTerminalId) + : mHasNext(hasNext), mProbability(probability), mHistoricalInfo(), + mTargetTerminalId(targetTerminalId) {} + + // Entry with historical information. + BigramEntry(const bool hasNext, const int probability, + const HistoricalInfo *const historicalInfo, const int targetTerminalId) + : mHasNext(hasNext), mProbability(probability), mHistoricalInfo(*historicalInfo), + mTargetTerminalId(targetTerminalId) {} + + const BigramEntry getInvalidatedEntry() const { + return updateTargetTerminalIdAndGetEntry(Ver4DictConstants::NOT_A_TERMINAL_ID); + } + + const BigramEntry updateHasNextAndGetEntry(const bool hasNext) const { + return BigramEntry(hasNext, mProbability, &mHistoricalInfo, mTargetTerminalId); + } + + const BigramEntry updateTargetTerminalIdAndGetEntry(const int newTargetTerminalId) const { + return BigramEntry(mHasNext, mProbability, &mHistoricalInfo, newTargetTerminalId); + } + + const BigramEntry updateProbabilityAndGetEntry(const int probability) const { + return BigramEntry(mHasNext, probability, &mHistoricalInfo, mTargetTerminalId); + } + + const BigramEntry updateHistoricalInfoAndGetEntry( + const HistoricalInfo *const historicalInfo) const { + return BigramEntry(mHasNext, mProbability, historicalInfo, mTargetTerminalId); + } + + bool isValid() const { + return mTargetTerminalId != Ver4DictConstants::NOT_A_TERMINAL_ID; + } + + bool hasNext() const { + return mHasNext; + } + + int getProbability() const { + return mProbability; + } + + bool hasHistoricalInfo() const { + return mHistoricalInfo.isValid(); + } + + const HistoricalInfo *getHistoricalInfo() const { + return &mHistoricalInfo; + } + + int getTargetTerminalId() const { + return mTargetTerminalId; + } + + private: + // Copy constructor is public to use this class as a type of return value. + DISALLOW_DEFAULT_CONSTRUCTOR(BigramEntry); + DISALLOW_ASSIGNMENT_OPERATOR(BigramEntry); + + const bool mHasNext; + const int mProbability; + const HistoricalInfo mHistoricalInfo; + const int mTargetTerminalId; +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif /* LATINIME_BACKWARD_V401_BIGRAM_ENTRY_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/dict_content.h new file mode 100644 index 000000000..39e29001c --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/dict_content.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/content/dict_content.h + */ + +#ifndef LATINIME_BACKWARD_V401_DICT_CONTENT_H +#define LATINIME_BACKWARD_V401_DICT_CONTENT_H + +#include "defines.h" + +namespace latinime { +namespace backward { +namespace v401 { + +class DictContent { + public: + virtual ~DictContent() {} + virtual bool isValid() const = 0; + + protected: + DictContent() {} + + private: + DISALLOW_COPY_AND_ASSIGN(DictContent); +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif /* LATINIME_BACKWARD_V401_DICT_CONTENT_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.cpp new file mode 100644 index 000000000..337b97c05 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.cpp + */ + +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.h" + +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/probability_entry.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" + +namespace latinime { +namespace backward { +namespace v401 { + +const ProbabilityEntry ProbabilityDictContent::getProbabilityEntry(const int terminalId) const { + if (terminalId < 0 || terminalId >= mSize) { + // This method can be called with invalid terminal id during GC. + return ProbabilityEntry(0 /* flags */, NOT_A_PROBABILITY); + } + const BufferWithExtendableBuffer *const buffer = getBuffer(); + int entryPos = getEntryPos(terminalId); + const int flags = buffer->readUintAndAdvancePosition( + Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE, &entryPos); + const int probability = buffer->readUintAndAdvancePosition( + Ver4DictConstants::PROBABILITY_SIZE, &entryPos); + if (mHasHistoricalInfo) { + const int timestamp = buffer->readUintAndAdvancePosition( + Ver4DictConstants::TIME_STAMP_FIELD_SIZE, &entryPos); + const int level = buffer->readUintAndAdvancePosition( + Ver4DictConstants::WORD_LEVEL_FIELD_SIZE, &entryPos); + const int count = buffer->readUintAndAdvancePosition( + Ver4DictConstants::WORD_COUNT_FIELD_SIZE, &entryPos); + const HistoricalInfo historicalInfo(timestamp, level, count); + return ProbabilityEntry(flags, probability, &historicalInfo); + } else { + return ProbabilityEntry(flags, probability); + } +} + +bool ProbabilityDictContent::setProbabilityEntry(const int terminalId, + const ProbabilityEntry *const probabilityEntry) { + if (terminalId < 0) { + return false; + } + const int entryPos = getEntryPos(terminalId); + if (terminalId >= mSize) { + ProbabilityEntry dummyEntry; + // Write new entry. + int writingPos = getBuffer()->getTailPosition(); + while (writingPos <= entryPos) { + // Fulfilling with dummy entries until writingPos. + if (!writeEntry(&dummyEntry, writingPos)) { + AKLOGE("Cannot write dummy entry. pos: %d, mSize: %d", writingPos, mSize); + return false; + } + writingPos += getEntrySize(); + mSize++; + } + } + return writeEntry(probabilityEntry, entryPos); +} + +bool ProbabilityDictContent::flushToFile(const char *const dictPath) const { + if (getEntryPos(mSize) < getBuffer()->getTailPosition()) { + ProbabilityDictContent probabilityDictContentToWrite(mHasHistoricalInfo); + for (int i = 0; i < mSize; ++i) { + const ProbabilityEntry probabilityEntry = getProbabilityEntry(i); + if (!probabilityDictContentToWrite.setProbabilityEntry(i, &probabilityEntry)) { + AKLOGE("Cannot set probability entry in flushToFile. terminalId: %d", i); + return false; + } + } + return probabilityDictContentToWrite.flush(dictPath, + Ver4DictConstants::FREQ_FILE_EXTENSION); + } else { + return flush(dictPath, Ver4DictConstants::FREQ_FILE_EXTENSION); + } +} + +bool ProbabilityDictContent::runGC( + const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, + const ProbabilityDictContent *const originalProbabilityDictContent) { + mSize = 0; + for (TerminalPositionLookupTable::TerminalIdMap::const_iterator it = terminalIdMap->begin(); + it != terminalIdMap->end(); ++it) { + const ProbabilityEntry probabilityEntry = + originalProbabilityDictContent->getProbabilityEntry(it->first); + if (!setProbabilityEntry(it->second, &probabilityEntry)) { + AKLOGE("Cannot set probability entry in runGC. terminalId: %d", it->second); + return false; + } + mSize++; + } + return true; +} + +int ProbabilityDictContent::getEntrySize() const { + if (mHasHistoricalInfo) { + return Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE + + Ver4DictConstants::PROBABILITY_SIZE + + Ver4DictConstants::TIME_STAMP_FIELD_SIZE + + Ver4DictConstants::WORD_LEVEL_FIELD_SIZE + + Ver4DictConstants::WORD_COUNT_FIELD_SIZE; + } else { + return Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE + + Ver4DictConstants::PROBABILITY_SIZE; + } +} + +int ProbabilityDictContent::getEntryPos(const int terminalId) const { + return terminalId * getEntrySize(); +} + +bool ProbabilityDictContent::writeEntry(const ProbabilityEntry *const probabilityEntry, + const int entryPos) { + BufferWithExtendableBuffer *const bufferToWrite = getWritableBuffer(); + int writingPos = entryPos; + if (!bufferToWrite->writeUintAndAdvancePosition(probabilityEntry->getFlags(), + Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE, &writingPos)) { + AKLOGE("Cannot write flags in probability dict content. pos: %d", writingPos); + return false; + } + if (!bufferToWrite->writeUintAndAdvancePosition(probabilityEntry->getProbability(), + Ver4DictConstants::PROBABILITY_SIZE, &writingPos)) { + AKLOGE("Cannot write probability in probability dict content. pos: %d", writingPos); + return false; + } + if (mHasHistoricalInfo) { + const HistoricalInfo *const historicalInfo = probabilityEntry->getHistoricalInfo(); + if (!bufferToWrite->writeUintAndAdvancePosition(historicalInfo->getTimeStamp(), + Ver4DictConstants::TIME_STAMP_FIELD_SIZE, &writingPos)) { + AKLOGE("Cannot write timestamp in probability dict content. pos: %d", writingPos); + return false; + } + if (!bufferToWrite->writeUintAndAdvancePosition(historicalInfo->getLevel(), + Ver4DictConstants::WORD_LEVEL_FIELD_SIZE, &writingPos)) { + AKLOGE("Cannot write level in probability dict content. pos: %d", writingPos); + return false; + } + if (!bufferToWrite->writeUintAndAdvancePosition(historicalInfo->getCount(), + Ver4DictConstants::WORD_COUNT_FIELD_SIZE, &writingPos)) { + AKLOGE("Cannot write count in probability dict content. pos: %d", writingPos); + return false; + } + } + return true; +} + +} // namespace v401 +} // namespace backward +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.h new file mode 100644 index 000000000..db3070994 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h + */ + +#ifndef LATINIME_BACKWARD_V401_PROBABILITY_DICT_CONTENT_H +#define LATINIME_BACKWARD_V401_PROBABILITY_DICT_CONTENT_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/single_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" + +namespace latinime { +namespace backward { +namespace v401 { + +class ProbabilityEntry; + +class ProbabilityDictContent : public SingleDictContent { + public: + ProbabilityDictContent(const char *const dictPath, const bool hasHistoricalInfo, + const bool isUpdatable) + : SingleDictContent(dictPath, Ver4DictConstants::FREQ_FILE_EXTENSION, isUpdatable), + mHasHistoricalInfo(hasHistoricalInfo), + mSize(getBuffer()->getTailPosition() / getEntrySize()) {} + + ProbabilityDictContent(const bool hasHistoricalInfo) + : mHasHistoricalInfo(hasHistoricalInfo), mSize(0) {} + + const ProbabilityEntry getProbabilityEntry(const int terminalId) const; + + bool setProbabilityEntry(const int terminalId, const ProbabilityEntry *const probabilityEntry); + + bool flushToFile(const char *const dictPath) const; + + bool runGC(const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, + const ProbabilityDictContent *const originalProbabilityDictContent); + + private: + DISALLOW_COPY_AND_ASSIGN(ProbabilityDictContent); + + int getEntrySize() const; + + int getEntryPos(const int terminalId) const; + + bool writeEntry(const ProbabilityEntry *const probabilityEntry, const int entryPos); + + bool mHasHistoricalInfo; + int mSize; +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif /* LATINIME_BACKWARD_V401_PROBABILITY_DICT_CONTENT_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_entry.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_entry.h new file mode 100644 index 000000000..d341e7b07 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_entry.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h + */ + +#ifndef LATINIME_BACKWARD_V401_PROBABILITY_ENTRY_H +#define LATINIME_BACKWARD_V401_PROBABILITY_ENTRY_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/utils/historical_info.h" + +namespace latinime { +namespace backward { +namespace v401 { + +class ProbabilityEntry { + public: + ProbabilityEntry(const ProbabilityEntry &probabilityEntry) + : mFlags(probabilityEntry.mFlags), mProbability(probabilityEntry.mProbability), + mHistoricalInfo(probabilityEntry.mHistoricalInfo) {} + + // Dummy entry + ProbabilityEntry() + : mFlags(0), mProbability(NOT_A_PROBABILITY), mHistoricalInfo() {} + + // Entry without historical information + ProbabilityEntry(const int flags, const int probability) + : mFlags(flags), mProbability(probability), mHistoricalInfo() {} + + // Entry with historical information. + ProbabilityEntry(const int flags, const int probability, + const HistoricalInfo *const historicalInfo) + : mFlags(flags), mProbability(probability), mHistoricalInfo(*historicalInfo) {} + + const ProbabilityEntry createEntryWithUpdatedProbability(const int probability) const { + return ProbabilityEntry(mFlags, probability, &mHistoricalInfo); + } + + const ProbabilityEntry createEntryWithUpdatedHistoricalInfo( + const HistoricalInfo *const historicalInfo) const { + return ProbabilityEntry(mFlags, mProbability, historicalInfo); + } + + bool hasHistoricalInfo() const { + return mHistoricalInfo.isValid(); + } + + int getFlags() const { + return mFlags; + } + + int getProbability() const { + return mProbability; + } + + const HistoricalInfo *getHistoricalInfo() const { + return &mHistoricalInfo; + } + + private: + // Copy constructor is public to use this class as a type of return value. + DISALLOW_ASSIGNMENT_OPERATOR(ProbabilityEntry); + + const int mFlags; + const int mProbability; + const HistoricalInfo mHistoricalInfo; +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif /* LATINIME_BACKWARD_V401_PROBABILITY_ENTRY_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.cpp new file mode 100644 index 000000000..3214807ad --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.cpp + */ + +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.h" + +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" + +namespace latinime { +namespace backward { +namespace v401 { + +void ShortcutDictContent::getShortcutEntryAndAdvancePosition(const int maxCodePointCount, + int *const outCodePoint, int *const outCodePointCount, int *const outProbability, + bool *const outhasNext, int *const shortcutEntryPos) const { + const BufferWithExtendableBuffer *const shortcutListBuffer = getContentBuffer(); + if (*shortcutEntryPos < 0 || *shortcutEntryPos >= shortcutListBuffer->getTailPosition()) { + AKLOGE("Invalid shortcut entry position. shortcutEntryPos: %d, bufSize: %d", + *shortcutEntryPos, shortcutListBuffer->getTailPosition()); + ASSERT(false); + if (outhasNext) { + *outhasNext = false; + } + if (outCodePointCount) { + *outCodePointCount = 0; + } + return; + } + + const int shortcutFlags = shortcutListBuffer->readUintAndAdvancePosition( + Ver4DictConstants::SHORTCUT_FLAGS_FIELD_SIZE, shortcutEntryPos); + if (outProbability) { + *outProbability = shortcutFlags & Ver4DictConstants::SHORTCUT_PROBABILITY_MASK; + } + if (outhasNext) { + *outhasNext = shortcutFlags & Ver4DictConstants::SHORTCUT_HAS_NEXT_MASK; + } + if (outCodePoint && outCodePointCount) { + shortcutListBuffer->readCodePointsAndAdvancePosition( + maxCodePointCount, outCodePoint, outCodePointCount, shortcutEntryPos); + } +} + +int ShortcutDictContent::getShortcutListHeadPos(const int terminalId) const { + const SparseTable *const addressLookupTable = getAddressLookupTable(); + if (!addressLookupTable->contains(terminalId)) { + return NOT_A_DICT_POS; + } + return addressLookupTable->get(terminalId); +} + +bool ShortcutDictContent::flushToFile(const char *const dictPath) const { + return flush(dictPath, Ver4DictConstants::SHORTCUT_LOOKUP_TABLE_FILE_EXTENSION, + Ver4DictConstants::SHORTCUT_CONTENT_TABLE_FILE_EXTENSION, + Ver4DictConstants::SHORTCUT_FILE_EXTENSION); +} + +bool ShortcutDictContent::runGC( + const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, + const ShortcutDictContent *const originalShortcutDictContent) { + for (TerminalPositionLookupTable::TerminalIdMap::const_iterator it = terminalIdMap->begin(); + it != terminalIdMap->end(); ++it) { + const int originalShortcutListPos = + originalShortcutDictContent->getShortcutListHeadPos(it->first); + if (originalShortcutListPos == NOT_A_DICT_POS) { + continue; + } + const int shortcutListPos = getContentBuffer()->getTailPosition(); + // Copy shortcut list from original content. + if (!copyShortcutListFromDictContent(originalShortcutListPos, originalShortcutDictContent, + shortcutListPos)) { + AKLOGE("Cannot copy shortcut list during GC. original pos: %d, pos: %d", + originalShortcutListPos, shortcutListPos); + return false; + } + // Set shortcut list position to the lookup table. + if (!getUpdatableAddressLookupTable()->set(it->second, shortcutListPos)) { + AKLOGE("Cannot set shortcut list position. terminal id: %d, pos: %d", + it->second, shortcutListPos); + return false; + } + } + return true; +} + +bool ShortcutDictContent::createNewShortcutList(const int terminalId) { + const int shortcutListListPos = getContentBuffer()->getTailPosition(); + return getUpdatableAddressLookupTable()->set(terminalId, shortcutListListPos); +} + +bool ShortcutDictContent::copyShortcutList(const int shortcutListPos, const int toPos) { + return copyShortcutListFromDictContent(shortcutListPos, this, toPos); +} + +bool ShortcutDictContent::copyShortcutListFromDictContent(const int shortcutListPos, + const ShortcutDictContent *const sourceShortcutDictContent, const int toPos) { + bool hasNext = true; + int readingPos = shortcutListPos; + int writingPos = toPos; + int codePoints[MAX_WORD_LENGTH]; + while (hasNext) { + int probability = 0; + int codePointCount = 0; + sourceShortcutDictContent->getShortcutEntryAndAdvancePosition(MAX_WORD_LENGTH, + codePoints, &codePointCount, &probability, &hasNext, &readingPos); + if (!writeShortcutEntryAndAdvancePosition(codePoints, codePointCount, probability, + hasNext, &writingPos)) { + AKLOGE("Cannot write shortcut entry to copy. pos: %d", writingPos); + return false; + } + } + return true; +} + +bool ShortcutDictContent::setProbability(const int probability, const int shortcutEntryPos) { + BufferWithExtendableBuffer *const shortcutListBuffer = getWritableContentBuffer(); + const int shortcutFlags = shortcutListBuffer->readUint( + Ver4DictConstants::SHORTCUT_FLAGS_FIELD_SIZE, shortcutEntryPos); + const bool hasNext = shortcutFlags & Ver4DictConstants::SHORTCUT_HAS_NEXT_MASK; + const int shortcutFlagsToWrite = createAndGetShortcutFlags(probability, hasNext); + return shortcutListBuffer->writeUint(shortcutFlagsToWrite, + Ver4DictConstants::SHORTCUT_FLAGS_FIELD_SIZE, shortcutEntryPos); +} + +bool ShortcutDictContent::writeShortcutEntryAndAdvancePosition(const int *const codePoint, + const int codePointCount, const int probability, const bool hasNext, + int *const shortcutEntryPos) { + BufferWithExtendableBuffer *const shortcutListBuffer = getWritableContentBuffer(); + const int shortcutFlags = createAndGetShortcutFlags(probability, hasNext); + if (!shortcutListBuffer->writeUintAndAdvancePosition(shortcutFlags, + Ver4DictConstants::SHORTCUT_FLAGS_FIELD_SIZE, shortcutEntryPos)) { + AKLOGE("Cannot write shortcut flags. flags; %x, pos: %d", shortcutFlags, *shortcutEntryPos); + return false; + } + if (!shortcutListBuffer->writeCodePointsAndAdvancePosition(codePoint, codePointCount, + true /* writesTerminator */, shortcutEntryPos)) { + AKLOGE("Cannot write shortcut target code points. pos: %d", *shortcutEntryPos); + return false; + } + return true; +} + +// Find a shortcut entry that has specified target and return its position. +int ShortcutDictContent::findShortcutEntryAndGetPos(const int shortcutListPos, + const int *const targetCodePointsToFind, const int codePointCount) const { + bool hasNext = true; + int readingPos = shortcutListPos; + int targetCodePoints[MAX_WORD_LENGTH]; + while (hasNext) { + const int entryPos = readingPos; + int probability = 0; + int targetCodePointCount = 0; + getShortcutEntryAndAdvancePosition(MAX_WORD_LENGTH, targetCodePoints, &targetCodePointCount, + &probability, &hasNext, &readingPos); + if (targetCodePointCount != codePointCount) { + continue; + } + bool matched = true; + for (int i = 0; i < codePointCount; ++i) { + if (targetCodePointsToFind[i] != targetCodePoints[i]) { + matched = false; + break; + } + } + if (matched) { + return entryPos; + } + } + return NOT_A_DICT_POS; +} + +int ShortcutDictContent::createAndGetShortcutFlags(const int probability, + const bool hasNext) const { + return (probability & Ver4DictConstants::SHORTCUT_PROBABILITY_MASK) + | (hasNext ? Ver4DictConstants::SHORTCUT_HAS_NEXT_MASK : 0); +} + +} // namespace v401 +} // namespace backward +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.h new file mode 100644 index 000000000..75fd4f3b2 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.h + */ + +#ifndef LATINIME_BACKWARD_V401_SHORTCUT_DICT_CONTENT_H +#define LATINIME_BACKWARD_V401_SHORTCUT_DICT_CONTENT_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h" + +namespace latinime { +namespace backward { +namespace v401 { + +class ShortcutDictContent : public SparseTableDictContent { + public: + ShortcutDictContent(const char *const dictPath, const bool isUpdatable) + : SparseTableDictContent(dictPath, + Ver4DictConstants::SHORTCUT_LOOKUP_TABLE_FILE_EXTENSION, + Ver4DictConstants::SHORTCUT_CONTENT_TABLE_FILE_EXTENSION, + Ver4DictConstants::SHORTCUT_FILE_EXTENSION, isUpdatable, + Ver4DictConstants::SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE, + Ver4DictConstants::SHORTCUT_ADDRESS_TABLE_DATA_SIZE) {} + + ShortcutDictContent() + : SparseTableDictContent(Ver4DictConstants::SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE, + Ver4DictConstants::SHORTCUT_ADDRESS_TABLE_DATA_SIZE) {} + + void getShortcutEntry(const int maxCodePointCount, int *const outCodePoint, + int *const outCodePointCount, int *const outProbability, bool *const outhasNext, + const int shortcutEntryPos) { + int readingPos = shortcutEntryPos; + return getShortcutEntryAndAdvancePosition(maxCodePointCount, outCodePoint, + outCodePointCount, outProbability, outhasNext, &readingPos); + } + + void getShortcutEntryAndAdvancePosition(const int maxCodePointCount, + int *const outCodePoint, int *const outCodePointCount, int *const outProbability, + bool *const outhasNext, int *const shortcutEntryPos) const; + + // Returns head position of shortcut list for a PtNode specified by terminalId. + int getShortcutListHeadPos(const int terminalId) const; + + bool flushToFile(const char *const dictPath) const; + + bool runGC(const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap, + const ShortcutDictContent *const originalShortcutDictContent); + + bool createNewShortcutList(const int terminalId); + + bool copyShortcutList(const int shortcutListPos, const int toPos); + + bool setProbability(const int probability, const int shortcutEntryPos); + + bool writeShortcutEntry(const int *const codePoint, const int codePointCount, + const int probability, const bool hasNext, const int shortcutEntryPos) { + int writingPos = shortcutEntryPos; + return writeShortcutEntryAndAdvancePosition(codePoint, codePointCount, probability, + hasNext, &writingPos); + } + + bool writeShortcutEntryAndAdvancePosition(const int *const codePoint, + const int codePointCount, const int probability, const bool hasNext, + int *const shortcutEntryPos); + + int findShortcutEntryAndGetPos(const int shortcutListPos, + const int *const targetCodePointsToFind, const int codePointCount) const; + + private: + DISALLOW_COPY_AND_ASSIGN(ShortcutDictContent); + + bool copyShortcutListFromDictContent(const int shortcutListPos, + const ShortcutDictContent *const sourceShortcutDictContent, const int toPos); + + int createAndGetShortcutFlags(const int probability, const bool hasNext) const; +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif /* LATINIME_BACKWARD_V401_SHORTCUT_DICT_CONTENT_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/single_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/single_dict_content.h new file mode 100644 index 000000000..a519cd835 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/single_dict_content.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h + */ + +#ifndef LATINIME_BACKWARD_V401_SINGLE_DICT_CONTENT_H +#define LATINIME_BACKWARD_V401_SINGLE_DICT_CONTENT_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/dict_content.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" +#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h" +#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h" + +namespace latinime { +namespace backward { +namespace v401 { + +class SingleDictContent : public DictContent { + public: + SingleDictContent(const char *const dictPath, const char *const contentFileName, + const bool isUpdatable) + : mMmappedBuffer(MmappedBuffer::openBuffer(dictPath, contentFileName, isUpdatable)), + mExpandableContentBuffer(mMmappedBuffer ? mMmappedBuffer->getBuffer() : nullptr, + mMmappedBuffer ? mMmappedBuffer->getBufferSize() : 0, + BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE), + mIsValid(mMmappedBuffer) {} + + SingleDictContent() + : mMmappedBuffer(nullptr), + mExpandableContentBuffer(Ver4DictConstants::MAX_DICTIONARY_SIZE), mIsValid(true) {} + + virtual ~SingleDictContent() {} + + virtual bool isValid() const { + return mIsValid; + } + + bool isNearSizeLimit() const { + return mExpandableContentBuffer.isNearSizeLimit(); + } + + protected: + BufferWithExtendableBuffer *getWritableBuffer() { + return &mExpandableContentBuffer; + } + + const BufferWithExtendableBuffer *getBuffer() const { + return &mExpandableContentBuffer; + } + + bool flush(const char *const dictPath, const char *const contentFileNameSuffix) const { + return DictFileWritingUtils::flushBufferToFileWithSuffix(dictPath, + contentFileNameSuffix, &mExpandableContentBuffer); + } + + private: + DISALLOW_COPY_AND_ASSIGN(SingleDictContent); + + const MmappedBuffer::MmappedBufferPtr mMmappedBuffer; + BufferWithExtendableBuffer mExpandableContentBuffer; + const bool mIsValid; +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif /* LATINIME_BACKWARD_V401_SINGLE_DICT_CONTENT_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.cpp new file mode 100644 index 000000000..638132c3d --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.cpp + */ + +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.h" + +namespace latinime { +namespace backward { +namespace v401 { + +bool SparseTableDictContent::flush(const char *const dictPath, + const char *const lookupTableFileNameSuffix, const char *const addressTableFileNameSuffix, + const char *const contentFileNameSuffix) const { + if (!DictFileWritingUtils::flushBufferToFileWithSuffix(dictPath, lookupTableFileNameSuffix, + &mExpandableLookupTableBuffer)){ + return false; + } + if (!DictFileWritingUtils::flushBufferToFileWithSuffix(dictPath, addressTableFileNameSuffix, + &mExpandableAddressTableBuffer)) { + return false; + } + if (!DictFileWritingUtils::flushBufferToFileWithSuffix(dictPath, contentFileNameSuffix, + &mExpandableContentBuffer)) { + return false; + } + return true; +} + +} // namespace v401 +} // namespace backward +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.h new file mode 100644 index 000000000..b95de2eda --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.h + */ + +#ifndef LATINIME_BACKWARD_V401_SPARSE_TABLE_DICT_CONTENT_H +#define LATINIME_BACKWARD_V401_SPARSE_TABLE_DICT_CONTENT_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/dict_content.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" +#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h" +#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h" +#include "suggest/policyimpl/dictionary/utils/sparse_table.h" + +namespace latinime { +namespace backward { +namespace v401 { + +// TODO: Support multiple contents. +class SparseTableDictContent : public DictContent { + public: + AK_FORCE_INLINE SparseTableDictContent(const char *const dictPath, + const char *const lookupTableFileName, const char *const addressTableFileName, + const char *const contentFileName, const bool isUpdatable, + const int sparseTableBlockSize, const int sparseTableDataSize) + : mLookupTableBuffer( + MmappedBuffer::openBuffer(dictPath, lookupTableFileName, isUpdatable)), + mAddressTableBuffer( + MmappedBuffer::openBuffer(dictPath, addressTableFileName, isUpdatable)), + mContentBuffer( + MmappedBuffer::openBuffer(dictPath, contentFileName, isUpdatable)), + mExpandableLookupTableBuffer( + mLookupTableBuffer ? mLookupTableBuffer->getBuffer() : nullptr, + mLookupTableBuffer ? mLookupTableBuffer->getBufferSize() : 0, + BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE), + mExpandableAddressTableBuffer( + mAddressTableBuffer ? mAddressTableBuffer->getBuffer() : nullptr, + mAddressTableBuffer ? mAddressTableBuffer->getBufferSize() : 0, + BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE), + mExpandableContentBuffer(mContentBuffer ? mContentBuffer->getBuffer() : nullptr, + mContentBuffer ? mContentBuffer->getBufferSize() : 0, + BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE), + mAddressLookupTable(&mExpandableLookupTableBuffer, &mExpandableAddressTableBuffer, + sparseTableBlockSize, sparseTableDataSize), + mIsValid(mLookupTableBuffer && mAddressTableBuffer && mContentBuffer) {} + + SparseTableDictContent(const int sparseTableBlockSize, const int sparseTableDataSize) + : mLookupTableBuffer(), mAddressTableBuffer(), mContentBuffer(), + mExpandableLookupTableBuffer(Ver4DictConstants::MAX_DICTIONARY_SIZE), + mExpandableAddressTableBuffer(Ver4DictConstants::MAX_DICTIONARY_SIZE), + mExpandableContentBuffer(Ver4DictConstants::MAX_DICTIONARY_SIZE), + mAddressLookupTable(&mExpandableLookupTableBuffer, &mExpandableAddressTableBuffer, + sparseTableBlockSize, sparseTableDataSize), mIsValid(true) {} + + virtual ~SparseTableDictContent() {} + + virtual bool isValid() const { + return mIsValid; + } + + bool isNearSizeLimit() const { + return mExpandableLookupTableBuffer.isNearSizeLimit() + || mExpandableAddressTableBuffer.isNearSizeLimit() + || mExpandableContentBuffer.isNearSizeLimit(); + } + + protected: + SparseTable *getUpdatableAddressLookupTable() { + return &mAddressLookupTable; + } + + const SparseTable *getAddressLookupTable() const { + return &mAddressLookupTable; + } + + BufferWithExtendableBuffer *getWritableContentBuffer() { + return &mExpandableContentBuffer; + } + + const BufferWithExtendableBuffer *getContentBuffer() const { + return &mExpandableContentBuffer; + } + + bool flush(const char *const dictDirPath, const char *const lookupTableFileName, + const char *const addressTableFileName, const char *const contentFileName) const; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(SparseTableDictContent); + + const MmappedBuffer::MmappedBufferPtr mLookupTableBuffer; + const MmappedBuffer::MmappedBufferPtr mAddressTableBuffer; + const MmappedBuffer::MmappedBufferPtr mContentBuffer; + BufferWithExtendableBuffer mExpandableLookupTableBuffer; + BufferWithExtendableBuffer mExpandableAddressTableBuffer; + BufferWithExtendableBuffer mExpandableContentBuffer; + SparseTable mAddressLookupTable; + const bool mIsValid; +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif /* LATINIME_BACKWARD_V401_SPARSE_TABLE_DICT_CONTENT_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.cpp new file mode 100644 index 000000000..ab8a3ae43 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.cpp + */ + +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h" + +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" + +namespace latinime { +namespace backward { +namespace v401 { + +int TerminalPositionLookupTable::getTerminalPtNodePosition(const int terminalId) const { + if (terminalId < 0 || terminalId >= mSize) { + return NOT_A_DICT_POS; + } + const int terminalPos = getBuffer()->readUint( + Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE, getEntryPos(terminalId)); + return (terminalPos == Ver4DictConstants::NOT_A_TERMINAL_ADDRESS) ? + NOT_A_DICT_POS : terminalPos; +} + +bool TerminalPositionLookupTable::setTerminalPtNodePosition( + const int terminalId, const int terminalPtNodePos) { + if (terminalId < 0) { + return NOT_A_DICT_POS; + } + while (terminalId >= mSize) { + // Write new entry. + if (!getWritableBuffer()->writeUint(Ver4DictConstants::NOT_A_TERMINAL_ADDRESS, + Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE, getEntryPos(mSize))) { + return false; + } + mSize++; + } + const int terminalPos = (terminalPtNodePos != NOT_A_DICT_POS) ? + terminalPtNodePos : Ver4DictConstants::NOT_A_TERMINAL_ADDRESS; + return getWritableBuffer()->writeUint(terminalPos, + Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE, getEntryPos(terminalId)); +} + +bool TerminalPositionLookupTable::flushToFile(const char *const dictPath) const { + // If the used buffer size is smaller than the actual buffer size, regenerate the lookup + // table and write the new table to the file. + if (getEntryPos(mSize) < getBuffer()->getTailPosition()) { + TerminalPositionLookupTable lookupTableToWrite; + for (int i = 0; i < mSize; ++i) { + const int terminalPtNodePosition = getTerminalPtNodePosition(i); + if (!lookupTableToWrite.setTerminalPtNodePosition(i, terminalPtNodePosition)) { + AKLOGE("Cannot set terminal position to lookupTableToWrite." + " terminalId: %d, position: %d", i, terminalPtNodePosition); + return false; + } + } + return lookupTableToWrite.flush(dictPath, + Ver4DictConstants::TERMINAL_ADDRESS_TABLE_FILE_EXTENSION); + } else { + // We can simply use this lookup table because the buffer size has not been + // changed. + return flush(dictPath, Ver4DictConstants::TERMINAL_ADDRESS_TABLE_FILE_EXTENSION); + } +} + +bool TerminalPositionLookupTable::runGCTerminalIds(TerminalIdMap *const terminalIdMap) { + int removedEntryCount = 0; + int nextNewTerminalId = 0; + for (int i = 0; i < mSize; ++i) { + const int terminalPos = getBuffer()->readUint( + Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE, getEntryPos(i)); + if (terminalPos == Ver4DictConstants::NOT_A_TERMINAL_ADDRESS) { + // This entry is a garbage. + removedEntryCount++; + } else { + // Give a new terminal id to the entry. + if (!getWritableBuffer()->writeUint(terminalPos, + Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE, + getEntryPos(nextNewTerminalId))) { + return false; + } + // Memorize the mapping to the old terminal id to the new terminal id. + terminalIdMap->insert(TerminalIdMap::value_type(i, nextNewTerminalId)); + nextNewTerminalId++; + } + } + mSize = nextNewTerminalId; + return true; +} + +} // namespace v401 +} // namespace backward +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h new file mode 100644 index 000000000..dbf0e6088 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h + */ + +#ifndef LATINIME_BACKWARD_V401_TERMINAL_POSITION_LOOKUP_TABLE_H +#define LATINIME_BACKWARD_V401_TERMINAL_POSITION_LOOKUP_TABLE_H + +#include <unordered_map> + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/single_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h" + +namespace latinime { +namespace backward { +namespace v401 { + +class TerminalPositionLookupTable : public SingleDictContent { + public: + typedef std::unordered_map<int, int> TerminalIdMap; + + TerminalPositionLookupTable(const char *const dictPath, const bool isUpdatable) + : SingleDictContent(dictPath, + Ver4DictConstants::TERMINAL_ADDRESS_TABLE_FILE_EXTENSION, isUpdatable), + mSize(getBuffer()->getTailPosition() + / Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE) {} + + TerminalPositionLookupTable() : mSize(0) {} + + int getTerminalPtNodePosition(const int terminalId) const; + + bool setTerminalPtNodePosition(const int terminalId, const int terminalPtNodePos); + + int getNextTerminalId() const { + return mSize; + } + + bool flushToFile(const char *const dictPath) const; + + bool runGCTerminalIds(TerminalIdMap *const terminalIdMap); + + private: + DISALLOW_COPY_AND_ASSIGN(TerminalPositionLookupTable); + + int getEntryPos(const int terminalId) const { + return terminalId * Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE; + } + + int mSize; +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif // LATINIME_BACKWARD_V401_TERMINAL_POSITION_LOOKUP_TABLE_H diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/shortcut/ver4_shortcut_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/shortcut/ver4_shortcut_list_policy.h new file mode 100644 index 000000000..6a4e83c0d --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/shortcut/ver4_shortcut_list_policy.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT CHANGE THE LOGIC IN THIS FILE !!!!! + * Do not edit this file other than updating policy's interface. + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/shortcut/ver4_shortcut_list_policy.h + */ + +#ifndef LATINIME_BACKWARD_V401_VER4_SHORTCUT_LIST_POLICY_H +#define LATINIME_BACKWARD_V401_VER4_SHORTCUT_LIST_POLICY_H + +#include "defines.h" +#include "suggest/core/policy/dictionary_shortcuts_structure_policy.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h" + +namespace latinime { +namespace backward { +namespace v401 { + +class Ver4ShortcutListPolicy : public DictionaryShortcutsStructurePolicy { + public: + Ver4ShortcutListPolicy(ShortcutDictContent *const shortcutDictContent, + const TerminalPositionLookupTable *const terminalPositionLookupTable) + : mShortcutDictContent(shortcutDictContent) {} + + ~Ver4ShortcutListPolicy() {} + + int getStartPos(const int pos) const { + // The first shortcut entry is located at the head position of the shortcut list. + return pos; + } + + void getNextShortcut(const int maxCodePointCount, int *const outCodePoint, + int *const outCodePointCount, bool *const outIsWhitelist, bool *const outHasNext, + int *const pos) const { + int probability = 0; + mShortcutDictContent->getShortcutEntryAndAdvancePosition(maxCodePointCount, + outCodePoint, outCodePointCount, &probability, outHasNext, pos); + if (outIsWhitelist) { + *outIsWhitelist = ShortcutListReadingUtils::isWhitelist(probability); + } + } + + void skipAllShortcuts(int *const pos) const { + // Do nothing because we don't need to skip shortcut lists in ver4 dictionaries. + } + + bool addNewShortcut(const int terminalId, const int *const codePoints, const int codePointCount, + const int probability) { + const int shortcutListPos = mShortcutDictContent->getShortcutListHeadPos(terminalId); + if (shortcutListPos == NOT_A_DICT_POS) { + // Create shortcut list. + if (!mShortcutDictContent->createNewShortcutList(terminalId)) { + AKLOGE("Cannot create new shortcut list. terminal id: %d", terminalId); + return false; + } + const int writingPos = mShortcutDictContent->getShortcutListHeadPos(terminalId); + return mShortcutDictContent->writeShortcutEntry(codePoints, codePointCount, probability, + false /* hasNext */, writingPos); + } + const int entryPos = mShortcutDictContent->findShortcutEntryAndGetPos(shortcutListPos, + codePoints, codePointCount); + if (entryPos == NOT_A_DICT_POS) { + // Add new entry to the shortcut list. + // Create new shortcut list. + if (!mShortcutDictContent->createNewShortcutList(terminalId)) { + AKLOGE("Cannot create new shortcut list. terminal id: %d", terminalId); + return false; + } + int writingPos = mShortcutDictContent->getShortcutListHeadPos(terminalId); + if (!mShortcutDictContent->writeShortcutEntryAndAdvancePosition(codePoints, + codePointCount, probability, true /* hasNext */, &writingPos)) { + AKLOGE("Cannot write shortcut entry. terminal id: %d, pos: %d", terminalId, + writingPos); + return false; + } + return mShortcutDictContent->copyShortcutList(shortcutListPos, writingPos); + } + // Overwrite existing entry. + bool hasNext = false; + mShortcutDictContent->getShortcutEntry(MAX_WORD_LENGTH, 0 /* outCodePoint */, + 0 /* outCodePointCount */ , 0 /* probability */, &hasNext, entryPos); + if (!mShortcutDictContent->writeShortcutEntry(codePoints, + codePointCount, probability, hasNext, entryPos)) { + AKLOGE("Cannot overwrite shortcut entry. terminal id: %d, pos: %d", terminalId, + entryPos); + return false; + } + return true; + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4ShortcutListPolicy); + + ShortcutDictContent *const mShortcutDictContent; +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif // LATINIME_BACKWARD_V401_VER4_SHORTCUT_LIST_POLICY_H diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.cpp new file mode 100644 index 000000000..55ead01a9 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp + */ + +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.h" + +#include <cerrno> +#include <cstring> +#include <sys/stat.h> +#include <sys/types.h> + +#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h" +#include "suggest/policyimpl/dictionary/utils/file_utils.h" + +namespace latinime { +namespace backward { +namespace v401 { + +/* static */ Ver4DictBuffers::Ver4DictBuffersPtr Ver4DictBuffers::openVer4DictBuffers( + const char *const dictPath, MmappedBuffer::MmappedBufferPtr headerBuffer, + const FormatUtils::FORMAT_VERSION formatVersion) { + if (!headerBuffer) { + ASSERT(false); + AKLOGE("The header buffer must be valid to open ver4 dict buffers."); + return Ver4DictBuffersPtr(nullptr); + } + // TODO: take only dictDirPath, and open both header and trie files in the constructor below + const bool isUpdatable = headerBuffer->isUpdatable(); + return Ver4DictBuffersPtr(new Ver4DictBuffers(dictPath, std::move(headerBuffer), isUpdatable, + formatVersion)); +} + +bool Ver4DictBuffers::flushHeaderAndDictBuffers(const char *const dictDirPath, + const BufferWithExtendableBuffer *const headerBuffer) const { + // Create temporary directory. + const int tmpDirPathBufSize = FileUtils::getFilePathWithSuffixBufSize(dictDirPath, + DictFileWritingUtils::TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE); + char tmpDirPath[tmpDirPathBufSize]; + FileUtils::getFilePathWithSuffix(dictDirPath, + DictFileWritingUtils::TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE, tmpDirPathBufSize, + tmpDirPath); + if (FileUtils::existsDir(tmpDirPath)) { + if (!FileUtils::removeDirAndFiles(tmpDirPath)) { + AKLOGE("Existing directory %s cannot be removed.", tmpDirPath); + ASSERT(false); + return false; + } + } + if (mkdir(tmpDirPath, S_IRWXU) == -1) { + AKLOGE("Cannot create directory: %s. errno: %d.", tmpDirPath, errno); + return false; + } + // Get dictionary base path. + const int dictNameBufSize = strlen(dictDirPath) + 1 /* terminator */; + char dictName[dictNameBufSize]; + FileUtils::getBasename(dictDirPath, dictNameBufSize, dictName); + const int dictPathBufSize = FileUtils::getFilePathBufSize(tmpDirPath, dictName); + char dictPath[dictPathBufSize]; + FileUtils::getFilePath(tmpDirPath, dictName, dictPathBufSize, dictPath); + + // Write header file. + if (!DictFileWritingUtils::flushBufferToFileWithSuffix(dictPath, + Ver4DictConstants::HEADER_FILE_EXTENSION, headerBuffer)) { + AKLOGE("Dictionary header file %s%s cannot be written.", tmpDirPath, + Ver4DictConstants::HEADER_FILE_EXTENSION); + return false; + } + // Write trie file. + if (!DictFileWritingUtils::flushBufferToFileWithSuffix(dictPath, + Ver4DictConstants::TRIE_FILE_EXTENSION, &mExpandableTrieBuffer)) { + AKLOGE("Dictionary trie file %s%s cannot be written.", tmpDirPath, + Ver4DictConstants::TRIE_FILE_EXTENSION); + return false; + } + // Write dictionary contents. + if (!mTerminalPositionLookupTable.flushToFile(dictPath)) { + AKLOGE("Terminal position lookup table cannot be written. %s", tmpDirPath); + return false; + } + if (!mProbabilityDictContent.flushToFile(dictPath)) { + AKLOGE("Probability dict content cannot be written. %s", tmpDirPath); + return false; + } + if (!mBigramDictContent.flushToFile(dictPath)) { + AKLOGE("Bigram dict content cannot be written. %s", tmpDirPath); + return false; + } + if (!mShortcutDictContent.flushToFile(dictPath)) { + AKLOGE("Shortcut dict content cannot be written. %s", tmpDirPath); + return false; + } + // Remove existing dictionary. + if (!FileUtils::removeDirAndFiles(dictDirPath)) { + AKLOGE("Existing directory %s cannot be removed.", dictDirPath); + ASSERT(false); + return false; + } + // Rename temporary directory. + if (rename(tmpDirPath, dictDirPath) != 0) { + AKLOGE("%s cannot be renamed to %s", tmpDirPath, dictDirPath); + ASSERT(false); + return false; + } + return true; +} + +Ver4DictBuffers::Ver4DictBuffers(const char *const dictPath, + MmappedBuffer::MmappedBufferPtr headerBuffer, const bool isUpdatable, + const FormatUtils::FORMAT_VERSION formatVersion) + : mHeaderBuffer(std::move(headerBuffer)), + mDictBuffer(MmappedBuffer::openBuffer(dictPath, + Ver4DictConstants::TRIE_FILE_EXTENSION, isUpdatable)), + mHeaderPolicy(mHeaderBuffer->getBuffer(), formatVersion), + mExpandableHeaderBuffer(mHeaderBuffer ? mHeaderBuffer->getBuffer() : nullptr, + mHeaderPolicy.getSize(), + BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE), + mExpandableTrieBuffer(mDictBuffer ? mDictBuffer->getBuffer() : nullptr, + mDictBuffer ? mDictBuffer->getBufferSize() : 0, + BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE), + mTerminalPositionLookupTable(dictPath, isUpdatable), + mProbabilityDictContent(dictPath, mHeaderPolicy.hasHistoricalInfoOfWords(), isUpdatable), + mBigramDictContent(dictPath, mHeaderPolicy.hasHistoricalInfoOfWords(), isUpdatable), + mShortcutDictContent(dictPath, isUpdatable), + mIsUpdatable(isUpdatable) {} + +Ver4DictBuffers::Ver4DictBuffers(const HeaderPolicy *const headerPolicy, const int maxTrieSize) + : mHeaderBuffer(nullptr), mDictBuffer(nullptr), mHeaderPolicy(headerPolicy), + mExpandableHeaderBuffer(Ver4DictConstants::MAX_DICTIONARY_SIZE), + mExpandableTrieBuffer(maxTrieSize), mTerminalPositionLookupTable(), + mProbabilityDictContent(headerPolicy->hasHistoricalInfoOfWords()), + mBigramDictContent(headerPolicy->hasHistoricalInfoOfWords()), mShortcutDictContent(), + mIsUpdatable(true) {} + +} // namespace v401 +} // namespace backward +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.h new file mode 100644 index 000000000..716ed931b --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h + */ + +#ifndef LATINIME_BACKWARD_V401_VER4_DICT_BUFFER_H +#define LATINIME_BACKWARD_V401_VER4_DICT_BUFFER_H + +#include <memory> + +#include "defines.h" +#include "suggest/policyimpl/dictionary/header/header_policy.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" +#include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h" + +namespace latinime { +namespace backward { +namespace v401 { + +class Ver4DictBuffers { + public: + typedef std::unique_ptr<Ver4DictBuffers> Ver4DictBuffersPtr; + + static Ver4DictBuffersPtr openVer4DictBuffers(const char *const dictDirPath, + MmappedBuffer::MmappedBufferPtr headerBuffer, + const FormatUtils::FORMAT_VERSION formatVersion); + + static AK_FORCE_INLINE Ver4DictBuffersPtr createVer4DictBuffers( + const HeaderPolicy *const headerPolicy, const int maxTrieSize) { + return Ver4DictBuffersPtr(new Ver4DictBuffers(headerPolicy, maxTrieSize)); + } + + AK_FORCE_INLINE bool isValid() const { + return mHeaderBuffer && mDictBuffer && mHeaderPolicy.isValid() + && mProbabilityDictContent.isValid() && mTerminalPositionLookupTable.isValid() + && mBigramDictContent.isValid() && mShortcutDictContent.isValid(); + } + + AK_FORCE_INLINE bool isNearSizeLimit() const { + return mExpandableTrieBuffer.isNearSizeLimit() + || mTerminalPositionLookupTable.isNearSizeLimit() + || mProbabilityDictContent.isNearSizeLimit() + || mBigramDictContent.isNearSizeLimit() + || mShortcutDictContent.isNearSizeLimit(); + } + + AK_FORCE_INLINE const HeaderPolicy *getHeaderPolicy() const { + return &mHeaderPolicy; + } + + AK_FORCE_INLINE BufferWithExtendableBuffer *getWritableHeaderBuffer() { + return &mExpandableHeaderBuffer; + } + + AK_FORCE_INLINE BufferWithExtendableBuffer *getWritableTrieBuffer() { + return &mExpandableTrieBuffer; + } + + AK_FORCE_INLINE const BufferWithExtendableBuffer *getTrieBuffer() const { + return &mExpandableTrieBuffer; + } + + AK_FORCE_INLINE TerminalPositionLookupTable *getMutableTerminalPositionLookupTable() { + return &mTerminalPositionLookupTable; + } + + AK_FORCE_INLINE const TerminalPositionLookupTable *getTerminalPositionLookupTable() const { + return &mTerminalPositionLookupTable; + } + + AK_FORCE_INLINE ProbabilityDictContent *getMutableProbabilityDictContent() { + return &mProbabilityDictContent; + } + + AK_FORCE_INLINE const ProbabilityDictContent *getProbabilityDictContent() const { + return &mProbabilityDictContent; + } + + AK_FORCE_INLINE BigramDictContent *getMutableBigramDictContent() { + return &mBigramDictContent; + } + + AK_FORCE_INLINE const BigramDictContent *getBigramDictContent() const { + return &mBigramDictContent; + } + + AK_FORCE_INLINE ShortcutDictContent *getMutableShortcutDictContent() { + return &mShortcutDictContent; + } + + AK_FORCE_INLINE const ShortcutDictContent *getShortcutDictContent() const { + return &mShortcutDictContent; + } + + AK_FORCE_INLINE bool isUpdatable() const { + return mIsUpdatable; + } + + bool flush(const char *const dictDirPath) const { + return flushHeaderAndDictBuffers(dictDirPath, &mExpandableHeaderBuffer); + } + + bool flushHeaderAndDictBuffers(const char *const dictDirPath, + const BufferWithExtendableBuffer *const headerBuffer) const; + + private: + DISALLOW_COPY_AND_ASSIGN(Ver4DictBuffers); + + Ver4DictBuffers(const char *const dictDirPath, + const MmappedBuffer::MmappedBufferPtr headerBuffer, const bool isUpdatable, + const FormatUtils::FORMAT_VERSION formatVersion); + + Ver4DictBuffers(const HeaderPolicy *const headerPolicy, const int maxTrieSize); + + const MmappedBuffer::MmappedBufferPtr mHeaderBuffer; + const MmappedBuffer::MmappedBufferPtr mDictBuffer; + const HeaderPolicy mHeaderPolicy; + BufferWithExtendableBuffer mExpandableHeaderBuffer; + BufferWithExtendableBuffer mExpandableTrieBuffer; + TerminalPositionLookupTable mTerminalPositionLookupTable; + ProbabilityDictContent mProbabilityDictContent; + BigramDictContent mBigramDictContent; + ShortcutDictContent mShortcutDictContent; + const int mIsUpdatable; +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif /* LATINIME_BACKWARD_V401_VER4_DICT_BUFFER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.cpp new file mode 100644 index 000000000..793b44ed4 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp + */ + +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h" + +namespace latinime { +namespace backward { +namespace v401 { + +// These values MUST match the definitions in FormatSpec.java. +const char *const Ver4DictConstants::TRIE_FILE_EXTENSION = ".trie"; +const char *const Ver4DictConstants::HEADER_FILE_EXTENSION = ".header"; +const char *const Ver4DictConstants::FREQ_FILE_EXTENSION = ".freq"; +// tat = Terminal Address Table +const char *const Ver4DictConstants::TERMINAL_ADDRESS_TABLE_FILE_EXTENSION = ".tat"; +const char *const Ver4DictConstants::BIGRAM_FILE_EXTENSION = ".bigram_freq"; +const char *const Ver4DictConstants::BIGRAM_LOOKUP_TABLE_FILE_EXTENSION = ".bigram_lookup"; +const char *const Ver4DictConstants::BIGRAM_CONTENT_TABLE_FILE_EXTENSION = ".bigram_index_freq"; +const char *const Ver4DictConstants::SHORTCUT_FILE_EXTENSION = ".shortcut_shortcut"; +const char *const Ver4DictConstants::SHORTCUT_LOOKUP_TABLE_FILE_EXTENSION = ".shortcut_lookup"; +const char *const Ver4DictConstants::SHORTCUT_CONTENT_TABLE_FILE_EXTENSION = + ".shortcut_index_shortcut"; + +// Version 4 dictionary size is implicitly limited to 8MB due to 3-byte offsets. +const int Ver4DictConstants::MAX_DICTIONARY_SIZE = 8 * 1024 * 1024; +// Extended region size, which is not GCed region size in dict file + additional buffer size, is +// limited to 1MB to prevent from inefficient traversing. +const int Ver4DictConstants::MAX_DICT_EXTENDED_REGION_SIZE = 1 * 1024 * 1024; + +const int Ver4DictConstants::NOT_A_TERMINAL_ID = -1; +const int Ver4DictConstants::PROBABILITY_SIZE = 1; +const int Ver4DictConstants::FLAGS_IN_PROBABILITY_FILE_SIZE = 1; +const int Ver4DictConstants::TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE = 3; +const int Ver4DictConstants::NOT_A_TERMINAL_ADDRESS = 0; +const int Ver4DictConstants::TERMINAL_ID_FIELD_SIZE = 4; +const int Ver4DictConstants::TIME_STAMP_FIELD_SIZE = 4; +const int Ver4DictConstants::WORD_LEVEL_FIELD_SIZE = 1; +const int Ver4DictConstants::WORD_COUNT_FIELD_SIZE = 1; + +const int Ver4DictConstants::BIGRAM_ADDRESS_TABLE_BLOCK_SIZE = 16; +const int Ver4DictConstants::BIGRAM_ADDRESS_TABLE_DATA_SIZE = 4; +const int Ver4DictConstants::SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE = 64; +const int Ver4DictConstants::SHORTCUT_ADDRESS_TABLE_DATA_SIZE = 4; + +const int Ver4DictConstants::BIGRAM_TARGET_TERMINAL_ID_FIELD_SIZE = 3; +// Unsigned int max value of BIGRAM_TARGET_TERMINAL_ID_FIELD_SIZE-byte is used for representing +// invalid terminal ID in bigram lists. +const int Ver4DictConstants::INVALID_BIGRAM_TARGET_TERMINAL_ID = + (1 << (BIGRAM_TARGET_TERMINAL_ID_FIELD_SIZE * 8)) - 1; +const int Ver4DictConstants::BIGRAM_FLAGS_FIELD_SIZE = 1; +const int Ver4DictConstants::BIGRAM_PROBABILITY_MASK = 0x0F; +const int Ver4DictConstants::BIGRAM_HAS_NEXT_MASK = 0x80; +const int Ver4DictConstants::BIGRAM_LARGE_PROBABILITY_FIELD_SIZE = 1; + +const int Ver4DictConstants::SHORTCUT_FLAGS_FIELD_SIZE = 1; +const int Ver4DictConstants::SHORTCUT_PROBABILITY_MASK = 0x0F; +const int Ver4DictConstants::SHORTCUT_HAS_NEXT_MASK = 0x80; + +} // namespace v401 +} // namespace backward +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h new file mode 100644 index 000000000..17afeb156 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h + */ + +#ifndef LATINIME_BACKWARD_V401_VER4_DICT_CONSTANTS_H +#define LATINIME_BACKWARD_V401_VER4_DICT_CONSTANTS_H + +#include "defines.h" + +namespace latinime { +namespace backward { +namespace v401 { + +// TODO: Create PtConstants under the pt_common and move some constant values there. +// Note that there are corresponding definitions in FormatSpec.java. +class Ver4DictConstants { + public: + static const char *const TRIE_FILE_EXTENSION; + static const char *const HEADER_FILE_EXTENSION; + static const char *const FREQ_FILE_EXTENSION; + static const char *const TERMINAL_ADDRESS_TABLE_FILE_EXTENSION; + static const char *const BIGRAM_FILE_EXTENSION; + static const char *const BIGRAM_LOOKUP_TABLE_FILE_EXTENSION; + static const char *const BIGRAM_CONTENT_TABLE_FILE_EXTENSION; + static const char *const SHORTCUT_FILE_EXTENSION; + static const char *const SHORTCUT_LOOKUP_TABLE_FILE_EXTENSION; + static const char *const SHORTCUT_CONTENT_TABLE_FILE_EXTENSION; + + static const int MAX_DICTIONARY_SIZE; + static const int MAX_DICT_EXTENDED_REGION_SIZE; + + static const int NOT_A_TERMINAL_ID; + static const int PROBABILITY_SIZE; + static const int FLAGS_IN_PROBABILITY_FILE_SIZE; + static const int TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE; + static const int NOT_A_TERMINAL_ADDRESS; + static const int TERMINAL_ID_FIELD_SIZE; + static const int TIME_STAMP_FIELD_SIZE; + static const int WORD_LEVEL_FIELD_SIZE; + static const int WORD_COUNT_FIELD_SIZE; + + static const int BIGRAM_ADDRESS_TABLE_BLOCK_SIZE; + static const int BIGRAM_ADDRESS_TABLE_DATA_SIZE; + static const int SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE; + static const int SHORTCUT_ADDRESS_TABLE_DATA_SIZE; + + static const int BIGRAM_FLAGS_FIELD_SIZE; + static const int BIGRAM_TARGET_TERMINAL_ID_FIELD_SIZE; + static const int INVALID_BIGRAM_TARGET_TERMINAL_ID; + static const int BIGRAM_PROBABILITY_MASK; + static const int BIGRAM_HAS_NEXT_MASK; + // Used when bigram list has time stamp. + static const int BIGRAM_LARGE_PROBABILITY_FIELD_SIZE; + + static const int SHORTCUT_FLAGS_FIELD_SIZE; + static const int SHORTCUT_PROBABILITY_MASK; + static const int SHORTCUT_HAS_NEXT_MASK; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4DictConstants); +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif /* LATINIME_BACKWARD_V401_VER4_DICT_CONSTANTS_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.cpp new file mode 100644 index 000000000..80b51b292 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.cpp + */ + +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.h" + +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/probability_entry.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" +#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h" + +namespace latinime { +namespace backward { +namespace v401 { + +const PtNodeParams Ver4PatriciaTrieNodeReader::fetchPtNodeInfoFromBufferAndProcessMovedPtNode( + const int ptNodePos, const int siblingNodePos) const { + if (ptNodePos < 0 || ptNodePos >= mBuffer->getTailPosition()) { + // Reading invalid position because of bug or broken dictionary. + AKLOGE("Fetching PtNode info from invalid dictionary position: %d, dictionary size: %d", + ptNodePos, mBuffer->getTailPosition()); + ASSERT(false); + return PtNodeParams(); + } + const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(ptNodePos); + const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer); + int pos = ptNodePos; + const int headPos = ptNodePos; + if (usesAdditionalBuffer) { + pos -= mBuffer->getOriginalBufferSize(); + } + const PatriciaTrieReadingUtils::NodeFlags flags = + PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictBuf, &pos); + const int parentPosOffset = + DynamicPtReadingUtils::getParentPtNodePosOffsetAndAdvancePosition( + dictBuf, &pos); + const int parentPos = + DynamicPtReadingUtils::getParentPtNodePos(parentPosOffset, headPos); + int codePoints[MAX_WORD_LENGTH]; + const int codePonitCount = PatriciaTrieReadingUtils::getCharsAndAdvancePosition( + dictBuf, flags, MAX_WORD_LENGTH, codePoints, &pos); + int terminalIdFieldPos = NOT_A_DICT_POS; + int terminalId = Ver4DictConstants::NOT_A_TERMINAL_ID; + int probability = NOT_A_PROBABILITY; + if (PatriciaTrieReadingUtils::isTerminal(flags)) { + terminalIdFieldPos = pos; + if (usesAdditionalBuffer) { + terminalIdFieldPos += mBuffer->getOriginalBufferSize(); + } + terminalId = Ver4PatriciaTrieReadingUtils::getTerminalIdAndAdvancePosition(dictBuf, &pos); + const ProbabilityEntry probabilityEntry = + mProbabilityDictContent->getProbabilityEntry(terminalId); + if (probabilityEntry.hasHistoricalInfo()) { + probability = ForgettingCurveUtils::decodeProbability( + probabilityEntry.getHistoricalInfo(), mHeaderPolicy); + } else { + probability = probabilityEntry.getProbability(); + } + } + int childrenPosFieldPos = pos; + if (usesAdditionalBuffer) { + childrenPosFieldPos += mBuffer->getOriginalBufferSize(); + } + int childrenPos = DynamicPtReadingUtils::readChildrenPositionAndAdvancePosition( + dictBuf, &pos); + if (usesAdditionalBuffer && childrenPos != NOT_A_DICT_POS) { + childrenPos += mBuffer->getOriginalBufferSize(); + } + if (usesAdditionalBuffer) { + pos += mBuffer->getOriginalBufferSize(); + } + // Sibling position is the tail position of original PtNode. + int newSiblingNodePos = (siblingNodePos == NOT_A_DICT_POS) ? pos : siblingNodePos; + // Read destination node if the read node is a moved node. + if (DynamicPtReadingUtils::isMoved(flags)) { + // The destination position is stored at the same place as the parent position. + return fetchPtNodeInfoFromBufferAndProcessMovedPtNode(parentPos, newSiblingNodePos); + } else { + return PtNodeParams(headPos, flags, parentPos, codePonitCount, codePoints, + terminalIdFieldPos, terminalId, probability, childrenPosFieldPos, childrenPos, + newSiblingNodePos); + } +} + +} // namespace v401 +} // namespace backward +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.h new file mode 100644 index 000000000..0531b0a29 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h + */ + +#ifndef LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_NODE_READER_H +#define LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_NODE_READER_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_reader.h" + +namespace latinime { +namespace backward { +namespace v401 { + +} // namespace v401 +} // namespace backward +class BufferWithExtendableBuffer; +namespace backward { +namespace v401 { +} // namespace v401 +} // namespace backward +class HeaderPolicy; +namespace backward { +namespace v401 { +class ProbabilityDictContent; + +/* + * This class is used for helping to read nodes of ver4 patricia trie. This class handles moved + * node and reads node attributes including probability form probabilityBuffer. + */ +class Ver4PatriciaTrieNodeReader : public PtNodeReader { + public: + Ver4PatriciaTrieNodeReader(const BufferWithExtendableBuffer *const buffer, + const ProbabilityDictContent *const probabilityDictContent, + const HeaderPolicy *const headerPolicy) + : mBuffer(buffer), mProbabilityDictContent(probabilityDictContent), + mHeaderPolicy(headerPolicy) {} + + ~Ver4PatriciaTrieNodeReader() {} + + virtual const PtNodeParams fetchNodeInfoInBufferFromPtNodePos(const int ptNodePos) const { + return fetchPtNodeInfoFromBufferAndProcessMovedPtNode(ptNodePos, + NOT_A_DICT_POS /* siblingNodePos */); + } + + private: + DISALLOW_COPY_AND_ASSIGN(Ver4PatriciaTrieNodeReader); + + const BufferWithExtendableBuffer *const mBuffer; + const ProbabilityDictContent *const mProbabilityDictContent; + const HeaderPolicy *const mHeaderPolicy; + + const PtNodeParams fetchPtNodeInfoFromBufferAndProcessMovedPtNode(const int ptNodePos, + const int siblingNodePos) const; +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif /* LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_NODE_READER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.cpp new file mode 100644 index 000000000..8de6bacfc --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.cpp @@ -0,0 +1,429 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp + */ + +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.h" + +#include "suggest/core/dictionary/property/unigram_property.h" +#include "suggest/policyimpl/dictionary/header/header_policy.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/probability_entry.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/shortcut/ver4_shortcut_list_policy.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" +#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h" + +namespace latinime { +namespace backward { +namespace v401 { + +const int Ver4PatriciaTrieNodeWriter::CHILDREN_POSITION_FIELD_SIZE = 3; + +bool Ver4PatriciaTrieNodeWriter::markPtNodeAsDeleted( + const PtNodeParams *const toBeUpdatedPtNodeParams) { + int pos = toBeUpdatedPtNodeParams->getHeadPos(); + const bool usesAdditionalBuffer = mTrieBuffer->isInAdditionalBuffer(pos); + const uint8_t *const dictBuf = mTrieBuffer->getBuffer(usesAdditionalBuffer); + if (usesAdditionalBuffer) { + pos -= mTrieBuffer->getOriginalBufferSize(); + } + // Read original flags + const PatriciaTrieReadingUtils::NodeFlags originalFlags = + PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictBuf, &pos); + const PatriciaTrieReadingUtils::NodeFlags updatedFlags = + DynamicPtReadingUtils::updateAndGetFlags(originalFlags, false /* isMoved */, + true /* isDeleted */, false /* willBecomeNonTerminal */); + int writingPos = toBeUpdatedPtNodeParams->getHeadPos(); + // Update flags. + if (!DynamicPtWritingUtils::writeFlagsAndAdvancePosition(mTrieBuffer, updatedFlags, + &writingPos)) { + return false; + } + if (toBeUpdatedPtNodeParams->isTerminal()) { + // The PtNode is a terminal. Delete entry from the terminal position lookup table. + return mBuffers->getMutableTerminalPositionLookupTable()->setTerminalPtNodePosition( + toBeUpdatedPtNodeParams->getTerminalId(), NOT_A_DICT_POS /* ptNodePos */); + } else { + return true; + } +} + +bool Ver4PatriciaTrieNodeWriter::markPtNodeAsMoved( + const PtNodeParams *const toBeUpdatedPtNodeParams, + const int movedPos, const int bigramLinkedNodePos) { + int pos = toBeUpdatedPtNodeParams->getHeadPos(); + const bool usesAdditionalBuffer = mTrieBuffer->isInAdditionalBuffer(pos); + const uint8_t *const dictBuf = mTrieBuffer->getBuffer(usesAdditionalBuffer); + if (usesAdditionalBuffer) { + pos -= mTrieBuffer->getOriginalBufferSize(); + } + // Read original flags + const PatriciaTrieReadingUtils::NodeFlags originalFlags = + PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictBuf, &pos); + const PatriciaTrieReadingUtils::NodeFlags updatedFlags = + DynamicPtReadingUtils::updateAndGetFlags(originalFlags, true /* isMoved */, + false /* isDeleted */, false /* willBecomeNonTerminal */); + int writingPos = toBeUpdatedPtNodeParams->getHeadPos(); + // Update flags. + if (!DynamicPtWritingUtils::writeFlagsAndAdvancePosition(mTrieBuffer, updatedFlags, + &writingPos)) { + return false; + } + // Update moved position, which is stored in the parent offset field. + if (!DynamicPtWritingUtils::writeParentPosOffsetAndAdvancePosition( + mTrieBuffer, movedPos, toBeUpdatedPtNodeParams->getHeadPos(), &writingPos)) { + return false; + } + if (toBeUpdatedPtNodeParams->hasChildren()) { + // Update children's parent position. + mReadingHelper.initWithPtNodeArrayPos(toBeUpdatedPtNodeParams->getChildrenPos()); + while (!mReadingHelper.isEnd()) { + const PtNodeParams childPtNodeParams(mReadingHelper.getPtNodeParams()); + int parentOffsetFieldPos = childPtNodeParams.getHeadPos() + + DynamicPtWritingUtils::NODE_FLAG_FIELD_SIZE; + if (!DynamicPtWritingUtils::writeParentPosOffsetAndAdvancePosition( + mTrieBuffer, bigramLinkedNodePos, childPtNodeParams.getHeadPos(), + &parentOffsetFieldPos)) { + // Parent offset cannot be written because of a bug or a broken dictionary; thus, + // we give up to update dictionary. + return false; + } + mReadingHelper.readNextSiblingNode(childPtNodeParams); + } + } + return true; +} + +bool Ver4PatriciaTrieNodeWriter::markPtNodeAsWillBecomeNonTerminal( + const PtNodeParams *const toBeUpdatedPtNodeParams) { + int pos = toBeUpdatedPtNodeParams->getHeadPos(); + const bool usesAdditionalBuffer = mTrieBuffer->isInAdditionalBuffer(pos); + const uint8_t *const dictBuf = mTrieBuffer->getBuffer(usesAdditionalBuffer); + if (usesAdditionalBuffer) { + pos -= mTrieBuffer->getOriginalBufferSize(); + } + // Read original flags + const PatriciaTrieReadingUtils::NodeFlags originalFlags = + PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictBuf, &pos); + const PatriciaTrieReadingUtils::NodeFlags updatedFlags = + DynamicPtReadingUtils::updateAndGetFlags(originalFlags, false /* isMoved */, + false /* isDeleted */, true /* willBecomeNonTerminal */); + if (!mBuffers->getMutableTerminalPositionLookupTable()->setTerminalPtNodePosition( + toBeUpdatedPtNodeParams->getTerminalId(), NOT_A_DICT_POS /* ptNodePos */)) { + AKLOGE("Cannot update terminal position lookup table. terminal id: %d", + toBeUpdatedPtNodeParams->getTerminalId()); + return false; + } + // Update flags. + int writingPos = toBeUpdatedPtNodeParams->getHeadPos(); + return DynamicPtWritingUtils::writeFlagsAndAdvancePosition(mTrieBuffer, updatedFlags, + &writingPos); +} + +bool Ver4PatriciaTrieNodeWriter::updatePtNodeUnigramProperty( + const PtNodeParams *const toBeUpdatedPtNodeParams, + const UnigramProperty *const unigramProperty) { + // Update probability and historical information. + // TODO: Update other information in the unigram property. + if (!toBeUpdatedPtNodeParams->isTerminal()) { + return false; + } + const ProbabilityEntry originalProbabilityEntry = + mBuffers->getProbabilityDictContent()->getProbabilityEntry( + toBeUpdatedPtNodeParams->getTerminalId()); + const ProbabilityEntry probabilityEntry = createUpdatedEntryFrom(&originalProbabilityEntry, + unigramProperty); + return mBuffers->getMutableProbabilityDictContent()->setProbabilityEntry( + toBeUpdatedPtNodeParams->getTerminalId(), &probabilityEntry); +} + +bool Ver4PatriciaTrieNodeWriter::updatePtNodeProbabilityAndGetNeedsToKeepPtNodeAfterGC( + const PtNodeParams *const toBeUpdatedPtNodeParams, bool *const outNeedsToKeepPtNode) { + if (!toBeUpdatedPtNodeParams->isTerminal()) { + AKLOGE("updatePtNodeProbabilityAndGetNeedsToSaveForGC is called for non-terminal PtNode."); + return false; + } + const ProbabilityEntry originalProbabilityEntry = + mBuffers->getProbabilityDictContent()->getProbabilityEntry( + toBeUpdatedPtNodeParams->getTerminalId()); + if (originalProbabilityEntry.hasHistoricalInfo()) { + const HistoricalInfo historicalInfo = ForgettingCurveUtils::createHistoricalInfoToSave( + originalProbabilityEntry.getHistoricalInfo(), mHeaderPolicy); + const ProbabilityEntry probabilityEntry = + originalProbabilityEntry.createEntryWithUpdatedHistoricalInfo(&historicalInfo); + if (!mBuffers->getMutableProbabilityDictContent()->setProbabilityEntry( + toBeUpdatedPtNodeParams->getTerminalId(), &probabilityEntry)) { + AKLOGE("Cannot write updated probability entry. terminalId: %d", + toBeUpdatedPtNodeParams->getTerminalId()); + return false; + } + const bool isValid = ForgettingCurveUtils::needsToKeep(&historicalInfo, mHeaderPolicy); + if (!isValid) { + if (!markPtNodeAsWillBecomeNonTerminal(toBeUpdatedPtNodeParams)) { + AKLOGE("Cannot mark PtNode as willBecomeNonTerminal."); + return false; + } + } + *outNeedsToKeepPtNode = isValid; + } else { + // No need to update probability. + *outNeedsToKeepPtNode = true; + } + return true; +} + +bool Ver4PatriciaTrieNodeWriter::updateChildrenPosition( + const PtNodeParams *const toBeUpdatedPtNodeParams, const int newChildrenPosition) { + int childrenPosFieldPos = toBeUpdatedPtNodeParams->getChildrenPosFieldPos(); + return DynamicPtWritingUtils::writeChildrenPositionAndAdvancePosition(mTrieBuffer, + newChildrenPosition, &childrenPosFieldPos); +} + +bool Ver4PatriciaTrieNodeWriter::updateTerminalId(const PtNodeParams *const toBeUpdatedPtNodeParams, + const int newTerminalId) { + return mTrieBuffer->writeUint(newTerminalId, Ver4DictConstants::TERMINAL_ID_FIELD_SIZE, + toBeUpdatedPtNodeParams->getTerminalIdFieldPos()); +} + +bool Ver4PatriciaTrieNodeWriter::writePtNodeAndAdvancePosition( + const PtNodeParams *const ptNodeParams, int *const ptNodeWritingPos) { + return writePtNodeAndGetTerminalIdAndAdvancePosition(ptNodeParams, 0 /* outTerminalId */, + ptNodeWritingPos); +} + + +bool Ver4PatriciaTrieNodeWriter::writeNewTerminalPtNodeAndAdvancePosition( + const PtNodeParams *const ptNodeParams, const UnigramProperty *const unigramProperty, + int *const ptNodeWritingPos) { + int terminalId = Ver4DictConstants::NOT_A_TERMINAL_ID; + if (!writePtNodeAndGetTerminalIdAndAdvancePosition(ptNodeParams, &terminalId, + ptNodeWritingPos)) { + return false; + } + // Write probability. + ProbabilityEntry newProbabilityEntry; + const ProbabilityEntry probabilityEntryToWrite = createUpdatedEntryFrom( + &newProbabilityEntry, unigramProperty); + return mBuffers->getMutableProbabilityDictContent()->setProbabilityEntry(terminalId, + &probabilityEntryToWrite); +} + +bool Ver4PatriciaTrieNodeWriter::addNewBigramEntry( + const PtNodeParams *const sourcePtNodeParams, const PtNodeParams *const targetPtNodeParam, + const BigramProperty *const bigramProperty, bool *const outAddedNewBigram) { + if (!mBigramPolicy->addNewEntry(sourcePtNodeParams->getTerminalId(), + targetPtNodeParam->getTerminalId(), bigramProperty, outAddedNewBigram)) { + AKLOGE("Cannot add new bigram entry. terminalId: %d, targetTerminalId: %d", + sourcePtNodeParams->getTerminalId(), targetPtNodeParam->getTerminalId()); + return false; + } + if (!sourcePtNodeParams->hasBigrams()) { + // Update has bigrams flag. + return updatePtNodeFlags(sourcePtNodeParams->getHeadPos(), + sourcePtNodeParams->isBlacklisted(), sourcePtNodeParams->isNotAWord(), + sourcePtNodeParams->isTerminal(), sourcePtNodeParams->hasShortcutTargets(), + true /* hasBigrams */, + sourcePtNodeParams->getCodePointCount() > 1 /* hasMultipleChars */); + } + return true; +} + +bool Ver4PatriciaTrieNodeWriter::removeBigramEntry( + const PtNodeParams *const sourcePtNodeParams, const PtNodeParams *const targetPtNodeParam) { + return mBigramPolicy->removeEntry(sourcePtNodeParams->getTerminalId(), + targetPtNodeParam->getTerminalId()); +} + +bool Ver4PatriciaTrieNodeWriter::updateAllBigramEntriesAndDeleteUselessEntries( + const PtNodeParams *const sourcePtNodeParams, int *const outBigramEntryCount) { + return mBigramPolicy->updateAllBigramEntriesAndDeleteUselessEntries( + sourcePtNodeParams->getTerminalId(), outBigramEntryCount); +} + +bool Ver4PatriciaTrieNodeWriter::updateAllPositionFields( + const PtNodeParams *const toBeUpdatedPtNodeParams, + const DictPositionRelocationMap *const dictPositionRelocationMap, + int *const outBigramEntryCount) { + int parentPos = toBeUpdatedPtNodeParams->getParentPos(); + if (parentPos != NOT_A_DICT_POS) { + PtNodeWriter::PtNodePositionRelocationMap::const_iterator it = + dictPositionRelocationMap->mPtNodePositionRelocationMap.find(parentPos); + if (it != dictPositionRelocationMap->mPtNodePositionRelocationMap.end()) { + parentPos = it->second; + } + } + int writingPos = toBeUpdatedPtNodeParams->getHeadPos() + + DynamicPtWritingUtils::NODE_FLAG_FIELD_SIZE; + // Write updated parent offset. + if (!DynamicPtWritingUtils::writeParentPosOffsetAndAdvancePosition(mTrieBuffer, + parentPos, toBeUpdatedPtNodeParams->getHeadPos(), &writingPos)) { + return false; + } + + // Updates children position. + int childrenPos = toBeUpdatedPtNodeParams->getChildrenPos(); + if (childrenPos != NOT_A_DICT_POS) { + PtNodeWriter::PtNodeArrayPositionRelocationMap::const_iterator it = + dictPositionRelocationMap->mPtNodeArrayPositionRelocationMap.find(childrenPos); + if (it != dictPositionRelocationMap->mPtNodeArrayPositionRelocationMap.end()) { + childrenPos = it->second; + } + } + if (!updateChildrenPosition(toBeUpdatedPtNodeParams, childrenPos)) { + return false; + } + + // Counts bigram entries. + if (outBigramEntryCount) { + *outBigramEntryCount = mBigramPolicy->getBigramEntryConut( + toBeUpdatedPtNodeParams->getTerminalId()); + } + return true; +} + +bool Ver4PatriciaTrieNodeWriter::addShortcutTarget(const PtNodeParams *const ptNodeParams, + const int *const targetCodePoints, const int targetCodePointCount, + const int shortcutProbability) { + if (!mShortcutPolicy->addNewShortcut(ptNodeParams->getTerminalId(), + targetCodePoints, targetCodePointCount, shortcutProbability)) { + AKLOGE("Cannot add new shortuct entry. terminalId: %d", ptNodeParams->getTerminalId()); + return false; + } + if (!ptNodeParams->hasShortcutTargets()) { + // Update has shortcut targets flag. + return updatePtNodeFlags(ptNodeParams->getHeadPos(), + ptNodeParams->isBlacklisted(), ptNodeParams->isNotAWord(), + ptNodeParams->isTerminal(), true /* hasShortcutTargets */, + ptNodeParams->hasBigrams(), + ptNodeParams->getCodePointCount() > 1 /* hasMultipleChars */); + } + return true; +} + +bool Ver4PatriciaTrieNodeWriter::updatePtNodeHasBigramsAndShortcutTargetsFlags( + const PtNodeParams *const ptNodeParams) { + const bool hasBigrams = mBuffers->getBigramDictContent()->getBigramListHeadPos( + ptNodeParams->getTerminalId()) != NOT_A_DICT_POS; + const bool hasShortcutTargets = mBuffers->getShortcutDictContent()->getShortcutListHeadPos( + ptNodeParams->getTerminalId()) != NOT_A_DICT_POS; + return updatePtNodeFlags(ptNodeParams->getHeadPos(), ptNodeParams->isBlacklisted(), + ptNodeParams->isNotAWord(), ptNodeParams->isTerminal(), hasShortcutTargets, + hasBigrams, ptNodeParams->getCodePointCount() > 1 /* hasMultipleChars */); +} + +bool Ver4PatriciaTrieNodeWriter::writePtNodeAndGetTerminalIdAndAdvancePosition( + const PtNodeParams *const ptNodeParams, int *const outTerminalId, + int *const ptNodeWritingPos) { + const int nodePos = *ptNodeWritingPos; + // Write dummy flags. The Node flags are updated with appropriate flags at the last step of the + // PtNode writing. + if (!DynamicPtWritingUtils::writeFlagsAndAdvancePosition(mTrieBuffer, + 0 /* nodeFlags */, ptNodeWritingPos)) { + return false; + } + // Calculate a parent offset and write the offset. + if (!DynamicPtWritingUtils::writeParentPosOffsetAndAdvancePosition(mTrieBuffer, + ptNodeParams->getParentPos(), nodePos, ptNodeWritingPos)) { + return false; + } + // Write code points + if (!DynamicPtWritingUtils::writeCodePointsAndAdvancePosition(mTrieBuffer, + ptNodeParams->getCodePoints(), ptNodeParams->getCodePointCount(), ptNodeWritingPos)) { + return false; + } + int terminalId = Ver4DictConstants::NOT_A_TERMINAL_ID; + if (!ptNodeParams->willBecomeNonTerminal()) { + if (ptNodeParams->getTerminalId() != Ver4DictConstants::NOT_A_TERMINAL_ID) { + terminalId = ptNodeParams->getTerminalId(); + } else if (ptNodeParams->isTerminal()) { + // Write terminal information using a new terminal id. + // Get a new unused terminal id. + terminalId = mBuffers->getTerminalPositionLookupTable()->getNextTerminalId(); + } + } + const int isTerminal = terminalId != Ver4DictConstants::NOT_A_TERMINAL_ID; + if (isTerminal) { + // Update the lookup table. + if (!mBuffers->getMutableTerminalPositionLookupTable()->setTerminalPtNodePosition( + terminalId, nodePos)) { + return false; + } + // Write terminal Id. + if (!mTrieBuffer->writeUintAndAdvancePosition(terminalId, + Ver4DictConstants::TERMINAL_ID_FIELD_SIZE, ptNodeWritingPos)) { + return false; + } + if (outTerminalId) { + *outTerminalId = terminalId; + } + } + // Write children position + if (!DynamicPtWritingUtils::writeChildrenPositionAndAdvancePosition(mTrieBuffer, + ptNodeParams->getChildrenPos(), ptNodeWritingPos)) { + return false; + } + return updatePtNodeFlags(nodePos, ptNodeParams->isBlacklisted(), ptNodeParams->isNotAWord(), + isTerminal, ptNodeParams->hasShortcutTargets(), ptNodeParams->hasBigrams(), + ptNodeParams->getCodePointCount() > 1 /* hasMultipleChars */); +} + +const ProbabilityEntry Ver4PatriciaTrieNodeWriter::createUpdatedEntryFrom( + const ProbabilityEntry *const originalProbabilityEntry, + const UnigramProperty *const unigramProperty) const { + // TODO: Consolidate historical info and probability. + if (mHeaderPolicy->hasHistoricalInfoOfWords()) { + const HistoricalInfo historicalInfoForUpdate(unigramProperty->getTimestamp(), + unigramProperty->getLevel(), unigramProperty->getCount()); + const HistoricalInfo updatedHistoricalInfo = + ForgettingCurveUtils::createUpdatedHistoricalInfo( + originalProbabilityEntry->getHistoricalInfo(), + unigramProperty->getProbability(), &historicalInfoForUpdate, mHeaderPolicy); + return originalProbabilityEntry->createEntryWithUpdatedHistoricalInfo( + &updatedHistoricalInfo); + } else { + return originalProbabilityEntry->createEntryWithUpdatedProbability( + unigramProperty->getProbability()); + } +} + +bool Ver4PatriciaTrieNodeWriter::updatePtNodeFlags(const int ptNodePos, + const bool isBlacklisted, const bool isNotAWord, const bool isTerminal, + const bool hasShortcutTargets, const bool hasBigrams, const bool hasMultipleChars) { + // Create node flags and write them. + PatriciaTrieReadingUtils::NodeFlags nodeFlags = + PatriciaTrieReadingUtils::createAndGetFlags(isBlacklisted, isNotAWord, isTerminal, + hasShortcutTargets, hasBigrams, hasMultipleChars, + CHILDREN_POSITION_FIELD_SIZE); + if (!DynamicPtWritingUtils::writeFlags(mTrieBuffer, nodeFlags, ptNodePos)) { + AKLOGE("Cannot write PtNode flags. flags: %x, pos: %d", nodeFlags, ptNodePos); + return false; + } + return true; +} + +} // namespace v401 +} // namespace backward +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.h new file mode 100644 index 000000000..7f1851d63 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h + */ + +#ifndef LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_NODE_WRITER_H +#define LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_NODE_WRITER_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/probability_entry.h" + +namespace latinime { +namespace backward { +namespace v401 { + +} // namespace v401 +} // namespace backward +class BufferWithExtendableBuffer; +namespace backward { +namespace v401 { +} // namespace v401 +} // namespace backward +class HeaderPolicy; +namespace backward { +namespace v401 { +class Ver4BigramListPolicy; +class Ver4DictBuffers; +class Ver4PatriciaTrieNodeReader; +class Ver4PtNodeArrayReader; +class Ver4ShortcutListPolicy; + +/* + * This class is used for helping to writes nodes of ver4 patricia trie. + */ +class Ver4PatriciaTrieNodeWriter : public PtNodeWriter { + public: + Ver4PatriciaTrieNodeWriter(BufferWithExtendableBuffer *const trieBuffer, + Ver4DictBuffers *const buffers, const HeaderPolicy *const headerPolicy, + const PtNodeReader *const ptNodeReader, + const PtNodeArrayReader *const ptNodeArrayReader, + Ver4BigramListPolicy *const bigramPolicy, Ver4ShortcutListPolicy *const shortcutPolicy) + : mTrieBuffer(trieBuffer), mBuffers(buffers), mHeaderPolicy(headerPolicy), + mReadingHelper(ptNodeReader, ptNodeArrayReader), mBigramPolicy(bigramPolicy), + mShortcutPolicy(shortcutPolicy) {} + + virtual ~Ver4PatriciaTrieNodeWriter() {} + + virtual bool markPtNodeAsDeleted(const PtNodeParams *const toBeUpdatedPtNodeParams); + + virtual bool markPtNodeAsMoved(const PtNodeParams *const toBeUpdatedPtNodeParams, + const int movedPos, const int bigramLinkedNodePos); + + virtual bool markPtNodeAsWillBecomeNonTerminal( + const PtNodeParams *const toBeUpdatedPtNodeParams); + + virtual bool updatePtNodeUnigramProperty(const PtNodeParams *const toBeUpdatedPtNodeParams, + const UnigramProperty *const unigramProperty); + + virtual bool updatePtNodeProbabilityAndGetNeedsToKeepPtNodeAfterGC( + const PtNodeParams *const toBeUpdatedPtNodeParams, bool *const outNeedsToKeepPtNode); + + virtual bool updateChildrenPosition(const PtNodeParams *const toBeUpdatedPtNodeParams, + const int newChildrenPosition); + + bool updateTerminalId(const PtNodeParams *const toBeUpdatedPtNodeParams, + const int newTerminalId); + + virtual bool writePtNodeAndAdvancePosition(const PtNodeParams *const ptNodeParams, + int *const ptNodeWritingPos); + + virtual bool writeNewTerminalPtNodeAndAdvancePosition(const PtNodeParams *const ptNodeParams, + const UnigramProperty *const unigramProperty, int *const ptNodeWritingPos); + + virtual bool addNewBigramEntry(const PtNodeParams *const sourcePtNodeParams, + const PtNodeParams *const targetPtNodeParam, const BigramProperty *const bigramProperty, + bool *const outAddedNewBigram); + + virtual bool removeBigramEntry(const PtNodeParams *const sourcePtNodeParams, + const PtNodeParams *const targetPtNodeParam); + + virtual bool updateAllBigramEntriesAndDeleteUselessEntries( + const PtNodeParams *const sourcePtNodeParams, int *const outBigramEntryCount); + + virtual bool updateAllPositionFields(const PtNodeParams *const toBeUpdatedPtNodeParams, + const DictPositionRelocationMap *const dictPositionRelocationMap, + int *const outBigramEntryCount); + + virtual bool addShortcutTarget(const PtNodeParams *const ptNodeParams, + const int *const targetCodePoints, const int targetCodePointCount, + const int shortcutProbability); + + bool updatePtNodeHasBigramsAndShortcutTargetsFlags(const PtNodeParams *const ptNodeParams); + + private: + DISALLOW_COPY_AND_ASSIGN(Ver4PatriciaTrieNodeWriter); + + bool writePtNodeAndGetTerminalIdAndAdvancePosition( + const PtNodeParams *const ptNodeParams, int *const outTerminalId, + int *const ptNodeWritingPos); + + // Create updated probability entry using given unigram property. In addition to the + // probability, this method updates historical information if needed. + // TODO: Update flags belonging to the unigram property. + const ProbabilityEntry createUpdatedEntryFrom( + const ProbabilityEntry *const originalProbabilityEntry, + const UnigramProperty *const unigramProperty) const; + + bool updatePtNodeFlags(const int ptNodePos, const bool isBlacklisted, const bool isNotAWord, + const bool isTerminal, const bool hasShortcutTargets, const bool hasBigrams, + const bool hasMultipleChars); + + static const int CHILDREN_POSITION_FIELD_SIZE; + + BufferWithExtendableBuffer *const mTrieBuffer; + Ver4DictBuffers *const mBuffers; + const HeaderPolicy *const mHeaderPolicy; + DynamicPtReadingHelper mReadingHelper; + Ver4BigramListPolicy *const mBigramPolicy; + Ver4ShortcutListPolicy *const mShortcutPolicy; +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif /* LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_NODE_WRITER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_policy.cpp new file mode 100644 index 000000000..dde1af299 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_policy.cpp @@ -0,0 +1,475 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT CHANGE THE LOGIC IN THIS FILE !!!!! + * Do not edit this file other than updating policy's interface. + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp + */ + +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_policy.h" + +#include <vector> + +#include "suggest/core/dicnode/dic_node.h" +#include "suggest/core/dicnode/dic_node_vector.h" +#include "suggest/core/dictionary/property/bigram_property.h" +#include "suggest/core/dictionary/property/unigram_property.h" +#include "suggest/core/dictionary/property/word_property.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.h" +#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h" +#include "suggest/policyimpl/dictionary/utils/probability_utils.h" + +namespace latinime { +namespace backward { +namespace v401 { + +// Note that there are corresponding definitions in Java side in BinaryDictionaryTests and +// BinaryDictionaryDecayingTests. +const char *const Ver4PatriciaTriePolicy::UNIGRAM_COUNT_QUERY = "UNIGRAM_COUNT"; +const char *const Ver4PatriciaTriePolicy::BIGRAM_COUNT_QUERY = "BIGRAM_COUNT"; +const char *const Ver4PatriciaTriePolicy::MAX_UNIGRAM_COUNT_QUERY = "MAX_UNIGRAM_COUNT"; +const char *const Ver4PatriciaTriePolicy::MAX_BIGRAM_COUNT_QUERY = "MAX_BIGRAM_COUNT"; +const int Ver4PatriciaTriePolicy::MARGIN_TO_REFUSE_DYNAMIC_OPERATIONS = 1024; +const int Ver4PatriciaTriePolicy::MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS = + Ver4DictConstants::MAX_DICTIONARY_SIZE - MARGIN_TO_REFUSE_DYNAMIC_OPERATIONS; + +void Ver4PatriciaTriePolicy::createAndGetAllChildDicNodes(const DicNode *const dicNode, + DicNodeVector *const childDicNodes) const { + if (!dicNode->hasChildren()) { + return; + } + DynamicPtReadingHelper readingHelper(&mNodeReader, &mPtNodeArrayReader); + readingHelper.initWithPtNodeArrayPos(dicNode->getChildrenPtNodeArrayPos()); + while (!readingHelper.isEnd()) { + const PtNodeParams ptNodeParams = readingHelper.getPtNodeParams(); + if (!ptNodeParams.isValid()) { + break; + } + bool isTerminal = ptNodeParams.isTerminal() && !ptNodeParams.isDeleted(); + if (isTerminal && mHeaderPolicy->isDecayingDict()) { + // A DecayingDict may have a terminal PtNode that has a terminal DicNode whose + // probability is NOT_A_PROBABILITY. In such case, we don't want to treat it as a + // valid terminal DicNode. + isTerminal = ptNodeParams.getProbability() != NOT_A_PROBABILITY; + } + childDicNodes->pushLeavingChild(dicNode, ptNodeParams.getHeadPos(), + ptNodeParams.getChildrenPos(), ptNodeParams.getProbability(), isTerminal, + ptNodeParams.hasChildren(), + ptNodeParams.isBlacklisted() + || ptNodeParams.isNotAWord() /* isBlacklistedOrNotAWord */, + ptNodeParams.getCodePointCount(), ptNodeParams.getCodePoints()); + readingHelper.readNextSiblingNode(ptNodeParams); + } + if (readingHelper.isError()) { + mIsCorrupted = true; + AKLOGE("Dictionary reading error in createAndGetAllChildDicNodes()."); + } +} + +int Ver4PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount( + const int ptNodePos, const int maxCodePointCount, int *const outCodePoints, + int *const outUnigramProbability) const { + DynamicPtReadingHelper readingHelper(&mNodeReader, &mPtNodeArrayReader); + readingHelper.initWithPtNodePos(ptNodePos); + const int codePointCount = readingHelper.getCodePointsAndProbabilityAndReturnCodePointCount( + maxCodePointCount, outCodePoints, outUnigramProbability); + if (readingHelper.isError()) { + mIsCorrupted = true; + AKLOGE("Dictionary reading error in getCodePointsAndProbabilityAndReturnCodePointCount()."); + } + return codePointCount; +} + +int Ver4PatriciaTriePolicy::getTerminalPtNodePositionOfWord(const int *const inWord, + const int length, const bool forceLowerCaseSearch) const { + DynamicPtReadingHelper readingHelper(&mNodeReader, &mPtNodeArrayReader); + readingHelper.initWithPtNodeArrayPos(getRootPosition()); + const int ptNodePos = + readingHelper.getTerminalPtNodePositionOfWord(inWord, length, forceLowerCaseSearch); + if (readingHelper.isError()) { + mIsCorrupted = true; + AKLOGE("Dictionary reading error in createAndGetAllChildDicNodes()."); + } + return ptNodePos; +} + +int Ver4PatriciaTriePolicy::getProbability(const int unigramProbability, + const int bigramProbability) const { + if (mHeaderPolicy->isDecayingDict()) { + // Both probabilities are encoded. Decode them and get probability. + return ForgettingCurveUtils::getProbability(unigramProbability, bigramProbability); + } else { + if (unigramProbability == NOT_A_PROBABILITY) { + return NOT_A_PROBABILITY; + } else if (bigramProbability == NOT_A_PROBABILITY) { + return ProbabilityUtils::backoff(unigramProbability); + } else { + // bigramProbability is a bigram probability delta. + return ProbabilityUtils::computeProbabilityForBigram(unigramProbability, + bigramProbability); + } + } +} + +int Ver4PatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int ptNodePos) const { + if (ptNodePos == NOT_A_DICT_POS) { + return NOT_A_PROBABILITY; + } + const PtNodeParams ptNodeParams(mNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos)); + if (ptNodeParams.isDeleted() || ptNodeParams.isBlacklisted() || ptNodeParams.isNotAWord()) { + return NOT_A_PROBABILITY; + } + return getProbability(ptNodeParams.getProbability(), NOT_A_PROBABILITY); +} + +int Ver4PatriciaTriePolicy::getShortcutPositionOfPtNode(const int ptNodePos) const { + if (ptNodePos == NOT_A_DICT_POS) { + return NOT_A_DICT_POS; + } + const PtNodeParams ptNodeParams(mNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos)); + if (ptNodeParams.isDeleted()) { + return NOT_A_DICT_POS; + } + return mBuffers->getShortcutDictContent()->getShortcutListHeadPos( + ptNodeParams.getTerminalId()); +} + +int Ver4PatriciaTriePolicy::getBigramsPositionOfPtNode(const int ptNodePos) const { + if (ptNodePos == NOT_A_DICT_POS) { + return NOT_A_DICT_POS; + } + const PtNodeParams ptNodeParams(mNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos)); + if (ptNodeParams.isDeleted()) { + return NOT_A_DICT_POS; + } + return mBuffers->getBigramDictContent()->getBigramListHeadPos( + ptNodeParams.getTerminalId()); +} + +bool Ver4PatriciaTriePolicy::addUnigramWord(const int *const word, const int length, + const UnigramProperty *const unigramProperty) { + if (!mBuffers->isUpdatable()) { + AKLOGI("Warning: addUnigramWord() is called for non-updatable dictionary."); + return false; + } + if (mDictBuffer->getTailPosition() >= MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS) { + AKLOGE("The dictionary is too large to dynamically update. Dictionary size: %d", + mDictBuffer->getTailPosition()); + return false; + } + if (length > MAX_WORD_LENGTH) { + AKLOGE("The word is too long to insert to the dictionary, length: %d", length); + return false; + } + for (const auto &shortcut : unigramProperty->getShortcuts()) { + if (shortcut.getTargetCodePoints()->size() > MAX_WORD_LENGTH) { + AKLOGE("One of shortcut targets is too long to insert to the dictionary, length: %d", + shortcut.getTargetCodePoints()->size()); + return false; + } + } + DynamicPtReadingHelper readingHelper(&mNodeReader, &mPtNodeArrayReader); + readingHelper.initWithPtNodeArrayPos(getRootPosition()); + bool addedNewUnigram = false; + if (mUpdatingHelper.addUnigramWord(&readingHelper, word, length, + unigramProperty, &addedNewUnigram)) { + if (addedNewUnigram) { + mUnigramCount++; + } + if (unigramProperty->getShortcuts().size() > 0) { + // Add shortcut target. + const int wordPos = getTerminalPtNodePositionOfWord(word, length, + false /* forceLowerCaseSearch */); + if (wordPos == NOT_A_DICT_POS) { + AKLOGE("Cannot find terminal PtNode position to add shortcut target."); + return false; + } + for (const auto &shortcut : unigramProperty->getShortcuts()) { + if (!mUpdatingHelper.addShortcutTarget(wordPos, + shortcut.getTargetCodePoints()->data(), + shortcut.getTargetCodePoints()->size(), shortcut.getProbability())) { + AKLOGE("Cannot add new shortcut target. PtNodePos: %d, length: %d, " + "probability: %d", wordPos, shortcut.getTargetCodePoints()->size(), + shortcut.getProbability()); + return false; + } + } + } + return true; + } else { + return false; + } +} + +bool Ver4PatriciaTriePolicy::addBigramWords(const int *const word0, const int length0, + const BigramProperty *const bigramProperty) { + if (!mBuffers->isUpdatable()) { + AKLOGI("Warning: addBigramWords() is called for non-updatable dictionary."); + return false; + } + if (mDictBuffer->getTailPosition() >= MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS) { + AKLOGE("The dictionary is too large to dynamically update. Dictionary size: %d", + mDictBuffer->getTailPosition()); + return false; + } + if (length0 > MAX_WORD_LENGTH + || bigramProperty->getTargetCodePoints()->size() > MAX_WORD_LENGTH) { + AKLOGE("Either src word or target word is too long to insert the bigram to the dictionary. " + "length0: %d, length1: %d", length0, bigramProperty->getTargetCodePoints()->size()); + return false; + } + const int word0Pos = getTerminalPtNodePositionOfWord(word0, length0, + false /* forceLowerCaseSearch */); + if (word0Pos == NOT_A_DICT_POS) { + return false; + } + const int word1Pos = getTerminalPtNodePositionOfWord( + bigramProperty->getTargetCodePoints()->data(), + bigramProperty->getTargetCodePoints()->size(), false /* forceLowerCaseSearch */); + if (word1Pos == NOT_A_DICT_POS) { + return false; + } + bool addedNewBigram = false; + if (mUpdatingHelper.addBigramWords(word0Pos, word1Pos, bigramProperty, &addedNewBigram)) { + if (addedNewBigram) { + mBigramCount++; + } + return true; + } else { + return false; + } +} + +bool Ver4PatriciaTriePolicy::removeBigramWords(const int *const word0, const int length0, + const int *const word1, const int length1) { + if (!mBuffers->isUpdatable()) { + AKLOGI("Warning: addBigramWords() is called for non-updatable dictionary."); + return false; + } + if (mDictBuffer->getTailPosition() >= MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS) { + AKLOGE("The dictionary is too large to dynamically update. Dictionary size: %d", + mDictBuffer->getTailPosition()); + return false; + } + if (length0 > MAX_WORD_LENGTH || length1 > MAX_WORD_LENGTH) { + AKLOGE("Either src word or target word is too long to remove the bigram to from the " + "dictionary. length0: %d, length1: %d", length0, length1); + return false; + } + const int word0Pos = getTerminalPtNodePositionOfWord(word0, length0, + false /* forceLowerCaseSearch */); + if (word0Pos == NOT_A_DICT_POS) { + return false; + } + const int word1Pos = getTerminalPtNodePositionOfWord(word1, length1, + false /* forceLowerCaseSearch */); + if (word1Pos == NOT_A_DICT_POS) { + return false; + } + if (mUpdatingHelper.removeBigramWords(word0Pos, word1Pos)) { + mBigramCount--; + return true; + } else { + return false; + } +} + +void Ver4PatriciaTriePolicy::flush(const char *const filePath) { + if (!mBuffers->isUpdatable()) { + AKLOGI("Warning: flush() is called for non-updatable dictionary. filePath: %s", filePath); + return; + } + if (!mWritingHelper.writeToDictFile(filePath, mUnigramCount, mBigramCount)) { + AKLOGE("Cannot flush the dictionary to file."); + mIsCorrupted = true; + } +} + +void Ver4PatriciaTriePolicy::flushWithGC(const char *const filePath) { + if (!mBuffers->isUpdatable()) { + AKLOGI("Warning: flushWithGC() is called for non-updatable dictionary."); + return; + } + if (!mWritingHelper.writeToDictFileWithGC(getRootPosition(), filePath)) { + AKLOGE("Cannot flush the dictionary to file with GC."); + mIsCorrupted = true; + } +} + +bool Ver4PatriciaTriePolicy::needsToRunGC(const bool mindsBlockByGC) const { + if (!mBuffers->isUpdatable()) { + AKLOGI("Warning: needsToRunGC() is called for non-updatable dictionary."); + return false; + } + if (mBuffers->isNearSizeLimit()) { + // Additional buffer size is near the limit. + return true; + } else if (mHeaderPolicy->getExtendedRegionSize() + mDictBuffer->getUsedAdditionalBufferSize() + > Ver4DictConstants::MAX_DICT_EXTENDED_REGION_SIZE) { + // Total extended region size of the trie exceeds the limit. + return true; + } else if (mDictBuffer->getTailPosition() >= MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS + && mDictBuffer->getUsedAdditionalBufferSize() > 0) { + // Needs to reduce dictionary size. + return true; + } else if (mHeaderPolicy->isDecayingDict()) { + return ForgettingCurveUtils::needsToDecay(mindsBlockByGC, mUnigramCount, mBigramCount, + mHeaderPolicy); + } + return false; +} + +void Ver4PatriciaTriePolicy::getProperty(const char *const query, const int queryLength, + char *const outResult, const int maxResultLength) { + const int compareLength = queryLength + 1 /* terminator */; + if (strncmp(query, UNIGRAM_COUNT_QUERY, compareLength) == 0) { + snprintf(outResult, maxResultLength, "%d", mUnigramCount); + } else if (strncmp(query, BIGRAM_COUNT_QUERY, compareLength) == 0) { + snprintf(outResult, maxResultLength, "%d", mBigramCount); + } else if (strncmp(query, MAX_UNIGRAM_COUNT_QUERY, compareLength) == 0) { + snprintf(outResult, maxResultLength, "%d", + mHeaderPolicy->isDecayingDict() ? + ForgettingCurveUtils::getUnigramCountHardLimit( + mHeaderPolicy->getMaxUnigramCount()) : + static_cast<int>(Ver4DictConstants::MAX_DICTIONARY_SIZE)); + } else if (strncmp(query, MAX_BIGRAM_COUNT_QUERY, compareLength) == 0) { + snprintf(outResult, maxResultLength, "%d", + mHeaderPolicy->isDecayingDict() ? + ForgettingCurveUtils::getBigramCountHardLimit( + mHeaderPolicy->getMaxBigramCount()) : + static_cast<int>(Ver4DictConstants::MAX_DICTIONARY_SIZE)); + } +} + +const WordProperty Ver4PatriciaTriePolicy::getWordProperty(const int *const codePoints, + const int codePointCount) const { + const int ptNodePos = getTerminalPtNodePositionOfWord(codePoints, codePointCount, + false /* forceLowerCaseSearch */); + if (ptNodePos == NOT_A_DICT_POS) { + AKLOGE("getWordProperty is called for invalid word."); + return WordProperty(); + } + const PtNodeParams ptNodeParams = mNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos); + std::vector<int> codePointVector(ptNodeParams.getCodePoints(), + ptNodeParams.getCodePoints() + ptNodeParams.getCodePointCount()); + const ProbabilityEntry probabilityEntry = + mBuffers->getProbabilityDictContent()->getProbabilityEntry( + ptNodeParams.getTerminalId()); + const HistoricalInfo *const historicalInfo = probabilityEntry.getHistoricalInfo(); + // Fetch bigram information. + std::vector<BigramProperty> bigrams; + const int bigramListPos = getBigramsPositionOfPtNode(ptNodePos); + if (bigramListPos != NOT_A_DICT_POS) { + int bigramWord1CodePoints[MAX_WORD_LENGTH]; + const BigramDictContent *const bigramDictContent = mBuffers->getBigramDictContent(); + const TerminalPositionLookupTable *const terminalPositionLookupTable = + mBuffers->getTerminalPositionLookupTable(); + bool hasNext = true; + int readingPos = bigramListPos; + while (hasNext) { + const BigramEntry bigramEntry = + bigramDictContent->getBigramEntryAndAdvancePosition(&readingPos); + hasNext = bigramEntry.hasNext(); + const int word1TerminalId = bigramEntry.getTargetTerminalId(); + const int word1TerminalPtNodePos = + terminalPositionLookupTable->getTerminalPtNodePosition(word1TerminalId); + if (word1TerminalPtNodePos == NOT_A_DICT_POS) { + continue; + } + // Word (unigram) probability + int word1Probability = NOT_A_PROBABILITY; + const int codePointCount = getCodePointsAndProbabilityAndReturnCodePointCount( + word1TerminalPtNodePos, MAX_WORD_LENGTH, bigramWord1CodePoints, + &word1Probability); + const std::vector<int> word1(bigramWord1CodePoints, + bigramWord1CodePoints + codePointCount); + const HistoricalInfo *const historicalInfo = bigramEntry.getHistoricalInfo(); + const int probability = bigramEntry.hasHistoricalInfo() ? + ForgettingCurveUtils::decodeProbability( + bigramEntry.getHistoricalInfo(), mHeaderPolicy) : + getProbability(word1Probability, bigramEntry.getProbability()); + bigrams.emplace_back(&word1, probability, + historicalInfo->getTimeStamp(), historicalInfo->getLevel(), + historicalInfo->getCount()); + } + } + // Fetch shortcut information. + std::vector<UnigramProperty::ShortcutProperty> shortcuts; + int shortcutPos = getShortcutPositionOfPtNode(ptNodePos); + if (shortcutPos != NOT_A_DICT_POS) { + int shortcutTarget[MAX_WORD_LENGTH]; + const ShortcutDictContent *const shortcutDictContent = + mBuffers->getShortcutDictContent(); + bool hasNext = true; + while (hasNext) { + int shortcutTargetLength = 0; + int shortcutProbability = NOT_A_PROBABILITY; + shortcutDictContent->getShortcutEntryAndAdvancePosition(MAX_WORD_LENGTH, shortcutTarget, + &shortcutTargetLength, &shortcutProbability, &hasNext, &shortcutPos); + const std::vector<int> target(shortcutTarget, shortcutTarget + shortcutTargetLength); + shortcuts.emplace_back(&target, shortcutProbability); + } + } + const UnigramProperty unigramProperty(ptNodeParams.isNotAWord(), + ptNodeParams.isBlacklisted(), ptNodeParams.getProbability(), + historicalInfo->getTimeStamp(), historicalInfo->getLevel(), + historicalInfo->getCount(), &shortcuts); + return WordProperty(&codePointVector, &unigramProperty, &bigrams); +} + +int Ver4PatriciaTriePolicy::getNextWordAndNextToken(const int token, int *const outCodePoints) { + // TODO: Return code point count like other methods. + // Null termination. + outCodePoints[0] = 0; + if (token == 0) { + mTerminalPtNodePositionsForIteratingWords.clear(); + DynamicPtReadingHelper::TraversePolicyToGetAllTerminalPtNodePositions traversePolicy( + &mTerminalPtNodePositionsForIteratingWords); + DynamicPtReadingHelper readingHelper(&mNodeReader, &mPtNodeArrayReader); + readingHelper.initWithPtNodeArrayPos(getRootPosition()); + readingHelper.traverseAllPtNodesInPostorderDepthFirstManner(&traversePolicy); + } + const int terminalPtNodePositionsVectorSize = + static_cast<int>(mTerminalPtNodePositionsForIteratingWords.size()); + if (token < 0 || token >= terminalPtNodePositionsVectorSize) { + AKLOGE("Given token %d is invalid.", token); + return 0; + } + const int terminalPtNodePos = mTerminalPtNodePositionsForIteratingWords[token]; + int unigramProbability = NOT_A_PROBABILITY; + const int codePointCount = getCodePointsAndProbabilityAndReturnCodePointCount( + terminalPtNodePos, MAX_WORD_LENGTH, outCodePoints, &unigramProbability); + if (codePointCount < MAX_WORD_LENGTH) { + // Null termination. outCodePoints have to be null terminated or contain MAX_WORD_LENGTH + // code points. + outCodePoints[codePointCount] = 0; + } + const int nextToken = token + 1; + if (nextToken >= terminalPtNodePositionsVectorSize) { + // All words have been iterated. + mTerminalPtNodePositionsForIteratingWords.clear(); + return 0; + } + return nextToken; +} + +} // namespace v401 +} // namespace backward +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_policy.h new file mode 100644 index 000000000..2f8ad539c --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_policy.h @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT CHANGE THE LOGIC IN THIS FILE !!!!! + * Do not edit this file other than updating policy's interface. + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h + */ + +#ifndef LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_POLICY_H +#define LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_POLICY_H + +#include <vector> + +#include "defines.h" +#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h" +#include "suggest/policyimpl/dictionary/header/header_policy.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/shortcut/ver4_shortcut_list_policy.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_writing_helper.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" + +namespace latinime { +namespace backward { +namespace v401 { + +} // namespace v401 +} // namespace backward +class DicNode; +namespace backward { +namespace v401 { +} // namespace v401 +} // namespace backward +class DicNodeVector; +namespace backward { +namespace v401 { + +class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { + public: + Ver4PatriciaTriePolicy(Ver4DictBuffers::Ver4DictBuffersPtr buffers) + : mBuffers(std::move(buffers)), mHeaderPolicy(mBuffers->getHeaderPolicy()), + mDictBuffer(mBuffers->getWritableTrieBuffer()), + mBigramPolicy(mBuffers->getMutableBigramDictContent(), + mBuffers->getTerminalPositionLookupTable(), mHeaderPolicy), + mShortcutPolicy(mBuffers->getMutableShortcutDictContent(), + mBuffers->getTerminalPositionLookupTable()), + mNodeReader(mDictBuffer, mBuffers->getProbabilityDictContent(), mHeaderPolicy), + mPtNodeArrayReader(mDictBuffer), + mNodeWriter(mDictBuffer, mBuffers.get(), mHeaderPolicy, &mNodeReader, + &mPtNodeArrayReader, &mBigramPolicy, &mShortcutPolicy), + mUpdatingHelper(mDictBuffer, &mNodeReader, &mNodeWriter), + mWritingHelper(mBuffers.get()), + mUnigramCount(mHeaderPolicy->getUnigramCount()), + mBigramCount(mHeaderPolicy->getBigramCount()), + mTerminalPtNodePositionsForIteratingWords(), mIsCorrupted(false) {}; + + AK_FORCE_INLINE int getRootPosition() const { + return 0; + } + + void createAndGetAllChildDicNodes(const DicNode *const dicNode, + DicNodeVector *const childDicNodes) const; + + int getCodePointsAndProbabilityAndReturnCodePointCount( + const int terminalPtNodePos, const int maxCodePointCount, int *const outCodePoints, + int *const outUnigramProbability) const; + + int getTerminalPtNodePositionOfWord(const int *const inWord, + const int length, const bool forceLowerCaseSearch) const; + + int getProbability(const int unigramProbability, const int bigramProbability) const; + + int getUnigramProbabilityOfPtNode(const int ptNodePos) const; + + int getShortcutPositionOfPtNode(const int ptNodePos) const; + + int getBigramsPositionOfPtNode(const int ptNodePos) const; + + const DictionaryHeaderStructurePolicy *getHeaderStructurePolicy() const { + return mHeaderPolicy; + } + + const DictionaryBigramsStructurePolicy *getBigramsStructurePolicy() const { + return &mBigramPolicy; + } + + const DictionaryShortcutsStructurePolicy *getShortcutsStructurePolicy() const { + return &mShortcutPolicy; + } + + bool addUnigramWord(const int *const word, const int length, + const UnigramProperty *const unigramProperty); + + bool addBigramWords(const int *const word0, const int length0, + const BigramProperty *const bigramProperty); + + bool removeBigramWords(const int *const word0, const int length0, const int *const word1, + const int length1); + + void flush(const char *const filePath); + + void flushWithGC(const char *const filePath); + + bool needsToRunGC(const bool mindsBlockByGC) const; + + void getProperty(const char *const query, const int queryLength, char *const outResult, + const int maxResultLength); + + const WordProperty getWordProperty(const int *const codePoints, + const int codePointCount) const; + + int getNextWordAndNextToken(const int token, int *const outCodePoints); + + bool isCorrupted() const { + return mIsCorrupted; + } + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4PatriciaTriePolicy); + + static const char *const UNIGRAM_COUNT_QUERY; + static const char *const BIGRAM_COUNT_QUERY; + static const char *const MAX_UNIGRAM_COUNT_QUERY; + static const char *const MAX_BIGRAM_COUNT_QUERY; + // When the dictionary size is near the maximum size, we have to refuse dynamic operations to + // prevent the dictionary from overflowing. + static const int MARGIN_TO_REFUSE_DYNAMIC_OPERATIONS; + static const int MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS; + + const Ver4DictBuffers::Ver4DictBuffersPtr mBuffers; + const HeaderPolicy *const mHeaderPolicy; + BufferWithExtendableBuffer *const mDictBuffer; + Ver4BigramListPolicy mBigramPolicy; + Ver4ShortcutListPolicy mShortcutPolicy; + Ver4PatriciaTrieNodeReader mNodeReader; + Ver4PtNodeArrayReader mPtNodeArrayReader; + Ver4PatriciaTrieNodeWriter mNodeWriter; + DynamicPtUpdatingHelper mUpdatingHelper; + Ver4PatriciaTrieWritingHelper mWritingHelper; + int mUnigramCount; + int mBigramCount; + std::vector<int> mTerminalPtNodePositionsForIteratingWords; + mutable bool mIsCorrupted; +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif // LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_POLICY_H diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.cpp new file mode 100644 index 000000000..6cc36fbef --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.cpp + */ + +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.h" + +#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h" + +namespace latinime { +namespace backward { +namespace v401 { + +/* static */ int Ver4PatriciaTrieReadingUtils::getTerminalIdAndAdvancePosition( + const uint8_t *const buffer, int *pos) { + return ByteArrayUtils::readUint32AndAdvancePosition(buffer, pos); +} + +} // namespace v401 +} // namespace backward +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.h new file mode 100644 index 000000000..7417c261e --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.h + */ + +#ifndef LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_READING_UTILS_H +#define LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_READING_UTILS_H + +#include <cstdint> + +#include "defines.h" + +namespace latinime { +namespace backward { +namespace v401 { + +} // namespace v401 +} // namespace backward +class BufferWithExtendableBuffer; +namespace backward { +namespace v401 { + +class Ver4PatriciaTrieReadingUtils { + public: + static int getTerminalIdAndAdvancePosition(const uint8_t *const buffer, + int *const pos); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4PatriciaTrieReadingUtils); +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif /* LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_READING_UTILS_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_writing_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_writing_helper.cpp new file mode 100644 index 000000000..10f27beb7 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_writing_helper.cpp @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp + */ + +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_writing_helper.h" + +#include <cstring> +#include <queue> + +#include "suggest/policyimpl/dictionary/header/header_policy.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/shortcut/ver4_shortcut_list_policy.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" +#include "suggest/policyimpl/dictionary/utils/file_utils.h" +#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h" + +namespace latinime { +namespace backward { +namespace v401 { + +bool Ver4PatriciaTrieWritingHelper::writeToDictFile(const char *const dictDirPath, + const int unigramCount, const int bigramCount) const { + const HeaderPolicy *const headerPolicy = mBuffers->getHeaderPolicy(); + BufferWithExtendableBuffer headerBuffer( + BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE); + const int extendedRegionSize = headerPolicy->getExtendedRegionSize() + + mBuffers->getTrieBuffer()->getUsedAdditionalBufferSize(); + if (!headerPolicy->fillInAndWriteHeaderToBuffer(false /* updatesLastDecayedTime */, + unigramCount, bigramCount, extendedRegionSize, &headerBuffer)) { + AKLOGE("Cannot write header structure to buffer. " + "updatesLastDecayedTime: %d, unigramCount: %d, bigramCount: %d, " + "extendedRegionSize: %d", false, unigramCount, bigramCount, + extendedRegionSize); + return false; + } + return mBuffers->flushHeaderAndDictBuffers(dictDirPath, &headerBuffer); +} + +bool Ver4PatriciaTrieWritingHelper::writeToDictFileWithGC(const int rootPtNodeArrayPos, + const char *const dictDirPath) { + const HeaderPolicy *const headerPolicy = mBuffers->getHeaderPolicy(); + Ver4DictBuffers::Ver4DictBuffersPtr dictBuffers( + Ver4DictBuffers::createVer4DictBuffers(headerPolicy, + Ver4DictConstants::MAX_DICTIONARY_SIZE)); + int unigramCount = 0; + int bigramCount = 0; + if (!runGC(rootPtNodeArrayPos, headerPolicy, dictBuffers.get(), &unigramCount, &bigramCount)) { + return false; + } + BufferWithExtendableBuffer headerBuffer( + BufferWithExtendableBuffer::DEFAULT_MAX_ADDITIONAL_BUFFER_SIZE); + if (!headerPolicy->fillInAndWriteHeaderToBuffer(true /* updatesLastDecayedTime */, + unigramCount, bigramCount, 0 /* extendedRegionSize */, &headerBuffer)) { + return false; + } + return dictBuffers->flushHeaderAndDictBuffers(dictDirPath, &headerBuffer); +} + +bool Ver4PatriciaTrieWritingHelper::runGC(const int rootPtNodeArrayPos, + const HeaderPolicy *const headerPolicy, Ver4DictBuffers *const buffersToWrite, + int *const outUnigramCount, int *const outBigramCount) { + Ver4PatriciaTrieNodeReader ptNodeReader(mBuffers->getTrieBuffer(), + mBuffers->getProbabilityDictContent(), headerPolicy); + Ver4PtNodeArrayReader ptNodeArrayReader(mBuffers->getTrieBuffer()); + Ver4BigramListPolicy bigramPolicy(mBuffers->getMutableBigramDictContent(), + mBuffers->getTerminalPositionLookupTable(), headerPolicy); + Ver4ShortcutListPolicy shortcutPolicy(mBuffers->getMutableShortcutDictContent(), + mBuffers->getTerminalPositionLookupTable()); + Ver4PatriciaTrieNodeWriter ptNodeWriter(mBuffers->getWritableTrieBuffer(), + mBuffers, headerPolicy, &ptNodeReader, &ptNodeArrayReader, &bigramPolicy, + &shortcutPolicy); + + DynamicPtReadingHelper readingHelper(&ptNodeReader, &ptNodeArrayReader); + readingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos); + DynamicPtGcEventListeners + ::TraversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted + traversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted( + &ptNodeWriter); + if (!readingHelper.traverseAllPtNodesInPostorderDepthFirstManner( + &traversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted)) { + return false; + } + const int unigramCount = traversePolicyToUpdateUnigramProbabilityAndMarkUselessPtNodesAsDeleted + .getValidUnigramCount(); + const int maxUnigramCount = headerPolicy->getMaxUnigramCount(); + if (headerPolicy->isDecayingDict() && unigramCount > maxUnigramCount) { + if (!truncateUnigrams(&ptNodeReader, &ptNodeWriter, maxUnigramCount)) { + AKLOGE("Cannot remove unigrams. current: %d, max: %d", unigramCount, + maxUnigramCount); + return false; + } + } + + readingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos); + DynamicPtGcEventListeners::TraversePolicyToUpdateBigramProbability + traversePolicyToUpdateBigramProbability(&ptNodeWriter); + if (!readingHelper.traverseAllPtNodesInPostorderDepthFirstManner( + &traversePolicyToUpdateBigramProbability)) { + return false; + } + const int bigramCount = traversePolicyToUpdateBigramProbability.getValidBigramEntryCount(); + const int maxBigramCount = headerPolicy->getMaxBigramCount(); + if (headerPolicy->isDecayingDict() && bigramCount > maxBigramCount) { + if (!truncateBigrams(maxBigramCount)) { + AKLOGE("Cannot remove bigrams. current: %d, max: %d", bigramCount, maxBigramCount); + return false; + } + } + + // Mapping from positions in mBuffer to positions in bufferToWrite. + PtNodeWriter::DictPositionRelocationMap dictPositionRelocationMap; + readingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos); + Ver4PatriciaTrieNodeWriter ptNodeWriterForNewBuffers(buffersToWrite->getWritableTrieBuffer(), + buffersToWrite, headerPolicy, &ptNodeReader, &ptNodeArrayReader, &bigramPolicy, + &shortcutPolicy); + DynamicPtGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer + traversePolicyToPlaceAndWriteValidPtNodesToBuffer(&ptNodeWriterForNewBuffers, + buffersToWrite->getWritableTrieBuffer(), &dictPositionRelocationMap); + if (!readingHelper.traverseAllPtNodesInPtNodeArrayLevelPreorderDepthFirstManner( + &traversePolicyToPlaceAndWriteValidPtNodesToBuffer)) { + return false; + } + + // Create policy instances for the GCed dictionary. + Ver4PatriciaTrieNodeReader newPtNodeReader(buffersToWrite->getTrieBuffer(), + buffersToWrite->getProbabilityDictContent(), headerPolicy); + Ver4PtNodeArrayReader newPtNodeArrayreader(buffersToWrite->getTrieBuffer()); + Ver4BigramListPolicy newBigramPolicy(buffersToWrite->getMutableBigramDictContent(), + buffersToWrite->getTerminalPositionLookupTable(), headerPolicy); + Ver4ShortcutListPolicy newShortcutPolicy(buffersToWrite->getMutableShortcutDictContent(), + buffersToWrite->getTerminalPositionLookupTable()); + Ver4PatriciaTrieNodeWriter newPtNodeWriter(buffersToWrite->getWritableTrieBuffer(), + buffersToWrite, headerPolicy, &newPtNodeReader, &newPtNodeArrayreader, &newBigramPolicy, + &newShortcutPolicy); + // Re-assign terminal IDs for valid terminal PtNodes. + TerminalPositionLookupTable::TerminalIdMap terminalIdMap; + if(!buffersToWrite->getMutableTerminalPositionLookupTable()->runGCTerminalIds( + &terminalIdMap)) { + return false; + } + // Run GC for probability dict content. + if (!buffersToWrite->getMutableProbabilityDictContent()->runGC(&terminalIdMap, + mBuffers->getProbabilityDictContent())) { + return false; + } + // Run GC for bigram dict content. + if(!buffersToWrite->getMutableBigramDictContent()->runGC(&terminalIdMap, + mBuffers->getBigramDictContent(), outBigramCount)) { + return false; + } + // Run GC for shortcut dict content. + if(!buffersToWrite->getMutableShortcutDictContent()->runGC(&terminalIdMap, + mBuffers->getShortcutDictContent())) { + return false; + } + DynamicPtReadingHelper newDictReadingHelper(&newPtNodeReader, &newPtNodeArrayreader); + newDictReadingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos); + DynamicPtGcEventListeners::TraversePolicyToUpdateAllPositionFields + traversePolicyToUpdateAllPositionFields(&newPtNodeWriter, &dictPositionRelocationMap); + if (!newDictReadingHelper.traverseAllPtNodesInPtNodeArrayLevelPreorderDepthFirstManner( + &traversePolicyToUpdateAllPositionFields)) { + return false; + } + newDictReadingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos); + TraversePolicyToUpdateAllPtNodeFlagsAndTerminalIds + traversePolicyToUpdateAllPtNodeFlagsAndTerminalIds(&newPtNodeWriter, &terminalIdMap); + if (!newDictReadingHelper.traverseAllPtNodesInPostorderDepthFirstManner( + &traversePolicyToUpdateAllPtNodeFlagsAndTerminalIds)) { + return false; + } + *outUnigramCount = traversePolicyToUpdateAllPositionFields.getUnigramCount(); + return true; +} + +bool Ver4PatriciaTrieWritingHelper::truncateUnigrams( + const Ver4PatriciaTrieNodeReader *const ptNodeReader, + Ver4PatriciaTrieNodeWriter *const ptNodeWriter, const int maxUnigramCount) { + const TerminalPositionLookupTable *const terminalPosLookupTable = + mBuffers->getTerminalPositionLookupTable(); + const int nextTerminalId = terminalPosLookupTable->getNextTerminalId(); + std::priority_queue<DictProbability, std::vector<DictProbability>, DictProbabilityComparator> + priorityQueue; + for (int i = 0; i < nextTerminalId; ++i) { + const int terminalPos = terminalPosLookupTable->getTerminalPtNodePosition(i); + if (terminalPos == NOT_A_DICT_POS) { + continue; + } + const ProbabilityEntry probabilityEntry = + mBuffers->getProbabilityDictContent()->getProbabilityEntry(i); + const int probability = probabilityEntry.hasHistoricalInfo() ? + ForgettingCurveUtils::decodeProbability( + probabilityEntry.getHistoricalInfo(), mBuffers->getHeaderPolicy()) : + probabilityEntry.getProbability(); + priorityQueue.push(DictProbability(terminalPos, probability, + probabilityEntry.getHistoricalInfo()->getTimeStamp())); + } + + // Delete unigrams. + while (static_cast<int>(priorityQueue.size()) > maxUnigramCount) { + const int ptNodePos = priorityQueue.top().getDictPos(); + const PtNodeParams ptNodeParams = + ptNodeReader->fetchNodeInfoInBufferFromPtNodePos(ptNodePos); + if (!ptNodeWriter->markPtNodeAsWillBecomeNonTerminal(&ptNodeParams)) { + AKLOGE("Cannot mark PtNode as willBecomeNonterminal. PtNode pos: %d", ptNodePos); + return false; + } + priorityQueue.pop(); + } + return true; +} + +bool Ver4PatriciaTrieWritingHelper::truncateBigrams(const int maxBigramCount) { + const TerminalPositionLookupTable *const terminalPosLookupTable = + mBuffers->getTerminalPositionLookupTable(); + const int nextTerminalId = terminalPosLookupTable->getNextTerminalId(); + std::priority_queue<DictProbability, std::vector<DictProbability>, DictProbabilityComparator> + priorityQueue; + BigramDictContent *const bigramDictContent = mBuffers->getMutableBigramDictContent(); + for (int i = 0; i < nextTerminalId; ++i) { + const int bigramListPos = bigramDictContent->getBigramListHeadPos(i); + if (bigramListPos == NOT_A_DICT_POS) { + continue; + } + bool hasNext = true; + int readingPos = bigramListPos; + while (hasNext) { + const int entryPos = readingPos; + const BigramEntry bigramEntry = + bigramDictContent->getBigramEntryAndAdvancePosition(&readingPos); + hasNext = bigramEntry.hasNext(); + if (!bigramEntry.isValid()) { + continue; + } + const int probability = bigramEntry.hasHistoricalInfo() ? + ForgettingCurveUtils::decodeProbability( + bigramEntry.getHistoricalInfo(), mBuffers->getHeaderPolicy()) : + bigramEntry.getProbability(); + priorityQueue.push(DictProbability(entryPos, probability, + bigramEntry.getHistoricalInfo()->getTimeStamp())); + } + } + + // Delete bigrams. + while (static_cast<int>(priorityQueue.size()) > maxBigramCount) { + const int entryPos = priorityQueue.top().getDictPos(); + const BigramEntry bigramEntry = bigramDictContent->getBigramEntry(entryPos); + const BigramEntry invalidatedBigramEntry = bigramEntry.getInvalidatedEntry(); + if (!bigramDictContent->writeBigramEntry(&invalidatedBigramEntry, entryPos)) { + AKLOGE("Cannot write bigram entry to remove. pos: %d", entryPos); + return false; + } + priorityQueue.pop(); + } + return true; +} + +bool Ver4PatriciaTrieWritingHelper::TraversePolicyToUpdateAllPtNodeFlagsAndTerminalIds + ::onVisitingPtNode(const PtNodeParams *const ptNodeParams) { + if (!ptNodeParams->isTerminal()) { + return true; + } + TerminalPositionLookupTable::TerminalIdMap::const_iterator it = + mTerminalIdMap->find(ptNodeParams->getTerminalId()); + if (it == mTerminalIdMap->end()) { + AKLOGE("terminal Id %d is not in the terminal position map. map size: %zd", + ptNodeParams->getTerminalId(), mTerminalIdMap->size()); + return false; + } + if (!mPtNodeWriter->updateTerminalId(ptNodeParams, it->second)) { + AKLOGE("Cannot update terminal id. %d -> %d", it->first, it->second); + } + return mPtNodeWriter->updatePtNodeHasBigramsAndShortcutTargetsFlags(ptNodeParams); +} + +} // namespace v401 +} // namespace backward +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_writing_helper.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_writing_helper.h new file mode 100644 index 000000000..be44aaa33 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_writing_helper.h @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.h + */ + +#ifndef LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_WRITING_HELPER_H +#define LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_WRITING_HELPER_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_gc_event_listeners.h" +#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h" + +namespace latinime { +namespace backward { +namespace v401 { + +} // namespace v401 +} // namespace backward +class HeaderPolicy; +namespace backward { +namespace v401 { +class Ver4DictBuffers; +class Ver4PatriciaTrieNodeReader; +class Ver4PatriciaTrieNodeWriter; + +class Ver4PatriciaTrieWritingHelper { + public: + Ver4PatriciaTrieWritingHelper(Ver4DictBuffers *const buffers) + : mBuffers(buffers) {} + + bool writeToDictFile(const char *const dictDirPath, const int unigramCount, + const int bigramCount) const; + + // This method cannot be const because the original dictionary buffer will be updated to detect + // useless PtNodes during GC. + bool writeToDictFileWithGC(const int rootPtNodeArrayPos, const char *const dictDirPath); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4PatriciaTrieWritingHelper); + + class TraversePolicyToUpdateAllPtNodeFlagsAndTerminalIds + : public DynamicPtReadingHelper::TraversingEventListener { + public: + TraversePolicyToUpdateAllPtNodeFlagsAndTerminalIds( + Ver4PatriciaTrieNodeWriter *const ptNodeWriter, + const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap) + : mPtNodeWriter(ptNodeWriter), mTerminalIdMap(terminalIdMap) {} + + bool onAscend() { return true; } + + bool onDescend(const int ptNodeArrayPos) { return true; } + + bool onReadingPtNodeArrayTail() { return true; } + + bool onVisitingPtNode(const PtNodeParams *const ptNodeParams); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(TraversePolicyToUpdateAllPtNodeFlagsAndTerminalIds); + + Ver4PatriciaTrieNodeWriter *const mPtNodeWriter; + const TerminalPositionLookupTable::TerminalIdMap *const mTerminalIdMap; + }; + + // For truncateUnigrams() and truncateBigrams(). + class DictProbability { + public: + DictProbability(const int dictPos, const int probability, const int timestamp) + : mDictPos(dictPos), mProbability(probability), mTimestamp(timestamp) {} + + int getDictPos() const { + return mDictPos; + } + + int getProbability() const { + return mProbability; + } + + int getTimestamp() const { + return mTimestamp; + } + + private: + DISALLOW_DEFAULT_CONSTRUCTOR(DictProbability); + + int mDictPos; + int mProbability; + int mTimestamp; + }; + + // For truncateUnigrams() and truncateBigrams(). + class DictProbabilityComparator { + public: + bool operator()(const DictProbability &left, const DictProbability &right) { + if (left.getProbability() != right.getProbability()) { + return left.getProbability() > right.getProbability(); + } + if (left.getTimestamp() != right.getTimestamp()) { + return left.getTimestamp() < right.getTimestamp(); + } + return left.getDictPos() > right.getDictPos(); + } + + private: + DISALLOW_ASSIGNMENT_OPERATOR(DictProbabilityComparator); + }; + + bool runGC(const int rootPtNodeArrayPos, const HeaderPolicy *const headerPolicy, + Ver4DictBuffers *const buffersToWrite, int *const outUnigramCount, + int *const outBigramCount); + + bool truncateUnigrams(const Ver4PatriciaTrieNodeReader *const ptNodeReader, + Ver4PatriciaTrieNodeWriter *const ptNodeWriter, const int maxUnigramCount); + + bool truncateBigrams(const int maxBigramCount); + + Ver4DictBuffers *const mBuffers; +}; +} // namespace v401 +} // namespace backward +} // namespace latinime + +#endif /* LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_WRITING_HELPER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.cpp new file mode 100644 index 000000000..33e4e55e2 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/ver4_pt_node_array_reader.cpp + */ + +#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.h" + +#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h" +#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h" + +namespace latinime { +namespace backward { +namespace v401 { + +bool Ver4PtNodeArrayReader::readPtNodeArrayInfoAndReturnIfValid(const int ptNodeArrayPos, + int *const outPtNodeCount, int *const outFirstPtNodePos) const { + if (ptNodeArrayPos < 0 || ptNodeArrayPos >= mBuffer->getTailPosition()) { + // Reading invalid position because of a bug or a broken dictionary. + AKLOGE("Reading PtNode array info from invalid dictionary position: %d, dict size: %d", + ptNodeArrayPos, mBuffer->getTailPosition()); + ASSERT(false); + return false; + } + const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(ptNodeArrayPos); + const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer); + int readingPos = ptNodeArrayPos; + if (usesAdditionalBuffer) { + readingPos -= mBuffer->getOriginalBufferSize(); + } + const int ptNodeCountInArray = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition( + dictBuf, &readingPos); + if (usesAdditionalBuffer) { + readingPos += mBuffer->getOriginalBufferSize(); + } + if (ptNodeCountInArray < 0) { + AKLOGE("Invalid PtNode count in an array: %d.", ptNodeCountInArray); + return false; + } + *outPtNodeCount = ptNodeCountInArray; + *outFirstPtNodePos = readingPos; + return true; +} + +bool Ver4PtNodeArrayReader::readForwardLinkAndReturnIfValid(const int forwordLinkPos, + int *const outNextPtNodeArrayPos) const { + if (forwordLinkPos < 0 || forwordLinkPos >= mBuffer->getTailPosition()) { + // Reading invalid position because of bug or broken dictionary. + AKLOGE("Reading forward link from invalid dictionary position: %d, dict size: %d", + forwordLinkPos, mBuffer->getTailPosition()); + ASSERT(false); + return false; + } + const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(forwordLinkPos); + const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer); + int readingPos = forwordLinkPos; + if (usesAdditionalBuffer) { + readingPos -= mBuffer->getOriginalBufferSize(); + } + const int nextPtNodeArrayOffset = + DynamicPtReadingUtils::getForwardLinkPosition(dictBuf, readingPos); + if (DynamicPtReadingUtils::isValidForwardLinkPosition(nextPtNodeArrayOffset)) { + *outNextPtNodeArrayPos = forwordLinkPos + nextPtNodeArrayOffset; + } else { + *outNextPtNodeArrayPos = NOT_A_DICT_POS; + } + return true; +} + +} // namespace v401 +} // namespace backward +} // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.h new file mode 100644 index 000000000..3a7eefa44 --- /dev/null +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * !!!!! DO NOT EDIT THIS FILE !!!!! + * + * This file was generated from + * suggest/policyimpl/dictionary/structure/v4/ver4_pt_node_array_reader.h + */ + +#ifndef LATINIME_BACKWARD_V401_VER4_PT_NODE_ARRAY_READER_H +#define LATINIME_BACKWARD_V401_VER4_PT_NODE_ARRAY_READER_H + +#include "defines.h" +#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_array_reader.h" + +namespace latinime { +namespace backward { +namespace v401 { + +} // namespace v401 +} // namespace backward +class BufferWithExtendableBuffer; +namespace backward { +namespace v401 { + +class Ver4PtNodeArrayReader : public PtNodeArrayReader { + public: + Ver4PtNodeArrayReader(const BufferWithExtendableBuffer *const buffer) : mBuffer(buffer) {}; + + virtual bool readPtNodeArrayInfoAndReturnIfValid(const int ptNodeArrayPos, + int *const outPtNodeCount, int *const outFirstPtNodePos) const; + virtual bool readForwardLinkAndReturnIfValid(const int forwordLinkPos, + int *const outNextPtNodeArrayPos) const; + + private: + DISALLOW_COPY_AND_ASSIGN(Ver4PtNodeArrayReader); + + const BufferWithExtendableBuffer *const mBuffer; +}; +} // namespace v401 +} // namespace backward +} // namespace latinime +#endif /* LATINIME_BACKWARD_V401_VER4_PT_NODE_ARRAY_READER_H */ diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h index 91192fc57..bef401f87 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h @@ -23,6 +23,7 @@ #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h" #include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h" #include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h" +#include "utils/char_utils.h" namespace latinime { @@ -158,6 +159,10 @@ class PtNodeParams { return PatriciaTrieReadingUtils::hasShortcutTargets(mFlags); } + AK_FORCE_INLINE bool representsNonWordInfo() const { + return getCodePointCount() > 0 && CharUtils::isInUnicodeSpace(getCodePoints()[0]); + } + // Parent node position AK_FORCE_INLINE int getParentPos() const { return mParentPos; diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp index b3af1f47a..30dcfba37 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp @@ -24,6 +24,7 @@ #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h" #include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h" #include "suggest/policyimpl/dictionary/utils/probability_utils.h" +#include "utils/char_utils.h" namespace latinime { @@ -318,12 +319,15 @@ int PatriciaTriePolicy::createAndGetLeavingChildNode(const DicNode *const dicNod PatriciaTrieReadingUtils::readPtNodeInfo(mDictRoot, ptNodePos, getShortcutsStructurePolicy(), getBigramsStructurePolicy(), &flags, &mergedNodeCodePointCount, mergedNodeCodePoints, &probability, &childrenPos, &shortcutPos, &bigramPos, &siblingPos); - childDicNodes->pushLeavingChild(dicNode, ptNodePos, childrenPos, probability, - PatriciaTrieReadingUtils::isTerminal(flags), - PatriciaTrieReadingUtils::hasChildrenInFlags(flags), - PatriciaTrieReadingUtils::isBlacklisted(flags) - || PatriciaTrieReadingUtils::isNotAWord(flags), - mergedNodeCodePointCount, mergedNodeCodePoints); + // Skip PtNodes don't start with Unicode code point because they represent non-word information. + if (CharUtils::isInUnicodeSpace(mergedNodeCodePoints[0])) { + childDicNodes->pushLeavingChild(dicNode, ptNodePos, childrenPos, probability, + PatriciaTrieReadingUtils::isTerminal(flags), + PatriciaTrieReadingUtils::hasChildrenInFlags(flags), + PatriciaTrieReadingUtils::isBlacklisted(flags) + || PatriciaTrieReadingUtils::isNotAWord(flags), + mergedNodeCodePointCount, mergedNodeCodePoints); + } return siblingPos; } diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp index 77ed38b89..5aa6b9a92 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp @@ -56,6 +56,7 @@ bool Ver4DictBuffers::flushHeaderAndDictBuffers(const char *const dictDirPath, return false; } } + umask(S_IWGRP | S_IWOTH); if (mkdir(tmpDirPath, S_IRWXU) == -1) { AKLOGE("Cannot create directory: %s. errno: %d.", tmpDirPath, errno); return false; diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp index 2fb3decee..8373dc549 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp @@ -59,13 +59,17 @@ void Ver4PatriciaTriePolicy::createAndGetAllChildDicNodes(const DicNode *const d // valid terminal DicNode. isTerminal = ptNodeParams.getProbability() != NOT_A_PROBABILITY; } + readingHelper.readNextSiblingNode(ptNodeParams); + if (!ptNodeParams.representsNonWordInfo()) { + // Skip PtNodes that represent non-word information. + continue; + } childDicNodes->pushLeavingChild(dicNode, ptNodeParams.getHeadPos(), ptNodeParams.getChildrenPos(), ptNodeParams.getProbability(), isTerminal, ptNodeParams.hasChildren(), ptNodeParams.isBlacklisted() || ptNodeParams.isNotAWord() /* isBlacklistedOrNotAWord */, ptNodeParams.getCodePointCount(), ptNodeParams.getCodePoints()); - readingHelper.readNextSiblingNode(ptNodeParams); } if (readingHelper.isError()) { mIsCorrupted = true; diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp index 7bc7b0a48..80970c7f8 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp @@ -17,6 +17,10 @@ #include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h" #include <cstdio> +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> #include "suggest/policyimpl/dictionary/header/header_policy.h" #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.h" @@ -100,9 +104,15 @@ const char *const DictFileWritingUtils::TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE = /* static */ bool DictFileWritingUtils::flushBufferToFile(const char *const filePath, const BufferWithExtendableBuffer *const buffer) { - FILE *const file = fopen(filePath, "wb"); + const int fd = open(filePath, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + if (fd == -1) { + AKLOGE("File %s cannot be opened. errno: %d", filePath, errno); + ASSERT(false); + return false; + } + FILE *const file = fdopen(fd, "wb"); if (!file) { - AKLOGE("File %s cannot be opened.", filePath); + AKLOGE("fdopen failed for the file %s. errno: %d", filePath, errno); ASSERT(false); return false; } diff --git a/native/jni/src/utils/char_utils.cpp b/native/jni/src/utils/char_utils.cpp index adc474b4c..b17e0847d 100644 --- a/native/jni/src/utils/char_utils.cpp +++ b/native/jni/src/utils/char_utils.cpp @@ -22,6 +22,9 @@ namespace latinime { +const int CharUtils::MIN_UNICODE_CODE_POINT = 0; +const int CharUtils::MAX_UNICODE_CODE_POINT = 0x10FFFF; + struct LatinCapitalSmallPair { unsigned short capital; unsigned short small; diff --git a/native/jni/src/utils/char_utils.h b/native/jni/src/utils/char_utils.h index 239419d5b..634c45b04 100644 --- a/native/jni/src/utils/char_utils.h +++ b/native/jni/src/utils/char_utils.h @@ -86,12 +86,19 @@ class CharUtils { return spaceCount; } + static AK_FORCE_INLINE int isInUnicodeSpace(const int codePoint) { + return codePoint >= MIN_UNICODE_CODE_POINT && codePoint <= MAX_UNICODE_CODE_POINT; + } + static unsigned short latin_tolower(const unsigned short c); static const std::vector<int> EMPTY_STRING; private: DISALLOW_IMPLICIT_CONSTRUCTORS(CharUtils); + static const int MIN_UNICODE_CODE_POINT; + static const int MAX_UNICODE_CODE_POINT; + /** * Table mapping most combined Latin, Greek, and Cyrillic characters * to their base characters. If c is in range, BASE_CHARS[c] == c diff --git a/native/jni/src/utils/jni_data_utils.cpp b/native/jni/src/utils/jni_data_utils.cpp new file mode 100644 index 000000000..5555293d5 --- /dev/null +++ b/native/jni/src/utils/jni_data_utils.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils/jni_data_utils.h" + +namespace latinime { + +const int JniDataUtils::CODE_POINT_REPLACEMENT_CHARACTER = 0xFFFD; +const int JniDataUtils::CODE_POINT_NULL = 0; + +} // namespace latinime diff --git a/native/jni/src/utils/jni_data_utils.h b/native/jni/src/utils/jni_data_utils.h index 2ce02dc05..67a66fdfe 100644 --- a/native/jni/src/utils/jni_data_utils.h +++ b/native/jni/src/utils/jni_data_utils.h @@ -23,6 +23,7 @@ #include "jni.h" #include "suggest/core/policy/dictionary_header_structure_policy.h" #include "suggest/policyimpl/dictionary/header/header_read_write_utils.h" +#include "utils/char_utils.h" namespace latinime { @@ -65,8 +66,44 @@ class JniDataUtils { return attributeMap; } + static void outputCodePoints(JNIEnv *env, jintArray intArrayToOutputCodePoints, const int start, + const int maxLength, const int *const codePoints, const int codePointCount, + const bool needsNullTermination) { + const int outputCodePointCount = std::min(maxLength, codePointCount); + int outputCodePonts[outputCodePointCount]; + for (int i = 0; i < outputCodePointCount; ++i) { + const int codePoint = codePoints[i]; + if (!CharUtils::isInUnicodeSpace(codePoint)) { + outputCodePonts[i] = CODE_POINT_REPLACEMENT_CHARACTER; + } else if (codePoint >= 0x01 && codePoint <= 0x1F) { + // Control code. + outputCodePonts[i] = CODE_POINT_REPLACEMENT_CHARACTER; + } else { + outputCodePonts[i] = codePoint; + } + } + env->SetIntArrayRegion(intArrayToOutputCodePoints, start, outputCodePointCount, + outputCodePonts); + if (needsNullTermination && outputCodePointCount < maxLength) { + env->SetIntArrayRegion(intArrayToOutputCodePoints, start + outputCodePointCount, + 1 /* len */, &CODE_POINT_NULL); + } + } + + static void putIntToArray(JNIEnv *env, jintArray array, const int index, const int value) { + env->SetIntArrayRegion(array, index, 1 /* len */, &value); + } + + static void putFloatToArray(JNIEnv *env, jfloatArray array, const int index, + const float value) { + env->SetFloatArrayRegion(array, index, 1 /* len */, &value); + } + private: DISALLOW_IMPLICIT_CONSTRUCTORS(JniDataUtils); + + static const int CODE_POINT_REPLACEMENT_CHARACTER; + static const int CODE_POINT_NULL; }; } // namespace latinime #endif // LATINIME_JNI_DATA_UTILS_H diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java index 9b532fe6f..555b1a47a 100644 --- a/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java +++ b/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java @@ -29,7 +29,7 @@ public class KeyboardThemeTests extends AndroidTestCase { private static final int THEME_ID_NULL = -1; private static final int THEME_ID_ICS = KeyboardTheme.THEME_ID_ICS; private static final int THEME_ID_KLP = KeyboardTheme.THEME_ID_KLP; - private static final int THEME_ID_LMP = KeyboardTheme.THEME_ID_LMP; + private static final int THEME_ID_LXX = KeyboardTheme.THEME_ID_LXX; @Override protected void setUp() throws Exception { @@ -64,11 +64,11 @@ public class KeyboardThemeTests extends AndroidTestCase { assertDefaultKeyboardTheme(sdkVersion, THEME_ID_KLP, THEME_ID_KLP); } - private void assertDefaultKeyboardThemeLMP(final int sdkVersion) { - // Forced to switch to LMP theme. - assertDefaultKeyboardTheme(sdkVersion, THEME_ID_NULL, THEME_ID_LMP); - assertDefaultKeyboardTheme(sdkVersion, THEME_ID_ICS, THEME_ID_LMP); - assertDefaultKeyboardTheme(sdkVersion, THEME_ID_KLP, THEME_ID_LMP); + private void assertDefaultKeyboardThemeLXX(final int sdkVersion) { + // Forced to switch to LXX theme. + assertDefaultKeyboardTheme(sdkVersion, THEME_ID_NULL, THEME_ID_LXX); + assertDefaultKeyboardTheme(sdkVersion, THEME_ID_ICS, THEME_ID_LXX); + assertDefaultKeyboardTheme(sdkVersion, THEME_ID_KLP, THEME_ID_LXX); } public void testDefaultKeyboardThemeICS() { @@ -86,8 +86,8 @@ public class KeyboardThemeTests extends AndroidTestCase { assertDefaultKeyboardThemeKLP(VERSION_CODES.KITKAT); } - public void testDefaultKeyboardThemeLMP() { + public void testDefaultKeyboardThemeLXX() { // TODO: Update this constant once the *next* version becomes available. - assertDefaultKeyboardThemeLMP(VERSION_CODES.CUR_DEVELOPMENT); + assertDefaultKeyboardThemeLXX(VERSION_CODES.CUR_DEVELOPMENT); } } diff --git a/tests/src/com/android/inputmethod/latin/DistracterFilterTest.java b/tests/src/com/android/inputmethod/latin/DistracterFilterTest.java new file mode 100644 index 000000000..186542ae5 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/DistracterFilterTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.latin; + +import android.test.suitebuilder.annotation.LargeTest; + +import com.android.inputmethod.latin.utils.DistracterFilter; + +/** + * Unit test for DistracterFilter + */ +@LargeTest +public class DistracterFilterTest extends InputTestsBase { + private DistracterFilter mDistracterFilter; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mDistracterFilter = mLatinIME.createDistracterFilter(); + } + + public void testIsDistractorToWordsInDictionaries() { + final String EMPTY_PREV_WORD = null; + String typedWord = "alot"; + // For this test case, we consider "alot" is a distracter to "a lot". + assertTrue(mDistracterFilter.isDistracterToWordsInDictionaries(EMPTY_PREV_WORD, typedWord)); + + typedWord = "mot"; + // For this test case, we consider "mot" is a distracter to "not". + assertTrue(mDistracterFilter.isDistracterToWordsInDictionaries(EMPTY_PREV_WORD, typedWord)); + + typedWord = "wierd"; + // For this test case, we consider "wierd" is a distracter to "weird". + assertTrue(mDistracterFilter.isDistracterToWordsInDictionaries(EMPTY_PREV_WORD, typedWord)); + + typedWord = "hoe"; + // For this test case, we consider "hoe" is a distracter to "how". + assertTrue(mDistracterFilter.isDistracterToWordsInDictionaries(EMPTY_PREV_WORD, typedWord)); + + typedWord = "nit"; + // For this test case, we consider "nit" is a distracter to "not". + assertTrue(mDistracterFilter.isDistracterToWordsInDictionaries(EMPTY_PREV_WORD, typedWord)); + + typedWord = "ill"; + // For this test case, we consider "ill" is a distracter to "I'll". + assertTrue(mDistracterFilter.isDistracterToWordsInDictionaries(EMPTY_PREV_WORD, typedWord)); + + typedWord = "asdfd"; + // For this test case, we consider "asdfd" is not a distracter to any word in dictionaries. + assertFalse( + mDistracterFilter.isDistracterToWordsInDictionaries(EMPTY_PREV_WORD, typedWord)); + + typedWord = "thank"; + // For this test case, we consider "thank" is not a distracter to any other word + // in dictionaries. + assertFalse( + mDistracterFilter.isDistracterToWordsInDictionaries(EMPTY_PREV_WORD, typedWord)); + } +} diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java index 29423e8e3..a9444160f 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java @@ -600,4 +600,16 @@ public class InputLogicTests extends InputTestsBase { assertEquals("type words letter by letter", EXPECTED_RESULT, mEditText.getText().toString()); } + + public void testSwitchLanguages() { + final String WORD_TO_TYPE_FIRST_PART = "com"; + final String WORD_TO_TYPE_SECOND_PART = "md "; + final String EXPECTED_RESULT = "comme "; + changeLanguage("en"); + type(WORD_TO_TYPE_FIRST_PART); + changeLanguage("fr"); + type(WORD_TO_TYPE_SECOND_PART); + assertEquals("Composing continues after switching languages", EXPECTED_RESULT, + mEditText.getText().toString()); + } } diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTestsReorderingMyanmar.java b/tests/src/com/android/inputmethod/latin/InputLogicTestsReorderingMyanmar.java index b3f2819cf..bb36a2a16 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicTestsReorderingMyanmar.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicTestsReorderingMyanmar.java @@ -220,7 +220,7 @@ public class InputLogicTestsReorderingMyanmar extends InputTestsBase { public void testMyanmarReordering() { int testNumber = 0; - changeLanguage("mm_MY"); + changeLanguage("my_MM", "CombiningRules=MyanmarReordering"); for (final Pair[] test : TESTS) { // Small trick to reset LatinIME : setText("") and send updateSelection with values // LatinIME has never seen, and cursor pos 0,0. diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java index 260e534ee..09c53204b 100644 --- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java +++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java @@ -299,11 +299,15 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> { } protected void changeLanguage(final String locale) { - changeLanguageWithoutWait(locale); + changeLanguage(locale, null); + } + + protected void changeLanguage(final String locale, final String combiningSpec) { + changeLanguageWithoutWait(locale, combiningSpec); waitForDictionariesToBeLoaded(); } - protected void changeLanguageWithoutWait(final String locale) { + protected void changeLanguageWithoutWait(final String locale, final String combiningSpec) { mEditText.mCurrentLocale = LocaleUtils.constructLocaleFromString(locale); // TODO: this is forcing a QWERTY keyboard for all locales, which is wrong. // It's still better than using whatever keyboard is the current one, but we @@ -314,7 +318,8 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> { "KeyboardLayoutSet=" + SubtypeLocaleUtils.QWERTY + "," + Constants.Subtype.ExtraValue.ASCII_CAPABLE + "," + Constants.Subtype.ExtraValue.ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE - + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE; + + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE + + null == combiningSpec ? "" : ("," + combiningSpec); final InputMethodSubtype subtype = InputMethodSubtypeCompatUtils.newInputMethodSubtype( R.string.subtype_no_language_qwerty, R.drawable.ic_ime_switcher_dark, @@ -325,7 +330,7 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> { false /* overridesImplicitlyEnabledSubtype */, 0 /* id */); SubtypeSwitcher.getInstance().forceSubtype(subtype); - mLatinIME.loadKeyboard(); + mLatinIME.onCurrentInputMethodSubtypeChanged(subtype); runMessages(); mKeyboard = mLatinIME.mKeyboardSwitcher.getKeyboard(); mLatinIME.clearPersonalizedDictionariesForTest(); diff --git a/tests/src/com/android/inputmethod/latin/LatinImeStressTests.java b/tests/src/com/android/inputmethod/latin/LatinImeStressTests.java index db14b8329..0a29d8326 100644 --- a/tests/src/com/android/inputmethod/latin/LatinImeStressTests.java +++ b/tests/src/com/android/inputmethod/latin/LatinImeStressTests.java @@ -33,7 +33,8 @@ public class LatinImeStressTests extends InputTestsBase { final int codePointSetSize = 30; final int[] codePointSet = CodePointUtils.LATIN_ALPHABETS_LOWER; for (int i = 0; i < switchCount; ++i) { - changeLanguageWithoutWait(locales[random.nextInt(locales.length)]); + changeLanguageWithoutWait(locales[random.nextInt(locales.length)], + null /* combiningSpec */); final int wordCount = random.nextInt(maxWordCountToTypeInEachIteration); for (int j = 0; j < wordCount; ++j) { final String word = CodePointUtils.generateWord(random, codePointSet); @@ -50,7 +51,8 @@ public class LatinImeStressTests extends InputTestsBase { final int codePointSetSize = 30; final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random); for (int i = 0; i < switchCount; ++i) { - changeLanguageWithoutWait(locales[random.nextInt(locales.length)]); + changeLanguageWithoutWait(locales[random.nextInt(locales.length)], + null /* combiningSpec */); final int wordCount = random.nextInt(maxWordCountToTypeInEachIteration); for (int j = 0; j < wordCount; ++j) { final String word = CodePointUtils.generateWord(random, codePointSet); diff --git a/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java b/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java index 47f781e62..538d759c8 100644 --- a/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java +++ b/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java @@ -28,8 +28,10 @@ import java.util.ArrayList; // TODO: there should not be a dependency to this in dicttool, so there // should be a sensible way to separate them cleanly. public class CombinerChain { - private StringBuilder mComposingWord = new StringBuilder(); - public CombinerChain(final Combiner... combinerList) {} + private StringBuilder mComposingWord; + public CombinerChain(final String initialText, final Combiner... combinerList) { + mComposingWord = new StringBuilder(initialText); + } public void processEvent(final ArrayList<Event> previousEvents, final Event newEvent) { mComposingWord.append(newEvent.getTextToCommit()); |