aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/latin/LatinIME.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/latin/LatinIME.java')
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java376
1 files changed, 270 insertions, 106 deletions
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 03c11c0c8..270dc4c06 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -46,6 +46,7 @@ import android.text.InputType;
import android.text.TextUtils;
import android.text.style.SuggestionSpan;
import android.util.Log;
+import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.view.KeyCharacterMap;
@@ -86,6 +87,7 @@ import com.android.inputmethod.latin.settings.SettingsActivity;
import com.android.inputmethod.latin.settings.SettingsValues;
import com.android.inputmethod.latin.suggestions.SuggestionStripView;
import com.android.inputmethod.latin.utils.ApplicationUtils;
+import com.android.inputmethod.latin.utils.AsyncResultHolder;
import com.android.inputmethod.latin.utils.AutoCorrectionUtils;
import com.android.inputmethod.latin.utils.CapsModeUtils;
import com.android.inputmethod.latin.utils.CollectionUtils;
@@ -94,7 +96,6 @@ import com.android.inputmethod.latin.utils.InputTypeUtils;
import com.android.inputmethod.latin.utils.IntentUtils;
import com.android.inputmethod.latin.utils.JniUtils;
import com.android.inputmethod.latin.utils.LatinImeLoggerUtils;
-import com.android.inputmethod.latin.utils.PositionalInfoForUserDictPendingAddition;
import com.android.inputmethod.latin.utils.RecapitalizeStatus;
import com.android.inputmethod.latin.utils.StaticInnerHandlerWrapper;
import com.android.inputmethod.latin.utils.TargetPackageInfoGetterTask;
@@ -129,6 +130,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private static final int PERIOD_FOR_AUDIO_AND_HAPTIC_FEEDBACK_IN_KEY_REPEAT = 2;
+ // TODO: Set this value appropriately.
+ private static final int GET_SUGGESTED_WORDS_TIMEOUT = 200;
+
/**
* The name of the scheme used by the Package Manager to warn of a new package installation,
* replacement or removal.
@@ -181,8 +185,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private boolean mIsUserDictionaryAvailable;
private LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
- private PositionalInfoForUserDictPendingAddition
- mPositionalInfoForUserDictPendingAddition = null;
private final WordComposer mWordComposer = new WordComposer();
private final RichInputConnection mConnection = new RichInputConnection(this);
private final RecapitalizeStatus mRecapitalizeStatus = new RecapitalizeStatus();
@@ -221,6 +223,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private final boolean mIsHardwareAcceleratedDrawingEnabled;
public final UIHandler mHandler = new UIHandler(this);
+ private InputUpdater mInputUpdater;
public static final class UIHandler extends StaticInnerHandlerWrapper<LatinIME> {
private static final int MSG_UPDATE_SHIFT_STATE = 0;
@@ -229,8 +232,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private static final int MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP = 3;
private static final int MSG_RESUME_SUGGESTIONS = 4;
private static final int MSG_REOPEN_DICTIONARIES = 5;
+ private static final int MSG_ON_END_BATCH_INPUT = 6;
+ private static final int MSG_RESET_CACHES = 7;
+ private static final int ARG1_NOT_GESTURE_INPUT = 0;
private static final int ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1;
+ private static final int ARG1_SHOW_GESTURE_FLOATING_PREVIEW_TEXT = 2;
+ private static final int ARG2_WITHOUT_TYPED_WORD = 0;
+ private static final int ARG2_WITH_TYPED_WORD = 1;
private int mDelayUpdateSuggestions;
private int mDelayUpdateShiftState;
@@ -263,8 +272,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
switcher.updateShiftState();
break;
case MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP:
- latinIme.showGesturePreviewAndSuggestionStrip((SuggestedWords)msg.obj,
- msg.arg1 == ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT);
+ if (msg.arg1 == ARG1_NOT_GESTURE_INPUT) {
+ if (msg.arg2 == ARG2_WITH_TYPED_WORD) {
+ final Pair<SuggestedWords, String> p =
+ (Pair<SuggestedWords, String>) msg.obj;
+ latinIme.showSuggestionStripWithTypedWord(p.first, p.second);
+ } else {
+ latinIme.showSuggestionStrip((SuggestedWords) msg.obj);
+ }
+ } else {
+ latinIme.showGesturePreviewAndSuggestionStrip((SuggestedWords) msg.obj,
+ msg.arg1 == ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT);
+ }
break;
case MSG_RESUME_SUGGESTIONS:
latinIme.restartSuggestionsOnWordTouchedByCursor();
@@ -276,6 +295,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// get any suggestions. Wait one frame.
postUpdateSuggestionStrip();
break;
+ case MSG_ON_END_BATCH_INPUT:
+ latinIme.onEndBatchInputAsyncInternal((SuggestedWords) msg.obj);
+ break;
+ case MSG_RESET_CACHES:
+ latinIme.retryResetCaches(msg.arg1 == 1 /* tryResumeSuggestions */,
+ msg.arg2 /* remainingTries */);
+ break;
}
}
@@ -292,6 +318,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
sendMessageDelayed(obtainMessage(MSG_RESUME_SUGGESTIONS), mDelayUpdateSuggestions);
}
+ public void postResetCaches(final boolean tryResumeSuggestions, final int remainingTries) {
+ removeMessages(MSG_RESET_CACHES);
+ sendMessage(obtainMessage(MSG_RESET_CACHES, tryResumeSuggestions ? 1 : 0,
+ remainingTries, null));
+ }
+
public void cancelUpdateSuggestionStrip() {
removeMessages(MSG_UPDATE_SUGGESTION_STRIP);
}
@@ -317,9 +349,29 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final boolean dismissGestureFloatingPreviewText) {
removeMessages(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP);
final int arg1 = dismissGestureFloatingPreviewText
- ? ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT : 0;
- obtainMessage(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP, arg1, 0, suggestedWords)
- .sendToTarget();
+ ? ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT
+ : ARG1_SHOW_GESTURE_FLOATING_PREVIEW_TEXT;
+ obtainMessage(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP, arg1,
+ ARG2_WITHOUT_TYPED_WORD, suggestedWords).sendToTarget();
+ }
+
+ public void showSuggestionStrip(final SuggestedWords suggestedWords) {
+ removeMessages(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP);
+ obtainMessage(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP,
+ ARG1_NOT_GESTURE_INPUT, ARG2_WITHOUT_TYPED_WORD, suggestedWords).sendToTarget();
+ }
+
+ // TODO: Remove this method.
+ public void showSuggestionStripWithTypedWord(final SuggestedWords suggestedWords,
+ final String typedWord) {
+ removeMessages(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP);
+ obtainMessage(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP, ARG1_NOT_GESTURE_INPUT,
+ ARG2_WITH_TYPED_WORD,
+ new Pair<SuggestedWords, String>(suggestedWords, typedWord)).sendToTarget();
+ }
+
+ public void onEndBatchInput(final SuggestedWords suggestedWords) {
+ obtainMessage(MSG_ON_END_BATCH_INPUT, suggestedWords).sendToTarget();
}
public void startDoubleSpacePeriodTimer() {
@@ -514,6 +566,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final IntentFilter newDictFilter = new IntentFilter();
newDictFilter.addAction(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION);
registerReceiver(mDictionaryPackInstallReceiver, newDictFilter);
+
+ mInputUpdater = new InputUpdater(this);
}
// Has to be package-visible for unit tests
@@ -650,6 +704,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
PersonalizationDictionarySessionRegister.onDestroy(this);
LatinImeLogger.commit();
LatinImeLogger.onDestroy();
+ if (mInputUpdater != null) {
+ mInputUpdater.onDestroy();
+ mInputUpdater = null;
+ }
super.onDestroy();
}
@@ -805,7 +863,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// span, so we should reset our state unconditionally, even if restarting is true.
mEnteredText = null;
resetComposingState(true /* alsoResetLastComposedWord */);
- if (isDifferentTextField) mHandler.postResumeSuggestions();
mDeleteCount = 0;
mSpaceState = SPACE_STATE_NONE;
mRecapitalizeStatus.deactivate();
@@ -824,8 +881,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
mSuggestedWords = SuggestedWords.EMPTY;
- mConnection.resetCachesUponCursorMove(editorInfo.initialSelStart,
- false /* shouldFinishComposition */);
+ // Sometimes, while rotating, for some reason the framework tells the app we are not
+ // connected to it and that means we can't refresh the cache. In this case, schedule a
+ // refresh later.
+ if (!mConnection.resetCachesUponCursorMoveAndReturnSuccess(editorInfo.initialSelStart,
+ false /* shouldFinishComposition */)) {
+ // We try resetting the caches up to 5 times before giving up.
+ mHandler.postResetCaches(isDifferentTextField, 5 /* remainingTries */);
+ } else {
+ if (isDifferentTextField) mHandler.postResumeSuggestions();
+ }
if (isDifferentTextField) {
mainKeyboardView.closing();
@@ -852,6 +917,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mLastSelectionStart = editorInfo.initialSelStart;
mLastSelectionEnd = editorInfo.initialSelEnd;
+ // In some cases (namely, after rotation of the device) editorInfo.initialSelStart is lying
+ // so we try using some heuristics to find out about these and fix them.
+ tryFixLyingCursorPosition();
mHandler.cancelUpdateSuggestionStrip();
mHandler.cancelDoubleSpacePeriodTimer();
@@ -866,24 +934,40 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
currentSettingsValues.mGestureTrailEnabled,
currentSettingsValues.mGestureFloatingPreviewTextEnabled);
- // If we have a user dictionary addition in progress, we should check now if we should
- // replace the previously committed string with the word that has actually been added
- // to the user dictionary.
- if (null != mPositionalInfoForUserDictPendingAddition
- && mPositionalInfoForUserDictPendingAddition.tryReplaceWithActualWord(
- mConnection, editorInfo, mLastSelectionEnd, currentLocale)) {
- mPositionalInfoForUserDictPendingAddition = null;
- }
- // If tryReplaceWithActualWord returns false, we don't know what word was
- // added to the user dictionary yet, so we keep the data and defer processing. The word will
- // be replaced when the user dictionary reports back with the actual word, which ends
- // up calling #onWordAddedToUserDictionary() in this class.
-
initPersonalizationDebugSettings(currentSettingsValues);
if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
}
+ /**
+ * Try to get the text from the editor to expose lies the framework may have been
+ * telling us. Concretely, when the device rotates, the frameworks tells us about where the
+ * cursor used to be initially in the editor at the time it first received the focus; this
+ * may be completely different from the place it is upon rotation. Since we don't have any
+ * means to get the real value, try at least to ask the text view for some characters and
+ * detect the most damaging cases: when the cursor position is declared to be much smaller
+ * than it really is.
+ */
+ private void tryFixLyingCursorPosition() {
+ final CharSequence textBeforeCursor =
+ mConnection.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0);
+ if (null == textBeforeCursor) {
+ mLastSelectionStart = mLastSelectionEnd = NOT_A_CURSOR_POSITION;
+ } else {
+ final int textLength = textBeforeCursor.length();
+ if (textLength > mLastSelectionStart
+ || (textLength < Constants.EDITOR_CONTENTS_CACHE_SIZE
+ && mLastSelectionStart < Constants.EDITOR_CONTENTS_CACHE_SIZE)) {
+ mLastSelectionStart = textLength;
+ // We can't figure out the value of mLastSelectionEnd :(
+ // But at least if it's smaller than mLastSelectionStart something is wrong
+ if (mLastSelectionStart > mLastSelectionEnd) {
+ mLastSelectionEnd = mLastSelectionStart;
+ }
+ }
+ }
+ }
+
// Initialization of personalization debug settings. This must be called inside
// onStartInputView.
private void initPersonalizationDebugSettings(SettingsValues currentSettingsValues) {
@@ -1038,7 +1122,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// argument as true. But in all cases where we don't reset the entire input state,
// we still want to tell the rich input connection about the new cursor position so
// that it can update its caches.
- mConnection.resetCachesUponCursorMove(newSelStart,
+ mConnection.resetCachesUponCursorMoveAndReturnSuccess(newSelStart,
false /* shouldFinishComposition */);
}
@@ -1218,7 +1302,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
int visibleTopY = extraHeight;
// Need to set touchable region only if input view is being shown
if (visibleKeyboardView.isShown()) {
- if (mSuggestionStripView.getVisibility() == View.VISIBLE) {
+ // Note that the height of Emoji layout is the same as the height of the main keyboard
+ // and the suggestion strip
+ if (mKeyboardSwitcher.isShowingEmojiKeyboard()
+ || mSuggestionStripView.getVisibility() == View.VISIBLE) {
visibleTopY -= suggestionsHeight;
}
final int touchY = mKeyboardSwitcher.isShowingMoreKeysPanel() ? 0 : visibleTopY;
@@ -1271,7 +1358,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} else {
setSuggestedWords(settingsValues.mSuggestPuncList, false);
}
- mConnection.resetCachesUponCursorMove(newCursorPosition, shouldFinishComposition);
+ mConnection.resetCachesUponCursorMoveAndReturnSuccess(newCursorPosition,
+ shouldFinishComposition);
}
private void resetComposingState(final boolean alsoResetLastComposedWord) {
@@ -1375,7 +1463,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|| codePoint == Constants.CODE_CLOSING_PARENTHESIS
|| codePoint == Constants.CODE_CLOSING_SQUARE_BRACKET
|| codePoint == Constants.CODE_CLOSING_CURLY_BRACKET
- || codePoint == Constants.CODE_CLOSING_ANGLE_BRACKET;
+ || codePoint == Constants.CODE_CLOSING_ANGLE_BRACKET
+ || codePoint == Constants.CODE_PLUS;
}
// Callback for the {@link SuggestionStripView}, to call when the "add to dictionary" hint is
@@ -1384,7 +1473,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public void addWordToUserDictionary(final String word) {
if (TextUtils.isEmpty(word)) {
// Probably never supposed to happen, but just in case.
- mPositionalInfoForUserDictPendingAddition = null;
return;
}
final String wordToEdit;
@@ -1396,22 +1484,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mUserDictionary.addWordToUserDictionary(wordToEdit);
}
- public void onWordAddedToUserDictionary(final String newSpelling) {
- // If word was added but not by us, bail out
- if (null == mPositionalInfoForUserDictPendingAddition) return;
- if (mWordComposer.isComposingWord()) {
- // We are late... give up and return
- mPositionalInfoForUserDictPendingAddition = null;
- return;
- }
- mPositionalInfoForUserDictPendingAddition.setActualWordBeingAdded(newSpelling);
- if (mPositionalInfoForUserDictPendingAddition.tryReplaceWithActualWord(
- mConnection, getCurrentInputEditorInfo(), mLastSelectionEnd,
- mSubtypeSwitcher.getCurrentSubtypeLocale())) {
- mPositionalInfoForUserDictPendingAddition = null;
- }
- }
-
private void onSettingsKeyPressed() {
if (isShowingOptionDialog()) return;
showSubtypeSelectorAndSettings();
@@ -1668,7 +1740,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void onStartBatchInput() {
- BatchInputUpdater.getInstance().onStartBatchInput(this);
+ mInputUpdater.onStartBatchInput();
mHandler.cancelUpdateSuggestionStrip();
mConnection.beginBatchEdit();
final SettingsValues settingsValues = mSettings.getCurrent();
@@ -1708,46 +1780,41 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode());
}
- private static final class BatchInputUpdater implements Handler.Callback {
+ private static final class InputUpdater implements Handler.Callback {
private final Handler mHandler;
- private LatinIME mLatinIme;
+ private final LatinIME mLatinIme;
private final Object mLock = new Object();
private boolean mInBatchInput; // synchronized using {@link #mLock}.
- private BatchInputUpdater() {
+ private InputUpdater(final LatinIME latinIme) {
final HandlerThread handlerThread = new HandlerThread(
- BatchInputUpdater.class.getSimpleName());
+ InputUpdater.class.getSimpleName());
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper(), this);
- }
-
- // Initialization-on-demand holder
- private static final class OnDemandInitializationHolder {
- public static final BatchInputUpdater sInstance = new BatchInputUpdater();
- }
-
- public static BatchInputUpdater getInstance() {
- return OnDemandInitializationHolder.sInstance;
+ mLatinIme = latinIme;
}
private static final int MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP = 1;
+ private static final int MSG_GET_SUGGESTED_WORDS = 2;
@Override
public boolean handleMessage(final Message msg) {
switch (msg.what) {
- case MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP:
- updateBatchInput((InputPointers)msg.obj);
- break;
+ case MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP:
+ updateBatchInput((InputPointers)msg.obj);
+ break;
+ case MSG_GET_SUGGESTED_WORDS:
+ mLatinIme.getSuggestedWords(msg.arg1, (OnGetSuggestedWordsCallback) msg.obj);
+ break;
}
return true;
}
// Run in the UI thread.
- public void onStartBatchInput(final LatinIME latinIme) {
+ public void onStartBatchInput() {
synchronized (mLock) {
mHandler.removeMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP);
mInBatchInput = true;
- mLatinIme = latinIme;
mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip(
SuggestedWords.EMPTY, false /* dismissGestureFloatingPreviewText */);
}
@@ -1766,7 +1833,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public void onGetSuggestedWords(final SuggestedWords suggestedWords) {
mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip(
suggestedWords, false /* dismissGestureFloatingPreviewText */);
- }});
+ }
+ });
}
}
@@ -1797,7 +1865,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mInBatchInput = false;
mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip(suggestedWords,
true /* dismissGestureFloatingPreviewText */);
- mLatinIme.onEndBatchInputAsyncInternal(suggestedWords);
+ mLatinIme.mHandler.onEndBatchInput(suggestedWords);
}
});
}
@@ -1808,7 +1876,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private void getSuggestedWordsGestureLocked(final InputPointers batchPointers,
final OnGetSuggestedWordsCallback callback) {
mLatinIme.mWordComposer.setBatchInputPointers(batchPointers);
- mLatinIme.getSuggestedWordsOrOlderSuggestions(Suggest.SESSION_GESTURE,
+ mLatinIme.getSuggestedWordsOrOlderSuggestionsAsync(Suggest.SESSION_GESTURE,
new OnGetSuggestedWordsCallback() {
@Override
public void onGetSuggestedWords(SuggestedWords suggestedWords) {
@@ -1823,11 +1891,23 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
});
}
+
+ public void getSuggestedWords(final int sessionId,
+ final OnGetSuggestedWordsCallback callback) {
+ mHandler.obtainMessage(MSG_GET_SUGGESTED_WORDS, sessionId, 0, callback).sendToTarget();
+ }
+
+ private void onDestroy() {
+ mHandler.removeMessages(MSG_GET_SUGGESTED_WORDS);
+ mHandler.removeMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP);
+ mHandler.getLooper().quit();
+ }
}
+ // This method must run in UI Thread.
private void showGesturePreviewAndSuggestionStrip(final SuggestedWords suggestedWords,
final boolean dismissGestureFloatingPreviewText) {
- showSuggestionStrip(suggestedWords, null);
+ showSuggestionStrip(suggestedWords);
final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
mainKeyboardView.showGestureFloatingPreviewText(suggestedWords);
if (dismissGestureFloatingPreviewText) {
@@ -1837,27 +1917,48 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void onUpdateBatchInput(final InputPointers batchPointers) {
- final SuggestedWordInfo candidate = mSuggestedWords.getAutoCommitCandidate();
- if (null != candidate) {
- if (candidate.mSourceDict.shouldAutoCommit(candidate)) {
- // TODO: implement auto-commit
+ if (mSettings.getCurrent().mPhraseGestureEnabled) {
+ final SuggestedWordInfo candidate = mSuggestedWords.getAutoCommitCandidate();
+ if (null != candidate) {
+ if (candidate.mSourceDict.shouldAutoCommit(candidate)) {
+ final String[] commitParts = candidate.mWord.split(" ", 2);
+ batchPointers.shift(candidate.mIndexOfTouchPointOfSecondWord);
+ promotePhantomSpace();
+ mConnection.commitText(commitParts[0], 0);
+ mSpaceState = SPACE_STATE_PHANTOM;
+ mKeyboardSwitcher.updateShiftState();
+ mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode());
+ }
}
}
- BatchInputUpdater.getInstance().onUpdateBatchInput(batchPointers);
+ mInputUpdater.onUpdateBatchInput(batchPointers);
}
+ // This method must run in UI Thread.
public void onEndBatchInputAsyncInternal(final SuggestedWords suggestedWords) {
final String batchInputText = suggestedWords.isEmpty()
? null : suggestedWords.getWord(0);
if (TextUtils.isEmpty(batchInputText)) {
return;
}
- mWordComposer.setBatchInputWord(batchInputText);
mConnection.beginBatchEdit();
if (SPACE_STATE_PHANTOM == mSpaceState) {
promotePhantomSpace();
}
- mConnection.setComposingText(batchInputText, 1);
+ if (mSettings.getCurrent().mPhraseGestureEnabled) {
+ // Find the last space
+ final int indexOfLastSpace = batchInputText.lastIndexOf(Constants.CODE_SPACE) + 1;
+ if (0 != indexOfLastSpace) {
+ mConnection.commitText(batchInputText.substring(0, indexOfLastSpace), 1);
+ showSuggestionStrip(suggestedWords.getSuggestedWordsForLastWordOfPhraseGesture());
+ }
+ final String lastWord = batchInputText.substring(indexOfLastSpace);
+ mWordComposer.setBatchInputWord(lastWord);
+ mConnection.setComposingText(lastWord, 1);
+ } else {
+ mWordComposer.setBatchInputWord(batchInputText);
+ mConnection.setComposingText(batchInputText, 1);
+ }
mExpectingUpdateSelection = true;
mConnection.endBatchEdit();
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
@@ -1870,7 +1971,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void onEndBatchInput(final InputPointers batchPointers) {
- BatchInputUpdater.getInstance().onEndBatchInput(batchPointers);
+ mInputUpdater.onEndBatchInput(batchPointers);
}
private String specificTldProcessingOnTextInput(final String text) {
@@ -1908,7 +2009,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void onCancelBatchInput() {
- BatchInputUpdater.getInstance().onCancelBatchInput();
+ mInputUpdater.onCancelBatchInput();
}
private void handleBackspace(final int spaceState) {
@@ -2176,7 +2277,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mKeyboardSwitcher.updateShiftState();
}
- // Returns true if we did an autocorrection, false otherwise.
+ // Returns true if we do an autocorrection, false otherwise.
private boolean handleSeparator(final int primaryCode, final int x, final int y,
final int spaceState) {
boolean didAutoCorrect = false;
@@ -2343,14 +2444,21 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return;
}
- final String typedWord = mWordComposer.getTypedWord();
- getSuggestedWordsOrOlderSuggestions(Suggest.SESSION_TYPING,
+ final AsyncResultHolder<SuggestedWords> holder = new AsyncResultHolder<SuggestedWords>();
+ getSuggestedWordsOrOlderSuggestionsAsync(Suggest.SESSION_TYPING,
new OnGetSuggestedWordsCallback() {
- @Override
- public void onGetSuggestedWords(SuggestedWords suggestedWords) {
- showSuggestionStrip(suggestedWords, typedWord);
- }
- });
+ @Override
+ public void onGetSuggestedWords(final SuggestedWords suggestedWords) {
+ holder.set(suggestedWords);
+ }
+ }
+ );
+
+ // This line may cause the current thread to wait.
+ final SuggestedWords suggestedWords = holder.get(null, GET_SUGGESTED_WORDS_TIMEOUT);
+ if (suggestedWords != null) {
+ showSuggestionStrip(suggestedWords);
+ }
}
private void getSuggestedWords(final int sessionId,
@@ -2381,9 +2489,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
additionalFeaturesOptions, sessionId, callback);
}
- private void getSuggestedWordsOrOlderSuggestions(final int sessionId,
+ private void getSuggestedWordsOrOlderSuggestionsAsync(final int sessionId,
final OnGetSuggestedWordsCallback callback) {
- getSuggestedWords(sessionId, new OnGetSuggestedWordsCallback() {
+ mInputUpdater.getSuggestedWords(sessionId, new OnGetSuggestedWordsCallback() {
@Override
public void onGetSuggestedWords(SuggestedWords suggestedWords) {
callback.onGetSuggestedWords(maybeRetrieveOlderSuggestions(
@@ -2429,25 +2537,42 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
false /* isPrediction */);
}
- private void showSuggestionStrip(final SuggestedWords suggestedWords, final String typedWord) {
- if (suggestedWords.isEmpty()) {
- clearSuggestionStrip();
- return;
- }
+ private void setAutoCorrection(final SuggestedWords suggestedWords, final String typedWord) {
+ if (suggestedWords.isEmpty()) return;
final String autoCorrection;
if (suggestedWords.mWillAutoCorrect) {
- autoCorrection = suggestedWords.getWord(1);
+ autoCorrection = suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION);
} else {
+ // We can't use suggestedWords.getWord(SuggestedWords.INDEX_OF_TYPED_WORD)
+ // because it may differ from mWordComposer.mTypedWord.
autoCorrection = typedWord;
}
mWordComposer.setAutoCorrection(autoCorrection);
- final boolean isAutoCorrection = suggestedWords.willAutoCorrect();
- setSuggestedWords(suggestedWords, isAutoCorrection);
- setAutoCorrectionIndicator(isAutoCorrection);
- setSuggestionStripShown(isSuggestionsStripVisible());
}
- private void commitCurrentAutoCorrection(final String separatorString) {
+ private void showSuggestionStripWithTypedWord(final SuggestedWords suggestedWords,
+ final String typedWord) {
+ if (suggestedWords.isEmpty()) {
+ clearSuggestionStrip();
+ return;
+ }
+ setAutoCorrection(suggestedWords, typedWord);
+ final boolean isAutoCorrection = suggestedWords.willAutoCorrect();
+ setSuggestedWords(suggestedWords, isAutoCorrection);
+ setAutoCorrectionIndicator(isAutoCorrection);
+ setSuggestionStripShown(isSuggestionsStripVisible());
+ }
+
+ private void showSuggestionStrip(final SuggestedWords suggestedWords) {
+ if (suggestedWords.isEmpty()) {
+ clearSuggestionStrip();
+ return;
+ }
+ showSuggestionStripWithTypedWord(suggestedWords,
+ suggestedWords.getWord(SuggestedWords.INDEX_OF_TYPED_WORD));
+ }
+
+ private void commitCurrentAutoCorrection(final String separator) {
// Complete any pending suggestions query first
if (mHandler.hasPendingUpdateSuggestions()) {
updateSuggestionStrip();
@@ -2463,16 +2588,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
if (mSettings.isInternal()) {
LatinImeLoggerUtils.onAutoCorrection(
- typedWord, autoCorrection, separatorString, mWordComposer);
+ typedWord, autoCorrection, separator, mWordComposer);
}
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
final SuggestedWords suggestedWords = mSuggestedWords;
ResearchLogger.latinIme_commitCurrentAutoCorrection(typedWord, autoCorrection,
- separatorString, mWordComposer.isBatchMode(), suggestedWords);
+ separator, mWordComposer.isBatchMode(), suggestedWords);
}
mExpectingUpdateSelection = true;
commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD,
- separatorString);
+ separator);
if (!typedWord.equals(autoCorrection)) {
// This will make the correction flash for a short while as a visual clue
// to the user that auto-correction happened. It has no other effect; in particular
@@ -2642,6 +2767,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return prevWord;
}
+ private boolean isResumableWord(final String word, final SettingsValues settings) {
+ final int firstCodePoint = word.codePointAt(0);
+ return settings.isWordCodePoint(firstCodePoint)
+ && Constants.CODE_SINGLE_QUOTE != firstCodePoint
+ && Constants.CODE_DASH != firstCodePoint;
+ }
+
/**
* Check if the cursor is touching a word. If so, restart suggestions on this word, else
* do nothing.
@@ -2651,6 +2783,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// recorrection. This is a temporary, stopgap measure that will be removed later.
// TODO: remove this.
if (mAppWorkAroundsUtils.isBrokenByRecorrection()) return;
+ // A simple way to test for support from the TextView.
+ if (!isSuggestionsStripVisible()) return;
// Recorrection is not supported in languages without spaces because we don't know
// how to segment them yet.
if (!mSettings.getCurrent().mCurrentLanguageHasSpaces) return;
@@ -2663,12 +2797,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final TextRange range = mConnection.getWordRangeAtCursor(currentSettings.mWordSeparators,
0 /* additionalPrecedingWordsCount */);
if (null == range) return; // Happens if we don't have an input connection at all
+ if (range.length() <= 0) return; // Race condition. No text to resume on, so bail out.
// If for some strange reason (editor bug or so) we measure the text before the cursor as
// longer than what the entire text is supposed to be, the safe thing to do is bail out.
final int numberOfCharsInWordBeforeCursor = range.getNumberOfCharsInWordBeforeCursor();
if (numberOfCharsInWordBeforeCursor > mLastSelectionStart) return;
final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
final String typedWord = range.mWord.toString();
+ if (!isResumableWord(typedWord, currentSettings)) return;
int i = 0;
for (final SuggestionSpan span : range.getSuggestionSpansAtWord()) {
for (final String s : span.getSuggestions()) {
@@ -2677,7 +2813,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
suggestions.add(new SuggestedWordInfo(s,
SuggestionStripView.MAX_SUGGESTIONS - i,
SuggestedWordInfo.KIND_RESUMED, Dictionary.DICTIONARY_RESUMED,
- SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE
+ /* autoCommitFirstWordConfidence */));
}
}
}
@@ -2690,9 +2828,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
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.
- getSuggestedWords(Suggest.SESSION_TYPING, new OnGetSuggestedWordsCallback() {
+ mInputUpdater.getSuggestedWords(Suggest.SESSION_TYPING,
+ new OnGetSuggestedWordsCallback() {
@Override
- public void onGetSuggestedWords(SuggestedWords suggestedWordsIncludingTypedWord) {
+ public void onGetSuggestedWords(
+ final SuggestedWords suggestedWordsIncludingTypedWord) {
final SuggestedWords suggestedWords;
if (suggestedWordsIncludingTypedWord.size() > 1) {
// We were able to compute new suggestions for this word.
@@ -2708,8 +2848,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Since there is only one word, willAutoCorrect is false.
suggestedWords = suggestedWordsIncludingTypedWord;
}
+ // We need to pass typedWord because mWordComposer.mTypedWord may differ from
+ // typedWord.
unsetIsAutoCorrectionIndicatorOnAndCallShowSuggestionStrip(suggestedWords,
- typedWord);
+ typedWord);
}});
} else {
// We found suggestion spans in the word. We'll create the SuggestedWords out of
@@ -2718,6 +2860,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
true /* typedWordValid */, false /* willAutoCorrect */,
false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */,
false /* isPrediction */);
+ // We need to pass typedWord because mWordComposer.mTypedWord may differ from typedWord.
unsetIsAutoCorrectionIndicatorOnAndCallShowSuggestionStrip(suggestedWords, typedWord);
}
}
@@ -2731,7 +2874,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// the text to adapt it.
// TODO: remove mIsAutoCorrectionIndicatorOn (see comment on definition)
mIsAutoCorrectionIndicatorOn = false;
- showSuggestionStrip(suggestedWords, typedWord);
+ mHandler.showSuggestionStripWithTypedWord(suggestedWords, typedWord);
}
/**
@@ -2761,6 +2904,27 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mHandler.postUpdateSuggestionStrip();
}
+ /**
+ * Retry resetting caches in the rich input connection.
+ *
+ * When the editor can't be accessed we can't reset the caches, so we schedule a retry.
+ * This method handles the retry, and re-schedules a new retry if we still can't access.
+ * We only retry up to 5 times before giving up.
+ *
+ * @param tryResumeSuggestions Whether we should resume suggestions or not.
+ * @param remainingTries How many times we may try again before giving up.
+ */
+ private void retryResetCaches(final boolean tryResumeSuggestions, final int remainingTries) {
+ if (!mConnection.resetCachesUponCursorMoveAndReturnSuccess(mLastSelectionStart, false)) {
+ if (0 < remainingTries) {
+ mHandler.postResetCaches(tryResumeSuggestions, remainingTries - 1);
+ }
+ return;
+ }
+ tryFixLyingCursorPosition();
+ if (tryResumeSuggestions) mHandler.postResumeSuggestions();
+ }
+
private void revertCommit() {
final String previousWord = mLastComposedWord.mPrevWord;
final String originallyTypedWord = mLastComposedWord.mTypedWord;