diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin')
7 files changed, 125 insertions, 57 deletions
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java index c9bcfe369..aa8bb2ccb 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java @@ -36,6 +36,7 @@ import java.util.HashSet; import java.util.Locale; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; // TODO: Consolidate dictionaries in native code. @@ -55,8 +56,7 @@ public class DictionaryFacilitatorForSuggest { private UserHistoryDictionary mUserHistoryDictionary; private PersonalizationDictionary mPersonalizationDictionary; - @UsedForTesting - private boolean mIsCurrentlyWaitingForMainDictionary = false; + private final CountDownLatch mLatchForWaitingLoadingMainDictionary; public interface DictionaryInitializationListener { public void onUpdateMainDictionaryAvailability(boolean isMainDictionaryAvailable); @@ -77,13 +77,41 @@ public class DictionaryFacilitatorForSuggest { final DictionaryFacilitatorForSuggest oldDictionaryFacilitator) { mContext = context; mLocale = locale; + mLatchForWaitingLoadingMainDictionary = new CountDownLatch(1); initForDebug(settingsValues); - reloadMainDict(context, locale, listener); + loadMainDict(context, locale, listener); setUserDictionary(new UserBinaryDictionary(context, locale)); resetAdditionalDictionaries(oldDictionaryFacilitator, settingsValues); } /** + * Creates instance for reloading the main dict. + * + * @param listener the listener + * @param oldDictionaryFacilitator the instance having old dictionaries. This must not be null. + */ + public DictionaryFacilitatorForSuggest(final DictionaryInitializationListener listener, + final DictionaryFacilitatorForSuggest oldDictionaryFacilitator) { + mContext = oldDictionaryFacilitator.mContext; + mLocale = oldDictionaryFacilitator.mLocale; + mDictionarySubsetForDebug = oldDictionaryFacilitator.mDictionarySubsetForDebug; + mLatchForWaitingLoadingMainDictionary = new CountDownLatch(1); + loadMainDict(mContext, mLocale, listener); + // Transfer user dictionary. + setUserDictionary(oldDictionaryFacilitator.mUserDictionary); + oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_USER); + // Transfer contacts dictionary. + setContactsDictionary(oldDictionaryFacilitator.mContactsDictionary); + oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_CONTACTS); + // Transfer user history dictionary. + setUserHistoryDictionary(oldDictionaryFacilitator.mUserHistoryDictionary); + oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_USER_HISTORY); + // Transfer personalization dictionary. + setPersonalizationDictionary(oldDictionaryFacilitator.mPersonalizationDictionary); + oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_PERSONALIZATION); + } + + /** * Creates instance for when the settings values have been changed. * * @param settingsValues the new settings values @@ -94,6 +122,7 @@ public class DictionaryFacilitatorForSuggest { final DictionaryFacilitatorForSuggest oldDictionaryFacilitator) { mContext = oldDictionaryFacilitator.mContext; mLocale = oldDictionaryFacilitator.mLocale; + mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0); initForDebug(settingsValues); // Transfer main dictionary. setMainDictionary(oldDictionaryFacilitator.mMainDictionary); @@ -110,6 +139,7 @@ public class DictionaryFacilitatorForSuggest { final ArrayList<String> dictionaryTypes, final HashMap<String, File> dictionaryFiles) { mContext = context; mLocale = locale; + mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0); for (final String dictType : dictionaryTypes) { if (dictType.equals(Dictionary.TYPE_MAIN)) { final DictionaryCollection mainDictionary = @@ -167,9 +197,8 @@ public class DictionaryFacilitatorForSuggest { } } - public void reloadMainDict(final Context context, final Locale locale, + private void loadMainDict(final Context context, final Locale locale, final DictionaryInitializationListener listener) { - mIsCurrentlyWaitingForMainDictionary = true; mMainDictionary = null; if (listener != null) { listener.onUpdateMainDictionaryAvailability(hasMainDictionary()); @@ -183,7 +212,7 @@ public class DictionaryFacilitatorForSuggest { if (listener != null) { listener.onUpdateMainDictionaryAvailability(hasMainDictionary()); } - mIsCurrentlyWaitingForMainDictionary = false; + mLatchForWaitingLoadingMainDictionary.countDown(); } }.start(); } @@ -194,9 +223,9 @@ public class DictionaryFacilitatorForSuggest { return null != mMainDictionary && mMainDictionary.isInitialized(); } - @UsedForTesting - public boolean isCurrentlyWaitingForMainDictionary() { - return mIsCurrentlyWaitingForMainDictionary; + public void waitForLoadingMainDictionary(final long timeout, final TimeUnit unit) + throws InterruptedException { + mLatchForWaitingLoadingMainDictionary.await(timeout, unit); } private void setMainDictionary(final Dictionary mainDictionary) { diff --git a/java/src/com/android/inputmethod/latin/InputPointers.java b/java/src/com/android/inputmethod/latin/InputPointers.java index 2e638aaf3..c3bcf3785 100644 --- a/java/src/com/android/inputmethod/latin/InputPointers.java +++ b/java/src/com/android/inputmethod/latin/InputPointers.java @@ -16,14 +16,16 @@ package com.android.inputmethod.latin; +import android.util.Log; + import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.utils.ResizableIntArray; -import android.util.Log; - // TODO: This class is not thread-safe. public final class InputPointers { private static final String TAG = InputPointers.class.getSimpleName(); + private static final boolean DEBUG_TIME = false; + private final int mDefaultCapacity; private final ResizableIntArray mXCoordinates; private final ResizableIntArray mYCoordinates; @@ -38,11 +40,29 @@ public final class InputPointers { mTimes = new ResizableIntArray(defaultCapacity); } - public void addPointer(int index, int x, int y, int pointerId, int time) { - mXCoordinates.add(index, x); - mYCoordinates.add(index, y); - mPointerIds.add(index, pointerId); - mTimes.add(index, time); + private void fillWithLastTimeUntil(final int index) { + final int fromIndex = mTimes.getLength(); + // Fill the gap with the latest time. + // See {@link #getTime(int)} and {@link #isValidTimeStamps()}. + if (fromIndex <= 0) { + return; + } + final int fillLength = index - fromIndex + 1; + if (fillLength <= 0) { + return; + } + final int lastTime = mTimes.get(fromIndex - 1); + mTimes.fill(lastTime, fromIndex, fillLength); + } + + public void addPointerAt(int index, int x, int y, int pointerId, int time) { + mXCoordinates.addAt(index, x); + mYCoordinates.addAt(index, y); + mPointerIds.addAt(index, pointerId); + if (LatinImeLogger.sDBG || DEBUG_TIME) { + fillWithLastTimeUntil(index); + } + mTimes.addAt(index, time); } @UsedForTesting @@ -68,23 +88,6 @@ public final class InputPointers { } /** - * Append the pointers in the specified {@link InputPointers} to the end of this. - * @param src the source {@link InputPointers} to read the data from. - * @param startPos the starting index of the pointers in {@code src}. - * @param length the number of pointers to be appended. - */ - @UsedForTesting - void append(InputPointers src, int startPos, int length) { - if (length == 0) { - return; - } - mXCoordinates.append(src.mXCoordinates, startPos, length); - mYCoordinates.append(src.mYCoordinates, startPos, length); - mPointerIds.append(src.mPointerIds, startPos, length); - mTimes.append(src.mTimes, startPos, length); - } - - /** * Append the times, x-coordinates and y-coordinates in the specified {@link ResizableIntArray} * to the end of this. * @param pointerId the pointer id of the source. @@ -141,7 +144,7 @@ public final class InputPointers { } public int[] getTimes() { - if (LatinImeLogger.sDBG) { + if (LatinImeLogger.sDBG || DEBUG_TIME) { if (!isValidTimeStamps()) { throw new RuntimeException("Time stamps are invalid."); } @@ -157,10 +160,11 @@ public final class InputPointers { private boolean isValidTimeStamps() { final int[] times = mTimes.getPrimitiveArray(); - for (int i = 1; i < getPointerSize(); ++i) { + final int size = getPointerSize(); + for (int i = 1; i < size; ++i) { if (times[i] < times[i - 1]) { // dump - for (int j = 0; j < times.length; ++j) { + for (int j = 0; j < size; ++j) { Log.d(TAG, "--- (" + j + ") " + times[j]); } return false; diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index b7f035747..aadb65192 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -89,6 +89,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Locale; +import java.util.concurrent.TimeUnit; /** * Input method implementation for Qwerty'ish keyboard. @@ -519,10 +520,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen new DictionaryFacilitatorForSuggest(currentSettingsValues, oldDictionaryFacilitator); // Create Suggest instance with the new dictionary facilitator. - mInputLogic.mSuggest = new Suggest(suggest /* oldSuggest */, dictionaryFacilitator); - suggest.close(); + resetSuggest(new Suggest(suggest /* oldSuggest */, dictionaryFacilitator)); + } else if (suggest == null) { + initSuggestForLocale(locale); } - if (currentSettingsValues.mUsePersonalizedDicts) { + } + + private void refreshPersonalizationDictionarySession() { + if (mSettings.getCurrent().mUsePersonalizedDicts) { if (mSubtypeSwitcher.isSystemLocaleSameAsLocaleOfAllEnabledSubtypes()) { final DictionaryFacilitatorForSuggest dictionaryFacilitator = (mInputLogic.mSuggest == null) ? @@ -562,33 +567,41 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } else { subtypeLocale = switcherSubtypeLocale; } + initSuggestForLocale(subtypeLocale); + } + private void initSuggestForLocale(final Locale locale) { final SettingsValues settingsValues = mSettings.getCurrent(); final DictionaryFacilitatorForSuggest oldDictionaryFacilitator = (mInputLogic.mSuggest == null) ? null : mInputLogic.mSuggest.mDictionaryFacilitator; // Creates new dictionary facilitator for the new locale. final DictionaryFacilitatorForSuggest dictionaryFacilitator = - new DictionaryFacilitatorForSuggest(this /* context */, subtypeLocale, + new DictionaryFacilitatorForSuggest(this /* context */, locale, settingsValues, this /* DictionaryInitializationListener */, oldDictionaryFacilitator); - PersonalizationDictionarySessionRegistrar.onConfigurationChanged( - this, getResources().getConfiguration(), dictionaryFacilitator); - final Suggest newSuggest = new Suggest(subtypeLocale, dictionaryFacilitator); + final Suggest newSuggest = new Suggest(locale, dictionaryFacilitator); if (settingsValues.mCorrectionEnabled) { newSuggest.setAutoCorrectionThreshold(settingsValues.mAutoCorrectionThreshold); } + resetSuggest(newSuggest); + } + + /* package private */ void resetSuggestMainDict() { + final DictionaryFacilitatorForSuggest oldDictionaryFacilitator = + mInputLogic.mSuggest.mDictionaryFacilitator; + final DictionaryFacilitatorForSuggest dictionaryFacilitator = + new DictionaryFacilitatorForSuggest(this /* listener */, oldDictionaryFacilitator); + resetSuggest(new Suggest(mInputLogic.mSuggest /* oldSuggest */, dictionaryFacilitator)); + } + + private void resetSuggest(final Suggest newSuggest) { if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.getInstance().initDictionary(newSuggest.mDictionaryFacilitator); } final Suggest oldSuggest = mInputLogic.mSuggest; mInputLogic.mSuggest = newSuggest; if (oldSuggest != null) oldSuggest.close(); - } - - /* package private */ void resetSuggestMainDict() { - final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); - mInputLogic.mSuggest.mDictionaryFacilitator.reloadMainDict(this, subtypeLocale, - this /* SuggestInitializationListener */); + refreshPersonalizationDictionarySession(); } @Override @@ -1789,14 +1802,20 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // DO NOT USE THIS for any other purpose than testing. This is information private to LatinIME. @UsedForTesting - /* package for test */ boolean isCurrentlyWaitingForMainDictionary() { - return mInputLogic.mSuggest.mDictionaryFacilitator.isCurrentlyWaitingForMainDictionary(); + /* package for test */ void waitForMainDictionary(final long timeout, final TimeUnit unit) + throws InterruptedException { + mInputLogic.mSuggest.mDictionaryFacilitator.waitForLoadingMainDictionary(timeout, unit); } // DO NOT USE THIS for any other purpose than testing. This can break the keyboard badly. @UsedForTesting - /* package for test */ void replaceMainDictionaryForTest(final Locale locale) { - mInputLogic.mSuggest.mDictionaryFacilitator.reloadMainDict(this, locale, null); + /* package for test */ void replaceDictionariesForTest(final Locale locale) { + final DictionaryFacilitatorForSuggest oldDictionaryFacilitator = + mInputLogic.mSuggest.mDictionaryFacilitator; + final DictionaryFacilitatorForSuggest dictionaryFacilitator = + new DictionaryFacilitatorForSuggest(this, locale, mSettings.getCurrent(), + this /* listener */, oldDictionaryFacilitator); + resetSuggest(new Suggest(locale, dictionaryFacilitator)); } public void debugDumpStateAndCrashWithException(final String context) { diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index c6049da9f..79b91f32d 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -684,6 +684,10 @@ public final class RichInputConnection { && !settingsValues.isWordConnector(codePointBeforeCursor)) { return true; } + return isCursorFollowedByWordCharacter(settingsValues); + } + + public boolean isCursorFollowedByWordCharacter(final SettingsValues settingsValues) { final CharSequence after = getTextAfterCursor(1, 0); if (!TextUtils.isEmpty(after) && !settingsValues.isWordSeparator(after.charAt(0)) && !settingsValues.isWordConnector(after.charAt(0))) { diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index f078c7346..b4f2d1a58 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -186,7 +186,7 @@ public final class WordComposer { // (See {@link #setBatchInputWord}). if (!mIsBatchMode) { // TODO: Set correct pointer id and time - mInputPointers.addPointer(newIndex, keyX, keyY, 0, 0); + mInputPointers.addPointerAt(newIndex, keyX, keyY, 0, 0); } } mIsFirstCharCapitalized = isFirstCharCapitalized( diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index cc42d8785..968129a96 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -813,7 +813,8 @@ public final class InputLogic { } } if (settingsValues.isSuggestionStripVisible() - && settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces) { + && settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces + && !mConnection.isCursorFollowedByWordCharacter(settingsValues)) { restartSuggestionsOnWordTouchedByCursor(settingsValues, deleteCountAtStart - mDeleteCount /* offset */, true /* includeResumedWordInSuggestions */, keyboardSwitcher); @@ -1114,8 +1115,19 @@ public final class InputLogic { keyboardSwitcher.getKeyboard()); mWordComposer.setCursorPositionWithinWord( typedWord.codePointCount(0, numberOfCharsInWordBeforeCursor)); - mConnection.setComposingRegion(expectedCursorPosition - numberOfCharsInWordBeforeCursor, + // TODO: Change these lines to setComposingRegion(cursorPosition, + // cursorPosition + range.getNumberOfCharsInWordAfterCursor()); + if (0 != offset) { + // Backspace was pressed. We are at the end of a word, and we don't know the cursor + // position for sure, so use relative methods. + mConnection.deleteSurroundingText(numberOfCharsInWordBeforeCursor, 0); + mConnection.setComposingText(typedWord, 1); + } else { + // This is recorrection. The cursor position is reasonably reliable, and the cursor + // may be in the middle of a word so use setComposingRegion. + mConnection.setComposingRegion(expectedCursorPosition - numberOfCharsInWordBeforeCursor, expectedCursorPosition + range.getNumberOfCharsInWordAfterCursor()); + } if (suggestions.isEmpty()) { // We come here if there weren't any suggestion spans on this word. We will try to // compute suggestions for it instead. diff --git a/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java b/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java index 7c6fe93ac..64c9e2cff 100644 --- a/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java +++ b/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java @@ -34,7 +34,7 @@ public final class ResizableIntArray { throw new ArrayIndexOutOfBoundsException("length=" + mLength + "; index=" + index); } - public void add(final int index, final int val) { + public void addAt(final int index, final int val) { if (index < mLength) { mArray[index] = val; } else { |