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.java547
1 files changed, 375 insertions, 172 deletions
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 5c5b7b7c0..6be9ded5c 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;
@@ -96,6 +99,7 @@ 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;
@@ -103,6 +107,8 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Locale;
import java.util.TreeSet;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Input method implementation for Qwerty'ish keyboard.
@@ -123,6 +129,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,6 +182,7 @@ 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;
@@ -190,7 +202,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 +226,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 +235,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 +272,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 +289,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 +333,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 +509,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
KeyboardSwitcher.init(this);
AudioAndHapticFeedbackManager.init(this);
AccessibilityUtils.init(this);
+ PersonalizationDictionarySessionRegister.init(this);
super.onCreate();
@@ -503,6 +541,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 +598,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 +676,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 +700,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mOptionsDialog.dismiss();
}
}
+ PersonalizationDictionarySessionRegister.onConfigurationChanged(this, conf);
super.onConfigurationChanged(conf);
}
@@ -863,9 +912,35 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// 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 +1210,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 +1234,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 +1250,13 @@ 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 (visibleKeyboardView.isShown()) {
if (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;
@@ -1368,10 +1445,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
- private static boolean isAlphabet(final int code) {
- return Character.isLetter(code);
- }
-
private void onSettingsKeyPressed() {
if (isShowingOptionDialog()) return;
showSubtypeSelectorAndSettings();
@@ -1479,7 +1552,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 +1566,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 +1584,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 +1701,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 +1741,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 +1788,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 +1818,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 +1878,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 +1910,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 +1950,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 +1966,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 +1997,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 +2043,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 +2052,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 +2098,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 +2120,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
@@ -2099,16 +2222,20 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
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 +2252,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 +2385,71 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return;
}
- final SuggestedWords suggestedWords =
- getSuggestedWordsOrOlderSuggestions(Suggest.SESSION_TYPING);
- final String typedWord = mWordComposer.getTypedWord();
- showSuggestionStrip(suggestedWords, typedWord);
+ final CountDownLatch latch = new CountDownLatch(1);
+ final SuggestedWords[] suggestedWordsArray = new SuggestedWords[1];
+ getSuggestedWordsOrOlderSuggestionsAsync(Suggest.SESSION_TYPING,
+ new OnGetSuggestedWordsCallback() {
+ @Override
+ public void onGetSuggestedWords(final SuggestedWords suggestedWords) {
+ suggestedWordsArray[0] = suggestedWords;
+ latch.countDown();
+ }
+ }
+ );
+
+ // TODO: Quit blocking the main thread.
+ try {
+ // Wait for the result of getSuggestedWords
+ // We set the time out to avoid ANR.
+ latch.await(GET_SUGGESTED_WORDS_TIMEOUT, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ // TODO: Cancel all pending "getSuggestedWords" tasks when it failed. We may want to add
+ // "onGetSuggestionFailed" to "OnGetSuggestedWordsCallback".
+ Log.e(TAG, "InterruptedException while waiting for getSuggestedWords.", e);
+ return;
+ }
+ if (suggestedWordsArray[0] != null) {
+ showSuggestionStrip(suggestedWordsArray[0]);
+ }
}
- 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,16 +2489,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
false /* isPrediction */);
}
- private void showSuggestionStrip(final SuggestedWords suggestedWords, final String typedWord) {
+ private void showSuggestionStrip(final SuggestedWords suggestedWords) {
if (suggestedWords.isEmpty()) {
clearSuggestionStrip();
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);
final boolean isAutoCorrection = suggestedWords.willAutoCorrect();
@@ -2440,7 +2607,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 +2711,9 @@ 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;
+ // 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 +2736,63 @@ 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 */));
}
}
}
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 +2848,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 +2877,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 +2905,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;
+ }
+ }
+ final AudioAndHapticFeedbackManager feedbackManager =
+ AudioAndHapticFeedbackManager.getInstance();
+ if (repeatCount == 0) {
+ // TODO: Reconsider how to perform haptic feedback when repeating key.
+ feedbackManager.performHapticFeedback(keyboardView);
}
- AudioAndHapticFeedbackManager.getInstance().hapticAndAudioFeedback(code, 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 +2957,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 +3092,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)