diff options
Diffstat (limited to 'java/src')
17 files changed, 551 insertions, 454 deletions
diff --git a/java/src/com/android/inputmethod/event/InputTransaction.java b/java/src/com/android/inputmethod/event/InputTransaction.java new file mode 100644 index 000000000..3f709a674 --- /dev/null +++ b/java/src/com/android/inputmethod/event/InputTransaction.java @@ -0,0 +1,66 @@ +/* + * 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.event; + +import com.android.inputmethod.latin.settings.SettingsValues; + +/** + * An object encapsulating a single transaction for input. + */ +public class InputTransaction { + // UPDATE_LATER is stronger than UPDATE_NOW. The reason for this is, if we have to update later, + // it's because something will change that we can't evaluate now, which means that even if we + // re-evaluate now we'll have to do it again later. The only case where that wouldn't apply + // would be if we needed to update now to find out the new state right away, but then we + // can't do it with this deferred mechanism anyway. + public static final int SHIFT_NO_UPDATE = 0; + public static final int SHIFT_UPDATE_NOW = 1; + public static final int SHIFT_UPDATE_LATER = 2; + + // Initial conditions + public final SettingsValues mSettingsValues; + // If the key inserts a code point, mKeyCode is always equal to the code points. Otherwise, + // it's always a code that may not be a code point, typically a negative number. + public final int mKeyCode; + public final int mX; // Pressed x-coordinate, or one of Constants.*_COORDINATE + public final int mY; // Pressed y-coordinate, or one of Constants.*_COORDINATE + public final long mTimestamp; + public final int mSpaceState; + public final int mShiftState; + + // Outputs + private int mRequiredShiftUpdate = SHIFT_NO_UPDATE; + + public InputTransaction(final SettingsValues settingsValues, final int keyCode, + final int x, final int y, final long timestamp, final int spaceState, + final int shiftState) { + mSettingsValues = settingsValues; + mKeyCode = keyCode; + mX = x; + mY = y; + mTimestamp = timestamp; + mSpaceState = spaceState; + mShiftState = shiftState; + } + + public void requireShiftUpdate(final int updateType) { + mRequiredShiftUpdate = Math.max(mRequiredShiftUpdate, updateType); + } + public int getRequiredShiftUpdate() { + return mRequiredShiftUpdate; + } +} diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 59cf64d4b..3539a874c 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -323,7 +323,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element, } // Note that we need primaryCode argument because the keyboard may in shifted state and the - // primaryCode is different from {@link Key#mCode}. + // primaryCode is different from {@link Key#mKeyCode}. private void callListenerOnCodeInput(final Key key, final int primaryCode, final int x, final int y, final long eventTime) { final boolean ignoreModifierKey = mIsInDraggingFinger && key.isModifier(); @@ -360,7 +360,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element, } // Note that we need primaryCode argument because the keyboard may be in shifted state and the - // primaryCode is different from {@link Key#mCode}. + // primaryCode is different from {@link Key#mKeyCode}. private void callListenerOnRelease(final Key key, final int primaryCode, final boolean withSliding) { // See the comment at {@link #callListenerOnPressAndCheckKeyboardLayoutChange(Key}}. diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java index ed2db07a8..cace069c4 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java @@ -107,149 +107,148 @@ public final class KeyboardTextsTable { /* 25: 6 */ "more_keys_for_cyrillic_ie", /* 26: 5 */ "more_keys_for_nordic_row2_10", /* 27: 5 */ "keylabel_for_east_slavic_row1_9", - /* 28: 5 */ "keylabel_for_east_slavic_row1_12", - /* 29: 5 */ "keylabel_for_east_slavic_row2_1", - /* 30: 5 */ "keylabel_for_east_slavic_row2_11", - /* 31: 5 */ "keylabel_for_east_slavic_row3_5", - /* 32: 5 */ "more_keys_for_cyrillic_soft_sign", - /* 33: 5 */ "more_keys_for_punctuation", - /* 34: 4 */ "more_keys_for_nordic_row2_11", - /* 35: 4 */ "keylabel_for_symbols_1", - /* 36: 4 */ "keylabel_for_symbols_2", - /* 37: 4 */ "keylabel_for_symbols_3", - /* 38: 4 */ "keylabel_for_symbols_4", - /* 39: 4 */ "keylabel_for_symbols_5", - /* 40: 4 */ "keylabel_for_symbols_6", - /* 41: 4 */ "keylabel_for_symbols_7", - /* 42: 4 */ "keylabel_for_symbols_8", - /* 43: 4 */ "keylabel_for_symbols_9", - /* 44: 4 */ "keylabel_for_symbols_0", - /* 45: 4 */ "label_to_symbol_key", - /* 46: 4 */ "label_to_symbol_with_microphone_key", - /* 47: 4 */ "additional_more_keys_for_symbols_1", - /* 48: 4 */ "additional_more_keys_for_symbols_2", - /* 49: 4 */ "additional_more_keys_for_symbols_3", - /* 50: 4 */ "additional_more_keys_for_symbols_4", - /* 51: 4 */ "additional_more_keys_for_symbols_5", - /* 52: 4 */ "additional_more_keys_for_symbols_6", - /* 53: 4 */ "additional_more_keys_for_symbols_7", - /* 54: 4 */ "additional_more_keys_for_symbols_8", - /* 55: 4 */ "additional_more_keys_for_symbols_9", - /* 56: 4 */ "additional_more_keys_for_symbols_0", - /* 57: 3 */ "more_keys_for_star", - /* 58: 3 */ "keyspec_left_parenthesis", - /* 59: 3 */ "keyspec_right_parenthesis", - /* 60: 3 */ "keyspec_left_square_bracket", - /* 61: 3 */ "keyspec_right_square_bracket", - /* 62: 3 */ "keyspec_left_curly_bracket", - /* 63: 3 */ "keyspec_right_curly_bracket", - /* 64: 3 */ "keyspec_less_than", - /* 65: 3 */ "keyspec_greater_than", - /* 66: 3 */ "keyspec_less_than_equal", - /* 67: 3 */ "keyspec_greater_than_equal", - /* 68: 3 */ "keyspec_left_double_angle_quote", - /* 69: 3 */ "keyspec_right_double_angle_quote", - /* 70: 3 */ "keyspec_left_single_angle_quote", - /* 71: 3 */ "keyspec_right_single_angle_quote", - /* 72: 3 */ "keylabel_for_tablet_comma", - /* 73: 3 */ "more_keys_for_tablet_period", - /* 74: 3 */ "more_keys_for_question", - /* 75: 2 */ "more_keys_for_h", - /* 76: 2 */ "more_keys_for_w", - /* 77: 2 */ "more_keys_for_cyrillic_u", - /* 78: 2 */ "more_keys_for_cyrillic_en", - /* 79: 2 */ "more_keys_for_cyrillic_ghe", - /* 80: 2 */ "more_keys_for_east_slavic_row2_1", - /* 81: 2 */ "more_keys_for_cyrillic_o", - /* 82: 2 */ "keylabel_for_south_slavic_row1_6", - /* 83: 2 */ "keylabel_for_south_slavic_row2_11", - /* 84: 2 */ "keylabel_for_south_slavic_row3_1", - /* 85: 2 */ "keylabel_for_south_slavic_row3_8", - /* 86: 2 */ "more_keys_for_cyrillic_i", - /* 87: 2 */ "keylabel_for_swiss_row1_11", - /* 88: 2 */ "keylabel_for_swiss_row2_10", - /* 89: 2 */ "keylabel_for_swiss_row2_11", - /* 90: 2 */ "more_keys_for_swiss_row1_11", - /* 91: 2 */ "more_keys_for_swiss_row2_10", - /* 92: 2 */ "more_keys_for_swiss_row2_11", - /* 93: 2 */ "keylabel_for_spanish_row2_10", - /* 94: 2 */ "more_keys_for_bullet", - /* 95: 2 */ "more_keys_for_left_parenthesis", - /* 96: 2 */ "more_keys_for_right_parenthesis", - /* 97: 2 */ "more_keys_for_arabic_diacritics", - /* 98: 2 */ "keylabel_for_comma", - /* 99: 2 */ "more_keys_for_comma", - /* 100: 2 */ "keyhintlabel_for_tablet_comma", - /* 101: 2 */ "more_keys_for_tablet_comma", - /* 102: 2 */ "keyhintlabel_for_period", - /* 103: 2 */ "more_keys_for_period", - /* 104: 2 */ "keyhintlabel_for_tablet_period", - /* 105: 2 */ "keylabel_for_symbols_question", - /* 106: 2 */ "keylabel_for_symbols_semicolon", - /* 107: 2 */ "keylabel_for_symbols_percent", - /* 108: 2 */ "more_keys_for_symbols_semicolon", - /* 109: 2 */ "more_keys_for_symbols_percent", - /* 110: 1 */ "more_keys_for_v", - /* 111: 1 */ "more_keys_for_j", - /* 112: 1 */ "more_keys_for_cyrillic_ka", - /* 113: 1 */ "more_keys_for_cyrillic_a", - /* 114: 1 */ "more_keys_for_east_slavic_row2_11", - /* 115: 1 */ "more_keys_for_currency_dollar", - /* 116: 1 */ "more_keys_for_tablet_punctuation", - /* 117: 1 */ "more_keys_for_plus", - /* 118: 1 */ "more_keys_for_less_than", - /* 119: 1 */ "more_keys_for_greater_than", - /* 120: 1 */ "keylabel_for_period", - /* 121: 1 */ "keylabel_for_tablet_period", - /* 122: 1 */ "more_keys_for_exclamation", - /* 123: 1 */ "more_keys_for_q", - /* 124: 1 */ "more_keys_for_x", - /* 125: 1 */ "keylabel_for_q", - /* 126: 1 */ "keylabel_for_w", - /* 127: 1 */ "keylabel_for_y", - /* 128: 1 */ "keylabel_for_x", - /* 129: 0 */ "more_keys_for_currency", - /* 130: 0 */ "more_keys_for_symbols_1", - /* 131: 0 */ "more_keys_for_symbols_2", - /* 132: 0 */ "more_keys_for_symbols_3", - /* 133: 0 */ "more_keys_for_symbols_4", - /* 134: 0 */ "more_keys_for_symbols_5", - /* 135: 0 */ "more_keys_for_symbols_6", - /* 136: 0 */ "more_keys_for_symbols_7", - /* 137: 0 */ "more_keys_for_symbols_8", - /* 138: 0 */ "more_keys_for_symbols_9", - /* 139: 0 */ "more_keys_for_symbols_0", - /* 140: 0 */ "more_keys_for_am_pm", - /* 141: 0 */ "settings_as_more_key", - /* 142: 0 */ "shortcut_as_more_key", - /* 143: 0 */ "action_next_as_more_key", - /* 144: 0 */ "action_previous_as_more_key", - /* 145: 0 */ "label_to_more_symbol_key", - /* 146: 0 */ "label_to_more_symbol_for_tablet_key", - /* 147: 0 */ "label_to_phone_numeric_key", - /* 148: 0 */ "label_to_phone_symbols_key", - /* 149: 0 */ "label_time_am", - /* 150: 0 */ "label_time_pm", - /* 151: 0 */ "keylabel_for_popular_domain", - /* 152: 0 */ "more_keys_for_popular_domain", - /* 153: 0 */ "keyspecs_for_left_parenthesis_more_keys", - /* 154: 0 */ "keyspecs_for_right_parenthesis_more_keys", - /* 155: 0 */ "single_laqm_raqm", - /* 156: 0 */ "single_raqm_laqm", - /* 157: 0 */ "double_laqm_raqm", - /* 158: 0 */ "double_raqm_laqm", - /* 159: 0 */ "single_lqm_rqm", - /* 160: 0 */ "single_9qm_lqm", - /* 161: 0 */ "single_9qm_rqm", - /* 162: 0 */ "single_rqm_9qm", - /* 163: 0 */ "double_lqm_rqm", - /* 164: 0 */ "double_9qm_lqm", - /* 165: 0 */ "double_9qm_rqm", - /* 166: 0 */ "double_rqm_9qm", - /* 167: 0 */ "more_keys_for_single_quote", - /* 168: 0 */ "more_keys_for_double_quote", - /* 169: 0 */ "more_keys_for_tablet_double_quote", - /* 170: 0 */ "emoji_key_as_more_key", + /* 28: 5 */ "keylabel_for_east_slavic_row2_2", + /* 29: 5 */ "keylabel_for_east_slavic_row2_11", + /* 30: 5 */ "keylabel_for_east_slavic_row3_5", + /* 31: 5 */ "more_keys_for_cyrillic_soft_sign", + /* 32: 5 */ "more_keys_for_punctuation", + /* 33: 4 */ "more_keys_for_nordic_row2_11", + /* 34: 4 */ "keylabel_for_symbols_1", + /* 35: 4 */ "keylabel_for_symbols_2", + /* 36: 4 */ "keylabel_for_symbols_3", + /* 37: 4 */ "keylabel_for_symbols_4", + /* 38: 4 */ "keylabel_for_symbols_5", + /* 39: 4 */ "keylabel_for_symbols_6", + /* 40: 4 */ "keylabel_for_symbols_7", + /* 41: 4 */ "keylabel_for_symbols_8", + /* 42: 4 */ "keylabel_for_symbols_9", + /* 43: 4 */ "keylabel_for_symbols_0", + /* 44: 4 */ "label_to_symbol_key", + /* 45: 4 */ "label_to_symbol_with_microphone_key", + /* 46: 4 */ "additional_more_keys_for_symbols_1", + /* 47: 4 */ "additional_more_keys_for_symbols_2", + /* 48: 4 */ "additional_more_keys_for_symbols_3", + /* 49: 4 */ "additional_more_keys_for_symbols_4", + /* 50: 4 */ "additional_more_keys_for_symbols_5", + /* 51: 4 */ "additional_more_keys_for_symbols_6", + /* 52: 4 */ "additional_more_keys_for_symbols_7", + /* 53: 4 */ "additional_more_keys_for_symbols_8", + /* 54: 4 */ "additional_more_keys_for_symbols_9", + /* 55: 4 */ "additional_more_keys_for_symbols_0", + /* 56: 3 */ "more_keys_for_star", + /* 57: 3 */ "keyspec_left_parenthesis", + /* 58: 3 */ "keyspec_right_parenthesis", + /* 59: 3 */ "keyspec_left_square_bracket", + /* 60: 3 */ "keyspec_right_square_bracket", + /* 61: 3 */ "keyspec_left_curly_bracket", + /* 62: 3 */ "keyspec_right_curly_bracket", + /* 63: 3 */ "keyspec_less_than", + /* 64: 3 */ "keyspec_greater_than", + /* 65: 3 */ "keyspec_less_than_equal", + /* 66: 3 */ "keyspec_greater_than_equal", + /* 67: 3 */ "keyspec_left_double_angle_quote", + /* 68: 3 */ "keyspec_right_double_angle_quote", + /* 69: 3 */ "keyspec_left_single_angle_quote", + /* 70: 3 */ "keyspec_right_single_angle_quote", + /* 71: 3 */ "keylabel_for_tablet_comma", + /* 72: 3 */ "more_keys_for_tablet_period", + /* 73: 3 */ "more_keys_for_question", + /* 74: 2 */ "more_keys_for_h", + /* 75: 2 */ "more_keys_for_w", + /* 76: 2 */ "more_keys_for_cyrillic_u", + /* 77: 2 */ "more_keys_for_cyrillic_en", + /* 78: 2 */ "more_keys_for_cyrillic_ghe", + /* 79: 2 */ "more_keys_for_east_slavic_row2_2", + /* 80: 2 */ "more_keys_for_cyrillic_o", + /* 81: 2 */ "keylabel_for_south_slavic_row1_6", + /* 82: 2 */ "keylabel_for_south_slavic_row2_11", + /* 83: 2 */ "keylabel_for_south_slavic_row3_1", + /* 84: 2 */ "keylabel_for_south_slavic_row3_8", + /* 85: 2 */ "more_keys_for_cyrillic_i", + /* 86: 2 */ "keylabel_for_swiss_row1_11", + /* 87: 2 */ "keylabel_for_swiss_row2_10", + /* 88: 2 */ "keylabel_for_swiss_row2_11", + /* 89: 2 */ "more_keys_for_swiss_row1_11", + /* 90: 2 */ "more_keys_for_swiss_row2_10", + /* 91: 2 */ "more_keys_for_swiss_row2_11", + /* 92: 2 */ "keylabel_for_spanish_row2_10", + /* 93: 2 */ "more_keys_for_bullet", + /* 94: 2 */ "more_keys_for_left_parenthesis", + /* 95: 2 */ "more_keys_for_right_parenthesis", + /* 96: 2 */ "more_keys_for_arabic_diacritics", + /* 97: 2 */ "keylabel_for_comma", + /* 98: 2 */ "more_keys_for_comma", + /* 99: 2 */ "keyhintlabel_for_tablet_comma", + /* 100: 2 */ "more_keys_for_tablet_comma", + /* 101: 2 */ "keyhintlabel_for_period", + /* 102: 2 */ "more_keys_for_period", + /* 103: 2 */ "keyhintlabel_for_tablet_period", + /* 104: 2 */ "keylabel_for_symbols_question", + /* 105: 2 */ "keylabel_for_symbols_semicolon", + /* 106: 2 */ "keylabel_for_symbols_percent", + /* 107: 2 */ "more_keys_for_symbols_semicolon", + /* 108: 2 */ "more_keys_for_symbols_percent", + /* 109: 1 */ "more_keys_for_v", + /* 110: 1 */ "more_keys_for_j", + /* 111: 1 */ "more_keys_for_cyrillic_ka", + /* 112: 1 */ "more_keys_for_cyrillic_a", + /* 113: 1 */ "more_keys_for_east_slavic_row2_11", + /* 114: 1 */ "more_keys_for_currency_dollar", + /* 115: 1 */ "more_keys_for_tablet_punctuation", + /* 116: 1 */ "more_keys_for_plus", + /* 117: 1 */ "more_keys_for_less_than", + /* 118: 1 */ "more_keys_for_greater_than", + /* 119: 1 */ "keylabel_for_period", + /* 120: 1 */ "keylabel_for_tablet_period", + /* 121: 1 */ "more_keys_for_exclamation", + /* 122: 1 */ "more_keys_for_q", + /* 123: 1 */ "more_keys_for_x", + /* 124: 1 */ "keylabel_for_q", + /* 125: 1 */ "keylabel_for_w", + /* 126: 1 */ "keylabel_for_y", + /* 127: 1 */ "keylabel_for_x", + /* 128: 0 */ "more_keys_for_currency", + /* 129: 0 */ "more_keys_for_symbols_1", + /* 130: 0 */ "more_keys_for_symbols_2", + /* 131: 0 */ "more_keys_for_symbols_3", + /* 132: 0 */ "more_keys_for_symbols_4", + /* 133: 0 */ "more_keys_for_symbols_5", + /* 134: 0 */ "more_keys_for_symbols_6", + /* 135: 0 */ "more_keys_for_symbols_7", + /* 136: 0 */ "more_keys_for_symbols_8", + /* 137: 0 */ "more_keys_for_symbols_9", + /* 138: 0 */ "more_keys_for_symbols_0", + /* 139: 0 */ "more_keys_for_am_pm", + /* 140: 0 */ "settings_as_more_key", + /* 141: 0 */ "shortcut_as_more_key", + /* 142: 0 */ "action_next_as_more_key", + /* 143: 0 */ "action_previous_as_more_key", + /* 144: 0 */ "label_to_more_symbol_key", + /* 145: 0 */ "label_to_more_symbol_for_tablet_key", + /* 146: 0 */ "label_to_phone_numeric_key", + /* 147: 0 */ "label_to_phone_symbols_key", + /* 148: 0 */ "label_time_am", + /* 149: 0 */ "label_time_pm", + /* 150: 0 */ "keylabel_for_popular_domain", + /* 151: 0 */ "more_keys_for_popular_domain", + /* 152: 0 */ "keyspecs_for_left_parenthesis_more_keys", + /* 153: 0 */ "keyspecs_for_right_parenthesis_more_keys", + /* 154: 0 */ "single_laqm_raqm", + /* 155: 0 */ "single_raqm_laqm", + /* 156: 0 */ "double_laqm_raqm", + /* 157: 0 */ "double_raqm_laqm", + /* 158: 0 */ "single_lqm_rqm", + /* 159: 0 */ "single_9qm_lqm", + /* 160: 0 */ "single_9qm_rqm", + /* 161: 0 */ "single_rqm_9qm", + /* 162: 0 */ "double_lqm_rqm", + /* 163: 0 */ "double_9qm_lqm", + /* 164: 0 */ "double_9qm_rqm", + /* 165: 0 */ "double_rqm_9qm", + /* 166: 0 */ "more_keys_for_single_quote", + /* 167: 0 */ "more_keys_for_double_quote", + /* 168: 0 */ "more_keys_for_tablet_double_quote", + /* 169: 0 */ "emoji_key_as_more_key", }; private static final String EMPTY = ""; @@ -273,7 +272,7 @@ public final class KeyboardTextsTable { /* double_angle_quotes */ "!text/double_laqm_raqm", /* keylabel_for_currency */ "$", /* more_keys_for_r ~ */ - EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, + EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, /* ~ more_keys_for_cyrillic_soft_sign */ /* more_keys_for_punctuation */ "!fixedColumnOrder!8,;,/,!text/keyspec_left_parenthesis,!text/keyspec_right_parenthesis,#,!,\\,,?,&,\\%,+,\",-,:,',@", /* more_keys_for_nordic_row2_11 */ EMPTY, @@ -533,7 +532,7 @@ public final class KeyboardTextsTable { /* label_to_alpha_key */ "\u0623\u200C\u0628\u200C\u062C", /* more_keys_for_y ~ */ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, + null, null, null, null, null, null, /* ~ more_keys_for_cyrillic_soft_sign */ /* more_keys_for_punctuation */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(|),)|(", /* more_keys_for_nordic_row2_11 */ null, @@ -722,10 +721,8 @@ public final class KeyboardTextsTable { /* more_keys_for_nordic_row2_10 */ null, // U+045E: "ў" CYRILLIC SMALL LETTER SHORT U /* keylabel_for_east_slavic_row1_9 */ "\u045E", - // U+0451: "ё" CYRILLIC SMALL LETTER IO - /* keylabel_for_east_slavic_row1_12 */ "\u0451", // U+044B: "ы" CYRILLIC SMALL LETTER YERU - /* keylabel_for_east_slavic_row2_1 */ "\u044B", + /* keylabel_for_east_slavic_row2_2 */ "\u044B", // U+044D: "э" CYRILLIC SMALL LETTER E /* keylabel_for_east_slavic_row2_11 */ "\u044D", // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I @@ -813,7 +810,7 @@ public final class KeyboardTextsTable { /* more_keys_for_l */ "l\u00B7l,\u0142", /* more_keys_for_g ~ */ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, + null, /* ~ more_keys_for_cyrillic_soft_sign */ // U+00B7: "·" MIDDLE DOT /* more_keys_for_punctuation */ "!fixedColumnOrder!9,;,/,(,),#,\u00B7,!,\\,,?,&,\\%,+,\",-,:,',@", @@ -974,7 +971,7 @@ public final class KeyboardTextsTable { // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS /* more_keys_for_nordic_row2_10 */ "\u00E4", /* keylabel_for_east_slavic_row1_9 ~ */ - null, null, null, null, null, null, null, + null, null, null, null, null, null, /* ~ more_keys_for_punctuation */ // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS /* more_keys_for_nordic_row2_11 */ "\u00F6", @@ -1033,7 +1030,7 @@ public final class KeyboardTextsTable { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, /* ~ more_keys_for_cyrillic_i */ // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS /* keylabel_for_swiss_row1_11 */ "\u00FC", @@ -1227,7 +1224,7 @@ public final class KeyboardTextsTable { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, /* ~ more_keys_for_question */ // U+0125: "ĥ" LATIN SMALL LETTER H WITH CIRCUMFLEX // U+0127: "ħ" LATIN SMALL LETTER H WITH STROKE @@ -1317,7 +1314,7 @@ public final class KeyboardTextsTable { /* more_keys_for_n */ "\u00F1,\u0144", /* label_to_alpha_key ~ */ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, /* ~ more_keys_for_cyrillic_soft_sign */ // U+00A1: "¡" INVERTED EXCLAMATION MARK // U+00BF: "¿" INVERTED QUESTION MARK @@ -1445,7 +1442,7 @@ public final class KeyboardTextsTable { // U+FDFC: "﷼" RIAL SIGN /* keylabel_for_currency */ "\uFDFC", /* more_keys_for_r ~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, /* ~ more_keys_for_cyrillic_soft_sign */ // U+061F: "؟" ARABIC QUESTION MARK // U+060C: "،" ARABIC COMMA @@ -1620,7 +1617,7 @@ public final class KeyboardTextsTable { // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE /* more_keys_for_nordic_row2_10 */ "\u00F8", /* keylabel_for_east_slavic_row1_9 ~ */ - null, null, null, null, null, null, null, + null, null, null, null, null, null, /* ~ more_keys_for_punctuation */ // U+00E6: "æ" LATIN SMALL LETTER AE /* more_keys_for_nordic_row2_11 */ "\u00E6", @@ -1685,7 +1682,7 @@ public final class KeyboardTextsTable { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, /* ~ more_keys_for_cyrillic_i */ // U+00E8: "è" LATIN SMALL LETTER E WITH GRAVE /* keylabel_for_swiss_row1_11 */ "\u00E8", @@ -1717,7 +1714,7 @@ public final class KeyboardTextsTable { // U+20B9: "₹" INDIAN RUPEE SIGN /* keylabel_for_currency */ "\u20B9", /* more_keys_for_r ~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, /* ~ more_keys_for_nordic_row2_11 */ // U+0967: "१" DEVANAGARI DIGIT ONE /* keylabel_for_symbols_1 */ "\u0967", @@ -1853,7 +1850,7 @@ public final class KeyboardTextsTable { /* label_to_alpha_key */ "\u0531\u0532\u0533", /* more_keys_for_y ~ */ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, + null, null, null, null, null, null, /* ~ more_keys_for_cyrillic_soft_sign */ // U+058A: "֊" ARMENIAN HYPHEN // U+055C: "՜" ARMENIAN EXCLAMATION MARK @@ -2025,7 +2022,7 @@ public final class KeyboardTextsTable { /* more_keys_for_r ~ */ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, + null, null, null, null, null, null, /* ~ additional_more_keys_for_symbols_0 */ // U+2605: "★" BLACK STAR /* more_keys_for_star */ "\u2605", @@ -2096,10 +2093,8 @@ public final class KeyboardTextsTable { /* more_keys_for_nordic_row2_10 */ null, // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA /* keylabel_for_east_slavic_row1_9 */ "\u0449", - // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* keylabel_for_east_slavic_row1_12 */ "\u044A", // U+044B: "ы" CYRILLIC SMALL LETTER YERU - /* keylabel_for_east_slavic_row2_1 */ "\u044B", + /* keylabel_for_east_slavic_row2_2 */ "\u044B", // U+044D: "э" CYRILLIC SMALL LETTER E /* keylabel_for_east_slavic_row2_11 */ "\u044D", // U+0438: "и" CYRILLIC SMALL LETTER I @@ -2119,7 +2114,7 @@ public final class KeyboardTextsTable { // U+0493: "ғ" CYRILLIC SMALL LETTER GHE WITH STROKE /* more_keys_for_cyrillic_ghe */ "\u0493", // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I - /* more_keys_for_east_slavic_row2_1 */ "\u0456", + /* more_keys_for_east_slavic_row2_2 */ "\u0456", // U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O /* more_keys_for_cyrillic_o */ "\u04E9", /* keylabel_for_south_slavic_row1_6 ~ */ @@ -2151,7 +2146,7 @@ public final class KeyboardTextsTable { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, /* ~ more_keys_for_east_slavic_row2_11 */ // U+17DB: "៛" KHMER CURRENCY SYMBOL RIEL /* more_keys_for_currency_dollar */ "\u17DB,\u00A2,\u00A3,\u20AC,\u00A5,\u20B1", @@ -2175,10 +2170,8 @@ public final class KeyboardTextsTable { /* more_keys_for_nordic_row2_10 */ null, // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA /* keylabel_for_east_slavic_row1_9 */ "\u0449", - // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* keylabel_for_east_slavic_row1_12 */ "\u044A", // U+044B: "ы" CYRILLIC SMALL LETTER YERU - /* keylabel_for_east_slavic_row2_1 */ "\u044B", + /* keylabel_for_east_slavic_row2_2 */ "\u044B", // U+044D: "э" CYRILLIC SMALL LETTER E /* keylabel_for_east_slavic_row2_11 */ "\u044D", // U+0438: "и" CYRILLIC SMALL LETTER I @@ -2195,7 +2188,7 @@ public final class KeyboardTextsTable { // U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER /* more_keys_for_cyrillic_en */ "\u04A3", /* more_keys_for_cyrillic_ghe */ null, - /* more_keys_for_east_slavic_row2_1 */ null, + /* more_keys_for_east_slavic_row2_2 */ null, // U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O /* more_keys_for_cyrillic_o */ "\u04E9", }; @@ -2432,7 +2425,7 @@ public final class KeyboardTextsTable { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, /* ~ more_keys_for_cyrillic_o */ // U+0455: "ѕ" CYRILLIC SMALL LETTER DZE /* keylabel_for_south_slavic_row1_6 */ "\u0455", @@ -2510,7 +2503,7 @@ public final class KeyboardTextsTable { // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS /* more_keys_for_nordic_row2_10 */ "\u00F6", /* keylabel_for_east_slavic_row1_9 ~ */ - null, null, null, null, null, null, null, + null, null, null, null, null, null, /* ~ more_keys_for_punctuation */ // U+00E4: "ä" LATIN SMALL LETTER A WITH DIAERESIS /* more_keys_for_nordic_row2_11 */ "\u00E4", @@ -2532,7 +2525,7 @@ public final class KeyboardTextsTable { // U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN /* keylabel_for_currency */ "\u0930\u0941.", /* more_keys_for_r ~ */ - null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, /* ~ more_keys_for_nordic_row2_11 */ // U+0967: "१" DEVANAGARI DIGIT ONE /* keylabel_for_symbols_1 */ "\u0967", @@ -2804,10 +2797,8 @@ public final class KeyboardTextsTable { /* more_keys_for_nordic_row2_10 */ null, // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA /* keylabel_for_east_slavic_row1_9 */ "\u0449", - // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN - /* keylabel_for_east_slavic_row1_12 */ "\u044A", // U+044B: "ы" CYRILLIC SMALL LETTER YERU - /* keylabel_for_east_slavic_row2_1 */ "\u044B", + /* keylabel_for_east_slavic_row2_2 */ "\u044B", // U+044D: "э" CYRILLIC SMALL LETTER E /* keylabel_for_east_slavic_row2_11 */ "\u044D", // U+0438: "и" CYRILLIC SMALL LETTER I @@ -2968,7 +2959,7 @@ public final class KeyboardTextsTable { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, /* ~ more_keys_for_cyrillic_o */ // TODO: Move these to sr-Latn once we can handle IETF language tag with script name specified. // BEGIN: More keys definitions for Serbian (Latin) @@ -3081,7 +3072,7 @@ public final class KeyboardTextsTable { // U+0153: "œ" LATIN SMALL LIGATURE OE /* more_keys_for_nordic_row2_10 */ "\u00F8,\u0153", /* keylabel_for_east_slavic_row1_9 ~ */ - null, null, null, null, null, null, null, + null, null, null, null, null, null, /* ~ more_keys_for_punctuation */ // U+00E6: "æ" LATIN SMALL LETTER AE /* more_keys_for_nordic_row2_11 */ "\u00E6", @@ -3284,10 +3275,8 @@ public final class KeyboardTextsTable { /* ~ more_keys_for_nordic_row2_10 */ // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA /* keylabel_for_east_slavic_row1_9 */ "\u0449", - // U+0457: "ї" CYRILLIC SMALL LETTER YI - /* keylabel_for_east_slavic_row1_12 */ "\u0457", // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I - /* keylabel_for_east_slavic_row2_1 */ "\u0456", + /* keylabel_for_east_slavic_row2_2 */ "\u0456", // U+0454: "є" CYRILLIC SMALL LETTER UKRAINIAN IE /* keylabel_for_east_slavic_row2_11 */ "\u0454", // U+0438: "и" CYRILLIC SMALL LETTER I @@ -3303,7 +3292,7 @@ public final class KeyboardTextsTable { // U+0491: "ґ" CYRILLIC SMALL LETTER GHE WITH UPTURN /* more_keys_for_cyrillic_ghe */ "\u0491", // U+0457: "ї" CYRILLIC SMALL LETTER YI - /* more_keys_for_east_slavic_row2_1 */ "\u0457", + /* more_keys_for_east_slavic_row2_2 */ "\u0457", }; /* Language vi: Vietnamese */ @@ -3565,7 +3554,7 @@ public final class KeyboardTextsTable { null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, /* ~ more_keys_for_question */ // U+0125: "ĥ" LATIN SMALL LETTER H WITH CIRCUMFLEX /* more_keys_for_h */ "\u0125", @@ -3584,60 +3573,60 @@ public final class KeyboardTextsTable { // Currently we are dropping the region from the key. private static final Object[] LANGUAGES_AND_TEXTS = { // "locale", TEXT_ARRAY, /* numberOfNonNullText/lengthOf_TEXT_ARRAY localeName */ - "DEFAULT", LANGUAGE_DEFAULT, /* 171/171 default */ + "DEFAULT", LANGUAGE_DEFAULT, /* 170/170 default */ "af", LANGUAGE_af, /* 7/ 12 Afrikaans */ - "ar", LANGUAGE_ar, /* 58/110 Arabic */ + "ar", LANGUAGE_ar, /* 58/109 Arabic */ "az", LANGUAGE_az_AZ, /* 8/ 17 Azerbaijani (Azerbaijan) */ - "be", LANGUAGE_be_BY, /* 10/ 33 Belarusian (Belarus) */ + "be", LANGUAGE_be_BY, /* 9/ 32 Belarusian (Belarus) */ "bg", LANGUAGE_bg, /* 2/ 11 Bulgarian */ - "ca", LANGUAGE_ca, /* 11/117 Catalan */ + "ca", LANGUAGE_ca, /* 11/116 Catalan */ "cs", LANGUAGE_cs, /* 17/ 21 Czech */ - "da", LANGUAGE_da, /* 19/ 35 Danish */ - "de", LANGUAGE_de, /* 16/ 93 German */ + "da", LANGUAGE_da, /* 19/ 34 Danish */ + "de", LANGUAGE_de, /* 16/ 92 German */ "el", LANGUAGE_el, /* 1/ 11 Greek */ "en", LANGUAGE_en, /* 8/ 10 English */ - "eo", LANGUAGE_eo, /* 26/129 Esperanto */ - "es", LANGUAGE_es, /* 8/ 34 Spanish */ + "eo", LANGUAGE_eo, /* 26/128 Esperanto */ + "es", LANGUAGE_es, /* 8/ 33 Spanish */ "et", LANGUAGE_et_EE, /* 22/ 27 Estonian (Estonia) */ - "fa", LANGUAGE_fa, /* 61/120 Persian */ - "fi", LANGUAGE_fi, /* 10/ 35 Finnish */ - "fr", LANGUAGE_fr, /* 13/ 93 French */ - "hi", LANGUAGE_hi, /* 24/ 57 Hindi */ + "fa", LANGUAGE_fa, /* 61/119 Persian */ + "fi", LANGUAGE_fi, /* 10/ 34 Finnish */ + "fr", LANGUAGE_fr, /* 13/ 92 French */ + "hi", LANGUAGE_hi, /* 24/ 56 Hindi */ "hr", LANGUAGE_hr, /* 9/ 19 Croatian */ "hu", LANGUAGE_hu, /* 9/ 19 Hungarian */ - "hy", LANGUAGE_hy_AM, /* 8/123 Armenian (Armenia) */ + "hy", LANGUAGE_hy_AM, /* 8/122 Armenian (Armenia) */ "is", LANGUAGE_is, /* 13/ 25 Icelandic */ "it", LANGUAGE_it, /* 5/ 5 Italian */ - "iw", LANGUAGE_iw, /* 20/118 Hebrew */ + "iw", LANGUAGE_iw, /* 20/117 Hebrew */ "ka", LANGUAGE_ka_GE, /* 3/ 11 Georgian (Georgia) */ - "kk", LANGUAGE_kk, /* 16/115 Kazakh */ - "km", LANGUAGE_km_KH, /* 2/116 Khmer (Cambodia) */ - "ky", LANGUAGE_ky, /* 11/ 82 Kirghiz */ + "kk", LANGUAGE_kk, /* 15/114 Kazakh */ + "km", LANGUAGE_km_KH, /* 2/115 Khmer (Cambodia) */ + "ky", LANGUAGE_ky, /* 10/ 81 Kirghiz */ "lo", LANGUAGE_lo_LA, /* 2/ 20 Lao (Laos) */ "lt", LANGUAGE_lt, /* 18/ 22 Lithuanian */ "lv", LANGUAGE_lv, /* 18/ 22 Latvian */ - "mk", LANGUAGE_mk, /* 9/ 87 Macedonian */ + "mk", LANGUAGE_mk, /* 9/ 86 Macedonian */ "mn", LANGUAGE_mn_MN, /* 2/ 20 Mongolian (Mongolia) */ - "nb", LANGUAGE_nb, /* 11/ 35 Norwegian Bokmål */ - "ne", LANGUAGE_ne_NP, /* 24/ 57 Nepali (Nepal) */ + "nb", LANGUAGE_nb, /* 11/ 34 Norwegian Bokmål */ + "ne", LANGUAGE_ne_NP, /* 24/ 56 Nepali (Nepal) */ "nl", LANGUAGE_nl, /* 9/ 12 Dutch */ "pl", LANGUAGE_pl, /* 10/ 16 Polish */ "pt", LANGUAGE_pt, /* 6/ 8 Portuguese */ "rm", LANGUAGE_rm, /* 1/ 2 Raeto-Romance */ "ro", LANGUAGE_ro, /* 6/ 15 Romanian */ - "ru", LANGUAGE_ru, /* 10/ 33 Russian */ + "ru", LANGUAGE_ru, /* 9/ 32 Russian */ "sk", LANGUAGE_sk, /* 20/ 22 Slovak */ "sl", LANGUAGE_sl, /* 8/ 19 Slovenian */ - "sr", LANGUAGE_sr, /* 11/ 87 Serbian */ - "sv", LANGUAGE_sv, /* 21/ 35 Swedish */ + "sr", LANGUAGE_sr, /* 11/ 86 Serbian */ + "sv", LANGUAGE_sv, /* 21/ 34 Swedish */ "sw", LANGUAGE_sw, /* 9/ 17 Swahili */ "th", LANGUAGE_th, /* 2/ 20 Thai */ "tl", LANGUAGE_tl, /* 7/ 10 Tagalog */ "tr", LANGUAGE_tr, /* 7/ 17 Turkish */ - "uk", LANGUAGE_uk, /* 12/ 81 Ukrainian */ + "uk", LANGUAGE_uk, /* 11/ 80 Ukrainian */ "vi", LANGUAGE_vi, /* 8/ 20 Vietnamese */ "zu", LANGUAGE_zu, /* 8/ 10 Zulu */ - "zz", LANGUAGE_zz, /* 19/112 Alphabet */ + "zz", LANGUAGE_zz, /* 19/111 Alphabet */ }; static { diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 851ecc042..a3a329a71 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -40,7 +40,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Locale; -import java.util.Map; /** * Implements a static, compacted, binary dictionary of standard words. @@ -142,8 +141,6 @@ public final class BinaryDictionary extends Dictionary { JniUtils.loadNativeLibrary(); } - private static native boolean createEmptyDictFileNative(String filePath, long dictVersion, - String locale, String[] attributeKeyStringArray, String[] attributeValueStringArray); private static native long openNative(String sourceDir, long dictOffset, long dictSize, boolean isUpdatable); private static native void getHeaderInfoNative(long dict, int[] outHeaderSize, @@ -167,8 +164,6 @@ public final class BinaryDictionary extends Dictionary { int[] suggestOptions, int[] prevWordCodePointArray, int[] outputCodePoints, int[] outputScores, int[] outputIndices, int[] outputTypes, int[] outputAutoCommitFirstWordConfidence); - private static native float calcNormalizedScoreNative(int[] before, int[] after, int score); - private static native int editDistanceNative(int[] before, int[] after); private static native void addUnigramWordNative(long dict, int[] word, int probability, int[] shortcutTarget, int shortcutProbability, boolean isNotAWord, boolean isBlacklisted, int timestamp); @@ -179,24 +174,9 @@ public final class BinaryDictionary extends Dictionary { LanguageModelParam[] languageModelParams, int startIndex); private static native int calculateProbabilityNative(long dict, int unigramProbability, int bigramProbability); - private static native int setCurrentTimeForTestNative(int currentTime); private static native String getPropertyNative(long dict, String query); private static native boolean isCorruptedNative(long dict); - public static boolean createEmptyDictFile(final String filePath, final long dictVersion, - final Locale locale, final Map<String, String> attributeMap) { - final String[] keyArray = new String[attributeMap.size()]; - final String[] valueArray = new String[attributeMap.size()]; - int index = 0; - for (final String key : attributeMap.keySet()) { - keyArray[index] = key; - valueArray[index] = attributeMap.get(key); - index++; - } - return createEmptyDictFileNative(filePath, dictVersion, locale.toString(), keyArray, - valueArray); - } - // TODO: Move native dict into session private final void loadDictionary(final String path, final long startOffset, final long length, final boolean isUpdatable) { @@ -219,7 +199,6 @@ public final class BinaryDictionary extends Dictionary { return true; } - @UsedForTesting public DictionaryHeader getHeader() throws UnsupportedFormatException { if (mNativeDict == 0) { return null; @@ -323,20 +302,6 @@ public final class BinaryDictionary extends Dictionary { return getFormatVersionNative(mNativeDict); } - public static float calcNormalizedScore(final String before, final String after, - final int score) { - return calcNormalizedScoreNative(StringUtils.toCodePointArray(before), - StringUtils.toCodePointArray(after), score); - } - - public static int editDistance(final String before, final String after) { - if (before == null || after == null) { - throw new IllegalArgumentException(); - } - return editDistanceNative(StringUtils.toCodePointArray(before), - StringUtils.toCodePointArray(after)); - } - @Override public boolean isValidWord(final String word) { return getFrequency(word) != NOT_A_PROBABILITY; @@ -497,22 +462,6 @@ public final class BinaryDictionary extends Dictionary { return calculateProbabilityNative(mNativeDict, unigramProbability, bigramProbability); } - /** - * Control the current time to be used in the native code. If currentTime >= 0, this method sets - * the current time and gets into test mode. - * In test mode, set timestamp is used as the current time in the native code. - * If currentTime < 0, quit the test mode and returns to using time() to get the current time. - * - * @param currentTime seconds since the unix epoch - * @return current time got in the native code. - */ - @UsedForTesting - public static int setCurrentTimeForTest(final int currentTime) { - final int currentNativeTimestamp = setCurrentTimeForTestNative(currentTime); - PersonalizationHelper.currentTimeChangedForTesting(currentNativeTimestamp); - return currentNativeTimestamp; - } - @UsedForTesting public String getPropertyForTest(final String query) { if (!isValidDictionary()) return ""; diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java index acbd919cd..4c49cb31c 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java @@ -21,10 +21,9 @@ import android.content.SharedPreferences; import android.content.res.AssetFileDescriptor; import android.util.Log; -import com.android.inputmethod.latin.makedict.DictDecoder; import com.android.inputmethod.latin.makedict.DictionaryHeader; -import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.DictionaryInfoUtils; import com.android.inputmethod.latin.utils.LocaleUtils; @@ -226,12 +225,10 @@ final public class BinaryDictionaryGetter { // ## HACK ## we prevent usage of a dictionary before version 18. The reason for this is, since // those do not include whitelist entries, the new code with an old version of the dictionary // would lose whitelist functionality. - private static boolean hackCanUseDictionaryFile(final Locale locale, final File f) { + private static boolean hackCanUseDictionaryFile(final Locale locale, final File file) { try { // Read the version of the file - final DictDecoder dictDecoder = FormatSpec.getDictDecoder(f, 0, f.length()); - final DictionaryHeader header = dictDecoder.readHeader(); - + final DictionaryHeader header = BinaryDictionaryUtils.getHeader(file); final String version = header.mDictionaryOptions.mAttributes.get(VERSION_KEY); if (null == version) { // No version in the options : the format is unexpected diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java index d1ff714fc..e71723a15 100644 --- a/java/src/com/android/inputmethod/latin/Constants.java +++ b/java/src/com/android/inputmethod/latin/Constants.java @@ -144,6 +144,7 @@ public final class Constants { public static final int NOT_A_CODE = -1; public static final int NOT_A_CURSOR_POSITION = -1; + // TODO: replace the following constants with state in InputTransaction? public static final int NOT_A_COORDINATE = -1; public static final int SUGGESTION_STRIP_COORDINATE = -2; public static final int SPELL_CHECKER_COORDINATE = -3; diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 26545acbd..7847738e0 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -27,6 +27,7 @@ import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.makedict.WordProperty; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.utils.AsyncResultHolder; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.CombinedFormatUtils; import com.android.inputmethod.latin.utils.ExecutorUtils; @@ -228,7 +229,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { } private void createBinaryDictionaryLocked() { - BinaryDictionary.createEmptyDictFile(mDictFile.getAbsolutePath(), + BinaryDictionaryUtils.createEmptyDictFile(mDictFile.getAbsolutePath(), DICTIONARY_FORMAT_VERSION, mLocale, getHeaderAttributeMap()); } diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 1747eeeda..ba64028ca 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -22,6 +22,7 @@ import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.latin.utils.AutoCorrectionUtils; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.BoundedTreeSet; import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.StringUtils; @@ -309,7 +310,7 @@ public final class Suggest { // than i because we added the typed word to mSuggestions without touching mScores. for (int i = 0; i < suggestionsSize - 1; ++i) { final SuggestedWordInfo cur = suggestions.get(i + 1); - final float normalizedScore = BinaryDictionary.calcNormalizedScore( + final float normalizedScore = BinaryDictionaryUtils.calcNormalizedScore( typedWord, cur.toString(), cur.mScore); final String scoreInfoString; if (normalizedScore > 0) { diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index f7cf8dea1..df0068266 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -23,12 +23,12 @@ import android.text.style.SuggestionSpan; import android.util.Log; import android.view.KeyCharacterMap; import android.view.KeyEvent; -import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.CorrectionInfo; import android.view.inputmethod.EditorInfo; import com.android.inputmethod.compat.SuggestionSpanUtils; import com.android.inputmethod.event.EventInterpreter; +import com.android.inputmethod.event.InputTransaction; import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.Dictionary; @@ -361,40 +361,37 @@ public final class InputLogic { final SettingsValues settingsValues, // TODO: remove these two arguments final LatinIME.UIHandler handler, final KeyboardSwitcher keyboardSwitcher) { + final InputTransaction inputTransaction = new InputTransaction(settingsValues, code, x, y, + SystemClock.uptimeMillis(), mSpaceState, + getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode())); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_onCodeInput(code, x, y); + ResearchLogger.latinIME_onCodeInput(inputTransaction.mKeyCode, + inputTransaction.mX, inputTransaction.mY); } - final long when = SystemClock.uptimeMillis(); - if (code != Constants.CODE_DELETE - || when > mLastKeyTime + Constants.LONG_PRESS_MILLISECONDS) { + if (inputTransaction.mKeyCode != Constants.CODE_DELETE + || inputTransaction.mTimestamp > mLastKeyTime + Constants.LONG_PRESS_MILLISECONDS) { mDeleteCount = 0; } - mLastKeyTime = when; + mLastKeyTime = inputTransaction.mTimestamp; mConnection.beginBatchEdit(); - // The space state depends only on the last character pressed and its own previous - // state. Here, we revert the space state to neutral if the key is actually modifying - // the input contents (any non-shift key), which is what we should do for - // all inputs that do not result in a special state. Each character handling is then - // free to override the state as they see fit. - final int spaceState = mSpaceState; if (!mWordComposer.isComposingWord()) { mIsAutoCorrectionIndicatorOn = false; } // TODO: Consolidate the double-space period timer, mLastKeyTime, and the space state. - if (code != Constants.CODE_SPACE) { + if (inputTransaction.mKeyCode != Constants.CODE_SPACE) { handler.cancelDoubleSpacePeriodTimer(); } boolean didAutoCorrect = false; - switch (code) { + switch (inputTransaction.mKeyCode) { case Constants.CODE_DELETE: - handleBackspace(settingsValues, spaceState, handler, keyboardSwitcher); - LatinImeLogger.logOnDelete(x, y); + handleBackspace(inputTransaction, handler); + LatinImeLogger.logOnDelete(inputTransaction.mX, inputTransaction.mY); break; case Constants.CODE_SHIFT: - performRecapitalization(settingsValues); - keyboardSwitcher.updateShiftState(); + performRecapitalization(inputTransaction.mSettingsValues); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); break; case Constants.CODE_CAPSLOCK: // Note: Changing keyboard to shift lock state is handled in @@ -448,32 +445,43 @@ public final class InputLogic { } else { // No action label, and the action from imeOptions is NONE: this is a regular // enter key that should input a carriage return. - didAutoCorrect = handleNonSpecialCharacter(settingsValues, Constants.CODE_ENTER, - x, y, spaceState, keyboardSwitcher, handler); + didAutoCorrect = handleNonSpecialCharacter(inputTransaction, handler); } break; case Constants.CODE_SHIFT_ENTER: - didAutoCorrect = handleNonSpecialCharacter(settingsValues, Constants.CODE_ENTER, - x, y, spaceState, keyboardSwitcher, handler); + // TODO: remove this object + final InputTransaction tmpTransaction = new InputTransaction( + inputTransaction.mSettingsValues, inputTransaction.mKeyCode, + inputTransaction.mX, inputTransaction.mY, inputTransaction.mTimestamp, + inputTransaction.mSpaceState, inputTransaction.mShiftState); + didAutoCorrect = handleNonSpecialCharacter(tmpTransaction, handler); break; case Constants.CODE_ALPHA_FROM_EMOJI: // Note: Switching back from Emoji keyboard to the main keyboard is being handled in // {@link KeyboardState#onCodeInput(int,int)}. break; default: - didAutoCorrect = handleNonSpecialCharacter(settingsValues, - code, x, y, spaceState, keyboardSwitcher, handler); + didAutoCorrect = handleNonSpecialCharacter(inputTransaction, handler); break; } // Reset after any single keystroke, except shift, capslock, and symbol-shift - if (!didAutoCorrect && code != Constants.CODE_SHIFT - && code != Constants.CODE_CAPSLOCK - && code != Constants.CODE_SWITCH_ALPHA_SYMBOL) + if (!didAutoCorrect && inputTransaction.mKeyCode != Constants.CODE_SHIFT + && inputTransaction.mKeyCode != Constants.CODE_CAPSLOCK + && inputTransaction.mKeyCode != Constants.CODE_SWITCH_ALPHA_SYMBOL) mLastComposedWord.deactivate(); - if (Constants.CODE_DELETE != code) { + if (Constants.CODE_DELETE != inputTransaction.mKeyCode) { mEnteredText = null; } mConnection.endBatchEdit(); + switch (inputTransaction.getRequiredShiftUpdate()) { + case InputTransaction.SHIFT_UPDATE_LATER: + mLatinIME.mHandler.postUpdateShiftState(); + break; + case InputTransaction.SHIFT_UPDATE_NOW: + keyboardSwitcher.updateShiftState(); + break; + default: // SHIFT_NO_UPDATE + } } public void onStartBatchInput(final SettingsValues settingsValues, @@ -617,31 +625,26 @@ public final class InputLogic { * manage keyboard-related stuff like shift, language switch, settings, layout switch, or * any key that results in multiple code points like the ".com" key. * - * @param settingsValues The current settings values. - * @param codePoint the code point associated with the key. - * @param x the x-coordinate of the key press, or Contants.NOT_A_COORDINATE if not applicable. - * @param y the y-coordinate of the key press, or Contants.NOT_A_COORDINATE if not applicable. - * @param spaceState the space state at start of the batch input. + * @param inputTransaction The transaction in progress. * @return whether this caused an auto-correction to happen. */ - private boolean handleNonSpecialCharacter(final SettingsValues settingsValues, - final int codePoint, final int x, final int y, final int spaceState, - // TODO: remove these arguments - final KeyboardSwitcher keyboardSwitcher, final LatinIME.UIHandler handler) { + private boolean handleNonSpecialCharacter(final InputTransaction inputTransaction, + // TODO: remove this argument + final LatinIME.UIHandler handler) { mSpaceState = SpaceState.NONE; final boolean didAutoCorrect; - if (settingsValues.isWordSeparator(codePoint) - || Character.getType(codePoint) == Character.OTHER_SYMBOL) { - didAutoCorrect = handleSeparator(settingsValues, codePoint, - Constants.SUGGESTION_STRIP_COORDINATE == x, spaceState, keyboardSwitcher, - handler); - if (settingsValues.mIsInternal) { - LatinImeLoggerUtils.onSeparator((char)codePoint, x, y); + if (inputTransaction.mSettingsValues.isWordSeparator(inputTransaction.mKeyCode) + || Character.getType(inputTransaction.mKeyCode) == Character.OTHER_SYMBOL) { + didAutoCorrect = handleSeparator(inputTransaction, + Constants.SUGGESTION_STRIP_COORDINATE == inputTransaction.mX, handler); + if (inputTransaction.mSettingsValues.mIsInternal) { + LatinImeLoggerUtils.onSeparator((char)inputTransaction.mKeyCode, + inputTransaction.mX, inputTransaction.mY); } } else { didAutoCorrect = false; - if (SpaceState.PHANTOM == spaceState) { - if (settingsValues.mIsInternal) { + if (SpaceState.PHANTOM == inputTransaction.mSpaceState) { + if (inputTransaction.mSettingsValues.mIsInternal) { if (mWordComposer.isComposingWord() && mWordComposer.isBatchMode()) { LatinImeLoggerUtils.onAutoCorrection("", mWordComposer.getTypedWord(), " ", mWordComposer); @@ -653,11 +656,10 @@ public final class InputLogic { resetEntireInputState(mConnection.getExpectedSelectionStart(), mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); } else { - commitTyped(settingsValues, LastComposedWord.NOT_A_SEPARATOR); + commitTyped(inputTransaction.mSettingsValues, LastComposedWord.NOT_A_SEPARATOR); } } - handleNonSeparator(settingsValues, codePoint, x, y, spaceState, - keyboardSwitcher, handler); + handleNonSeparator(inputTransaction.mSettingsValues, inputTransaction, handler); } return didAutoCorrect; } @@ -665,15 +667,12 @@ public final class InputLogic { /** * Handle a non-separator. * @param settingsValues The current settings values. - * @param codePoint the code point associated with the key. - * @param x the x-coordinate of the key press, or Contants.NOT_A_COORDINATE if not applicable. - * @param y the y-coordinate of the key press, or Contants.NOT_A_COORDINATE if not applicable. - * @param spaceState the space state at start of the batch input. + * @param inputTransaction The transaction in progress. */ private void handleNonSeparator(final SettingsValues settingsValues, - final int codePoint, final int x, final int y, final int spaceState, - // TODO: Remove these arguments - final KeyboardSwitcher keyboardSwitcher, final LatinIME.UIHandler handler) { + final InputTransaction inputTransaction, + // TODO: Remove this argument + final LatinIME.UIHandler handler) { // TODO: refactor this method to stop flipping isComposingWord around all the time, and // make it shorter (possibly cut into several pieces). Also factor handleNonSpecialCharacter // which has the same name as other handle* methods but is not the same. @@ -681,7 +680,8 @@ public final class InputLogic { // TODO: remove isWordConnector() and use isUsuallyFollowedBySpace() instead. // See onStartBatchInput() to see how to do it. - if (SpaceState.PHANTOM == spaceState && !settingsValues.isWordConnector(codePoint)) { + if (SpaceState.PHANTOM == inputTransaction.mSpaceState + && !settingsValues.isWordConnector(inputTransaction.mKeyCode)) { if (isComposingWord) { // Sanity check throw new RuntimeException("Should not be composing here"); @@ -703,7 +703,7 @@ public final class InputLogic { if (!isComposingWord // We only start composing if this is a word code point. Essentially that means it's a // a letter or a word connector. - && settingsValues.isWordCodePoint(codePoint) + && settingsValues.isWordCodePoint(inputTransaction.mKeyCode) // We never go into composing state if suggestions are not requested. && settingsValues.isSuggestionsRequested() && // In languages with spaces, we only start composing a word when we are not already @@ -714,8 +714,8 @@ public final class InputLogic { // the character is a single quote or a dash. The idea here is, single quote and dash // are not separators and they should be treated as normal characters, except in the // first position where they should not start composing a word. - isComposingWord = (Constants.CODE_SINGLE_QUOTE != codePoint - && Constants.CODE_DASH != codePoint); + isComposingWord = (Constants.CODE_SINGLE_QUOTE != inputTransaction.mKeyCode + && Constants.CODE_DASH != inputTransaction.mKeyCode); // Here we don't need to reset the last composed word. It will be reset // when we commit this one, if we ever do; if on the other hand we backspace // it entirely and resume suggestions on the previous word, we'd like to still @@ -723,26 +723,25 @@ public final class InputLogic { resetComposingState(false /* alsoResetLastComposedWord */); } if (isComposingWord) { - mWordComposer.add(codePoint, x, y); + mWordComposer.add(inputTransaction.mKeyCode, inputTransaction.mX, inputTransaction.mY); // If it's the first letter, make note of auto-caps state if (mWordComposer.size() == 1) { // We pass 1 to getPreviousWordForSuggestion because we were not composing a word // yet, so the word we want is the 1st word before the cursor. mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( - getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode()), - getNthPreviousWordForSuggestion( + inputTransaction.mShiftState, getNthPreviousWordForSuggestion( settingsValues.mSpacingAndPunctuations, 1 /* nthPreviousWord */)); } mConnection.setComposingText(getTextWithUnderline( mWordComposer.getTypedWord()), 1); } else { - final boolean swapWeakSpace = maybeStripSpace(settingsValues, - codePoint, spaceState, Constants.SUGGESTION_STRIP_COORDINATE == x); + final boolean swapWeakSpace = maybeStripSpace(inputTransaction, + Constants.SUGGESTION_STRIP_COORDINATE == inputTransaction.mX); - sendKeyCodePoint(settingsValues, codePoint); + sendKeyCodePoint(settingsValues, inputTransaction.mKeyCode); if (swapWeakSpace) { - swapSwapperAndSpace(keyboardSwitcher); + swapSwapperAndSpace(inputTransaction); mSpaceState = SpaceState.WEAK; } // In case the "add to dictionary" hint was still displayed. @@ -750,26 +749,26 @@ public final class InputLogic { } handler.postUpdateSuggestionStrip(); if (settingsValues.mIsInternal) { - LatinImeLoggerUtils.onNonSeparator((char)codePoint, x, y); + LatinImeLoggerUtils.onNonSeparator((char)inputTransaction.mKeyCode, inputTransaction.mX, + inputTransaction.mY); } } /** * Handle input of a separator code point. - * @param settingsValues The current settings values. - * @param codePoint the code point associated with the key. + * @param inputTransaction The transaction in progress. * @param isFromSuggestionStrip whether this code point comes from the suggestion strip. - * @param spaceState the space state at start of the batch input. * @return whether this caused an auto-correction to happen. */ - private boolean handleSeparator(final SettingsValues settingsValues, - final int codePoint, final boolean isFromSuggestionStrip, final int spaceState, - // TODO: remove these arguments - final KeyboardSwitcher keyboardSwitcher, final LatinIME.UIHandler handler) { + private boolean handleSeparator(final InputTransaction inputTransaction, + final boolean isFromSuggestionStrip, + // TODO: remove this argument + final LatinIME.UIHandler handler) { boolean didAutoCorrect = false; // We avoid sending spaces in languages without spaces if we were composing. - final boolean shouldAvoidSendingCode = Constants.CODE_SPACE == codePoint - && !settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces + final boolean shouldAvoidSendingCode = Constants.CODE_SPACE == inputTransaction.mKeyCode + && !inputTransaction.mSettingsValues.mSpacingAndPunctuations + .mCurrentLanguageHasSpaces && mWordComposer.isComposingWord(); if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection @@ -779,48 +778,51 @@ public final class InputLogic { } // isComposingWord() may have changed since we stored wasComposing if (mWordComposer.isComposingWord()) { - if (settingsValues.mCorrectionEnabled) { + if (inputTransaction.mSettingsValues.mCorrectionEnabled) { final String separator = shouldAvoidSendingCode ? LastComposedWord.NOT_A_SEPARATOR - : StringUtils.newSingleCodePointString(codePoint); - commitCurrentAutoCorrection(settingsValues, separator, handler); + : StringUtils.newSingleCodePointString(inputTransaction.mKeyCode); + commitCurrentAutoCorrection(inputTransaction.mSettingsValues, separator, handler); didAutoCorrect = true; } else { - commitTyped(settingsValues, StringUtils.newSingleCodePointString(codePoint)); + commitTyped(inputTransaction.mSettingsValues, + StringUtils.newSingleCodePointString(inputTransaction.mKeyCode)); } } - final boolean swapWeakSpace = maybeStripSpace(settingsValues, codePoint, spaceState, - isFromSuggestionStrip); + final boolean swapWeakSpace = maybeStripSpace(inputTransaction, isFromSuggestionStrip); - final boolean isInsideDoubleQuoteOrAfterDigit = Constants.CODE_DOUBLE_QUOTE == codePoint + final boolean isInsideDoubleQuoteOrAfterDigit = + Constants.CODE_DOUBLE_QUOTE == inputTransaction.mKeyCode && mConnection.isInsideDoubleQuoteOrAfterDigit(); final boolean needsPrecedingSpace; - if (SpaceState.PHANTOM != spaceState) { + if (SpaceState.PHANTOM != inputTransaction.mSpaceState) { needsPrecedingSpace = false; - } else if (Constants.CODE_DOUBLE_QUOTE == codePoint) { + } else if (Constants.CODE_DOUBLE_QUOTE == inputTransaction.mKeyCode) { // Double quotes behave like they are usually preceded by space iff we are // not inside a double quote or after a digit. needsPrecedingSpace = !isInsideDoubleQuoteOrAfterDigit; } else { - needsPrecedingSpace = settingsValues.isUsuallyPrecededBySpace(codePoint); + needsPrecedingSpace = inputTransaction.mSettingsValues.isUsuallyPrecededBySpace( + inputTransaction.mKeyCode); } if (needsPrecedingSpace) { - promotePhantomSpace(settingsValues); + promotePhantomSpace(inputTransaction.mSettingsValues); } if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_handleSeparator(codePoint, mWordComposer.isComposingWord()); + ResearchLogger.latinIME_handleSeparator(inputTransaction.mKeyCode, + mWordComposer.isComposingWord()); } if (!shouldAvoidSendingCode) { - sendKeyCodePoint(settingsValues, codePoint); + sendKeyCodePoint(inputTransaction.mSettingsValues, inputTransaction.mKeyCode); } - if (Constants.CODE_SPACE == codePoint) { - if (settingsValues.isSuggestionsRequested()) { - if (maybeDoubleSpacePeriod(settingsValues, handler)) { - keyboardSwitcher.updateShiftState(); + if (Constants.CODE_SPACE == inputTransaction.mKeyCode) { + if (inputTransaction.mSettingsValues.isSuggestionsRequested()) { + if (maybeDoubleSpacePeriod(inputTransaction.mSettingsValues, handler)) { + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); mSpaceState = SpaceState.DOUBLE; } else if (!mSuggestedWords.isPunctuationSuggestions()) { mSpaceState = SpaceState.WEAK; @@ -831,11 +833,12 @@ public final class InputLogic { handler.postUpdateSuggestionStrip(); } else { if (swapWeakSpace) { - swapSwapperAndSpace(keyboardSwitcher); + swapSwapperAndSpace(inputTransaction); mSpaceState = SpaceState.SWAP_PUNCTUATION; - } else if ((SpaceState.PHANTOM == spaceState - && settingsValues.isUsuallyFollowedBySpace(codePoint)) - || (Constants.CODE_DOUBLE_QUOTE == codePoint + } else if ((SpaceState.PHANTOM == inputTransaction.mSpaceState + && inputTransaction.mSettingsValues.isUsuallyFollowedBySpace( + inputTransaction.mKeyCode)) + || (Constants.CODE_DOUBLE_QUOTE == inputTransaction.mKeyCode && isInsideDoubleQuoteOrAfterDigit)) { // If we are in phantom space state, and the user presses a separator, we want to // stay in phantom space state so that the next keypress has a chance to add the @@ -856,25 +859,24 @@ public final class InputLogic { mSuggestionStripViewAccessor.setNeutralSuggestionStrip(); } - keyboardSwitcher.updateShiftState(); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); return didAutoCorrect; } /** * Handle a press on the backspace key. - * @param settingsValues The current settings values. - * @param spaceState The space state at start of this batch edit. + * @param inputTransaction The transaction in progress. */ - private void handleBackspace(final SettingsValues settingsValues, final int spaceState, - // TODO: remove these arguments - final LatinIME.UIHandler handler, final KeyboardSwitcher keyboardSwitcher) { + private void handleBackspace(final InputTransaction inputTransaction, + // TODO: remove this argument + final LatinIME.UIHandler handler) { mSpaceState = SpaceState.NONE; mDeleteCount++; // In many cases, we may have to put the keyboard in auto-shift state again. However // we want to wait a few milliseconds before doing it to avoid the keyboard flashing // during key repeat. - handler.postUpdateShiftState(); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_LATER); if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection @@ -900,14 +902,14 @@ public final class InputLogic { if (!mWordComposer.isComposingWord()) { // If we just removed the last character, auto-caps mode may have changed so we // need to re-evaluate. - keyboardSwitcher.updateShiftState(); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); } } else { if (mLastComposedWord.canRevertCommit()) { - if (settingsValues.mIsInternal) { + if (inputTransaction.mSettingsValues.mIsInternal) { LatinImeLoggerUtils.onAutoCorrectionCancellation(); } - revertCommit(settingsValues, handler); + revertCommit(inputTransaction.mSettingsValues, handler); return; } if (mEnteredText != null && mConnection.sameAsTextBeforeCursor(mEnteredText)) { @@ -924,14 +926,14 @@ public final class InputLogic { // reverting any autocorrect at this point. So we can safely return. return; } - if (SpaceState.DOUBLE == spaceState) { + if (SpaceState.DOUBLE == inputTransaction.mSpaceState) { handler.cancelDoubleSpacePeriodTimer(); if (mConnection.revertDoubleSpacePeriod()) { // No need to reset mSpaceState, it has already be done (that's why we // receive it as a parameter) return; } - } else if (SpaceState.SWAP_PUNCTUATION == spaceState) { + } else if (SpaceState.SWAP_PUNCTUATION == inputTransaction.mSpaceState) { if (mConnection.revertSwapPunctuation()) { // Likewise return; @@ -957,8 +959,8 @@ public final class InputLogic { // This should never happen. Log.e(TAG, "Backspace when we don't know the selection position"); } - if (settingsValues.isBeforeJellyBean() || - settingsValues.mInputAttributes.isTypeNull()) { + if (inputTransaction.mSettingsValues.isBeforeJellyBean() || + inputTransaction.mSettingsValues.mInputAttributes.isTypeNull()) { // There are two possible reasons to send a key event: either the field has // type TYPE_NULL, in which case the keyboard should send events, or we are // running in backward compatibility mode. Before Jelly bean, the keyboard @@ -1004,15 +1006,16 @@ public final class InputLogic { } } } - if (settingsValues.isSuggestionStripVisible() - && settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces + if (inputTransaction.mSettingsValues.isSuggestionStripVisible() + && inputTransaction.mSettingsValues.mSpacingAndPunctuations + .mCurrentLanguageHasSpaces && !mConnection.isCursorFollowedByWordCharacter( - settingsValues.mSpacingAndPunctuations)) { - restartSuggestionsOnWordTouchedByCursor(settingsValues, + inputTransaction.mSettingsValues.mSpacingAndPunctuations)) { + restartSuggestionsOnWordTouchedByCursor(inputTransaction.mSettingsValues, true /* includeResumedWordInSuggestions */); } // We just removed at least one character. We need to update the auto-caps state. - keyboardSwitcher.updateShiftState(); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); } } @@ -1028,9 +1031,9 @@ public final class InputLogic { * * This method will check that there are two characters before the cursor and that the first * one is a space before it does the actual swapping. + * @param inputTransaction The transaction in progress. */ - // TODO: Remove this argument - private void swapSwapperAndSpace(final KeyboardSwitcher keyboardSwitcher) { + private void swapSwapperAndSpace(final InputTransaction inputTransaction) { final CharSequence lastTwo = mConnection.getTextBeforeCursor(2, 0); // It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called. if (lastTwo != null && lastTwo.length() == 2 && lastTwo.charAt(0) == Constants.CODE_SPACE) { @@ -1040,28 +1043,34 @@ public final class InputLogic { if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.latinIME_swapSwapperAndSpace(lastTwo, text); } - keyboardSwitcher.updateShiftState(); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); } } /* * Strip a trailing space if necessary and returns whether it's a swap weak space situation. - * @param settingsValues The current settings values. - * @param codePoint The code point that is about to be inserted. - * @param spaceState The space state at start of this batch edit. + * @param inputTransaction The transaction in progress. * @param isFromSuggestionStrip Whether this code point is coming from the suggestion strip. * @return whether we should swap the space instead of removing it. */ - private boolean maybeStripSpace(final SettingsValues settingsValues, - final int code, final int spaceState, final boolean isFromSuggestionStrip) { - if (Constants.CODE_ENTER == code && SpaceState.SWAP_PUNCTUATION == spaceState) { + private boolean maybeStripSpace(final InputTransaction inputTransaction, + final boolean isFromSuggestionStrip) { + if (Constants.CODE_ENTER == inputTransaction.mKeyCode && + SpaceState.SWAP_PUNCTUATION == inputTransaction.mSpaceState) { mConnection.removeTrailingSpace(); return false; } - if ((SpaceState.WEAK == spaceState || SpaceState.SWAP_PUNCTUATION == spaceState) + if ((SpaceState.WEAK == inputTransaction.mSpaceState + || SpaceState.SWAP_PUNCTUATION == inputTransaction.mSpaceState) && isFromSuggestionStrip) { - if (settingsValues.isUsuallyPrecededBySpace(code)) return false; - if (settingsValues.isUsuallyFollowedBySpace(code)) return true; + if (inputTransaction.mSettingsValues.isUsuallyPrecededBySpace( + inputTransaction.mKeyCode)) { + return false; + } + if (inputTransaction.mSettingsValues.isUsuallyFollowedBySpace( + inputTransaction.mKeyCode)) { + return true; + } mConnection.removeTrailingSpace(); } return false; @@ -1479,7 +1488,9 @@ public final class InputLogic { */ private int getActualCapsMode(final SettingsValues settingsValues, final int keyboardShiftMode) { - if (keyboardShiftMode != WordComposer.CAPS_MODE_AUTO_SHIFTED) return keyboardShiftMode; + if (keyboardShiftMode != WordComposer.CAPS_MODE_AUTO_SHIFTED) { + return keyboardShiftMode; + } final int auto = getCurrentAutoCapsState(settingsValues); if (0 != (auto & TextUtils.CAP_MODE_CHARACTERS)) { return WordComposer.CAPS_MODE_AUTO_SHIFT_LOCKED; @@ -1721,6 +1732,7 @@ public final class InputLogic { * @param settingsValues the current values of the settings. * @param codePoint the code point to send. */ + // TODO: replace these two parameters with an InputTransaction private void sendKeyCodePoint(final SettingsValues settingsValues, final int codePoint) { if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.latinIME_sendKeyCodePoint(codePoint); diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java index 90e7400fb..caf3cf354 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java @@ -222,54 +222,6 @@ public final class BinaryDictIOUtils { return countSize; } - private static final int HEADER_READING_BUFFER_SIZE = 16384; - /** - * Convenience method to read the header of a binary file. - * - * This is quite resource intensive - don't call when performance is critical. - * - * @param file The file to read. - * @param offset The offset in the file where to start reading the data. - * @param length The length of the data file. - * @return the header of the specified dictionary file. - */ - private static DictionaryHeader getDictionaryFileHeader( - final File file, final long offset, final long length) - throws FileNotFoundException, IOException, UnsupportedFormatException { - final byte[] buffer = new byte[HEADER_READING_BUFFER_SIZE]; - final DictDecoder dictDecoder = FormatSpec.getDictDecoder(file, offset, length, - new DictDecoder.DictionaryBufferFactory() { - @Override - public DictBuffer getDictionaryBuffer(File file) - throws FileNotFoundException, IOException { - final FileInputStream inStream = new FileInputStream(file); - try { - inStream.skip(offset); - inStream.read(buffer); - return new ByteArrayDictBuffer(buffer); - } finally { - inStream.close(); - } - } - }); - if (dictDecoder == null) { - return null; - } - return dictDecoder.readHeader(); - } - - public static DictionaryHeader getDictionaryFileHeaderOrNull(final File file, final long offset, - final long length) { - try { - final DictionaryHeader header = getDictionaryFileHeader(file, offset, length); - return header; - } catch (UnsupportedFormatException e) { - return null; - } catch (IOException e) { - return null; - } - } - /** * Helper method to hide the actual value of the no children address. */ diff --git a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java index 9abecbfec..484bb4b23 100644 --- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java +++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java @@ -341,6 +341,7 @@ public final class FormatSpec { return null; } + @UsedForTesting public static DictDecoder getDictDecoder(final File dictFile, final long offset, final long length, final DictionaryBufferFactory factory) { if (dictFile.isDirectory()) { @@ -351,6 +352,7 @@ public final class FormatSpec { return null; } + @UsedForTesting public static DictDecoder getDictDecoder(final File dictFile, final long offset, final long length) { return getDictDecoder(dictFile, offset, length, DictDecoder.USE_READONLY_BYTEBUFFER); diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java index ae1e443c5..ab24fbc84 100644 --- a/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java +++ b/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java @@ -123,6 +123,7 @@ public class Ver2DictDecoder extends AbstractDictDecoder { private final DictionaryBufferFactory mBufferFactory; protected DictBuffer mDictBuffer; + @UsedForTesting /* package */ Ver2DictDecoder(final File file, final long offset, final long length, final int factoryFlag) { mDictionaryBinaryFile = file; diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java index 1050d1b0e..a50bad90a 100644 --- a/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java +++ b/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java @@ -22,6 +22,7 @@ import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.LocaleUtils; import java.io.File; @@ -54,7 +55,7 @@ public class Ver4DictEncoder implements DictEncoder { if (!mDictPlacedDir.isDirectory()) { throw new UnsupportedFormatException("Given path is not a directory."); } - if (!BinaryDictionary.createEmptyDictFile(mDictPlacedDir.getAbsolutePath(), + if (!BinaryDictionaryUtils.createEmptyDictFile(mDictPlacedDir.getAbsolutePath(), FormatSpec.VERSION4, LocaleUtils.constructLocaleFromString( dict.mOptions.mAttributes.get(DictionaryHeader.DICTIONARY_LOCALE_KEY)), dict.mOptions.mAttributes)) { diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index dae36f7dd..a07e8eb6a 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -37,6 +37,7 @@ import com.android.inputmethod.latin.SynchronouslyLoadedContactsBinaryDictionary import com.android.inputmethod.latin.SynchronouslyLoadedUserBinaryDictionary; import com.android.inputmethod.latin.UserBinaryDictionary; import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.LocaleUtils; import com.android.inputmethod.latin.utils.StringUtils; @@ -320,7 +321,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService hasRecommendedSuggestions = false; } else { gatheredSuggestions = EMPTY_STRING_ARRAY; - final float normalizedScore = BinaryDictionary.calcNormalizedScore( + final float normalizedScore = BinaryDictionaryUtils.calcNormalizedScore( mOriginalText, mBestSuggestion, mBestScore); hasRecommendedSuggestions = (normalizedScore > mRecommendedThreshold); } @@ -355,7 +356,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService final int bestScore = mScores[mLength - 1]; final String bestSuggestion = mSuggestions.get(0); final float normalizedScore = - BinaryDictionary.calcNormalizedScore( + BinaryDictionaryUtils.calcNormalizedScore( mOriginalText, bestSuggestion.toString(), bestScore); hasRecommendedSuggestions = (normalizedScore > mRecommendedThreshold); if (DBG) { diff --git a/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java b/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java index 37c173f96..22b9b77d2 100644 --- a/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java @@ -40,7 +40,7 @@ public final class AutoCorrectionUtils { final int autoCorrectionSuggestionScore = suggestion.mScore; // TODO: when the normalized score of the first suggestion is nearly equals to // the normalized score of the second suggestion, behave less aggressive. - final float normalizedScore = BinaryDictionary.calcNormalizedScore( + final float normalizedScore = BinaryDictionaryUtils.calcNormalizedScore( consideredWord, suggestion.mWord, autoCorrectionSuggestionScore); if (DBG) { Log.d(TAG, "Normalized " + consideredWord + "," + suggestion + "," @@ -71,9 +71,8 @@ public final class AutoCorrectionUtils { if (typedWordLength < MINIMUM_SAFETY_NET_CHAR_LENGTH) { return false; } - final int maxEditDistanceOfNativeDictionary = - (typedWordLength < 5 ? 2 : typedWordLength / 2) + 1; - final int distance = BinaryDictionary.editDistance(typedWord, suggestion); + final int maxEditDistanceOfNativeDictionary = (typedWordLength / 2) + 1; + final int distance = BinaryDictionaryUtils.editDistance(typedWord, suggestion); if (DBG) { Log.d(TAG, "Autocorrected edit distance = " + distance + ", " + maxEditDistanceOfNativeDictionary); diff --git a/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java b/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java new file mode 100644 index 000000000..638830046 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.latin.utils; + +import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.latin.BinaryDictionary; +import com.android.inputmethod.latin.makedict.DictionaryHeader; +import com.android.inputmethod.latin.makedict.UnsupportedFormatException; +import com.android.inputmethod.latin.personalization.PersonalizationHelper; + +import java.io.File; +import java.io.IOException; +import java.util.Locale; +import java.util.Map; + +public final class BinaryDictionaryUtils { + private static final String TAG = BinaryDictionaryUtils.class.getSimpleName(); + + private BinaryDictionaryUtils() { + // This utility class is not publicly instantiable. + } + + static { + JniUtils.loadNativeLibrary(); + } + + private static native boolean createEmptyDictFileNative(String filePath, long dictVersion, + String locale, String[] attributeKeyStringArray, String[] attributeValueStringArray); + private static native float calcNormalizedScoreNative(int[] before, int[] after, int score); + private static native int editDistanceNative(int[] before, int[] after); + private static native int setCurrentTimeForTestNative(int currentTime); + + public static DictionaryHeader getHeader(final File dictFile) + throws IOException, UnsupportedFormatException { + return getHeaderWithOffsetAndLength(dictFile, 0 /* offset */, dictFile.length()); + } + + public static DictionaryHeader getHeaderWithOffsetAndLength(final File dictFile, + final long offset, final long length) throws IOException, UnsupportedFormatException { + // dictType is never used for reading the header. Passing an empty string. + final BinaryDictionary binaryDictionary = new BinaryDictionary( + dictFile.getAbsolutePath(), offset, length, + true /* useFullEditDistance */, null /* locale */, "" /* dictType */, + false /* isUpdatable */); + final DictionaryHeader header = binaryDictionary.getHeader(); + binaryDictionary.close(); + if (header == null) { + throw new IOException(); + } + return header; + } + + public static boolean createEmptyDictFile(final String filePath, final long dictVersion, + final Locale locale, final Map<String, String> attributeMap) { + final String[] keyArray = new String[attributeMap.size()]; + final String[] valueArray = new String[attributeMap.size()]; + int index = 0; + for (final String key : attributeMap.keySet()) { + keyArray[index] = key; + valueArray[index] = attributeMap.get(key); + index++; + } + return createEmptyDictFileNative(filePath, dictVersion, locale.toString(), keyArray, + valueArray); + } + + public static float calcNormalizedScore(final String before, final String after, + final int score) { + return calcNormalizedScoreNative(StringUtils.toCodePointArray(before), + StringUtils.toCodePointArray(after), score); + } + + public static int editDistance(final String before, final String after) { + if (before == null || after == null) { + throw new IllegalArgumentException(); + } + return editDistanceNative(StringUtils.toCodePointArray(before), + StringUtils.toCodePointArray(after)); + } + + /** + * Control the current time to be used in the native code. If currentTime >= 0, this method sets + * the current time and gets into test mode. + * In test mode, set timestamp is used as the current time in the native code. + * If currentTime < 0, quit the test mode and returns to using time() to get the current time. + * + * @param currentTime seconds since the unix epoch + * @return current time got in the native code. + */ + @UsedForTesting + public static int setCurrentTimeForTest(final int currentTime) { + final int currentNativeTimestamp = setCurrentTimeForTestNative(currentTime); + PersonalizationHelper.currentTimeChangedForTesting(currentNativeTimestamp); + return currentNativeTimestamp; + } +} diff --git a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java index a15556511..e531d4b09 100644 --- a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java @@ -30,9 +30,11 @@ import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.makedict.BinaryDictIOUtils; import com.android.inputmethod.latin.makedict.DictionaryHeader; +import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.Locale; @@ -283,7 +285,20 @@ public class DictionaryInfoUtils { } public static DictionaryHeader getDictionaryFileHeaderOrNull(final File file) { - return BinaryDictIOUtils.getDictionaryFileHeaderOrNull(file, 0, file.length()); + return getDictionaryFileHeaderOrNull(file, 0, file.length()); + } + + private static DictionaryHeader getDictionaryFileHeaderOrNull(final File file, + final long offset, final long length) { + try { + final DictionaryHeader header = + BinaryDictionaryUtils.getHeaderWithOffsetAndLength(file, offset, length); + return header; + } catch (UnsupportedFormatException e) { + return null; + } catch (IOException e) { + return null; + } } /** @@ -294,7 +309,7 @@ public class DictionaryInfoUtils { */ private static DictionaryInfo createDictionaryInfoFromFileAddress( final AssetFileAddress fileAddress) { - final DictionaryHeader header = BinaryDictIOUtils.getDictionaryFileHeaderOrNull( + final DictionaryHeader header = getDictionaryFileHeaderOrNull( new File(fileAddress.mFilename), fileAddress.mOffset, fileAddress.mLength); if (header == null) { return null; |