aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java218
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java39
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java5
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java203
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java125
5 files changed, 262 insertions, 328 deletions
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 33f09e45b..5a5674f8f 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -35,8 +35,6 @@ import android.inputmethodservice.InputMethodService;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.os.Debug;
-import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
import android.os.SystemClock;
@@ -137,7 +135,6 @@ 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 LeakGuardHandlerWrapper<LatinIME> {
private static final int MSG_UPDATE_SHIFT_STATE = 0;
@@ -183,8 +180,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
switch (msg.what) {
case MSG_UPDATE_SUGGESTION_STRIP:
latinIme.mInputLogic.performUpdateSuggestionStripSync(
- latinIme.mSettings.getCurrent(), this /* handler */,
- latinIme.mInputUpdater);
+ latinIme.mSettings.getCurrent(), this /* handler */);
break;
case MSG_UPDATE_SHIFT_STATE:
switcher.updateShiftState();
@@ -205,8 +201,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
break;
case MSG_RESUME_SUGGESTIONS:
latinIme.mInputLogic.restartSuggestionsOnWordTouchedByCursor(
- latinIme.mSettings.getCurrent(), latinIme.mKeyboardSwitcher,
- latinIme.mInputUpdater);
+ latinIme.mSettings.getCurrent(), 0 /* offset */,
+ false /* includeResumedWordInSuggestions */, latinIme.mKeyboardSwitcher);
break;
case MSG_REOPEN_DICTIONARIES:
latinIme.initSuggest();
@@ -216,7 +212,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
postUpdateSuggestionStrip();
break;
case MSG_ON_END_BATCH_INPUT:
- latinIme.onEndBatchInputAsyncInternal((SuggestedWords) msg.obj);
+ latinIme.mInputLogic.endBatchInputAsyncInternal(latinIme.mSettings.getCurrent(),
+ (SuggestedWords) msg.obj, latinIme.mKeyboardSwitcher);
break;
case MSG_RESET_CACHES:
latinIme.mInputLogic.retryResetCaches(latinIme.mSettings.getCurrent(),
@@ -495,8 +492,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
registerReceiver(mDictionaryPackInstallReceiver, newDictFilter);
DictionaryDecayBroadcastReciever.setUpIntervalAlarmForDictionaryDecaying(this);
-
- mInputUpdater = new InputUpdater(this);
}
// Has to be package-visible for unit tests
@@ -594,9 +589,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
suggest.close();
mInputLogic.mSuggest = null;
}
- if (mInputUpdater != null) {
- mInputUpdater.quitLooper();
- }
mSettings.onDestroy();
unregisterReceiver(mReceiver);
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
@@ -754,12 +746,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// The app calling setText() has the effect of clearing the composing
// span, so we should reset our state unconditionally, even if restarting is true.
- mInputLogic.mEnteredText = null;
- mInputLogic.resetComposingState(true /* alsoResetLastComposedWord */);
- mInputLogic.mDeleteCount = 0;
- mInputLogic.mSpaceState = SpaceState.NONE;
- mInputLogic.mRecapitalizeStatus.deactivate();
- mInputLogic.mCurrentlyPressedHardwareKeys.clear();
+ mInputLogic.startInput(restarting, editorInfo);
// Note: the following does a round-trip IPC on the main thread: be careful
final Locale currentLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
@@ -772,11 +759,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// otherwise it will clear the suggestion strip.
setPunctuationSuggestions();
}
- mInputLogic.mSuggestedWords = SuggestedWords.EMPTY;
// 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.
+ // TODO[IL]: Can the following be moved to InputLogic#startInput?
final boolean canReachInputConnection;
if (!mInputLogic.mConnection.resetCachesUponCursorMoveAndReturnSuccess(
editorInfo.initialSelStart, editorInfo.initialSelEnd,
@@ -823,12 +810,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
setSuggestionStripShownInternal(
isSuggestionsStripVisible(), /* needsInputViewShown */ false);
- mInputLogic.mLastSelectionStart = editorInfo.initialSelStart;
- mInputLogic.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.
- mInputLogic.tryFixLyingCursorPosition();
-
mHandler.cancelUpdateSuggestionStrip();
mHandler.cancelDoubleSpacePeriodTimer();
@@ -872,10 +853,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Remove pending messages related to update suggestions
mHandler.cancelUpdateSuggestionStrip();
// Should do the following in onFinishInputInternal but until JB MR2 it's not called :(
- if (mInputLogic.mWordComposer.isComposingWord()) {
- mInputLogic.mConnection.finishComposingText();
- }
- mInputLogic.resetComposingState(true /* alsoResetLastComposedWord */);
+ mInputLogic.finishInput();
// Notify ResearchLogger
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_onFinishInputViewInternal(finishingInput,
@@ -1252,166 +1230,35 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Implementation of {@link KeyboardActionListener}.
@Override
public void onCodeInput(final int primaryCode, final int x, final int y) {
- mInputLogic.onCodeInput(primaryCode, x, y, mHandler, mInputUpdater,
- mKeyboardSwitcher, mSubtypeSwitcher);
+ mInputLogic.onCodeInput(primaryCode, x, y, mHandler, mKeyboardSwitcher, mSubtypeSwitcher);
}
// Called from PointerTracker through the KeyboardActionListener interface
@Override
public void onTextInput(final String rawText) {
- mInputLogic.onTextInput(mSettings.getCurrent(), rawText, mHandler, mInputUpdater);
+ mInputLogic.onTextInput(mSettings.getCurrent(), rawText, mHandler);
mKeyboardSwitcher.updateShiftState();
mKeyboardSwitcher.onCodeInput(Constants.CODE_OUTPUT_TEXT);
}
@Override
public void onStartBatchInput() {
- mInputLogic.onStartBatchInput(mSettings.getCurrent(), mKeyboardSwitcher, mHandler,
- mInputUpdater);
+ mInputLogic.onStartBatchInput(mSettings.getCurrent(), mKeyboardSwitcher, mHandler);
}
@Override
public void onUpdateBatchInput(final InputPointers batchPointers) {
- mInputLogic.onUpdateBatchInput(mSettings.getCurrent(), batchPointers, mKeyboardSwitcher,
- mInputUpdater);
+ mInputLogic.onUpdateBatchInput(mSettings.getCurrent(), batchPointers, mKeyboardSwitcher);
}
@Override
public void onEndBatchInput(final InputPointers batchPointers) {
- mInputLogic.onEndBatchInput(mSettings.getCurrent(), batchPointers, mInputUpdater);
+ mInputLogic.onEndBatchInput(mSettings.getCurrent(), batchPointers);
}
@Override
public void onCancelBatchInput() {
- mInputLogic.onCancelBatchInput(mHandler, mInputUpdater);
- }
-
- // TODO[IL]: Make this a package-private standalone class in inputlogic/ and remove all
- // references to it in LatinIME
- public static final class InputUpdater implements Handler.Callback {
- private final Handler mHandler;
- private final LatinIME mLatinIme;
- private final Object mLock = new Object();
- private boolean mInBatchInput; // synchronized using {@link #mLock}.
-
- InputUpdater(final LatinIME latinIme) {
- final HandlerThread handlerThread = new HandlerThread(
- InputUpdater.class.getSimpleName());
- handlerThread.start();
- mHandler = new Handler(handlerThread.getLooper(), this);
- 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) {
- // TODO: straighten message passing - we don't need two kinds of messages calling
- // each other.
- switch (msg.what) {
- case MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP:
- updateBatchInput((InputPointers)msg.obj, msg.arg2 /* sequenceNumber */);
- break;
- case MSG_GET_SUGGESTED_WORDS:
- mLatinIme.getSuggestedWords(msg.arg1 /* sessionId */,
- msg.arg2 /* sequenceNumber */, (OnGetSuggestedWordsCallback) msg.obj);
- break;
- }
- return true;
- }
-
- // Run on the UI thread.
- public void onStartBatchInput() {
- synchronized (mLock) {
- mHandler.removeMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP);
- mInBatchInput = true;
- }
- }
-
- // Run on the Handler thread.
- private void updateBatchInput(final InputPointers batchPointers, final int sequenceNumber) {
- synchronized (mLock) {
- if (!mInBatchInput) {
- // Batch input has ended or canceled while the message was being delivered.
- return;
- }
-
- getSuggestedWordsGestureLocked(batchPointers, sequenceNumber,
- new OnGetSuggestedWordsCallback() {
- @Override
- public void onGetSuggestedWords(final SuggestedWords suggestedWords) {
- mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip(
- suggestedWords, false /* dismissGestureFloatingPreviewText */);
- }
- });
- }
- }
-
- // Run on the UI thread.
- public void onUpdateBatchInput(final InputPointers batchPointers,
- final int sequenceNumber) {
- if (mHandler.hasMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP)) {
- return;
- }
- mHandler.obtainMessage(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP, 0 /* arg1 */,
- sequenceNumber /* arg2 */, batchPointers /* obj */).sendToTarget();
- }
-
- public void onCancelBatchInput() {
- synchronized (mLock) {
- mInBatchInput = false;
- }
- }
-
- // Run on the UI thread.
- public void onEndBatchInput(final InputPointers batchPointers) {
- synchronized(mLock) {
- getSuggestedWordsGestureLocked(batchPointers, SuggestedWords.NOT_A_SEQUENCE_NUMBER,
- new OnGetSuggestedWordsCallback() {
- @Override
- public void onGetSuggestedWords(final SuggestedWords suggestedWords) {
- mInBatchInput = false;
- mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip(suggestedWords,
- true /* dismissGestureFloatingPreviewText */);
- mLatinIme.mHandler.onEndBatchInput(suggestedWords);
- }
- });
- }
- }
-
- // {@link LatinIME#getSuggestedWords(int)} method calls with same session id have to
- // be synchronized.
- private void getSuggestedWordsGestureLocked(final InputPointers batchPointers,
- final int sequenceNumber, final OnGetSuggestedWordsCallback callback) {
- mLatinIme.mInputLogic.mWordComposer.setBatchInputPointers(batchPointers);
- getSuggestedWords(Suggest.SESSION_GESTURE, sequenceNumber,
- new OnGetSuggestedWordsCallback() {
- @Override
- public void onGetSuggestedWords(SuggestedWords suggestedWords) {
- if (suggestedWords.isEmpty()) {
- // Previous suggestions are found in InputLogic#mSuggestedWords.
- // Since these are the most recent ones and we just recomputed new
- // ones to update them, it means the previous ones are there.
- callback.onGetSuggestedWords(mLatinIme.mInputLogic.mSuggestedWords);
- } else {
- callback.onGetSuggestedWords(suggestedWords);
- }
- }
- });
- }
-
- public void getSuggestedWords(final int sessionId, final int sequenceNumber,
- final OnGetSuggestedWordsCallback callback) {
- mHandler.obtainMessage(MSG_GET_SUGGESTED_WORDS, sessionId, sequenceNumber, callback)
- .sendToTarget();
- }
-
- void quitLooper() {
- mHandler.removeMessages(MSG_GET_SUGGESTED_WORDS);
- mHandler.removeMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP);
- mHandler.getLooper().quit();
- }
+ mInputLogic.onCancelBatchInput(mHandler);
}
// This method must run on the UI Thread.
@@ -1425,40 +1272,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
- // This method must run on the UI Thread.
- public void onEndBatchInputAsyncInternal(final SuggestedWords suggestedWords) {
- final String batchInputText = suggestedWords.isEmpty() ? null : suggestedWords.getWord(0);
- if (TextUtils.isEmpty(batchInputText)) {
- return;
- }
- mInputLogic.mConnection.beginBatchEdit();
- if (SpaceState.PHANTOM == mInputLogic.mSpaceState) {
- mInputLogic.promotePhantomSpace(mSettings.getCurrent());
- }
- if (mSettings.getCurrent().mPhraseGestureEnabled) {
- // Find the last space
- final int indexOfLastSpace = batchInputText.lastIndexOf(Constants.CODE_SPACE) + 1;
- if (0 != indexOfLastSpace) {
- mInputLogic.mConnection.commitText(batchInputText.substring(0, indexOfLastSpace),
- 1);
- showSuggestionStrip(suggestedWords.getSuggestedWordsForLastWordOfPhraseGesture());
- }
- final String lastWord = batchInputText.substring(indexOfLastSpace);
- mInputLogic.mWordComposer.setBatchInputWord(lastWord);
- mInputLogic.mConnection.setComposingText(lastWord, 1);
- } else {
- mInputLogic.mWordComposer.setBatchInputWord(batchInputText);
- mInputLogic.mConnection.setComposingText(batchInputText, 1);
- }
- mInputLogic.mConnection.endBatchEdit();
- if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
- ResearchLogger.latinIME_onEndBatchInput(batchInputText, 0, suggestedWords);
- }
- // Space state must be updated before calling updateShiftState
- mInputLogic.mSpaceState = SpaceState.PHANTOM;
- mKeyboardSwitcher.updateShiftState();
- }
-
// Called from PointerTracker through the KeyboardActionListener interface
@Override
public void onFinishSlidingInput() {
@@ -1533,7 +1346,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
- private void getSuggestedWords(final int sessionId, final int sequenceNumber,
+ // TODO[IL]: Move this out of LatinIME.
+ public void getSuggestedWords(final int sessionId, final int sequenceNumber,
final OnGetSuggestedWordsCallback callback) {
final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
final Suggest suggest = mInputLogic.mSuggest;
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 37311acf2..4d174ddb8 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -706,45 +706,6 @@ public final class RichInputConnection {
return TextUtils.equals(text, beforeText);
}
- /* (non-javadoc)
- * Returns the word before the cursor if the cursor is at the end of a word, null otherwise
- */
- public CharSequence getWordBeforeCursorIfAtEndOfWord(final SettingsValues settings) {
- // Bail out if the cursor is in the middle of a word (cursor must be followed by whitespace,
- // separator or end of line/text)
- // Example: "test|"<EOL> "te|st" get rejected here
- final CharSequence textAfterCursor = getTextAfterCursor(1, 0);
- if (!TextUtils.isEmpty(textAfterCursor)
- && !settings.isWordSeparator(textAfterCursor.charAt(0))) return null;
-
- // Bail out if word before cursor is 0-length or a single non letter (like an apostrophe)
- // Example: " -|" gets rejected here but "e-|" and "e|" are okay
- CharSequence word = getWordAtCursor(settings.mWordSeparators);
- // We don't suggest on leading single quotes, so we have to remove them from the word if
- // it starts with single quotes.
- while (!TextUtils.isEmpty(word) && Constants.CODE_SINGLE_QUOTE == word.charAt(0)) {
- word = word.subSequence(1, word.length());
- }
- if (TextUtils.isEmpty(word)) return null;
- // Find the last code point of the string
- final int lastCodePoint = Character.codePointBefore(word, word.length());
- // If for some reason the text field contains non-unicode binary data, or if the
- // charsequence is exactly one char long and the contents is a low surrogate, return null.
- if (!Character.isDefined(lastCodePoint)) return null;
- // Bail out if the cursor is not at the end of a word (cursor must be preceded by
- // non-whitespace, non-separator, non-start-of-text)
- // Example ("|" is the cursor here) : <SOL>"|a" " |a" " | " all get rejected here.
- if (settings.isWordSeparator(lastCodePoint)) return null;
- final char firstChar = word.charAt(0); // we just tested that word is not empty
- if (word.length() == 1 && !Character.isLetter(firstChar)) return null;
-
- // We don't restart suggestion if the first character is not a letter, because we don't
- // start composing when the first character is not a letter.
- if (!Character.isLetter(firstChar)) return null;
-
- return word;
- }
-
public boolean revertDoubleSpacePeriod() {
if (DEBUG_BATCH_NESTING) checkBatchEdit();
// Here we test whether we indeed have a period and a space before us. This should not
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 5dc8f3053..fc85c1388 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -126,8 +126,9 @@ public final class Suggest {
} else {
wordComposerForLookup = wordComposer;
}
- mDictionaryFacilitator.getSuggestions(wordComposer, prevWordForBigram, proximityInfo,
- blockOffensiveWords, additionalFeaturesOptions, SESSION_TYPING, suggestionsSet);
+ mDictionaryFacilitator.getSuggestions(wordComposerForLookup, prevWordForBigram,
+ proximityInfo, blockOffensiveWords, additionalFeaturesOptions, SESSION_TYPING,
+ suggestionsSet);
final String whitelistedWord;
if (suggestionsSet.isEmpty()) {
whitelistedWord = null;
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 59b722134..b365003a5 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -88,12 +88,12 @@ public final class InputLogic {
public int mLastSelectionStart = Constants.NOT_A_CURSOR_POSITION;
public int mLastSelectionEnd = Constants.NOT_A_CURSOR_POSITION;
- public int mDeleteCount;
+ private int mDeleteCount;
private long mLastKeyTime;
public final TreeSet<Long> mCurrentlyPressedHardwareKeys = CollectionUtils.newTreeSet();
// Keeps track of most recently inserted text (multi-character key) for reverting
- public String mEnteredText;
+ private String mEnteredText;
// TODO: This boolean is persistent state and causes large side effects at unexpected times.
// Find a way to remove it for readability.
@@ -116,16 +116,33 @@ public final class InputLogic {
* some things must not be done (for example, the keyboard should not be reset to the
* alphabetic layout), so do not send false to this just in case.
*
- * @param restarting whether input is starting in the same field as before.
+ * @param restarting whether input is starting in the same field as before. Unused for now.
+ * @param editorInfo the editorInfo associated with the editor.
*/
- public void startInput(final boolean restarting) {
- mInputLogicHandler = new InputLogicHandler();
+ public void startInput(final boolean restarting, final EditorInfo editorInfo) {
+ mEnteredText = null;
+ resetComposingState(true /* alsoResetLastComposedWord */);
+ mDeleteCount = 0;
+ mSpaceState = SpaceState.NONE;
+ mRecapitalizeStatus.deactivate();
+ mCurrentlyPressedHardwareKeys.clear();
+ mSuggestedWords = SuggestedWords.EMPTY;
+ 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();
+ mInputLogicHandler = new InputLogicHandler(mLatinIME, this);
}
/**
* Clean up the input logic after input is finished.
*/
public void finishInput() {
+ if (mWordComposer.isComposingWord()) {
+ mConnection.finishComposingText();
+ }
+ resetComposingState(true /* alsoResetLastComposedWord */);
mInputLogicHandler.destroy();
mInputLogicHandler = null;
}
@@ -140,11 +157,11 @@ public final class InputLogic {
* @param rawText the text to input.
*/
public void onTextInput(final SettingsValues settingsValues, final String rawText,
- // TODO: remove these arguments
- final LatinIME.UIHandler handler, final LatinIME.InputUpdater inputUpdater) {
+ // TODO: remove this argument
+ final LatinIME.UIHandler handler) {
mConnection.beginBatchEdit();
if (mWordComposer.isComposingWord()) {
- commitCurrentAutoCorrection(settingsValues, rawText, handler, inputUpdater);
+ commitCurrentAutoCorrection(settingsValues, rawText, handler);
} else {
resetComposingState(true /* alsoResetLastComposedWord */);
}
@@ -180,8 +197,8 @@ public final class InputLogic {
* @param y the y-coordinate where the user pressed the key, or NOT_A_COORDINATE.
*/
public void onCodeInput(final int code, final int x, final int y,
- // TODO: remove these four arguments
- final LatinIME.UIHandler handler, final LatinIME.InputUpdater inputUpdater,
+ // TODO: remove these three arguments
+ final LatinIME.UIHandler handler,
final KeyboardSwitcher keyboardSwitcher, final SubtypeSwitcher subtypeSwitcher) {
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_onCodeInput(code, x, y);
@@ -274,16 +291,16 @@ 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, inputUpdater);
+ x, y, spaceState, keyboardSwitcher, handler);
}
break;
case Constants.CODE_SHIFT_ENTER:
didAutoCorrect = handleNonSpecialCharacter(settingsValues, Constants.CODE_ENTER,
- x, y, spaceState, keyboardSwitcher, handler, inputUpdater);
+ x, y, spaceState, keyboardSwitcher, handler);
break;
default:
didAutoCorrect = handleNonSpecialCharacter(settingsValues,
- code, x, y, spaceState, keyboardSwitcher, handler, inputUpdater);
+ code, x, y, spaceState, keyboardSwitcher, handler);
break;
}
keyboardSwitcher.onCodeInput(code);
@@ -300,9 +317,8 @@ public final class InputLogic {
public void onStartBatchInput(final SettingsValues settingsValues,
// TODO: remove these arguments
- final KeyboardSwitcher keyboardSwitcher, final LatinIME.UIHandler handler,
- final LatinIME.InputUpdater inputUpdater) {
- inputUpdater.onStartBatchInput();
+ final KeyboardSwitcher keyboardSwitcher, final LatinIME.UIHandler handler) {
+ mInputLogicHandler.onStartBatchInput();
handler.showGesturePreviewAndSuggestionStrip(
SuggestedWords.EMPTY, false /* dismissGestureFloatingPreviewText */);
handler.cancelUpdateSuggestionStrip();
@@ -329,7 +345,7 @@ public final class InputLogic {
// so we do not attempt to correct, on the assumption that if that was a dictionary
// word, the user would probably have gestured instead.
commitCurrentAutoCorrection(settingsValues, LastComposedWord.NOT_A_SEPARATOR,
- handler, inputUpdater);
+ handler);
} else {
commitTyped(settingsValues, LastComposedWord.NOT_A_SEPARATOR);
}
@@ -374,7 +390,7 @@ public final class InputLogic {
public void onUpdateBatchInput(final SettingsValues settingsValues,
final InputPointers batchPointers,
// TODO: remove these arguments
- final KeyboardSwitcher keyboardSwitcher, final LatinIME.InputUpdater inputUpdater) {
+ final KeyboardSwitcher keyboardSwitcher) {
if (settingsValues.mPhraseGestureEnabled) {
final SuggestedWordInfo candidate = mSuggestedWords.getAutoCommitCandidate();
// If these suggested words have been generated with out of date input pointers, then
@@ -395,20 +411,17 @@ public final class InputLogic {
}
}
}
- inputUpdater.onUpdateBatchInput(batchPointers, mAutoCommitSequenceNumber);
+ mInputLogicHandler.onUpdateBatchInput(batchPointers, mAutoCommitSequenceNumber);
}
public void onEndBatchInput(final SettingsValues settingValues,
- final InputPointers batchPointers,
- // TODO: remove these arguments
- final LatinIME.InputUpdater inputUpdater) {
- inputUpdater.onEndBatchInput(batchPointers);
+ final InputPointers batchPointers) {
+ mInputLogicHandler.onEndBatchInput(batchPointers, mAutoCommitSequenceNumber);
}
- // TODO: remove these arguments
- public void onCancelBatchInput(final LatinIME.UIHandler handler,
- final LatinIME.InputUpdater inputUpdater) {
- inputUpdater.onCancelBatchInput();
+ // TODO: remove this argument
+ public void onCancelBatchInput(final LatinIME.UIHandler handler) {
+ mInputLogicHandler.onCancelBatchInput();
handler.showGesturePreviewAndSuggestionStrip(
SuggestedWords.EMPTY, true /* dismissGestureFloatingPreviewText */);
}
@@ -431,14 +444,13 @@ public final class InputLogic {
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 LatinIME.InputUpdater inputUpdater) {
+ final KeyboardSwitcher keyboardSwitcher, final LatinIME.UIHandler handler) {
mSpaceState = SpaceState.NONE;
final boolean didAutoCorrect;
if (settingsValues.isWordSeparator(codePoint)
|| Character.getType(codePoint) == Character.OTHER_SYMBOL) {
didAutoCorrect = handleSeparator(settingsValues, codePoint, x, y, spaceState,
- keyboardSwitcher, handler, inputUpdater);
+ keyboardSwitcher, handler);
} else {
didAutoCorrect = false;
if (SpaceState.PHANTOM == spaceState) {
@@ -578,8 +590,7 @@ public final class InputLogic {
private boolean handleSeparator(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 LatinIME.InputUpdater inputUpdater) {
+ final KeyboardSwitcher keyboardSwitcher, 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
@@ -595,7 +606,7 @@ public final class InputLogic {
if (settingsValues.mCorrectionEnabled) {
final String separator = shouldAvoidSendingCode ? LastComposedWord.NOT_A_SEPARATOR
: StringUtils.newSingleCodePointString(codePoint);
- commitCurrentAutoCorrection(settingsValues, separator, handler, inputUpdater);
+ commitCurrentAutoCorrection(settingsValues, separator, handler);
didAutoCorrect = true;
} else {
commitTyped(settingsValues, StringUtils.newSingleCodePointString(codePoint));
@@ -669,6 +680,7 @@ public final class InputLogic {
// TODO: remove these arguments
final LatinIME.UIHandler handler, final KeyboardSwitcher keyboardSwitcher) {
mSpaceState = SpaceState.NONE;
+ final int deleteCountAtStart = mDeleteCount;
mDeleteCount++;
// In many cases, we may have to put the keyboard in auto-shift state again. However
@@ -800,12 +812,13 @@ public final class InputLogic {
}
}
}
- if (settingsValues.isSuggestionsRequested()
+ if (settingsValues.isSuggestionStripVisible()
&& settingsValues.mCurrentLanguageHasSpaces) {
- restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(settingsValues, keyboardSwitcher,
- handler);
+ restartSuggestionsOnWordTouchedByCursor(settingsValues,
+ deleteCountAtStart - mDeleteCount /* offset */,
+ true /* includeResumedWordInSuggestions */, keyboardSwitcher);
}
- // We just removed a character. We need to update the auto-caps state.
+ // We just removed at least one character. We need to update the auto-caps state.
keyboardSwitcher.updateShiftState();
}
}
@@ -991,8 +1004,8 @@ public final class InputLogic {
}
public void performUpdateSuggestionStripSync(final SettingsValues settingsValues,
- // TODO: Remove this variable
- final LatinIME.UIHandler handler, final LatinIME.InputUpdater inputUpdater) {
+ // TODO: Remove this argument
+ final LatinIME.UIHandler handler) {
handler.cancelUpdateSuggestionStrip();
// Check if we have a suggestion engine attached.
@@ -1010,7 +1023,7 @@ public final class InputLogic {
}
final AsyncResultHolder<SuggestedWords> holder = new AsyncResultHolder<SuggestedWords>();
- inputUpdater.getSuggestedWords(Suggest.SESSION_TYPING,
+ mInputLogicHandler.getSuggestedWords(Suggest.SESSION_TYPING,
SuggestedWords.NOT_A_SEQUENCE_NUMBER, new OnGetSuggestedWordsCallback() {
@Override
public void onGetSuggestedWords(final SuggestedWords suggestedWords) {
@@ -1031,45 +1044,19 @@ public final class InputLogic {
}
/**
- * Check if the cursor is actually at the end of a word. If so, restart suggestions on this
- * word, otherwise do nothing.
- * @param settingsValues the current values of the settings.
- */
- private void restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(
- final SettingsValues settingsValues,
- // TODO: remove these two arguments
- final KeyboardSwitcher keyboardSwitcher, final LatinIME.UIHandler handler) {
- final CharSequence word = mConnection.getWordBeforeCursorIfAtEndOfWord(settingsValues);
- if (null != word) {
- final String wordString = word.toString();
- mWordComposer.setComposingWord(word,
- // Previous word is the 2nd word before cursor because we are restarting on the
- // 1st word before cursor.
- getNthPreviousWordForSuggestion(settingsValues, 2 /* nthPreviousWord */),
- keyboardSwitcher.getKeyboard());
- final int length = word.length();
- mConnection.deleteSurroundingText(length, 0);
- mConnection.setComposingText(word, 1);
- handler.postUpdateSuggestionStrip();
- // TODO: Handle the case where the user manually moves the cursor and then backs up over
- // a separator. In that case, the current log unit should not be uncommitted.
- if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
- ResearchLogger.getInstance().uncommitCurrentLogUnit(wordString,
- true /* dumpCurrentLogUnit */);
- }
- }
- }
-
- /**
* Check if the cursor is touching a word. If so, restart suggestions on this word, else
* do nothing.
*
* @param settingsValues the current values of the settings.
+ * @param offset how much the cursor is expected to have moved since the last updateSelection.
+ * @param includeResumedWordInSuggestions whether to include the word on which we resume
+ * suggestions in the suggestion list.
*/
// TODO: make this private.
public void restartSuggestionsOnWordTouchedByCursor(final SettingsValues settingsValues,
- // TODO: Remove these argument.
- final KeyboardSwitcher keyboardSwitcher, final LatinIME.InputUpdater inputUpdater) {
+ final int offset, final boolean includeResumedWordInSuggestions,
+ // TODO: Remove this argument.
+ final KeyboardSwitcher keyboardSwitcher) {
// HACK: We may want to special-case some apps that exhibit bad behavior in case of
// recorrection. This is a temporary, stopgap measure that will be removed later.
// TODO: remove this.
@@ -1083,6 +1070,7 @@ public final class InputLogic {
if (mLastSelectionStart != mLastSelectionEnd) return;
// If we don't know the cursor location, return.
if (mLastSelectionStart < 0) return;
+ final int expectedCursorPosition = mLastSelectionStart + offset; // We know Start == End
if (!mConnection.isCursorTouchingWord(settingsValues)) return;
final TextRange range = mConnection.getWordRangeAtCursor(
settingsValues.mWordSeparators, 0 /* additionalPrecedingWordsCount */);
@@ -1091,9 +1079,16 @@ public final class InputLogic {
// 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;
+ if (numberOfCharsInWordBeforeCursor > expectedCursorPosition) return;
final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
final String typedWord = range.mWord.toString();
+ if (includeResumedWordInSuggestions) {
+ suggestions.add(new SuggestedWordInfo(typedWord,
+ SuggestionStripView.MAX_SUGGESTIONS + 1,
+ SuggestedWordInfo.KIND_TYPED, Dictionary.DICTIONARY_USER_TYPED,
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
+ }
if (!isResumableWord(settingsValues, typedWord)) return;
int i = 0;
for (final SuggestionSpan span : range.getSuggestionSpansAtWord()) {
@@ -1118,18 +1113,19 @@ public final class InputLogic {
keyboardSwitcher.getKeyboard());
mWordComposer.setCursorPositionWithinWord(
typedWord.codePointCount(0, numberOfCharsInWordBeforeCursor));
- mConnection.setComposingRegion(mLastSelectionStart - numberOfCharsInWordBeforeCursor,
- mLastSelectionEnd + range.getNumberOfCharsInWordAfterCursor());
+ 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.
- inputUpdater.getSuggestedWords(Suggest.SESSION_TYPING,
+ mInputLogicHandler.getSuggestedWords(Suggest.SESSION_TYPING,
SuggestedWords.NOT_A_SEQUENCE_NUMBER, new OnGetSuggestedWordsCallback() {
@Override
public void onGetSuggestedWords(
final SuggestedWords suggestedWordsIncludingTypedWord) {
final SuggestedWords suggestedWords;
- if (suggestedWordsIncludingTypedWord.size() > 1) {
+ if (suggestedWordsIncludingTypedWord.size() > 1
+ && !includeResumedWordInSuggestions) {
// We were able to compute new suggestions for this word.
// Remove the typed word, since we don't want to display it in this
// case. The #getSuggestedWordsExcludingTypedWord() method sets
@@ -1509,6 +1505,47 @@ public final class InputLogic {
}
/**
+ * Do the final processing after a batch input has ended. This commits the word to the editor.
+ * @param settingsValues the current values of the settings.
+ * @param suggestedWords suggestedWords to use.
+ */
+ public void endBatchInputAsyncInternal(final SettingsValues settingsValues,
+ final SuggestedWords suggestedWords,
+ // TODO: remove this argument
+ final KeyboardSwitcher keyboardSwitcher) {
+ final String batchInputText = suggestedWords.isEmpty() ? null : suggestedWords.getWord(0);
+ if (TextUtils.isEmpty(batchInputText)) {
+ return;
+ }
+ mConnection.beginBatchEdit();
+ if (SpaceState.PHANTOM == mSpaceState) {
+ promotePhantomSpace(settingsValues);
+ }
+ if (settingsValues.mPhraseGestureEnabled) {
+ // Find the last space
+ final int indexOfLastSpace = batchInputText.lastIndexOf(Constants.CODE_SPACE) + 1;
+ if (0 != indexOfLastSpace) {
+ mConnection.commitText(batchInputText.substring(0, indexOfLastSpace), 1);
+ mLatinIME.showSuggestionStrip(
+ suggestedWords.getSuggestedWordsForLastWordOfPhraseGesture());
+ }
+ final String lastWord = batchInputText.substring(indexOfLastSpace);
+ mWordComposer.setBatchInputWord(lastWord);
+ mConnection.setComposingText(lastWord, 1);
+ } else {
+ mWordComposer.setBatchInputWord(batchInputText);
+ mConnection.setComposingText(batchInputText, 1);
+ }
+ mConnection.endBatchEdit();
+ if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
+ ResearchLogger.latinIME_onEndBatchInput(batchInputText, 0, suggestedWords);
+ }
+ // Space state must be updated before calling updateShiftState
+ mSpaceState = SpaceState.PHANTOM;
+ keyboardSwitcher.updateShiftState();
+ }
+
+ /**
* Commit the typed string to the editor.
*
* This is typically called when we should commit the currently composing word without applying
@@ -1552,14 +1589,13 @@ public final class InputLogic {
* @param settingsValues the current value of the settings.
* @param separator the separator that's causing the commit to happen.
*/
- // TODO: Make this private
- public void commitCurrentAutoCorrection(final SettingsValues settingsValues,
+ private void commitCurrentAutoCorrection(final SettingsValues settingsValues,
final String separator,
- // TODO: Remove these arguments.
- final LatinIME.UIHandler handler, final LatinIME.InputUpdater inputUpdater) {
+ // TODO: Remove this argument.
+ final LatinIME.UIHandler handler) {
// Complete any pending suggestions query first
if (handler.hasPendingUpdateSuggestions()) {
- performUpdateSuggestionStripSync(settingsValues, handler, inputUpdater);
+ performUpdateSuggestionStripSync(settingsValues, handler);
}
final String typedAutoCorrection = mWordComposer.getAutoCorrectionOrNull();
final String typedWord = mWordComposer.getTypedWord();
@@ -1645,8 +1681,7 @@ public final class InputLogic {
* detect the most damaging cases: when the cursor position is declared to be much smaller
* than it really is.
*/
- // TODO: make this private
- public void tryFixLyingCursorPosition() {
+ private void tryFixLyingCursorPosition() {
final CharSequence textBeforeCursor = mConnection.getTextBeforeCursor(
Constants.EDITOR_CONTENTS_CACHE_SIZE, 0);
if (null == textBeforeCursor) {
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java
index d611e4bf8..3258dcdfb 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java
@@ -20,18 +20,33 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
+import com.android.inputmethod.latin.InputPointers;
+import com.android.inputmethod.latin.LatinIME;
+import com.android.inputmethod.latin.Suggest;
+import com.android.inputmethod.latin.SuggestedWords;
+import com.android.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback;
+
/**
* A helper to manage deferred tasks for the input logic.
*/
// TODO: Make this package private
public class InputLogicHandler implements Handler.Callback {
final Handler mNonUIThreadHandler;
+ // TODO: remove this reference.
+ final LatinIME mLatinIME;
+ final InputLogic mInputLogic;
+ private final Object mLock = new Object();
+ private boolean mInBatchInput; // synchronized using {@link #mLock}.
+
+ private static final int MSG_GET_SUGGESTED_WORDS = 1;
- public InputLogicHandler() {
+ public InputLogicHandler(final LatinIME latinIME, final InputLogic inputLogic) {
final HandlerThread handlerThread = new HandlerThread(
InputLogicHandler.class.getSimpleName());
handlerThread.start();
mNonUIThreadHandler = new Handler(handlerThread.getLooper(), this);
+ mLatinIME = latinIME;
+ mInputLogic = inputLogic;
}
public void destroy() {
@@ -42,8 +57,116 @@ public class InputLogicHandler implements Handler.Callback {
* Handle a message.
* @see android.os.Handler.Callback#handleMessage(android.os.Message)
*/
+ // Called on the Non-UI handler thread by the Handler code.
@Override
public boolean handleMessage(final Message msg) {
+ switch (msg.what) {
+ case MSG_GET_SUGGESTED_WORDS:
+ mLatinIME.getSuggestedWords(msg.arg1 /* sessionId */,
+ msg.arg2 /* sequenceNumber */, (OnGetSuggestedWordsCallback) msg.obj);
+ break;
+ }
return true;
}
+
+ // Called on the UI thread by InputLogic.
+ public void onStartBatchInput() {
+ synchronized (mLock) {
+ mInBatchInput = true;
+ }
+ }
+
+ /**
+ * Fetch suggestions corresponding to an update of a batch input.
+ * @param batchPointers the updated pointers, including the part that was passed last time.
+ * @param sequenceNumber the sequence number associated with this batch input.
+ * @param forEnd true if this is the end of a batch input, false if it's an update.
+ */
+ // This method can be called from any thread and will see to it that the correct threads
+ // are used for parts that require it. This method will send a message to the Non-UI handler
+ // thread to pull suggestions, and get the inlined callback to get called on the Non-UI
+ // handler thread. If this is the end of a batch input, the callback will then proceed to
+ // send a message to the UI handler in LatinIME so that showing suggestions can be done on
+ // the UI thread.
+ private void updateBatchInput(final InputPointers batchPointers,
+ final int sequenceNumber, final boolean forEnd) {
+ synchronized (mLock) {
+ if (!mInBatchInput) {
+ // Batch input has ended or canceled while the message was being delivered.
+ return;
+ }
+ mInputLogic.mWordComposer.setBatchInputPointers(batchPointers);
+ getSuggestedWords(Suggest.SESSION_GESTURE, sequenceNumber,
+ new OnGetSuggestedWordsCallback() {
+ @Override
+ public void onGetSuggestedWords(SuggestedWords suggestedWords) {
+ // We're now inside the callback. This always runs on the Non-UI thread,
+ // no matter what thread updateBatchInput was originally called on.
+ if (suggestedWords.isEmpty()) {
+ // Use old suggestions if we don't have any new ones.
+ // Previous suggestions are found in InputLogic#mSuggestedWords.
+ // Since these are the most recent ones and we just recomputed
+ // new ones to update them, then the previous ones are there.
+ suggestedWords = mInputLogic.mSuggestedWords;
+ }
+ mLatinIME.mHandler.showGesturePreviewAndSuggestionStrip(suggestedWords,
+ forEnd /* dismissGestureFloatingPreviewText */);
+ if (forEnd) {
+ mInBatchInput = false;
+ // The following call schedules onEndBatchInputAsyncInternal
+ // to be called on the UI thread.
+ mLatinIME.mHandler.onEndBatchInput(suggestedWords);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Update a batch input.
+ *
+ * This fetches suggestions and updates the suggestion strip and the floating text preview.
+ *
+ * @param batchPointers the updated batch pointers.
+ * @param sequenceNumber the sequence number associated with this batch input.
+ */
+ // Called on the UI thread by InputLogic.
+ public void onUpdateBatchInput(final InputPointers batchPointers,
+ final int sequenceNumber) {
+ updateBatchInput(batchPointers, sequenceNumber, false /* forEnd */);
+ }
+
+ /**
+ * Cancel a batch input.
+ *
+ * Note that as opposed to onEndBatchInput, we do the UI side of this immediately on the
+ * same thread, rather than get this to call a method in LatinIME. This is because
+ * canceling a batch input does not necessitate the long operation of pulling suggestions.
+ */
+ // Called on the UI thread by InputLogic.
+ public void onCancelBatchInput() {
+ synchronized (mLock) {
+ mInBatchInput = false;
+ }
+ }
+
+ /**
+ * Finish a batch input.
+ *
+ * This fetches suggestions, updates the suggestion strip and commits the first suggestion.
+ * It also dismisses the floating text preview.
+ *
+ * @param batchPointers the updated batch pointers.
+ * @param sequenceNumber the sequence number associated with this batch input.
+ */
+ // Called on the UI thread by InputLogic.
+ public void onEndBatchInput(final InputPointers batchPointers, final int sequenceNumber) {
+ updateBatchInput(batchPointers, sequenceNumber, true /* forEnd */);
+ }
+
+ public void getSuggestedWords(final int sessionId, final int sequenceNumber,
+ final OnGetSuggestedWordsCallback callback) {
+ mNonUIThreadHandler.obtainMessage(
+ MSG_GET_SUGGESTED_WORDS, sessionId, sequenceNumber, callback).sendToTarget();
+ }
}