diff options
31 files changed, 739 insertions, 376 deletions
diff --git a/java/res/values-ka-rGE/strings.xml b/java/res/values-ka-rGE/strings.xml index 056bc355e..8fe415d11 100644 --- a/java/res/values-ka-rGE/strings.xml +++ b/java/res/values-ka-rGE/strings.xml @@ -167,7 +167,7 @@ <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> - <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"კონტაქტების საქაღალდის ჩამოწერა"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"კონტაქტების საქაღალდის ამონაწერი"</string> <string name="prefs_dump_user_dict" msgid="294870685041741951">"პერსონალური საქაღალდის ჩამოწერა"</string> <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"მომხმ. ისტორიის საქაღალდის ჩამოწერა"</string> <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"პერსონალიზაციის საქაღალდის ჩამოწერა"</string> diff --git a/java/res/values-lo-rLA/strings.xml b/java/res/values-lo-rLA/strings.xml index 9f28cd1bb..dae75e350 100644 --- a/java/res/values-lo-rLA/strings.xml +++ b/java/res/values-lo-rLA/strings.xml @@ -167,7 +167,7 @@ <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> - <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"ເທຂໍ້ມູນວັດຈະນານຸກົມລາຍຊື່ຜູ່ຕິດຕໍ່"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"ດຶງຂໍ້ມູນວັດຈະນານຸກົມລາຍຊື່ຜູ່ຕິດຕໍ່"</string> <string name="prefs_dump_user_dict" msgid="294870685041741951">"ເທຂໍ້ມູນວັດຈະນານຸກົມສ່ວນໂຕ"</string> <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"ເທຂໍ້ມູນວັດຈະນານຸກົມປະຫວັດຜູ່ໃຊ້"</string> <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"ເທຂໍ້ມູນວັດຈະນານຸກົມຄວາມເປັນໂຕຕົນ"</string> 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..5e046a80e --- /dev/null +++ b/java/src/com/android/inputmethod/event/InputTransaction.java @@ -0,0 +1,48 @@ +/* + * 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; + +/** + * 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 int mShiftState; + + // Outputs + private int mRequiredShiftUpdate = SHIFT_NO_UPDATE; + + public InputTransaction(final int shiftState) { + 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/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 6c56b8aab..3590c486b 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -700,12 +700,12 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } @Override - public void onCancelMoreKeysPanel(final MoreKeysPanel panel) { + public void onCancelMoreKeysPanel() { PointerTracker.dismissAllMoreKeysPanels(); } @Override - public void onDismissMoreKeysPanel(final MoreKeysPanel panel) { + public void onDismissMoreKeysPanel() { dimEntireKeyboard(false /* dimmed */); if (isShowingMoreKeysPanel()) { mMoreKeysPanel.removeFromParent(); diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java index 1891dfc74..fc331970b 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java @@ -122,7 +122,7 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel onMoveKeyInternal(x, y, pointerId); if (hasOldKey && mCurrentKey == null) { // If the pointer has moved too far away from any target then cancel the panel. - mController.onCancelMoreKeysPanel(this); + mController.onCancelMoreKeysPanel(); } } @@ -184,7 +184,7 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel if (!isShowingInParent()) { return; } - mController.onDismissMoreKeysPanel(this); + mController.onDismissMoreKeysPanel(); } @Override diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java index b3422d177..7bddd09f6 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java @@ -29,26 +29,22 @@ public interface MoreKeysPanel { /** * Remove the current {@link MoreKeysPanel} from the target view. - * @param panel the panel to be dismissed. */ - // TODO: Remove unused {@link MoreKeysPanel} argument. - public void onDismissMoreKeysPanel(final MoreKeysPanel panel); + public void onDismissMoreKeysPanel(); /** * Instructs the parent to cancel the panel (e.g., when entering a different input mode). - * @param panel the panel to be canceled. */ - // TODO: Remove unused {@link MoreKeysPanel} argument. - public void onCancelMoreKeysPanel(final MoreKeysPanel panel); + public void onCancelMoreKeysPanel(); } public static final Controller EMPTY_CONTROLLER = new Controller() { @Override public void onShowMoreKeysPanel(final MoreKeysPanel panel) {} @Override - public void onDismissMoreKeysPanel(final MoreKeysPanel panel) {} + public void onDismissMoreKeysPanel() {} @Override - public void onCancelMoreKeysPanel(final MoreKeysPanel panel) {} + public void onCancelMoreKeysPanel() {} }; /** diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 851ecc042..05e6ef0d2 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) { @@ -323,20 +303,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 +463,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/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/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 4c2454c32..44353ba06 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -78,7 +78,6 @@ import com.android.inputmethod.latin.suggestions.SuggestionStripView; import com.android.inputmethod.latin.suggestions.SuggestionStripViewAccessor; import com.android.inputmethod.latin.utils.ApplicationUtils; import com.android.inputmethod.latin.utils.CapsModeUtils; -import com.android.inputmethod.latin.utils.CompletionInfoUtils; import com.android.inputmethod.latin.utils.CoordinateUtils; import com.android.inputmethod.latin.utils.ImportantNoticeUtils; import com.android.inputmethod.latin.utils.IntentUtils; @@ -124,9 +123,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private View mKeyPreviewBackingView; private SuggestionStripView mSuggestionStripView; - // TODO[IL]: remove this member completely. - public CompletionInfo[] mApplicationSpecifiedCompletions; - private RichInputMethodManager mRichImm; @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher; private final SubtypeSwitcher mSubtypeSwitcher; @@ -192,8 +188,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher; switch (msg.what) { case MSG_UPDATE_SUGGESTION_STRIP: + cancelUpdateSuggestionStrip(); latinIme.mInputLogic.performUpdateSuggestionStripSync( - latinIme.mSettings.getCurrent(), this /* handler */); + latinIme.mSettings.getCurrent()); break; case MSG_UPDATE_SHIFT_STATE: switcher.updateShiftState(); @@ -554,7 +551,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Create Suggest instance with the new dictionary facilitator. replaceSuggest(new Suggest(oldSuggest, dictionaryFacilitator)); } else if (oldSuggest == null) { - initSuggestForLocale(oldSuggest, locale); + initSuggest(); } } @@ -812,7 +809,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // The EditorInfo might have a flag that affects fullscreen mode. // Note: This call should be done by InputMethodService? updateFullscreenMode(); - mApplicationSpecifiedCompletions = null; // The app calling setText() has the effect of clearing the composing // span, so we should reset our state unconditionally, even if restarting is true. @@ -879,7 +875,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } // This will set the punctuation suggestions if next word suggestion is off; // otherwise it will clear the suggestion strip. - setNeutralSuggestionStripInternal(); + setNeutralSuggestionStrip(); mHandler.cancelUpdateSuggestionStrip(); mHandler.cancelDoubleSpacePeriodTimer(); @@ -954,8 +950,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // NOTE: the test harness subclasses LatinIME and overrides isInputViewShown(). // TODO: find a better way to simulate actual execution. if (isInputViewShown() && - mInputLogic.onUpdateSelection(mSettings.getCurrent(), oldSelStart, oldSelEnd, - newSelStart, newSelEnd, composingSpanStart, composingSpanEnd)) { + mInputLogic.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd)) { mKeyboardSwitcher.updateShiftState(); } @@ -1034,8 +1029,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } return; } - mApplicationSpecifiedCompletions = - CompletionInfoUtils.removeNulls(applicationSpecifiedCompletions); final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords = SuggestedWords.getFromApplicationSpecifiedCompletions( @@ -1050,18 +1043,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } - private void setSuggestionStripShownInternal(final boolean isSuggestionStripVisible) { - // TODO: Modify this if we support suggestions with hard keyboard - if (!onEvaluateInputViewShown() || !hasSuggestionStripView()) { - return; - } - if (isSuggestionStripVisible) { - mSuggestionStripView.setVisibility(View.VISIBLE); - } else { - mSuggestionStripView.setVisibility(isFullscreenMode() ? View.GONE : View.INVISIBLE); - } - } - private int getAdjustedBackingViewHeight() { final int currentHeight = mKeyPreviewBackingView.getHeight(); if (currentHeight > 0) { @@ -1299,7 +1280,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void onStartBatchInput() { - mInputLogic.onStartBatchInput(mSettings.getCurrent(), mKeyboardSwitcher, mHandler); + mInputLogic.onStartBatchInput(mSettings.getCurrent(), mKeyboardSwitcher, mHandler); } @Override @@ -1309,7 +1290,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void onEndBatchInput(final InputPointers batchPointers) { - mInputLogic.onEndBatchInput(mSettings.getCurrent(), batchPointers); + mInputLogic.onEndBatchInput(batchPointers); } @Override @@ -1387,13 +1368,23 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public void setSuggestedWords(final SuggestedWords suggestedWords, final boolean isSuggestionStripVisible) { mInputLogic.setSuggestedWords(suggestedWords); + // TODO: Modify this when we support suggestions with hard keyboard if (!hasSuggestionStripView()) { return; } + mKeyboardSwitcher.onAutoCorrectionStateChanged(suggestedWords.mWillAutoCorrect); + if (!onEvaluateInputViewShown()) { + return; + } + if (!isSuggestionStripVisible) { + mSuggestionStripView.setVisibility(isFullscreenMode() ? View.GONE : View.INVISIBLE); + return; + } + mSuggestionStripView.setVisibility(View.VISIBLE); + final SettingsValues currentSettings = mSettings.getCurrent(); final boolean showSuggestions; - if (SuggestedWords.EMPTY == suggestedWords - || suggestedWords.isPunctuationSuggestions() + if (SuggestedWords.EMPTY == suggestedWords || suggestedWords.isPunctuationSuggestions() || !currentSettings.isSuggestionsRequested()) { showSuggestions = !mSuggestionStripView.maybeShowImportantNoticeTitle( currentSettings.mInputAttributes); @@ -1404,8 +1395,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mSuggestionStripView.setSuggestions(suggestedWords, SubtypeLocaleUtils.isRtlLanguage(mSubtypeSwitcher.getCurrentSubtype())); } - mKeyboardSwitcher.onAutoCorrectionStateChanged(suggestedWords.mWillAutoCorrect); - setSuggestionStripShownInternal(isSuggestionStripVisible); } // TODO[IL]: Move this out of LatinIME. @@ -1449,32 +1438,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen sequenceNumber, callback); } - // TODO[IL]: Move this to InputLogic - public SuggestedWords maybeRetrieveOlderSuggestions(final String typedWord, - final SuggestedWords suggestedWords, final SuggestedWords previousSuggestedWords) { - // TODO: consolidate this into getSuggestedWords - // We update the suggestion strip only when we have some suggestions to show, i.e. when - // the suggestion count is > 1; else, we leave the old suggestions, with the typed word - // replaced with the new one. However, when the length of the typed word is 1 or 0 (after - // a deletion typically), we do want to remove the old suggestions. Also, if we are showing - // the "add to dictionary" hint, we need to revert to suggestions - although it is unclear - // how we can come here if it's displayed. - if (suggestedWords.size() > 1 || typedWord.length() <= 1 - || !hasSuggestionStripView() || isShowingAddToDictionaryHint()) { - return suggestedWords; - } else { - final SuggestedWords punctuationList = - mSettings.getCurrent().mSpacingAndPunctuations.mSuggestPuncList; - final SuggestedWords oldSuggestedWords = previousSuggestedWords == punctuationList - ? SuggestedWords.EMPTY : previousSuggestedWords; - final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions = - SuggestedWords.getTypedWordAndPreviousSuggestions(typedWord, oldSuggestedWords); - return new SuggestedWords(typedWordAndPreviousSuggestions, null /* rawSuggestions */, - false /* typedWordValid */, false /* hasAutoCorrectionCandidate */, - true /* isObsoleteSuggestions */, false /* isPrediction */); - } - } - @Override public void showSuggestionStrip(final SuggestedWords sourceSuggestedWords) { final SuggestedWords suggestedWords = @@ -1515,15 +1478,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mSuggestionStripView.showAddToDictionaryHint(word); } - // TODO[IL]: Define a clean interface for this // This will show either an empty suggestion strip (if prediction is enabled) or // punctuation suggestions (if it's disabled). @Override public void setNeutralSuggestionStrip() { - setNeutralSuggestionStripInternal(); - } - - private void setNeutralSuggestionStripInternal() { final SettingsValues currentSettings = mSettings.getCurrent(); final SuggestedWords neutralSuggestions = currentSettings.mBigramPredictionEnabled ? SuggestedWords.EMPTY : currentSettings.mSpacingAndPunctuations.mSuggestPuncList; 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/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index 06bc90c97..dc2c9fd0e 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -167,15 +167,10 @@ public class SuggestedWords { final CompletionInfo[] infos) { final ArrayList<SuggestedWordInfo> result = CollectionUtils.newArrayList(); for (final CompletionInfo info : infos) { - if (info == null) continue; - final CharSequence text = info.getText(); - if (null == text) continue; - final SuggestedWordInfo suggestedWordInfo = new SuggestedWordInfo(text.toString(), - SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_APP_DEFINED, - Dictionary.DICTIONARY_APPLICATION_DEFINED, - SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */, - SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */); - result.add(suggestedWordInfo); + if (null == info || null == info.getText()) { + continue; + } + result.add(new SuggestedWordInfo(info)); } return result; } @@ -234,6 +229,9 @@ public class SuggestedWords { public static final int KIND_FLAG_EXACT_MATCH = 0x40000000; public final String mWord; + // The completion info from the application. Null for suggestions that don't come from + // the application (including keyboard-computed ones, so this is almost always null) + public final CompletionInfo mApplicationSpecifiedCompletionInfo; public final int mScore; public final int mKind; // one of the KIND_* constants above public final int mCodePointCount; @@ -260,6 +258,7 @@ public class SuggestedWords { final Dictionary sourceDict, final int indexOfTouchPointOfSecondWord, final int autoCommitFirstWordConfidence) { mWord = word; + mApplicationSpecifiedCompletionInfo = null; mScore = score; mKind = kind; mSourceDict = sourceDict; @@ -268,6 +267,22 @@ public class SuggestedWords { mAutoCommitFirstWordConfidence = autoCommitFirstWordConfidence; } + /** + * Create a new suggested word info from an application-specified completion. + * If the passed argument or its contained text is null, this throws a NPE. + * @param applicationSpecifiedCompletion The application-specified completion info. + */ + public SuggestedWordInfo(final CompletionInfo applicationSpecifiedCompletion) { + mWord = applicationSpecifiedCompletion.getText().toString(); + mApplicationSpecifiedCompletionInfo = applicationSpecifiedCompletion; + mScore = SuggestedWordInfo.MAX_SCORE; + mKind = SuggestedWordInfo.KIND_APP_DEFINED; + mSourceDict = Dictionary.DICTIONARY_APPLICATION_DEFINED; + mCodePointCount = StringUtils.codePointCount(mWord); + mIndexOfTouchPointOfSecondWord = SuggestedWordInfo.NOT_AN_INDEX; + mAutoCommitFirstWordConfidence = SuggestedWordInfo.NOT_A_CONFIDENCE; + } + public boolean isEligibleForAutoCommit() { return (KIND_CORRECTION == mKind && NOT_AN_INDEX != mIndexOfTouchPointOfSecondWord); } diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index f2f9f1e68..daaac5913 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; @@ -74,7 +74,7 @@ public final class InputLogic { // TODO : make all these fields private as soon as possible. // Current space state of the input method. This can be any of the above constants. - public int mSpaceState; + private int mSpaceState; // Never null public SuggestedWords mSuggestedWords = SuggestedWords.EMPTY; // TODO: mSuggest should be touched by a single thread. @@ -85,7 +85,7 @@ public final class InputLogic { public LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; public final WordComposer mWordComposer; public final RichInputConnection mConnection; - public final RecapitalizeStatus mRecapitalizeStatus = new RecapitalizeStatus(); + private final RecapitalizeStatus mRecapitalizeStatus = new RecapitalizeStatus(); private int mDeleteCount; private long mLastKeyTime; @@ -96,7 +96,7 @@ public final class InputLogic { // TODO: This boolean is persistent state and causes large side effects at unexpected times. // Find a way to remove it for readability. - public boolean mIsAutoCorrectionIndicatorOn; + private boolean mIsAutoCorrectionIndicatorOn; public InputLogic(final LatinIME latinIME, final SuggestionStripViewAccessor suggestionStripViewAccessor) { @@ -227,17 +227,16 @@ public final class InputLogic { } } - // TODO: stop relying on mApplicationSpecifiedCompletions. The SuggestionInfo object - // should contain a reference to the CompletionInfo instead. - if (settingsValues.isApplicationSpecifiedCompletionsOn() - && mLatinIME.mApplicationSpecifiedCompletions != null - && index >= 0 && index < mLatinIME.mApplicationSpecifiedCompletions.length) { + // TODO: We should not need the following branch. We should be able to take the same + // code path as for other kinds, use commitChosenWord, and do everything normally. We will + // however need to reset the suggestion strip right away, because we know we can't take + // the risk of calling commitCompletion twice because we don't know how the app will react. + if (SuggestedWordInfo.KIND_APP_DEFINED == suggestionInfo.mKind) { mSuggestedWords = SuggestedWords.EMPTY; mSuggestionStripViewAccessor.setNeutralSuggestionStrip(); keyboardSwitcher.updateShiftState(); resetComposingState(true /* alsoResetLastComposedWord */); - final CompletionInfo completionInfo = mLatinIME.mApplicationSpecifiedCompletions[index]; - mConnection.commitCompletion(completionInfo); + mConnection.commitCompletion(suggestionInfo.mApplicationSpecifiedCompletionInfo); mConnection.endBatchEdit(); return; } @@ -290,19 +289,14 @@ public final class InputLogic { * Consider an update to the cursor position. Evaluate whether this update has happened as * part of normal typing or whether it was an explicit cursor move by the user. In any case, * do the necessary adjustments. - * @param settingsValues the current settings * @param oldSelStart old selection start * @param oldSelEnd old selection end * @param newSelStart new selection start * @param newSelEnd new selection end - * @param composingSpanStart composing span start - * @param composingSpanEnd composing span end * @return whether the cursor has moved as a result of user interaction. */ - public boolean onUpdateSelection(final SettingsValues settingsValues, - final int oldSelStart, final int oldSelEnd, - final int newSelStart, final int newSelEnd, - final int composingSpanStart, final int composingSpanEnd) { + public boolean onUpdateSelection(final int oldSelStart, final int oldSelEnd, + final int newSelStart, final int newSelEnd) { if (mConnection.isBelatedExpectedUpdate(oldSelStart, newSelStart, oldSelEnd, newSelEnd)) { return false; } @@ -335,8 +329,7 @@ public final class InputLogic { // we'd have the suggestion strip noticeably janky. To avoid that, we don't clear // it here, which means we'll keep outdated suggestions for a split second but the // visual result is better. - resetEntireInputState(settingsValues, newSelStart, newSelEnd, - false /* clearSuggestionStrip */); + resetEntireInputState(newSelStart, newSelEnd, false /* clearSuggestionStrip */); } else { // resetEntireInputState calls resetCachesUponCursorMove, but forcing the // composition to end. But in all cases where we don't reset the entire input @@ -372,6 +365,8 @@ public final class InputLogic { ResearchLogger.latinIME_onCodeInput(code, x, y); } final long when = SystemClock.uptimeMillis(); + final InputTransaction inputTransaction = new InputTransaction( + getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode())); if (code != Constants.CODE_DELETE || when > mLastKeyTime + Constants.LONG_PRESS_MILLISECONDS) { mDeleteCount = 0; @@ -396,12 +391,12 @@ public final class InputLogic { boolean didAutoCorrect = false; switch (code) { case Constants.CODE_DELETE: - handleBackspace(settingsValues, spaceState, handler, keyboardSwitcher); + handleBackspace(settingsValues, spaceState, inputTransaction, handler); LatinImeLogger.logOnDelete(x, y); break; case Constants.CODE_SHIFT: performRecapitalization(settingsValues); - keyboardSwitcher.updateShiftState(); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); break; case Constants.CODE_CAPSLOCK: // Note: Changing keyboard to shift lock state is handled in @@ -456,12 +451,12 @@ public final class InputLogic { // 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); + x, y, spaceState, inputTransaction, handler); } break; case Constants.CODE_SHIFT_ENTER: didAutoCorrect = handleNonSpecialCharacter(settingsValues, Constants.CODE_ENTER, - x, y, spaceState, keyboardSwitcher, handler); + x, y, spaceState, inputTransaction, handler); break; case Constants.CODE_ALPHA_FROM_EMOJI: // Note: Switching back from Emoji keyboard to the main keyboard is being handled in @@ -469,7 +464,7 @@ public final class InputLogic { break; default: didAutoCorrect = handleNonSpecialCharacter(settingsValues, - code, x, y, spaceState, keyboardSwitcher, handler); + code, x, y, spaceState, inputTransaction, handler); break; } // Reset after any single keystroke, except shift, capslock, and symbol-shift @@ -481,6 +476,15 @@ public final class InputLogic { 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, @@ -504,7 +508,7 @@ public final class InputLogic { if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the batch input at the current cursor position. - resetEntireInputState(settingsValues, mConnection.getExpectedSelectionStart(), + resetEntireInputState(mConnection.getExpectedSelectionStart(), mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); } else if (wordComposerSize <= 1) { // We auto-correct the previous (typed, not gestured) string iff it's one character @@ -585,8 +589,7 @@ public final class InputLogic { mInputLogicHandler.onUpdateBatchInput(batchPointers, mAutoCommitSequenceNumber); } - public void onEndBatchInput(final SettingsValues settingValues, - final InputPointers batchPointers) { + public void onEndBatchInput(final InputPointers batchPointers) { mInputLogicHandler.onEndBatchInput(batchPointers, mAutoCommitSequenceNumber); ++mAutoCommitSequenceNumber; } @@ -630,18 +633,20 @@ public final class InputLogic { * @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) { + 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, + Constants.SUGGESTION_STRIP_COORDINATE == x, spaceState, inputTransaction, handler); if (settingsValues.mIsInternal) { LatinImeLoggerUtils.onSeparator((char)codePoint, x, y); @@ -658,14 +663,14 @@ public final class InputLogic { if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the character at the current cursor position. - resetEntireInputState(settingsValues, mConnection.getExpectedSelectionStart(), + resetEntireInputState(mConnection.getExpectedSelectionStart(), mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); } else { commitTyped(settingsValues, LastComposedWord.NOT_A_SEPARATOR); } } handleNonSeparator(settingsValues, codePoint, x, y, spaceState, - keyboardSwitcher, handler); + inputTransaction, handler); } return didAutoCorrect; } @@ -677,11 +682,13 @@ public final class InputLogic { * @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. @@ -700,7 +707,7 @@ public final class InputLogic { if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the character at the current cursor position. - resetEntireInputState(settingsValues, mConnection.getExpectedSelectionStart(), + resetEntireInputState(mConnection.getExpectedSelectionStart(), mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); isComposingWord = false; } @@ -737,8 +744,7 @@ public final class InputLogic { // 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( @@ -750,7 +756,7 @@ public final class InputLogic { sendKeyCodePoint(settingsValues, codePoint); if (swapWeakSpace) { - swapSwapperAndSpace(keyboardSwitcher); + swapSwapperAndSpace(inputTransaction); mSpaceState = SpaceState.WEAK; } // In case the "add to dictionary" hint was still displayed. @@ -768,12 +774,14 @@ public final class InputLogic { * @param codePoint the code point associated with the key. * @param isFromSuggestionStrip whether this code point comes from the suggestion strip. * @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 handleSeparator(final SettingsValues settingsValues, final int codePoint, final boolean isFromSuggestionStrip, 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) { boolean didAutoCorrect = false; // We avoid sending spaces in languages without spaces if we were composing. final boolean shouldAvoidSendingCode = Constants.CODE_SPACE == codePoint @@ -782,7 +790,7 @@ public final class InputLogic { if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the separator at the current cursor position. - resetEntireInputState(settingsValues, mConnection.getExpectedSelectionStart(), + resetEntireInputState(mConnection.getExpectedSelectionStart(), mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); } // isComposingWord() may have changed since we stored wasComposing @@ -828,7 +836,7 @@ public final class InputLogic { if (Constants.CODE_SPACE == codePoint) { if (settingsValues.isSuggestionsRequested()) { if (maybeDoubleSpacePeriod(settingsValues, handler)) { - keyboardSwitcher.updateShiftState(); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); mSpaceState = SpaceState.DOUBLE; } else if (!mSuggestedWords.isPunctuationSuggestions()) { mSpaceState = SpaceState.WEAK; @@ -839,7 +847,7 @@ 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)) @@ -864,7 +872,7 @@ public final class InputLogic { mSuggestionStripViewAccessor.setNeutralSuggestionStrip(); } - keyboardSwitcher.updateShiftState(); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); return didAutoCorrect; } @@ -872,23 +880,24 @@ public final class InputLogic { * 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) { + final InputTransaction inputTransaction, + // TODO: remove this argument + final LatinIME.UIHandler handler) { mSpaceState = SpaceState.NONE; - final int deleteCountAtStart = mDeleteCount; 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 // first so that we can remove the character at the current cursor position. - resetEntireInputState(settingsValues, mConnection.getExpectedSelectionStart(), + resetEntireInputState(mConnection.getExpectedSelectionStart(), mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); // When we exit this if-clause, mWordComposer.isComposingWord() will return false. } @@ -909,7 +918,7 @@ 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()) { @@ -1021,7 +1030,7 @@ public final class InputLogic { 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); } } @@ -1037,9 +1046,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) { @@ -1049,7 +1058,7 @@ public final class InputLogic { if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.latinIME_swapSwapperAndSpace(lastTwo, text); } - keyboardSwitcher.updateShiftState(); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); } } @@ -1205,11 +1214,7 @@ public final class InputLogic { timeStampInSeconds); } - public void performUpdateSuggestionStripSync(final SettingsValues settingsValues, - // TODO: Remove this argument - final LatinIME.UIHandler handler) { - handler.cancelUpdateSuggestionStrip(); - + public void performUpdateSuggestionStripSync(final SettingsValues settingsValues) { // Check if we have a suggestion engine attached. if (mSuggest == null || !settingsValues.isSuggestionsRequested()) { if (mWordComposer.isComposingWord()) { @@ -1229,11 +1234,15 @@ public final class InputLogic { SuggestedWords.NOT_A_SEQUENCE_NUMBER, new OnGetSuggestedWordsCallback() { @Override public void onGetSuggestedWords(final SuggestedWords suggestedWords) { - final SuggestedWords suggestedWordsWithMaybeOlderSuggestions = - mLatinIME.maybeRetrieveOlderSuggestions( - mWordComposer.getTypedWord(), suggestedWords, - mSuggestedWords); - holder.set(suggestedWordsWithMaybeOlderSuggestions); + final String typedWord = mWordComposer.getTypedWord(); + // Show new suggestions if we have at least one. Otherwise keep the old + // suggestions with the new typed word. Exception: if the length of the + // typed word is <= 1 (after a deletion typically) we clear old suggestions. + if (suggestedWords.size() > 1 || typedWord.length() <= 1) { + holder.set(suggestedWords); + } else { + holder.set(retrieveOlderSuggestions(typedWord, mSuggestedWords)); + } } } ); @@ -1485,7 +1494,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; @@ -1623,15 +1634,13 @@ public final class InputLogic { * This will clear the composing word, reset the last composed word, clear the suggestion * strip and tell the input connection about it so that it can refresh its caches. * - * @param settingsValues the current values of the settings. * @param newSelStart the new selection start, in java characters. * @param newSelEnd the new selection end, in java characters. * @param clearSuggestionStrip whether this method should clear the suggestion strip. */ // TODO: how is this different from startInput ?! - // TODO: remove all references to this in LatinIME and make this private - public void resetEntireInputState(final SettingsValues settingsValues, - final int newSelStart, final int newSelEnd, final boolean clearSuggestionStrip) { + private void resetEntireInputState(final int newSelStart, final int newSelEnd, + final boolean clearSuggestionStrip) { final boolean shouldFinishComposition = mWordComposer.isComposingWord(); resetComposingState(true /* alsoResetLastComposedWord */); if (clearSuggestionStrip) { @@ -1649,8 +1658,7 @@ public final class InputLogic { * * @param alsoResetLastComposedWord whether to also reset the last composed word. */ - // TODO: remove all references to this in LatinIME and make this private. - public void resetComposingState(final boolean alsoResetLastComposedWord) { + private void resetComposingState(final boolean alsoResetLastComposedWord) { mWordComposer.reset(); if (alsoResetLastComposedWord) { mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; @@ -1658,6 +1666,27 @@ public final class InputLogic { } /** + * Make a {@link com.android.inputmethod.latin.SuggestedWords} object containing a typed word + * and obsolete suggestions. + * See {@link com.android.inputmethod.latin.SuggestedWords#getTypedWordAndPreviousSuggestions( + * String, com.android.inputmethod.latin.SuggestedWords)}. + * @param typedWord The typed word as a string. + * @param previousSuggestedWords The previously suggested words. + * @return Obsolete suggestions with the newly typed word. + */ + private SuggestedWords retrieveOlderSuggestions(final String typedWord, + final SuggestedWords previousSuggestedWords) { + final SuggestedWords oldSuggestedWords = + previousSuggestedWords.isPunctuationSuggestions() ? SuggestedWords.EMPTY + : previousSuggestedWords; + final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions = + SuggestedWords.getTypedWordAndPreviousSuggestions(typedWord, oldSuggestedWords); + return new SuggestedWords(typedWordAndPreviousSuggestions, null /* rawSuggestions */, + false /* typedWordValid */, false /* hasAutoCorrectionCandidate */, + true /* isObsoleteSuggestions */, false /* isPrediction */); + } + + /** * Gets a chunk of text with or the auto-correction indicator underline span as appropriate. * * This method looks at the old state of the auto-correction indicator to put or not put @@ -1674,9 +1703,8 @@ public final class InputLogic { * @param text the text on which to maybe apply the span. * @return the same text, with the auto-correction underline span if that's appropriate. */ - // TODO: remove all references to this in LatinIME and make this private. Also, shouldn't - // this go in some *Utils class instead? - public CharSequence getTextWithUnderline(final String text) { + // TODO: Shouldn't this go in some *Utils class instead? + private CharSequence getTextWithUnderline(final String text) { return mIsAutoCorrectionIndicatorOn ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(mLatinIME, text) : text; @@ -1741,8 +1769,7 @@ public final class InputLogic { * * @param settingsValues the current values of the settings. */ - // TODO: Make this private. - public void promotePhantomSpace(final SettingsValues settingsValues) { + private void promotePhantomSpace(final SettingsValues settingsValues) { if (settingsValues.shouldInsertSpacesAutomatically() && settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces && !mConnection.textBeforeCursorLooksLikeURL()) { @@ -1848,7 +1875,8 @@ public final class InputLogic { final LatinIME.UIHandler handler) { // Complete any pending suggestions query first if (handler.hasPendingUpdateSuggestions()) { - performUpdateSuggestionStripSync(settingsValues, handler); + handler.cancelUpdateSuggestionStrip(); + performUpdateSuggestionStripSync(settingsValues); } final String typedAutoCorrection = mWordComposer.getAutoCorrectionOrNull(); final String typedWord = mWordComposer.getTypedWord(); @@ -1892,8 +1920,7 @@ public final class InputLogic { * @param commitType the type of the commit, as one of LastComposedWord.COMMIT_TYPE_* * @param separatorString the separator that's causing the commit, or NOT_A_SEPARATOR if none. */ - // TODO: Make this private - public void commitChosenWord(final SettingsValues settingsValues, final String chosenWord, + private void commitChosenWord(final SettingsValues settingsValues, final String chosenWord, final int commitType, final String separatorString) { final SuggestedWords suggestedWords = mSuggestedWords; final CharSequence chosenWordWithSuggestions = 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/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java index be457ca8e..43cb11b14 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java @@ -280,8 +280,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick private final MoreKeysPanel.Controller mMoreSuggestionsController = new MoreKeysPanel.Controller() { @Override - public void onDismissMoreKeysPanel(final MoreKeysPanel panel) { - mMainKeyboardView.onDismissMoreKeysPanel(panel); + public void onDismissMoreKeysPanel() { + mMainKeyboardView.onDismissMoreKeysPanel(); } @Override @@ -290,7 +290,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick } @Override - public void onCancelMoreKeysPanel(final MoreKeysPanel panel) { + public void onCancelMoreKeysPanel() { dismissMoreSuggestionsPanel(); } }; @@ -321,8 +321,10 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick } // Dismiss another {@link MoreKeysPanel} that may be being showed, for example // {@link MoreKeysKeyboardView}. - // TODO: Remove unused null argument. - mMainKeyboardView.onDismissMoreKeysPanel(null /* unused */); + mMainKeyboardView.onDismissMoreKeysPanel(); + // Dismiss all key previews and sliding key input preview that may be being showed. + mMainKeyboardView.dismissAllKeyPreviews(); + mMainKeyboardView.dismissSlidingKeyInputPreview(); final int stripWidth = getWidth(); final View container = mMoreSuggestionsContainer; final int maxWidth = stripWidth - container.getPaddingLeft() - container.getPaddingRight(); 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..6872285ad --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java @@ -0,0 +1,85 @@ +/* + * 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.personalization.PersonalizationHelper; + +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 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/native/jni/NativeFileList.mk b/native/jni/NativeFileList.mk index eb24df601..82237dc24 100644 --- a/native/jni/NativeFileList.mk +++ b/native/jni/NativeFileList.mk @@ -15,6 +15,7 @@ LATIN_IME_JNI_SRC_FILES := \ com_android_inputmethod_keyboard_ProximityInfo.cpp \ com_android_inputmethod_latin_BinaryDictionary.cpp \ + com_android_inputmethod_latin_BinaryDictionaryUtils.cpp \ com_android_inputmethod_latin_DicTraverseSession.cpp \ jni_common.cpp diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index bb54cbdb9..7a7816d5a 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -27,8 +27,6 @@ #include "suggest/core/dictionary/word_property.h" #include "suggest/core/suggest_options.h" #include "suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h" -#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h" -#include "utils/autocorrection_threshold_utils.h" #include "utils/char_utils.h" #include "utils/time_keeper.h" @@ -36,49 +34,6 @@ namespace latinime { class ProximityInfo; -// TODO: Move to makedict. -static jboolean latinime_BinaryDictionary_createEmptyDictFile(JNIEnv *env, jclass clazz, - jstring filePath, jlong dictVersion, jstring locale, jobjectArray attributeKeyStringArray, - jobjectArray attributeValueStringArray) { - const jsize filePathUtf8Length = env->GetStringUTFLength(filePath); - char filePathChars[filePathUtf8Length + 1]; - env->GetStringUTFRegion(filePath, 0, env->GetStringLength(filePath), filePathChars); - filePathChars[filePathUtf8Length] = '\0'; - jsize localeLength = env->GetStringLength(locale); - jchar localeCodePoints[localeLength]; - env->GetStringRegion(locale, 0, localeLength, localeCodePoints); - const int keyCount = env->GetArrayLength(attributeKeyStringArray); - const int valueCount = env->GetArrayLength(attributeValueStringArray); - if (keyCount != valueCount) { - return false; - } - - DictionaryHeaderStructurePolicy::AttributeMap attributeMap; - for (int i = 0; i < keyCount; i++) { - jstring keyString = static_cast<jstring>( - env->GetObjectArrayElement(attributeKeyStringArray, i)); - const jsize keyUtf8Length = env->GetStringUTFLength(keyString); - char keyChars[keyUtf8Length + 1]; - env->GetStringUTFRegion(keyString, 0, env->GetStringLength(keyString), keyChars); - keyChars[keyUtf8Length] = '\0'; - DictionaryHeaderStructurePolicy::AttributeMap::key_type key; - HeaderReadWriteUtils::insertCharactersIntoVector(keyChars, &key); - - jstring valueString = static_cast<jstring>( - env->GetObjectArrayElement(attributeValueStringArray, i)); - const jsize valueUtf8Length = env->GetStringUTFLength(valueString); - char valueChars[valueUtf8Length + 1]; - env->GetStringUTFRegion(valueString, 0, env->GetStringLength(valueString), valueChars); - valueChars[valueUtf8Length] = '\0'; - DictionaryHeaderStructurePolicy::AttributeMap::mapped_type value; - HeaderReadWriteUtils::insertCharactersIntoVector(valueChars, &value); - attributeMap[key] = value; - } - - return DictFileWritingUtils::createEmptyDictFile(filePathChars, static_cast<int>(dictVersion), - CharUtils::convertShortArrayToIntVector(localeCodePoints, localeLength), &attributeMap); -} - static jlong latinime_BinaryDictionary_open(JNIEnv *env, jclass clazz, jstring sourceDir, jlong dictOffset, jlong dictSize, jboolean isUpdatable) { PROF_OPEN; @@ -335,30 +290,6 @@ static void latinime_BinaryDictionary_getWordProperty(JNIEnv *env, jclass clazz, outShortcutProbabilities); } -static jfloat latinime_BinaryDictionary_calcNormalizedScore(JNIEnv *env, jclass clazz, - jintArray before, jintArray after, jint score) { - jsize beforeLength = env->GetArrayLength(before); - jsize afterLength = env->GetArrayLength(after); - int beforeCodePoints[beforeLength]; - int afterCodePoints[afterLength]; - env->GetIntArrayRegion(before, 0, beforeLength, beforeCodePoints); - env->GetIntArrayRegion(after, 0, afterLength, afterCodePoints); - return AutocorrectionThresholdUtils::calcNormalizedScore(beforeCodePoints, beforeLength, - afterCodePoints, afterLength, score); -} - -static jint latinime_BinaryDictionary_editDistance(JNIEnv *env, jclass clazz, jintArray before, - jintArray after) { - jsize beforeLength = env->GetArrayLength(before); - jsize afterLength = env->GetArrayLength(after); - int beforeCodePoints[beforeLength]; - int afterCodePoints[afterLength]; - env->GetIntArrayRegion(before, 0, beforeLength, beforeCodePoints); - env->GetIntArrayRegion(after, 0, afterLength, afterCodePoints); - return AutocorrectionThresholdUtils::editDistance(beforeCodePoints, beforeLength, - afterCodePoints, afterLength); -} - static void latinime_BinaryDictionary_addUnigramWord(JNIEnv *env, jclass clazz, jlong dict, jintArray word, jint probability, jintArray shortcutTarget, jint shortuctProbability, jboolean isNotAWord, jboolean isBlacklisted, jint timestamp) { @@ -518,17 +449,6 @@ static jstring latinime_BinaryDictionary_getProperty(JNIEnv *env, jclass clazz, return env->NewStringUTF(resultChars); } -static int latinime_BinaryDictionary_setCurrentTimeForTest(JNIEnv *env, jclass clazz, - jint currentTime) { - if (currentTime >= 0) { - TimeKeeper::startTestModeWithForceCurrentTime(currentTime); - } else { - TimeKeeper::stopTestMode(); - } - TimeKeeper::setCurrentTime(); - return TimeKeeper::peekCurrentTime(); -} - static bool latinime_BinaryDictionary_isCorruptedNative(JNIEnv *env, jclass clazz, jlong dict) { Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict); if (!dictionary) { @@ -539,12 +459,6 @@ static bool latinime_BinaryDictionary_isCorruptedNative(JNIEnv *env, jclass claz static const JNINativeMethod sMethods[] = { { - const_cast<char *>("createEmptyDictFileNative"), - const_cast<char *>( - "(Ljava/lang/String;JLjava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)Z"), - reinterpret_cast<void *>(latinime_BinaryDictionary_createEmptyDictFile) - }, - { const_cast<char *>("openNative"), const_cast<char *>("(Ljava/lang/String;JJZ)J"), reinterpret_cast<void *>(latinime_BinaryDictionary_open) @@ -606,16 +520,6 @@ static const JNINativeMethod sMethods[] = { reinterpret_cast<void *>(latinime_BinaryDictionary_getNextWord) }, { - const_cast<char *>("calcNormalizedScoreNative"), - const_cast<char *>("([I[II)F"), - reinterpret_cast<void *>(latinime_BinaryDictionary_calcNormalizedScore) - }, - { - const_cast<char *>("editDistanceNative"), - const_cast<char *>("([I[I)I"), - reinterpret_cast<void *>(latinime_BinaryDictionary_editDistance) - }, - { const_cast<char *>("addUnigramWordNative"), const_cast<char *>("(J[II[IIZZI)V"), reinterpret_cast<void *>(latinime_BinaryDictionary_addUnigramWord) @@ -642,11 +546,6 @@ static const JNINativeMethod sMethods[] = { reinterpret_cast<void *>(latinime_BinaryDictionary_calculateProbabilityNative) }, { - const_cast<char *>("setCurrentTimeForTestNative"), - const_cast<char *>("(I)I"), - reinterpret_cast<void *>(latinime_BinaryDictionary_setCurrentTimeForTest) - }, - { const_cast<char *>("getPropertyNative"), const_cast<char *>("(JLjava/lang/String;)Ljava/lang/String;"), reinterpret_cast<void *>(latinime_BinaryDictionary_getProperty) diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionaryUtils.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionaryUtils.cpp new file mode 100644 index 000000000..f72366481 --- /dev/null +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionaryUtils.cpp @@ -0,0 +1,136 @@ +/* + * 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. + */ + +#define LOG_TAG "LatinIME: jni: BinaryDictionaryUtils" + +#include "com_android_inputmethod_latin_BinaryDictionaryUtils.h" + +#include "defines.h" +#include "jni.h" +#include "jni_common.h" +#include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h" +#include "utils/autocorrection_threshold_utils.h" +#include "utils/char_utils.h" +#include "utils/time_keeper.h" + +namespace latinime { + +static jboolean latinime_BinaryDictionaryUtils_createEmptyDictFile(JNIEnv *env, jclass clazz, + jstring filePath, jlong dictVersion, jstring locale, jobjectArray attributeKeyStringArray, + jobjectArray attributeValueStringArray) { + const jsize filePathUtf8Length = env->GetStringUTFLength(filePath); + char filePathChars[filePathUtf8Length + 1]; + env->GetStringUTFRegion(filePath, 0, env->GetStringLength(filePath), filePathChars); + filePathChars[filePathUtf8Length] = '\0'; + jsize localeLength = env->GetStringLength(locale); + jchar localeCodePoints[localeLength]; + env->GetStringRegion(locale, 0, localeLength, localeCodePoints); + const int keyCount = env->GetArrayLength(attributeKeyStringArray); + const int valueCount = env->GetArrayLength(attributeValueStringArray); + if (keyCount != valueCount) { + return false; + } + + DictionaryHeaderStructurePolicy::AttributeMap attributeMap; + for (int i = 0; i < keyCount; i++) { + jstring keyString = static_cast<jstring>( + env->GetObjectArrayElement(attributeKeyStringArray, i)); + const jsize keyUtf8Length = env->GetStringUTFLength(keyString); + char keyChars[keyUtf8Length + 1]; + env->GetStringUTFRegion(keyString, 0, env->GetStringLength(keyString), keyChars); + keyChars[keyUtf8Length] = '\0'; + DictionaryHeaderStructurePolicy::AttributeMap::key_type key; + HeaderReadWriteUtils::insertCharactersIntoVector(keyChars, &key); + + jstring valueString = static_cast<jstring>( + env->GetObjectArrayElement(attributeValueStringArray, i)); + const jsize valueUtf8Length = env->GetStringUTFLength(valueString); + char valueChars[valueUtf8Length + 1]; + env->GetStringUTFRegion(valueString, 0, env->GetStringLength(valueString), valueChars); + valueChars[valueUtf8Length] = '\0'; + DictionaryHeaderStructurePolicy::AttributeMap::mapped_type value; + HeaderReadWriteUtils::insertCharactersIntoVector(valueChars, &value); + attributeMap[key] = value; + } + + return DictFileWritingUtils::createEmptyDictFile(filePathChars, static_cast<int>(dictVersion), + CharUtils::convertShortArrayToIntVector(localeCodePoints, localeLength), &attributeMap); +} + +static jfloat latinime_BinaryDictionaryUtils_calcNormalizedScore(JNIEnv *env, jclass clazz, + jintArray before, jintArray after, jint score) { + jsize beforeLength = env->GetArrayLength(before); + jsize afterLength = env->GetArrayLength(after); + int beforeCodePoints[beforeLength]; + int afterCodePoints[afterLength]; + env->GetIntArrayRegion(before, 0, beforeLength, beforeCodePoints); + env->GetIntArrayRegion(after, 0, afterLength, afterCodePoints); + return AutocorrectionThresholdUtils::calcNormalizedScore(beforeCodePoints, beforeLength, + afterCodePoints, afterLength, score); +} + +static jint latinime_BinaryDictionaryUtils_editDistance(JNIEnv *env, jclass clazz, jintArray before, + jintArray after) { + jsize beforeLength = env->GetArrayLength(before); + jsize afterLength = env->GetArrayLength(after); + int beforeCodePoints[beforeLength]; + int afterCodePoints[afterLength]; + env->GetIntArrayRegion(before, 0, beforeLength, beforeCodePoints); + env->GetIntArrayRegion(after, 0, afterLength, afterCodePoints); + return AutocorrectionThresholdUtils::editDistance(beforeCodePoints, beforeLength, + afterCodePoints, afterLength); +} + +static int latinime_BinaryDictionaryUtils_setCurrentTimeForTest(JNIEnv *env, jclass clazz, + jint currentTime) { + if (currentTime >= 0) { + TimeKeeper::startTestModeWithForceCurrentTime(currentTime); + } else { + TimeKeeper::stopTestMode(); + } + TimeKeeper::setCurrentTime(); + return TimeKeeper::peekCurrentTime(); +} + +static const JNINativeMethod sMethods[] = { + { + const_cast<char *>("createEmptyDictFileNative"), + const_cast<char *>( + "(Ljava/lang/String;JLjava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)Z"), + reinterpret_cast<void *>(latinime_BinaryDictionaryUtils_createEmptyDictFile) + }, + { + const_cast<char *>("calcNormalizedScoreNative"), + const_cast<char *>("([I[II)F"), + reinterpret_cast<void *>(latinime_BinaryDictionaryUtils_calcNormalizedScore) + }, + { + const_cast<char *>("editDistanceNative"), + const_cast<char *>("([I[I)I"), + reinterpret_cast<void *>(latinime_BinaryDictionaryUtils_editDistance) + }, + { + const_cast<char *>("setCurrentTimeForTestNative"), + const_cast<char *>("(I)I"), + reinterpret_cast<void *>(latinime_BinaryDictionaryUtils_setCurrentTimeForTest) + } +}; + +int register_BinaryDictionaryUtils(JNIEnv *env) { + const char *const kClassPathName = "com/android/inputmethod/latin/utils/BinaryDictionaryUtils"; + return registerNativeMethods(env, kClassPathName, sMethods, NELEMS(sMethods)); +} +} // namespace latinime diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionaryUtils.h b/native/jni/com_android_inputmethod_latin_BinaryDictionaryUtils.h new file mode 100644 index 000000000..38edcd20c --- /dev/null +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionaryUtils.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _COM_ANDROID_INPUTMETHOD_LATIN_BINARYDICTIONARYUTILS_H +#define _COM_ANDROID_INPUTMETHOD_LATIN_BINARYDICTIONARYUTILS_H + +#include "jni.h" + +namespace latinime { +int register_BinaryDictionaryUtils(JNIEnv *env); +} // namespace latinime +#endif // _COM_ANDROID_INPUTMETHOD_LATIN_BINARYDICTIONARYUTILS_H diff --git a/native/jni/jni_common.cpp b/native/jni/jni_common.cpp index f2867d7c3..9fa7ef8f9 100644 --- a/native/jni/jni_common.cpp +++ b/native/jni/jni_common.cpp @@ -20,6 +20,7 @@ #include "com_android_inputmethod_keyboard_ProximityInfo.h" #include "com_android_inputmethod_latin_BinaryDictionary.h" +#include "com_android_inputmethod_latin_BinaryDictionaryUtils.h" #include "com_android_inputmethod_latin_DicTraverseSession.h" #include "defines.h" @@ -42,6 +43,10 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) { AKLOGE("ERROR: BinaryDictionary native registration failed"); return -1; } + if (!latinime::register_BinaryDictionaryUtils(env)) { + AKLOGE("ERROR: BinaryDictionaryUtils native registration failed"); + return -1; + } if (!latinime::register_DicTraverseSession(env)) { AKLOGE("ERROR: DicTraverseSession native registration failed"); return -1; diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelTests.java new file mode 100644 index 000000000..06139b808 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetActionLabelTests.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.keyboard; + +import android.content.res.Resources; +import android.test.suitebuilder.annotation.MediumTest; +import android.text.InputType; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodSubtype; + +import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; +import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.utils.RunInLocale; +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; + +@MediumTest +public final class KeyboardLayoutSetActionLabelTests extends KeyboardLayoutSetTestsBase { + private static void doTestActionKey(final String tag, final KeyboardLayoutSet layoutSet, + final int elementId, final String label, final int iconId) { + final Keyboard keyboard = layoutSet.getKeyboard(elementId); + final Key enterKey = keyboard.getKey(Constants.CODE_ENTER); + assertNotNull(tag + " enter key on " + keyboard.mId, enterKey); + assertEquals(tag + " enter label " + enterKey, label, enterKey.getLabel()); + assertEquals(tag + " enter icon " + enterKey, iconId, enterKey.getIconId()); + } + + private void doTestActionLabel(final String tag, final InputMethodSubtype subtype, + final int actionId, final int labelResId) { + final EditorInfo editorInfo = new EditorInfo(); + editorInfo.imeOptions = actionId; + final RunInLocale<String> job = new RunInLocale<String>() { + @Override + protected String job(final Resources res) { + return res.getString(labelResId); + } + }; + final Resources res = getContext().getResources(); + final String label; + if (subtype.getLocale().equals(SubtypeLocaleUtils.NO_LANGUAGE)) { + // Using system locale. + label = res.getString(labelResId); + } else { + label = job.runInLocale(res, SubtypeLocaleUtils.getSubtypeLocale(subtype)); + } + // Test text layouts. + editorInfo.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL; + final KeyboardLayoutSet layoutSet = createKeyboardLayoutSet(subtype, editorInfo); + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_ALPHABET, + label, KeyboardIconsSet.ICON_UNDEFINED); + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_SYMBOLS, + label, KeyboardIconsSet.ICON_UNDEFINED); + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_SYMBOLS_SHIFTED, + label, KeyboardIconsSet.ICON_UNDEFINED); + // Test phone number layouts. + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_PHONE, + label, KeyboardIconsSet.ICON_UNDEFINED); + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_PHONE_SYMBOLS, + label, KeyboardIconsSet.ICON_UNDEFINED); + // Test normal number layout. + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_NUMBER, + label, KeyboardIconsSet.ICON_UNDEFINED); + // Test number password layouts. + editorInfo.inputType = + InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD; + final KeyboardLayoutSet passwordSet = createKeyboardLayoutSet(subtype, editorInfo); + doTestActionKey(tag, passwordSet, KeyboardId.ELEMENT_NUMBER, + label, KeyboardIconsSet.ICON_UNDEFINED); + } + + private void doTestActionKeyIcon(final String tag, final InputMethodSubtype subtype, + final int actionId, final String iconName) { + final int iconId = KeyboardIconsSet.getIconId(iconName); + final EditorInfo editorInfo = new EditorInfo(); + editorInfo.imeOptions = actionId; + // Test text layouts. + editorInfo.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL; + final KeyboardLayoutSet layoutSet = createKeyboardLayoutSet(subtype, editorInfo); + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_ALPHABET, null /* label */, iconId); + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_SYMBOLS, null /* label */, iconId); + doTestActionKey( + tag, layoutSet, KeyboardId.ELEMENT_SYMBOLS_SHIFTED, null /* label */, iconId); + // Test phone number layouts. + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_PHONE, null /* label */, iconId); + doTestActionKey( + tag, layoutSet, KeyboardId.ELEMENT_PHONE_SYMBOLS, null /* label */, iconId); + // Test normal number layout. + doTestActionKey(tag, layoutSet, KeyboardId.ELEMENT_NUMBER, null /* label */, iconId); + // Test number password layout. + editorInfo.inputType = + InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD; + final KeyboardLayoutSet passwordSet = createKeyboardLayoutSet(subtype, editorInfo); + doTestActionKey(tag, passwordSet, KeyboardId.ELEMENT_NUMBER, null /* label */, iconId); + } + + public void testActionUnspecified() { + for (final InputMethodSubtype subtype : getAllSubtypesList()) { + final String tag = "unspecifiled " + + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); + doTestActionKeyIcon(tag, subtype, EditorInfo.IME_ACTION_UNSPECIFIED, "enter_key"); + } + } + + public void testActionNone() { + for (final InputMethodSubtype subtype : getAllSubtypesList()) { + final String tag = "none " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); + doTestActionKeyIcon(tag, subtype, EditorInfo.IME_ACTION_NONE, "enter_key"); + } + } + + public void testActionGo() { + for (final InputMethodSubtype subtype : getAllSubtypesList()) { + final String tag = "go " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); + doTestActionLabel(tag, subtype, EditorInfo.IME_ACTION_GO, R.string.label_go_key); + } + } + + public void testActionSearch() { + for (final InputMethodSubtype subtype : getAllSubtypesList()) { + final String tag = "search " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); + doTestActionKeyIcon(tag, subtype, EditorInfo.IME_ACTION_SEARCH, "search_key"); + } + } + + public void testActionSend() { + for (final InputMethodSubtype subtype : getAllSubtypesList()) { + final String tag = "send " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); + doTestActionLabel(tag, subtype, EditorInfo.IME_ACTION_SEND, R.string.label_send_key); + } + } + + public void testActionNext() { + for (final InputMethodSubtype subtype : getAllSubtypesList()) { + final String tag = "next " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); + doTestActionLabel(tag, subtype, EditorInfo.IME_ACTION_NEXT, R.string.label_next_key); + } + } + + public void testActionDone() { + for (final InputMethodSubtype subtype : getAllSubtypesList()) { + final String tag = "done " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); + doTestActionLabel(tag, subtype, EditorInfo.IME_ACTION_DONE, R.string.label_done_key); + } + } + + public void testActionPrevious() { + for (final InputMethodSubtype subtype : getAllSubtypesList()) { + final String tag = "previous " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); + doTestActionLabel( + tag, subtype, EditorInfo.IME_ACTION_PREVIOUS, R.string.label_previous_key); + } + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetSubtypesCountTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetSubtypesCountTests.java new file mode 100644 index 000000000..e691639a8 --- /dev/null +++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetSubtypesCountTests.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.keyboard; + +import android.test.suitebuilder.annotation.SmallTest; +import android.view.inputmethod.InputMethodSubtype; + +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; + +import java.util.ArrayList; + +@SmallTest +public class KeyboardLayoutSetSubtypesCountTests extends KeyboardLayoutSetTestsBase { + private static final int NUMBER_OF_SUBTYPES = 63; + private static final int NUMBER_OF_ASCII_CAPABLE_SUBTYPES = 40; + private static final int NUMBER_OF_PREDEFINED_ADDITIONAL_SUBTYPES = 2; + + private static String toString(final ArrayList<InputMethodSubtype> subtypeList) { + final StringBuilder sb = new StringBuilder(); + for (int index = 0; index < subtypeList.size(); index++) { + final InputMethodSubtype subtype = subtypeList.get(index); + sb.append(index + ": "); + sb.append(SubtypeLocaleUtils.getSubtypeNameForLogging(subtype)); + sb.append("\n"); + } + return sb.toString(); + } + + public final void testAllSubtypesCount() { + final ArrayList<InputMethodSubtype> allSubtypesList = getAllSubtypesList(); + assertEquals(toString(allSubtypesList), NUMBER_OF_SUBTYPES, allSubtypesList.size()); + } + + public final void testAsciiCapableSubtypesCount() { + final ArrayList<InputMethodSubtype> asciiCapableSubtypesList = + getAsciiCapableSubtypesList(); + assertEquals(toString(asciiCapableSubtypesList), + NUMBER_OF_ASCII_CAPABLE_SUBTYPES, asciiCapableSubtypesList.size()); + } + + public final void testAdditionalSubtypesCount() { + final ArrayList<InputMethodSubtype> additionalSubtypesList = getAdditionalSubtypesList(); + assertEquals(toString(additionalSubtypesList), + NUMBER_OF_PREDEFINED_ADDITIONAL_SUBTYPES, additionalSubtypesList.size()); + } +} diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java index cd97fc90e..0993c4b67 100644 --- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java +++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java @@ -41,10 +41,6 @@ import java.util.Locale; @SmallTest public class KeyboardLayoutSetTestsBase extends AndroidTestCase { - private static final int NUMBER_OF_SUBTYPES = 63; - private static final int NUMBER_OF_ASCII_CAPABLE_SUBTYPES = 40; - private static final int NUMBER_OF_PREDEFINED_ADDITIONAL_SUBTYPES = 2; - private static final KeyboardTheme DEFAULT_KEYBOARD_THEME = KeyboardSwitcher.KEYBOARD_THEMES[KeyboardSwitcher.THEME_INDEX_DEFAULT]; @@ -82,35 +78,21 @@ public class KeyboardLayoutSetTestsBase extends AndroidTestCase { } } - protected final boolean isPhone() { - return mScreenMetrics == Constants.SCREEN_METRICS_SMALL_PHONE - || mScreenMetrics == Constants.SCREEN_METRICS_LARGE_PHONE; - } - - private static String toString(final ArrayList<InputMethodSubtype> subtypeList) { - final StringBuilder sb = new StringBuilder(); - for (int index = 0; index < subtypeList.size(); index++) { - final InputMethodSubtype subtype = subtypeList.get(index); - sb.append(index + ": "); - sb.append(SubtypeLocaleUtils.getSubtypeNameForLogging(subtype)); - sb.append("\n"); - } - return sb.toString(); + protected final ArrayList<InputMethodSubtype> getAllSubtypesList() { + return mAllSubtypesList; } - public final void testAllSubtypesCount() { - assertEquals(toString(mAllSubtypesList), - NUMBER_OF_SUBTYPES, mAllSubtypesList.size()); + protected final ArrayList<InputMethodSubtype> getAsciiCapableSubtypesList() { + return mAsciiCapableSubtypesList; } - public final void testAsciiCapableSubtypesCount() { - assertEquals(toString(mAsciiCapableSubtypesList), - NUMBER_OF_ASCII_CAPABLE_SUBTYPES, mAsciiCapableSubtypesList.size()); + protected final ArrayList<InputMethodSubtype> getAdditionalSubtypesList() { + return mAdditionalSubtypesList; } - public final void testAdditionalSubtypesCount() { - assertEquals(toString(mAdditionalSubtypesList), - NUMBER_OF_PREDEFINED_ADDITIONAL_SUBTYPES, mAdditionalSubtypesList.size()); + protected final boolean isPhone() { + return mScreenMetrics == Constants.SCREEN_METRICS_SMALL_PHONE + || mScreenMetrics == Constants.SCREEN_METRICS_LARGE_PHONE; } protected final InputMethodSubtype getSubtype(final Locale locale, diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java index fa5123665..69420d6ac 100644 --- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java +++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java @@ -27,6 +27,7 @@ import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FusionDictionary; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.FileUtils; import com.android.inputmethod.latin.utils.LocaleUtils; @@ -111,7 +112,7 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { DictionaryHeader.ATTRIBUTE_VALUE_TRUE); attributeMap.put(DictionaryHeader.HAS_HISTORICAL_INFO_KEY, DictionaryHeader.ATTRIBUTE_VALUE_TRUE); - if (BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(), FormatSpec.VERSION4, + if (BinaryDictionaryUtils.createEmptyDictFile(file.getAbsolutePath(), FormatSpec.VERSION4, LocaleUtils.constructLocaleFromString(TEST_LOCALE), attributeMap)) { return file; } else { @@ -121,11 +122,11 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { } private static int setCurrentTimeForTestMode(final int currentTime) { - return BinaryDictionary.setCurrentTimeForTest(currentTime); + return BinaryDictionaryUtils.setCurrentTimeForTest(currentTime); } private static int stopTestModeInNativeCode() { - return BinaryDictionary.setCurrentTimeForTest(-1); + return BinaryDictionaryUtils.setCurrentTimeForTest(-1); } public void testReadDictInJavaSide() { diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java index c1adf6557..4f9245ce0 100644 --- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java @@ -25,6 +25,7 @@ import com.android.inputmethod.latin.makedict.CodePointUtils; import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; import com.android.inputmethod.latin.makedict.WordProperty; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.FileUtils; import com.android.inputmethod.latin.utils.LanguageModelParam; @@ -59,7 +60,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { file.delete(); file.mkdir(); Map<String, String> attributeMap = new HashMap<String, String>(); - if (BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(), FormatSpec.VERSION4, + if (BinaryDictionaryUtils.createEmptyDictFile(file.getAbsolutePath(), FormatSpec.VERSION4, Locale.ENGLISH, attributeMap)) { return file; } else { diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java index 0ee0fb577..80978df97 100644 --- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java @@ -30,6 +30,7 @@ import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.ByteArrayDictBuffer; import com.android.inputmethod.latin.utils.CollectionUtils; @@ -77,7 +78,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { public BinaryDictDecoderEncoderTests(final long seed, final int maxUnigrams) { super(); - BinaryDictionary.setCurrentTimeForTest(0); + BinaryDictionaryUtils.setCurrentTimeForTest(0); Log.e(TAG, "Testing dictionary: seed is " + seed); final Random random = new Random(seed); sWords.clear(); @@ -112,13 +113,13 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { @Override protected void setUp() throws Exception { super.setUp(); - BinaryDictionary.setCurrentTimeForTest(0); + BinaryDictionaryUtils.setCurrentTimeForTest(0); } @Override protected void tearDown() throws Exception { // Quit test mode. - BinaryDictionary.setCurrentTimeForTest(-1); + BinaryDictionaryUtils.setCurrentTimeForTest(-1); super.tearDown(); } diff --git a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java index 6ace2de4f..04840d667 100644 --- a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java @@ -20,8 +20,8 @@ import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; -import com.android.inputmethod.latin.BinaryDictionary; import com.android.inputmethod.latin.ExpandableBinaryDictionary; +import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.FileUtils; @@ -79,11 +79,11 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { } private static int setCurrentTimeForTestMode(final int currentTime) { - return BinaryDictionary.setCurrentTimeForTest(currentTime); + return BinaryDictionaryUtils.setCurrentTimeForTest(currentTime); } private static int stopTestModeInNativeCode() { - return BinaryDictionary.setCurrentTimeForTest(-1); + return BinaryDictionaryUtils.setCurrentTimeForTest(-1); } /** diff --git a/tests/src/com/android/inputmethod/latin/EditDistanceTests.java b/tests/src/com/android/inputmethod/latin/utils/EditDistanceTests.java index ffec20ab2..58312264b 100644 --- a/tests/src/com/android/inputmethod/latin/EditDistanceTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/EditDistanceTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.inputmethod.latin; +package com.android.inputmethod.latin.utils; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; @@ -29,7 +29,7 @@ public class EditDistanceTests extends AndroidTestCase { * sitting */ public void testExample1() { - final int dist = BinaryDictionary.editDistance("kitten", "sitting"); + final int dist = BinaryDictionaryUtils.editDistance("kitten", "sitting"); assertEquals("edit distance between 'kitten' and 'sitting' is 3", 3, dist); } @@ -42,26 +42,26 @@ public class EditDistanceTests extends AndroidTestCase { * S--unday */ public void testExample2() { - final int dist = BinaryDictionary.editDistance("Saturday", "Sunday"); + final int dist = BinaryDictionaryUtils.editDistance("Saturday", "Sunday"); assertEquals("edit distance between 'Saturday' and 'Sunday' is 3", 3, dist); } public void testBothEmpty() { - final int dist = BinaryDictionary.editDistance("", ""); + final int dist = BinaryDictionaryUtils.editDistance("", ""); assertEquals("when both string are empty, no edits are needed", 0, dist); } public void testFirstArgIsEmpty() { - final int dist = BinaryDictionary.editDistance("", "aaaa"); + final int dist = BinaryDictionaryUtils.editDistance("", "aaaa"); assertEquals("when only one string of the arguments is empty," + " the edit distance is the length of the other.", 4, dist); } public void testSecoondArgIsEmpty() { - final int dist = BinaryDictionary.editDistance("aaaa", ""); + final int dist = BinaryDictionaryUtils.editDistance("aaaa", ""); assertEquals("when only one string of the arguments is empty," + " the edit distance is the length of the other.", 4, dist); @@ -70,27 +70,27 @@ public class EditDistanceTests extends AndroidTestCase { public void testSameStrings() { final String arg1 = "The quick brown fox jumps over the lazy dog."; final String arg2 = "The quick brown fox jumps over the lazy dog."; - final int dist = BinaryDictionary.editDistance(arg1, arg2); + final int dist = BinaryDictionaryUtils.editDistance(arg1, arg2); assertEquals("when same strings are passed, distance equals 0.", 0, dist); } public void testSameReference() { final String arg = "The quick brown fox jumps over the lazy dog."; - final int dist = BinaryDictionary.editDistance(arg, arg); + final int dist = BinaryDictionaryUtils.editDistance(arg, arg); assertEquals("when same string references are passed, the distance equals 0.", 0, dist); } public void testNullArg() { try { - BinaryDictionary.editDistance(null, "aaa"); + BinaryDictionaryUtils.editDistance(null, "aaa"); fail("IllegalArgumentException should be thrown."); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { - BinaryDictionary.editDistance("aaa", null); + BinaryDictionaryUtils.editDistance("aaa", null); fail("IllegalArgumentException should be thrown."); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); diff --git a/tools/dicttool/Android.mk b/tools/dicttool/Android.mk index b83ce57e3..b1dd7f653 100644 --- a/tools/dicttool/Android.mk +++ b/tools/dicttool/Android.mk @@ -41,6 +41,7 @@ USED_TARGETTED_UTILS := \ $(LATINIME_CORE_SOURCE_DIRECTORY)/SuggestedWords.java \ $(LATINIME_CORE_SOURCE_DIRECTORY)/WordComposer.java \ $(LATINIME_CORE_SOURCE_DIRECTORY)/settings/NativeSuggestOptions.java \ + $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/BinaryDictionaryUtils.java \ $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/ByteArrayDictBuffer.java \ $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/CollectionUtils.java \ $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/CombinedFormatUtils.java \ |