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.java598
1 files changed, 384 insertions, 214 deletions
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 5c5b7b7c0..d8a47a307 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -73,9 +73,12 @@ import com.android.inputmethod.keyboard.KeyboardActionListener;
import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.keyboard.MainKeyboardView;
+import com.android.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.define.ProductionFlag;
-import com.android.inputmethod.latin.personalization.PersonalizationDictionaryHelper;
+import com.android.inputmethod.latin.personalization.PersonalizationDictionary;
+import com.android.inputmethod.latin.personalization.PersonalizationDictionarySessionRegister;
+import com.android.inputmethod.latin.personalization.PersonalizationHelper;
import com.android.inputmethod.latin.personalization.PersonalizationPredictionDictionary;
import com.android.inputmethod.latin.personalization.UserHistoryPredictionDictionary;
import com.android.inputmethod.latin.settings.Settings;
@@ -83,6 +86,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;
@@ -91,11 +95,11 @@ 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;
import com.android.inputmethod.latin.utils.TextRange;
+import com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils;
import com.android.inputmethod.research.ResearchLogger;
import java.io.FileDescriptor;
@@ -123,6 +127,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private static final int PENDING_IMS_CALLBACK_DURATION = 800;
+ 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.
@@ -171,11 +180,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private UserBinaryDictionary mUserDictionary;
private UserHistoryPredictionDictionary mUserHistoryPredictionDictionary;
private PersonalizationPredictionDictionary mPersonalizationPredictionDictionary;
+ private PersonalizationDictionary mPersonalizationDictionary;
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();
@@ -190,7 +198,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private boolean mExpectingUpdateSelection;
private int mDeleteCount;
private long mLastKeyTime;
- private TreeSet<Long> mCurrentlyPressedHardwareKeys = CollectionUtils.newTreeSet();
+ private final TreeSet<Long> mCurrentlyPressedHardwareKeys = CollectionUtils.newTreeSet();
+ // Personalization debugging params
+ private boolean mUseOnlyPersonalizationDictionaryForDebug = false;
+ private boolean mBoostPersonalizationDictionaryForDebug = false;
// Member variables for remembering the current device orientation.
private int mDisplayOrientation;
@@ -211,6 +222,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;
@@ -219,8 +231,11 @@ 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 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 int mDelayUpdateSuggestions;
private int mDelayUpdateShiftState;
@@ -253,8 +268,12 @@ 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) {
+ 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();
@@ -266,6 +285,9 @@ 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;
}
}
@@ -307,11 +329,22 @@ 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;
+ ? ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT
+ : ARG1_SHOW_GESTURE_FLOATING_PREVIEW_TEXT;
obtainMessage(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP, arg1, 0, 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, 0, suggestedWords).sendToTarget();
+ }
+
+ public void onEndBatchInput(final SuggestedWords suggestedWords) {
+ obtainMessage(MSG_ON_END_BATCH_INPUT, suggestedWords).sendToTarget();
+ }
+
public void startDoubleSpacePeriodTimer() {
mDoubleSpacePeriodTimerStart = SystemClock.uptimeMillis();
}
@@ -472,6 +505,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
KeyboardSwitcher.init(this);
AudioAndHapticFeedbackManager.init(this);
AccessibilityUtils.init(this);
+ PersonalizationDictionarySessionRegister.init(this);
super.onCreate();
@@ -503,6 +537,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
@@ -558,10 +594,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
- mUserHistoryPredictionDictionary = PersonalizationDictionaryHelper
+ mUserHistoryPredictionDictionary = PersonalizationHelper
.getUserHistoryPredictionDictionary(this, localeStr, prefs);
newSuggest.setUserHistoryPredictionDictionary(mUserHistoryPredictionDictionary);
- mPersonalizationPredictionDictionary = PersonalizationDictionaryHelper
+ mPersonalizationDictionary = PersonalizationHelper
+ .getPersonalizationDictionary(this, localeStr, prefs);
+ newSuggest.setPersonalizationDictionary(mPersonalizationDictionary);
+ mPersonalizationPredictionDictionary = PersonalizationHelper
.getPersonalizationPredictionDictionary(this, localeStr, prefs);
newSuggest.setPersonalizationPredictionDictionary(mPersonalizationPredictionDictionary);
@@ -633,8 +672,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
ResearchLogger.getInstance().onDestroy();
}
unregisterReceiver(mDictionaryPackInstallReceiver);
+ PersonalizationDictionarySessionRegister.onDestroy(this);
LatinImeLogger.commit();
LatinImeLogger.onDestroy();
+ if (mInputUpdater != null) {
+ mInputUpdater.onDestroy();
+ mInputUpdater = null;
+ }
super.onDestroy();
}
@@ -652,6 +696,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mOptionsDialog.dismiss();
}
}
+ PersonalizationDictionarySessionRegister.onConfigurationChanged(this, conf);
super.onConfigurationChanged(conf);
}
@@ -850,22 +895,35 @@ 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");
}
+ // Initialization of personalization debug settings. This must be called inside
+ // onStartInputView.
+ private void initPersonalizationDebugSettings(SettingsValues currentSettingsValues) {
+ if (mUseOnlyPersonalizationDictionaryForDebug
+ != currentSettingsValues.mUseOnlyPersonalizationDictionaryForDebug) {
+ // Only for debug
+ initSuggest();
+ mUseOnlyPersonalizationDictionaryForDebug =
+ currentSettingsValues.mUseOnlyPersonalizationDictionaryForDebug;
+ }
+
+ if (mBoostPersonalizationDictionaryForDebug !=
+ currentSettingsValues.mBoostPersonalizationDictionaryForDebug) {
+ // Only for debug
+ mBoostPersonalizationDictionaryForDebug =
+ currentSettingsValues.mBoostPersonalizationDictionaryForDebug;
+ if (mBoostPersonalizationDictionaryForDebug) {
+ UserHistoryForgettingCurveUtils.boostMaxFreqForDebug();
+ } else {
+ UserHistoryForgettingCurveUtils.resetMaxFreqForDebug();
+ }
+ }
+ }
+
// Callback for the TargetPackageInfoGetterTask
@Override
public void onTargetPackageInfoKnown(final PackageInfo info) {
@@ -1135,11 +1193,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return currentHeight;
}
- final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
- if (mainKeyboardView == null) {
+ final View visibleKeyboardView = mKeyboardSwitcher.getVisibleKeyboardView();
+ if (visibleKeyboardView == null) {
return 0;
}
- final int keyboardHeight = mainKeyboardView.getHeight();
+ // TODO: !!!!!!!!!!!!!!!!!!!! Handle different backing view heights between the main !!!
+ // keyboard and the emoji keyboard. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ final int keyboardHeight = visibleKeyboardView.getHeight();
final int suggestionsHeight = mSuggestionStripView.getHeight();
final int displayHeight = getResources().getDisplayMetrics().heightPixels;
final Rect rect = new Rect();
@@ -1157,8 +1217,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void onComputeInsets(final InputMethodService.Insets outInsets) {
super.onComputeInsets(outInsets);
- final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
- if (mainKeyboardView == null || mSuggestionStripView == null) {
+ final View visibleKeyboardView = mKeyboardSwitcher.getVisibleKeyboardView();
+ if (visibleKeyboardView == null || mSuggestionStripView == null) {
return;
}
final int adjustedBackingHeight = getAdjustedBackingViewHeight();
@@ -1173,13 +1233,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final int extraHeight = extractHeight + backingHeight + suggestionsHeight;
int visibleTopY = extraHeight;
// Need to set touchable region only if input view is being shown
- if (mainKeyboardView.isShown()) {
- if (mSuggestionStripView.getVisibility() == View.VISIBLE) {
+ if (visibleKeyboardView.isShown()) {
+ // 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 = mainKeyboardView.isShowingMoreKeysPanel() ? 0 : visibleTopY;
- final int touchWidth = mainKeyboardView.getWidth();
- final int touchHeight = mainKeyboardView.getHeight() + extraHeight
+ final int touchY = mKeyboardSwitcher.isShowingMoreKeysPanel() ? 0 : visibleTopY;
+ final int touchWidth = visibleKeyboardView.getWidth();
+ final int touchHeight = visibleKeyboardView.getHeight() + extraHeight
// Extend touchable region below the keyboard.
+ EXTENDED_TOUCHABLE_REGION_HEIGHT;
outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION;
@@ -1340,7 +1403,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;
@@ -1352,26 +1414,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 static boolean isAlphabet(final int code) {
- return Character.isLetter(code);
- }
-
private void onSettingsKeyPressed() {
if (isShowingOptionDialog()) return;
showSubtypeSelectorAndSettings();
@@ -1479,7 +1521,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
break;
case Constants.CODE_SHIFT:
// Note: Calling back to the keyboard on Shift key is handled in
- // {@link #onPressKey(int,boolean)} and {@link #onReleaseKey(int,boolean)}.
+ // {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}.
final Keyboard currentKeyboard = switcher.getKeyboard();
if (null != currentKeyboard && currentKeyboard.mId.isAlphabetKeyboard()) {
// TODO: Instead of checking for alphabetic keyboard here, separate keycodes for
@@ -1493,7 +1535,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
break;
case Constants.CODE_SWITCH_ALPHA_SYMBOL:
// Note: Calling back to the keyboard on symbol key is handled in
- // {@link #onPressKey(int,boolean)} and {@link #onReleaseKey(int,boolean)}.
+ // {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}.
break;
case Constants.CODE_SETTINGS:
onSettingsKeyPressed();
@@ -1511,7 +1553,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
handleLanguageSwitchKey();
break;
case Constants.CODE_EMOJI:
- // TODO: Implement emoji keyboard switch.
+ // Note: Switching emoji keyboard is being handled in
+ // {@link KeyboardState#onCodeInput(int,int)}.
break;
case Constants.CODE_ENTER:
final EditorInfo editorInfo = getCurrentInputEditorInfo();
@@ -1627,7 +1670,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();
@@ -1667,46 +1710,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 */);
}
@@ -1719,9 +1757,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Batch input has ended or canceled while the message was being delivered.
return;
}
- final SuggestedWords suggestedWords = getSuggestedWordsGestureLocked(batchPointers);
- mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip(
- suggestedWords, false /* dismissGestureFloatingPreviewText */);
+
+ getSuggestedWordsGestureLocked(batchPointers, new OnGetSuggestedWordsCallback() {
+ @Override
+ public void onGetSuggestedWords(final SuggestedWords suggestedWords) {
+ mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip(
+ suggestedWords, false /* dismissGestureFloatingPreviewText */);
+ }
+ });
}
}
@@ -1744,35 +1787,57 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
// Run in the UI thread.
- public SuggestedWords onEndBatchInput(final InputPointers batchPointers) {
- synchronized (mLock) {
- mInBatchInput = false;
- final SuggestedWords suggestedWords = getSuggestedWordsGestureLocked(batchPointers);
- mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip(
- suggestedWords, true /* dismissGestureFloatingPreviewText */);
- return suggestedWords;
+ public void onEndBatchInput(final InputPointers batchPointers) {
+ synchronized(mLock) {
+ getSuggestedWordsGestureLocked(batchPointers, 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 SuggestedWords getSuggestedWordsGestureLocked(final InputPointers batchPointers) {
+ private void getSuggestedWordsGestureLocked(final InputPointers batchPointers,
+ final OnGetSuggestedWordsCallback callback) {
mLatinIme.mWordComposer.setBatchInputPointers(batchPointers);
- final SuggestedWords suggestedWords =
- mLatinIme.getSuggestedWordsOrOlderSuggestions(Suggest.SESSION_GESTURE);
- final int suggestionCount = suggestedWords.size();
- if (suggestionCount <= 1) {
- final String mostProbableSuggestion = (suggestionCount == 0) ? null
- : suggestedWords.getWord(0);
- return mLatinIme.getOlderSuggestions(mostProbableSuggestion);
- }
- return suggestedWords;
+ mLatinIme.getSuggestedWordsOrOlderSuggestionsAsync(Suggest.SESSION_GESTURE,
+ new OnGetSuggestedWordsCallback() {
+ @Override
+ public void onGetSuggestedWords(SuggestedWords suggestedWords) {
+ final int suggestionCount = suggestedWords.size();
+ if (suggestionCount <= 1) {
+ final String mostProbableSuggestion = (suggestionCount == 0) ? null
+ : suggestedWords.getWord(0);
+ callback.onGetSuggestedWords(
+ mLatinIme.getOlderSuggestions(mostProbableSuggestion));
+ }
+ callback.onGetSuggestedWords(suggestedWords);
+ }
+ });
+ }
+
+ 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) {
@@ -1782,13 +1847,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void onUpdateBatchInput(final InputPointers batchPointers) {
- BatchInputUpdater.getInstance().onUpdateBatchInput(batchPointers);
+ final SuggestedWordInfo candidate = mSuggestedWords.getAutoCommitCandidate();
+ if (null != candidate) {
+ if (candidate.mSourceDict.shouldAutoCommit(candidate)) {
+ // TODO: implement auto-commit
+ }
+ }
+ mInputUpdater.onUpdateBatchInput(batchPointers);
}
- @Override
- public void onEndBatchInput(final InputPointers batchPointers) {
- final SuggestedWords suggestedWords = BatchInputUpdater.getInstance().onEndBatchInput(
- 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)) {
@@ -1810,6 +1879,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mKeyboardSwitcher.updateShiftState();
}
+ @Override
+ public void onEndBatchInput(final InputPointers batchPointers) {
+ mInputUpdater.onEndBatchInput(batchPointers);
+ }
+
private String specificTldProcessingOnTextInput(final String text) {
if (text.length() <= 1 || text.charAt(0) != Constants.CODE_PERIOD
|| !Character.isLetter(text.charAt(1))) {
@@ -1845,7 +1919,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void onCancelBatchInput() {
- BatchInputUpdater.getInstance().onCancelBatchInput();
+ mInputUpdater.onCancelBatchInput();
}
private void handleBackspace(final int spaceState) {
@@ -1861,23 +1935,23 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// When we exit this if-clause, mWordComposer.isComposingWord() will return false.
}
if (mWordComposer.isComposingWord()) {
- final int length = mWordComposer.size();
- if (length > 0) {
- if (mWordComposer.isBatchMode()) {
- if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
- final String word = mWordComposer.getTypedWord();
- ResearchLogger.latinIME_handleBackspace_batch(word, 1);
- }
- final String rejectedSuggestion = mWordComposer.getTypedWord();
- mWordComposer.reset();
- mWordComposer.setRejectedBatchModeSuggestion(rejectedSuggestion);
- } else {
- mWordComposer.deleteLast();
+ if (mWordComposer.isBatchMode()) {
+ if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
+ final String word = mWordComposer.getTypedWord();
+ ResearchLogger.latinIME_handleBackspace_batch(word, 1);
}
- mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1);
- mHandler.postUpdateSuggestionStrip();
+ final String rejectedSuggestion = mWordComposer.getTypedWord();
+ mWordComposer.reset();
+ mWordComposer.setRejectedBatchModeSuggestion(rejectedSuggestion);
} else {
- mConnection.deleteSurroundingText(1, 0);
+ mWordComposer.deleteLast();
+ }
+ mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1);
+ mHandler.postUpdateSuggestionStrip();
+ if (!mWordComposer.isComposingWord()) {
+ // If we just removed the last character, auto-caps mode may have changed so we
+ // need to re-evaluate.
+ mKeyboardSwitcher.updateShiftState();
}
} else {
final SettingsValues currentSettings = mSettings.getCurrent();
@@ -1892,8 +1966,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Cancel multi-character input: remove the text we just entered.
// This is triggered on backspace after a key that inputs multiple characters,
// like the smiley key or the .com key.
- final int length = mEnteredText.length();
- mConnection.deleteSurroundingText(length, 0);
+ mConnection.deleteSurroundingText(mEnteredText.length(), 0);
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_handleBackspace_cancelTextInput(mEnteredText);
}
@@ -1939,6 +2012,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// This should never happen.
Log.e(TAG, "Backspace when we don't know the selection position");
}
+ final int lengthToDelete = Character.isSupplementaryCodePoint(
+ mConnection.getCodePointBeforeCursor()) ? 2 : 1;
if (mAppWorkAroundsUtils.isBeforeJellyBean()) {
// Backward compatibility mode. Before Jelly bean, the keyboard would simulate
// a hardware keyboard event on pressing enter or delete. This is bad for many
@@ -1946,22 +2021,28 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// relying on this behavior so we continue to support it for older apps.
sendDownUpKeyEventForBackwardCompatibility(KeyEvent.KEYCODE_DEL);
} else {
- mConnection.deleteSurroundingText(1, 0);
+ mConnection.deleteSurroundingText(lengthToDelete, 0);
}
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
- ResearchLogger.latinIME_handleBackspace(1, true /* shouldUncommitLogUnit */);
+ ResearchLogger.latinIME_handleBackspace(lengthToDelete,
+ true /* shouldUncommitLogUnit */);
}
if (mDeleteCount > DELETE_ACCELERATE_AT) {
- mConnection.deleteSurroundingText(1, 0);
+ final int lengthToDeleteAgain = Character.isSupplementaryCodePoint(
+ mConnection.getCodePointBeforeCursor()) ? 2 : 1;
+ mConnection.deleteSurroundingText(lengthToDeleteAgain, 0);
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
- ResearchLogger.latinIME_handleBackspace(1,
+ ResearchLogger.latinIME_handleBackspace(lengthToDeleteAgain,
true /* shouldUncommitLogUnit */);
}
}
}
- if (currentSettings.isSuggestionsRequested(mDisplayOrientation)) {
+ if (currentSettings.isSuggestionsRequested(mDisplayOrientation)
+ && currentSettings.mCurrentLanguageHasSpaces) {
restartSuggestionsOnWordBeforeCursorIfAtEndOfWord();
}
+ // We just removed a character. We need to update the auto-caps state.
+ mKeyboardSwitcher.updateShiftState();
}
}
@@ -1986,6 +2067,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private void handleCharacter(final int primaryCode, final int x,
final int y, final int spaceState) {
+ // TODO: refactor this method to stop flipping isComposingWord around all the time, and
+ // make it shorter (possibly cut into several pieces). Also factor handleNonSpecialCharacter
+ // which has the same name as other handle* methods but is not the same.
boolean isComposingWord = mWordComposer.isComposingWord();
// TODO: remove isWordConnector() and use isUsuallyFollowedBySpace() instead.
@@ -2005,18 +2089,26 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
resetEntireInputState(mLastSelectionStart);
isComposingWord = false;
}
- // NOTE: isCursorTouchingWord() is a blocking IPC call, so it often takes several
- // dozen milliseconds. Avoid calling it as much as possible, since we are on the UI
- // thread here.
- if (!isComposingWord && (isAlphabet(primaryCode)
- || currentSettings.isWordConnector(primaryCode))
+ // We want to find out whether to start composing a new word with this character. If so,
+ // we need to reset the composing state and switch isComposingWord. The order of the
+ // tests is important for good performance.
+ // We only start composing if we're not already composing.
+ if (!isComposingWord
+ // We only start composing if this is a word code point. Essentially that means it's a
+ // a letter or a word connector.
+ && currentSettings.isWordCodePoint(primaryCode)
+ // We never go into composing state if suggestions are not requested.
&& currentSettings.isSuggestionsRequested(mDisplayOrientation) &&
- !mConnection.isCursorTouchingWord(currentSettings)) {
+ // In languages with spaces, we only start composing a word when we are not already
+ // touching a word. In languages without spaces, the above conditions are sufficient.
+ (!mConnection.isCursorTouchingWord(currentSettings)
+ || !currentSettings.mCurrentLanguageHasSpaces)) {
// Reset entirely the composing state anyway, then start composing a new word unless
- // the character is a single quote. The idea here is, single quote is not a
- // separator and it should be treated as a normal character, except in the first
- // position where it should not start composing a word.
- isComposingWord = (Constants.CODE_SINGLE_QUOTE != primaryCode);
+ // the character is a single quote or a dash. The idea here is, single quote and dash
+ // are not separators and they should be treated as normal characters, except in the
+ // first position where they should not start composing a word.
+ isComposingWord = (Constants.CODE_SINGLE_QUOTE != primaryCode
+ && Constants.CODE_DASH != primaryCode);
// Here we don't need to reset the last composed word. It will be reset
// when we commit this one, if we ever do; if on the other hand we backspace
// it entirely and resume suggestions on the previous word, we'd like to still
@@ -2095,20 +2187,24 @@ 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;
+ final SettingsValues currentSettings = mSettings.getCurrent();
+ // We avoid sending spaces in languages without spaces if we were composing.
+ final boolean shouldAvoidSendingCode = Constants.CODE_SPACE == primaryCode
+ && !currentSettings.mCurrentLanguageHasSpaces && mWordComposer.isComposingWord();
if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) {
// If we are in the middle of a recorrection, we need to commit the recorrection
// first so that we can insert the separator at the current cursor position.
resetEntireInputState(mLastSelectionStart);
}
- final SettingsValues currentSettings = mSettings.getCurrent();
- if (mWordComposer.isComposingWord()) {
+ if (mWordComposer.isComposingWord()) { // May have changed since we stored wasComposing
if (currentSettings.mCorrectionEnabled) {
- // TODO: maybe cache Strings in an <String> sparse array or something
- commitCurrentAutoCorrection(new String(new int[]{primaryCode}, 0, 1));
+ final String separator = shouldAvoidSendingCode ? LastComposedWord.NOT_A_SEPARATOR
+ : new String(new int[] { primaryCode }, 0, 1);
+ commitCurrentAutoCorrection(separator);
didAutoCorrect = true;
} else {
commitTyped(new String(new int[]{primaryCode}, 0, 1));
@@ -2125,7 +2221,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_handleSeparator(primaryCode, mWordComposer.isComposingWord());
}
- sendKeyCodePoint(primaryCode);
+
+ if (!shouldAvoidSendingCode) {
+ sendKeyCodePoint(primaryCode);
+ }
if (Constants.CODE_SPACE == primaryCode) {
if (currentSettings.isSuggestionsRequested(mDisplayOrientation)) {
@@ -2255,34 +2354,60 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return;
}
- final SuggestedWords suggestedWords =
- getSuggestedWordsOrOlderSuggestions(Suggest.SESSION_TYPING);
- final String typedWord = mWordComposer.getTypedWord();
- showSuggestionStrip(suggestedWords, typedWord);
+ final AsyncResultHolder<SuggestedWords> holder = new AsyncResultHolder<SuggestedWords>();
+ getSuggestedWordsOrOlderSuggestionsAsync(Suggest.SESSION_TYPING,
+ new OnGetSuggestedWordsCallback() {
+ @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 SuggestedWords getSuggestedWords(final int sessionId) {
+ private void getSuggestedWords(final int sessionId,
+ final OnGetSuggestedWordsCallback callback) {
final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
final Suggest suggest = mSuggest;
if (keyboard == null || suggest == null) {
- return SuggestedWords.EMPTY;
+ callback.onGetSuggestedWords(SuggestedWords.EMPTY);
+ return;
}
// Get the word on which we should search the bigrams. If we are composing a word, it's
// whatever is *before* the half-committed word in the buffer, hence 2; if we aren't, we
// should just skip whitespace if any, so 1.
- // TODO: this is slow (2-way IPC) - we should probably cache this instead.
final SettingsValues currentSettings = mSettings.getCurrent();
- final String prevWord =
- mConnection.getNthPreviousWord(currentSettings.mWordSeparators,
- mWordComposer.isComposingWord() ? 2 : 1);
- return suggest.getSuggestedWords(mWordComposer, prevWord, keyboard.getProximityInfo(),
- currentSettings.mBlockPotentiallyOffensive,
- currentSettings.mCorrectionEnabled, sessionId);
+ final int[] additionalFeaturesOptions = currentSettings.mAdditionalFeaturesSettingValues;
+ final String prevWord;
+ if (currentSettings.mCurrentLanguageHasSpaces) {
+ // If we are typing in a language with spaces we can just look up the previous
+ // word from textview.
+ prevWord = mConnection.getNthPreviousWord(currentSettings.mWordSeparators,
+ mWordComposer.isComposingWord() ? 2 : 1);
+ } else {
+ prevWord = LastComposedWord.NOT_A_COMPOSED_WORD == mLastComposedWord ? null
+ : mLastComposedWord.mCommittedWord;
+ }
+ suggest.getSuggestedWords(mWordComposer, prevWord, keyboard.getProximityInfo(),
+ currentSettings.mBlockPotentiallyOffensive, currentSettings.mCorrectionEnabled,
+ additionalFeaturesOptions, sessionId, callback);
}
- private SuggestedWords getSuggestedWordsOrOlderSuggestions(final int sessionId) {
- return maybeRetrieveOlderSuggestions(mWordComposer.getTypedWord(),
- getSuggestedWords(sessionId));
+ private void getSuggestedWordsOrOlderSuggestionsAsync(final int sessionId,
+ final OnGetSuggestedWordsCallback callback) {
+ mInputUpdater.getSuggestedWords(sessionId, new OnGetSuggestedWordsCallback() {
+ @Override
+ public void onGetSuggestedWords(SuggestedWords suggestedWords) {
+ callback.onGetSuggestedWords(maybeRetrieveOlderSuggestions(
+ mWordComposer.getTypedWord(), suggestedWords));
+ }
+ });
}
private SuggestedWords maybeRetrieveOlderSuggestions(final String typedWord,
@@ -2322,25 +2447,30 @@ 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) {
+ if (suggestedWords.isEmpty()) return;
final String autoCorrection;
if (suggestedWords.mWillAutoCorrect) {
- autoCorrection = suggestedWords.getWord(1);
+ autoCorrection = suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION);
} else {
- autoCorrection = typedWord;
+ autoCorrection = suggestedWords.getWord(SuggestedWords.INDEX_OF_TYPED_WORD);
}
mWordComposer.setAutoCorrection(autoCorrection);
+ }
+
+ private void showSuggestionStrip(final SuggestedWords suggestedWords) {
+ if (suggestedWords.isEmpty()) {
+ clearSuggestionStrip();
+ return;
+ }
+ setAutoCorrection(suggestedWords);
final boolean isAutoCorrection = suggestedWords.willAutoCorrect();
setSuggestedWords(suggestedWords, isAutoCorrection);
setAutoCorrectionIndicator(isAutoCorrection);
setSuggestionStripShown(isSuggestionsStripVisible());
}
- private void commitCurrentAutoCorrection(final String separatorString) {
+ private void commitCurrentAutoCorrection(final String separator) {
// Complete any pending suggestions query first
if (mHandler.hasPendingUpdateSuggestions()) {
updateSuggestionStrip();
@@ -2356,16 +2486,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
@@ -2440,7 +2570,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_pickSuggestionManually(replacedWord, index, suggestion,
mWordComposer.isBatchMode(), suggestionInfo.mScore, suggestionInfo.mKind,
- suggestionInfo.mSourceDict);
+ suggestionInfo.mSourceDict.mDictType);
}
mConnection.endBatchEdit();
// Don't allow cancellation of manual pick
@@ -2544,6 +2674,11 @@ 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;
// If the cursor is not touching a word, or if there is a selection, return right away.
if (mLastSelectionStart != mLastSelectionEnd) return;
// If we don't know the cursor location, return.
@@ -2566,51 +2701,65 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (!TextUtils.equals(s, typedWord)) {
suggestions.add(new SuggestedWordInfo(s,
SuggestionStripView.MAX_SUGGESTIONS - i,
- SuggestedWordInfo.KIND_RESUMED, Dictionary.TYPE_RESUMED));
+ SuggestedWordInfo.KIND_RESUMED, Dictionary.DICTIONARY_RESUMED,
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE
+ /* autoCommitFirstWordConfidence */));
}
}
}
mWordComposer.setComposingWord(typedWord, mKeyboardSwitcher.getKeyboard());
- // TODO: this is in chars but the callee expects code points!
- mWordComposer.setCursorPositionWithinWord(numberOfCharsInWordBeforeCursor);
+ mWordComposer.setCursorPositionWithinWord(
+ typedWord.codePointCount(0, numberOfCharsInWordBeforeCursor));
mConnection.setComposingRegion(
mLastSelectionStart - numberOfCharsInWordBeforeCursor,
mLastSelectionEnd + range.getNumberOfCharsInWordAfterCursor());
- final SuggestedWords suggestedWords;
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.
- final SuggestedWords suggestedWordsIncludingTypedWord =
- getSuggestedWords(Suggest.SESSION_TYPING);
- if (suggestedWordsIncludingTypedWord.size() > 1) {
- // 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 willAutoCorrect to false.
- suggestedWords =
- suggestedWordsIncludingTypedWord.getSuggestedWordsExcludingTypedWord();
- } else {
- // No saved suggestions, and we were unable to compute any good one either.
- // Rather than displaying an empty suggestion strip, we'll display the original
- // word alone in the middle.
- // Since there is only one word, willAutoCorrect is false.
- suggestedWords = suggestedWordsIncludingTypedWord;
- }
+ mInputUpdater.getSuggestedWords(Suggest.SESSION_TYPING,
+ new OnGetSuggestedWordsCallback() {
+ @Override
+ public void onGetSuggestedWords(
+ final SuggestedWords suggestedWordsIncludingTypedWord) {
+ final SuggestedWords suggestedWords;
+ if (suggestedWordsIncludingTypedWord.size() > 1) {
+ // 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 willAutoCorrect to
+ // false.
+ suggestedWords = suggestedWordsIncludingTypedWord
+ .getSuggestedWordsExcludingTypedWord();
+ } else {
+ // No saved suggestions, and we were unable to compute any good one either.
+ // Rather than displaying an empty suggestion strip, we'll display the
+ // original word alone in the middle.
+ // Since there is only one word, willAutoCorrect is false.
+ suggestedWords = suggestedWordsIncludingTypedWord;
+ }
+ unsetIsAutoCorrectionIndicatorOnAndCallShowSuggestionStrip(suggestedWords);
+ }});
} else {
// We found suggestion spans in the word. We'll create the SuggestedWords out of
// them, and make willAutoCorrect false.
- suggestedWords = new SuggestedWords(suggestions,
+ final SuggestedWords suggestedWords = new SuggestedWords(suggestions,
true /* typedWordValid */, false /* willAutoCorrect */,
false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */,
false /* isPrediction */);
+ unsetIsAutoCorrectionIndicatorOnAndCallShowSuggestionStrip(suggestedWords);
}
+ }
+ public void unsetIsAutoCorrectionIndicatorOnAndCallShowSuggestionStrip(
+ final SuggestedWords suggestedWords) {
// Note that it's very important here that suggestedWords.mWillAutoCorrect is false.
- // We never want to auto-correct on a resumed suggestion. Please refer to the three
- // places above where suggestedWords is affected. We also need to reset
- // mIsAutoCorrectionIndicatorOn to avoid showSuggestionStrip touching the text to adapt it.
- // TODO: remove mIsAutoCorrectionIndicator on (see comment on definition)
+ // We never want to auto-correct on a resumed suggestion. Please refer to the three places
+ // above in restartSuggestionsOnWordTouchedByCursor() where suggestedWords is affected.
+ // We also need to unset mIsAutoCorrectionIndicatorOn to avoid showSuggestionStrip touching
+ // the text to adapt it.
+ // TODO: remove mIsAutoCorrectionIndicatorOn (see comment on definition)
mIsAutoCorrectionIndicatorOn = false;
- showSuggestionStrip(suggestedWords, typedWord);
+ mHandler.showSuggestionStrip(suggestedWords);
}
/**
@@ -2666,7 +2815,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (!TextUtils.isEmpty(previousWord) && !TextUtils.isEmpty(committedWord)) {
mUserHistoryPredictionDictionary.cancelAddingUserHistory(previousWord, committedWord);
}
- mConnection.commitText(originallyTypedWord + mLastComposedWord.mSeparatorString, 1);
+ final String stringToCommit = originallyTypedWord + mLastComposedWord.mSeparatorString;
+ if (mSettings.getCurrent().mCurrentLanguageHasSpaces) {
+ // For languages with spaces, we revert to the typed string, but the cursor is still
+ // after the separator so we don't resume suggestions. If the user wants to correct
+ // the word, they have to press backspace again.
+ mConnection.commitText(stringToCommit, 1);
+ } else {
+ // For languages without spaces, we revert the typed string but the cursor is flush
+ // with the typed word, so we need to resume suggestions right away.
+ mWordComposer.setComposingWord(stringToCommit, mKeyboardSwitcher.getKeyboard());
+ mConnection.setComposingText(stringToCommit, 1);
+ }
if (mSettings.isInternal()) {
LatinImeLoggerUtils.onSeparator(mLastComposedWord.mSeparatorString,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
@@ -2684,7 +2844,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// This essentially inserts a space, and that's it.
public void promotePhantomSpace() {
- if (mSettings.getCurrent().shouldInsertSpacesAutomatically()
+ final SettingsValues currentSettings = mSettings.getCurrent();
+ if (currentSettings.shouldInsertSpacesAutomatically()
+ && currentSettings.mCurrentLanguageHasSpaces
&& !mConnection.textBeforeCursorLooksLikeURL()) {
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_promotePhantomSpace();
@@ -2710,30 +2872,43 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
- private void hapticAndAudioFeedback(final int code, final boolean isRepeatKey) {
+ private void hapticAndAudioFeedback(final int code, final int repeatCount) {
final MainKeyboardView keyboardView = mKeyboardSwitcher.getMainKeyboardView();
if (keyboardView != null && keyboardView.isInSlidingKeyInput()) {
// No need to feedback while sliding input.
return;
}
- if (isRepeatKey && code == Constants.CODE_DELETE && !mConnection.canDeleteCharacters()) {
- // No need to feedback when repeating delete key will have no effect.
- return;
+ if (repeatCount > 0) {
+ if (code == Constants.CODE_DELETE && !mConnection.canDeleteCharacters()) {
+ // No need to feedback when repeat delete key will have no effect.
+ return;
+ }
+ // TODO: Use event time that the last feedback has been generated instead of relying on
+ // a repeat count to thin out feedback.
+ if (repeatCount % PERIOD_FOR_AUDIO_AND_HAPTIC_FEEDBACK_IN_KEY_REPEAT == 0) {
+ return;
+ }
}
- AudioAndHapticFeedbackManager.getInstance().hapticAndAudioFeedback(code, keyboardView);
+ final AudioAndHapticFeedbackManager feedbackManager =
+ AudioAndHapticFeedbackManager.getInstance();
+ if (repeatCount == 0) {
+ // TODO: Reconsider how to perform haptic feedback when repeating key.
+ feedbackManager.performHapticFeedback(keyboardView);
+ }
+ feedbackManager.performAudioFeedback(code);
}
// Callback of the {@link KeyboardActionListener}. This is called when a key is depressed;
// release matching call is {@link #onReleaseKey(int,boolean)} below.
@Override
- public void onPressKey(final int primaryCode, final boolean isRepeatKey,
+ public void onPressKey(final int primaryCode, final int repeatCount,
final boolean isSinglePointer) {
mKeyboardSwitcher.onPressKey(primaryCode, isSinglePointer);
- hapticAndAudioFeedback(primaryCode, isRepeatKey);
+ hapticAndAudioFeedback(primaryCode, repeatCount);
}
// Callback of the {@link KeyboardActionListener}. This is called when a key is released;
- // press matching call is {@link #onPressKey(int,boolean,boolean)} above.
+ // press matching call is {@link #onPressKey(int,int,boolean)} above.
@Override
public void onReleaseKey(final int primaryCode, final boolean withSliding) {
mKeyboardSwitcher.onReleaseKey(primaryCode, withSliding);
@@ -2749,17 +2924,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
break;
}
}
-
- if (Constants.CODE_DELETE == primaryCode) {
- // This is a stopgap solution to avoid leaving a high surrogate alone in a text view.
- // In the future, we need to deprecate deteleSurroundingText() and have a surrogate
- // pair-friendly way of deleting characters in InputConnection.
- // TODO: use getCodePointBeforeCursor instead to improve performance
- final CharSequence lastChar = mConnection.getTextBeforeCursor(1, 0);
- if (!TextUtils.isEmpty(lastChar) && Character.isHighSurrogate(lastChar.charAt(0))) {
- mConnection.deleteSurroundingText(1, 0);
- }
- }
}
// Hooks for hardware keyboard
@@ -2895,6 +3059,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return mSuggest.hasMainDictionary();
}
+ // 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) {
+ mSuggest.resetMainDict(this, locale, null);
+ }
+
public void debugDumpStateAndCrashWithException(final String context) {
final StringBuilder s = new StringBuilder(mAppWorkAroundsUtils.toString());
s.append("\nAttributes : ").append(mSettings.getCurrent().mInputAttributes)