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.java507
1 files changed, 307 insertions, 200 deletions
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index c464a7067..719c7c81f 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -43,7 +43,6 @@ import android.os.Message;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.text.InputType;
-import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.SuggestionSpan;
import android.util.Log;
@@ -74,11 +73,29 @@ 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.RichInputConnection.Range;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-import com.android.inputmethod.latin.Utils.Stats;
import com.android.inputmethod.latin.define.ProductionFlag;
+import com.android.inputmethod.latin.personalization.PersonalizationDictionaryHelper;
+import com.android.inputmethod.latin.personalization.PersonalizationPredictionDictionary;
+import com.android.inputmethod.latin.personalization.UserHistoryPredictionDictionary;
+import com.android.inputmethod.latin.settings.Settings;
+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.AutoCorrectionUtils;
+import com.android.inputmethod.latin.utils.CapsModeUtils;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.CompletionInfoUtils;
+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.research.ResearchLogger;
import java.io.FileDescriptor;
@@ -139,7 +156,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private SuggestionStripView mSuggestionStripView;
// Never null
private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
- @UsedForTesting Suggest mSuggest;
+ private Suggest mSuggest;
private CompletionInfo[] mApplicationSpecifiedCompletions;
private AppWorkaroundsUtils mAppWorkAroundsUtils = new AppWorkaroundsUtils();
@@ -153,7 +170,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private boolean mIsMainDictionaryAvailable;
private UserBinaryDictionary mUserDictionary;
- private UserHistoryDictionary mUserHistoryDictionary;
+ private UserHistoryPredictionDictionary mUserHistoryPredictionDictionary;
+ private PersonalizationPredictionDictionary mPersonalizationPredictionDictionary;
private boolean mIsUserDictionaryAvailable;
private LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
@@ -179,11 +197,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private int mDisplayOrientation;
// Object for reacting to adding/removing a dictionary pack.
- // TODO: The development-only-diagnostic version is not supported by the Dictionary Pack
- // Service yet.
private BroadcastReceiver mDictionaryPackInstallReceiver =
- ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS
- ? null : new DictionaryPackInstallBroadcastReceiver(this);
+ new DictionaryPackInstallBroadcastReceiver(this);
// Keeps track of most recently inserted text (multi-character key) for reverting
private String mEnteredText;
@@ -204,6 +219,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private static final int MSG_UPDATE_SUGGESTION_STRIP = 2;
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 ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1;
@@ -244,6 +260,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
case MSG_RESUME_SUGGESTIONS:
latinIme.restartSuggestionsOnWordTouchedByCursor();
break;
+ case MSG_REOPEN_DICTIONARIES:
+ latinIme.initSuggest();
+ // In theory we could call latinIme.updateSuggestionStrip() right away, but
+ // in the practice, the dictionary is not finished opening yet so we wouldn't
+ // get any suggestions. Wait one frame.
+ postUpdateSuggestionStrip();
+ break;
}
}
@@ -251,6 +274,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION_STRIP), mDelayUpdateSuggestions);
}
+ public void postReopenDictionaries() {
+ sendMessage(obtainMessage(MSG_REOPEN_DICTIONARIES));
+ }
+
public void postResumeSuggestions() {
removeMessages(MSG_RESUME_SUGGESTIONS);
sendMessageDelayed(obtainMessage(MSG_RESUME_SUGGESTIONS), mDelayUpdateSuggestions);
@@ -264,6 +291,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return hasMessages(MSG_UPDATE_SUGGESTION_STRIP);
}
+ public boolean hasPendingReopenDictionaries() {
+ return hasMessages(MSG_REOPEN_DICTIONARIES);
+ }
+
public void postUpdateShiftState() {
removeMessages(MSG_UPDATE_SHIFT_STATE);
sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), mDelayUpdateShiftState);
@@ -416,6 +447,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
+ // Loading the native library eagerly to avoid unexpected UnsatisfiedLinkError at the initial
+ // JNI call as much as possible.
+ static {
+ JniUtils.loadNativeLibrary();
+ }
+
public LatinIME() {
super();
mSettings = Settings.getInstance();
@@ -458,19 +495,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
registerReceiver(mReceiver, filter);
- // TODO: The development-only-diagnostic version is not supported by the Dictionary Pack
- // Service yet.
- if (!ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
- final IntentFilter packageFilter = new IntentFilter();
- packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- packageFilter.addDataScheme(SCHEME_PACKAGE);
- registerReceiver(mDictionaryPackInstallReceiver, packageFilter);
+ final IntentFilter packageFilter = new IntentFilter();
+ packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ packageFilter.addDataScheme(SCHEME_PACKAGE);
+ registerReceiver(mDictionaryPackInstallReceiver, packageFilter);
- final IntentFilter newDictFilter = new IntentFilter();
- newDictFilter.addAction(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION);
- registerReceiver(mDictionaryPackInstallReceiver, newDictFilter);
- }
+ final IntentFilter newDictFilter = new IntentFilter();
+ newDictFilter.addAction(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION);
+ registerReceiver(mDictionaryPackInstallReceiver, newDictFilter);
}
// Has to be package-visible for unit tests
@@ -480,8 +513,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final InputAttributes inputAttributes =
new InputAttributes(getCurrentInputEditorInfo(), isFullscreenMode());
mSettings.loadSettings(locale, inputAttributes);
- // May need to reset the contacts dictionary depending on the user settings.
- resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary());
+ AudioAndHapticFeedbackManager.getInstance().onSettingsChanged(mSettings.getCurrent());
+ // To load the keyboard we need to load all the settings once, but resetting the
+ // contacts dictionary should be deferred until after the new layout has been displayed
+ // to improve responsivity. In the language switching process, we post a reopenDictionaries
+ // message, then come here to read the settings for the new language before we change
+ // the layout; at this time, we need to skip resetting the contacts dictionary. It will
+ // be done later inside {@see #initSuggest()} when the reopenDictionaries message is
+ // processed.
+ if (!mHandler.hasPendingReopenDictionaries()) {
+ // May need to reset the contacts dictionary depending on the user settings.
+ resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary());
+ }
}
// Note that this method is called from a non-UI thread.
@@ -498,33 +541,35 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
final String localeStr = subtypeLocale.toString();
- final ContactsBinaryDictionary oldContactsDictionary;
- if (mSuggest != null) {
- oldContactsDictionary = mSuggest.getContactsDictionary();
- mSuggest.close();
- } else {
- oldContactsDictionary = null;
- }
- mSuggest = new Suggest(this /* Context */, subtypeLocale,
+ final Suggest newSuggest = new Suggest(this /* Context */, subtypeLocale,
this /* SuggestInitializationListener */);
- if (mSettings.getCurrent().mCorrectionEnabled) {
- mSuggest.setAutoCorrectionThreshold(mSettings.getCurrent().mAutoCorrectionThreshold);
+ final SettingsValues settingsValues = mSettings.getCurrent();
+ if (settingsValues.mCorrectionEnabled) {
+ newSuggest.setAutoCorrectionThreshold(settingsValues.mAutoCorrectionThreshold);
}
mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale);
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
- ResearchLogger.getInstance().initSuggest(mSuggest);
+ ResearchLogger.getInstance().initSuggest(newSuggest);
}
mUserDictionary = new UserBinaryDictionary(this, localeStr);
mIsUserDictionaryAvailable = mUserDictionary.isEnabled();
- mSuggest.setUserDictionary(mUserDictionary);
-
- resetContactsDictionary(oldContactsDictionary);
+ newSuggest.setUserDictionary(mUserDictionary);
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
- mUserHistoryDictionary = UserHistoryDictionary.getInstance(this, localeStr, prefs);
- mSuggest.setUserHistoryDictionary(mUserHistoryDictionary);
+
+ mUserHistoryPredictionDictionary = PersonalizationDictionaryHelper
+ .getUserHistoryPredictionDictionary(this, localeStr, prefs);
+ newSuggest.setUserHistoryPredictionDictionary(mUserHistoryPredictionDictionary);
+ mPersonalizationPredictionDictionary = PersonalizationDictionaryHelper
+ .getPersonalizationPredictionDictionary(this, localeStr, prefs);
+ newSuggest.setPersonalizationPredictionDictionary(mPersonalizationPredictionDictionary);
+
+ final Suggest oldSuggest = mSuggest;
+ resetContactsDictionary(null != oldSuggest ? oldSuggest.getContactsDictionary() : null);
+ mSuggest = newSuggest;
+ if (oldSuggest != null) oldSuggest.close();
}
/**
@@ -536,8 +581,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
* @param oldContactsDictionary an optional dictionary to use, or null
*/
private void resetContactsDictionary(final ContactsBinaryDictionary oldContactsDictionary) {
+ final Suggest suggest = mSuggest;
final boolean shouldSetDictionary =
- (null != mSuggest && mSettings.getCurrent().mUseContactsDict);
+ (null != suggest && mSettings.getCurrent().mUseContactsDict);
final ContactsBinaryDictionary dictionaryToUse;
if (!shouldSetDictionary) {
@@ -564,8 +610,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
- if (null != mSuggest) {
- mSuggest.setContactsDictionary(dictionaryToUse);
+ if (null != suggest) {
+ suggest.setContactsDictionary(dictionaryToUse);
}
}
@@ -577,8 +623,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public void onDestroy() {
- if (mSuggest != null) {
- mSuggest.close();
+ final Suggest suggest = mSuggest;
+ if (suggest != null) {
+ suggest.close();
mSuggest = null;
}
mSettings.onDestroy();
@@ -586,11 +633,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.getInstance().onDestroy();
}
- // TODO: The development-only-diagnostic version is not supported by the Dictionary Pack
- // Service yet.
- if (!ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
- unregisterReceiver(mDictionaryPackInstallReceiver);
- }
+ unregisterReceiver(mDictionaryPackInstallReceiver);
LatinImeLogger.commit();
LatinImeLogger.onDestroy();
super.onDestroy();
@@ -676,7 +719,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
super.onStartInputView(editorInfo, restarting);
final KeyboardSwitcher switcher = mKeyboardSwitcher;
final MainKeyboardView mainKeyboardView = switcher.getMainKeyboardView();
- final SettingsValues currentSettings = mSettings.getCurrent();
+ // If we are starting input in a different text field from before, we'll have to reload
+ // settings, so currentSettingsValues can't be final.
+ SettingsValues currentSettingsValues = mSettings.getCurrent();
if (editorInfo == null) {
Log.e(TAG, "Null EditorInfo in onStartInputView()");
@@ -731,7 +776,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
accessUtils.onStartInputViewInternal(mainKeyboardView, editorInfo, restarting);
}
- final boolean inputTypeChanged = !currentSettings.isSameInputType(editorInfo);
+ final boolean inputTypeChanged = !currentSettingsValues.isSameInputType(editorInfo);
final boolean isDifferentTextField = !restarting || inputTypeChanged;
if (isDifferentTextField) {
mSubtypeSwitcher.updateParametersOnStartInputView();
@@ -746,6 +791,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// span, so we should reset our state unconditionally, even if restarting is true.
mEnteredText = null;
resetComposingState(true /* alsoResetLastComposedWord */);
+ if (isDifferentTextField) mHandler.postResumeSuggestions();
mDeleteCount = 0;
mSpaceState = SPACE_STATE_NONE;
mRecapitalizeStatus.deactivate();
@@ -753,7 +799,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Note: the following does a round-trip IPC on the main thread: be careful
final Locale currentLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
- if (null != mSuggest && null != currentLocale && !currentLocale.equals(mSuggest.mLocale)) {
+ final Suggest suggest = mSuggest;
+ if (null != suggest && null != currentLocale && !currentLocale.equals(suggest.mLocale)) {
initSuggest();
}
if (mSuggestionStripView != null) {
@@ -769,12 +816,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (isDifferentTextField) {
mainKeyboardView.closing();
loadSettings();
+ currentSettingsValues = mSettings.getCurrent();
- if (mSuggest != null && currentSettings.mCorrectionEnabled) {
- mSuggest.setAutoCorrectionThreshold(currentSettings.mAutoCorrectionThreshold);
+ if (suggest != null && currentSettingsValues.mCorrectionEnabled) {
+ suggest.setAutoCorrectionThreshold(currentSettingsValues.mAutoCorrectionThreshold);
}
- switcher.loadKeyboard(editorInfo, currentSettings);
+ switcher.loadKeyboard(editorInfo, currentSettingsValues);
} else if (restarting) {
// TODO: Come up with a more comprehensive way to reset the keyboard layout when
// a keyboard layout set doesn't get reloaded in this method.
@@ -795,14 +843,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mHandler.cancelDoubleSpacePeriodTimer();
mainKeyboardView.setMainDictionaryAvailability(mIsMainDictionaryAvailable);
- mainKeyboardView.setKeyPreviewPopupEnabled(currentSettings.mKeyPreviewPopupOn,
- currentSettings.mKeyPreviewPopupDismissDelay);
+ mainKeyboardView.setKeyPreviewPopupEnabled(currentSettingsValues.mKeyPreviewPopupOn,
+ currentSettingsValues.mKeyPreviewPopupDismissDelay);
mainKeyboardView.setSlidingKeyInputPreviewEnabled(
- currentSettings.mSlidingKeyInputPreviewEnabled);
+ currentSettingsValues.mSlidingKeyInputPreviewEnabled);
mainKeyboardView.setGestureHandlingEnabledByUser(
- currentSettings.mGestureInputEnabled);
- mainKeyboardView.setGesturePreviewMode(currentSettings.mGesturePreviewTrailEnabled,
- currentSettings.mGestureFloatingPreviewTextEnabled);
+ currentSettingsValues.mGestureInputEnabled);
+ mainKeyboardView.setGesturePreviewMode(currentSettingsValues.mGesturePreviewTrailEnabled,
+ 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
@@ -850,11 +898,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mKeyboardSwitcher.onFinishInputView();
final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
if (mainKeyboardView != null) {
- mainKeyboardView.cancelAllMessages();
+ mainKeyboardView.cancelAllOngoingEvents();
+ mainKeyboardView.deallocateMemory();
}
// Remove pending messages related to update suggestions
mHandler.cancelUpdateSuggestionStrip();
+ // Should do the following in onFinishInputInternal but until JB MR2 it's not called :(
+ if (mWordComposer.isComposingWord()) mConnection.finishComposingText();
resetComposingState(true /* alsoResetLastComposedWord */);
+ mRichImm.clearSubtypeCaches();
// Notify ResearchLogger
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_onFinishInputViewInternal(finishingInput, mLastSelectionStart,
@@ -891,20 +943,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
- // TODO: refactor the following code to be less contrived.
- // "newSelStart != composingSpanEnd" || "newSelEnd != composingSpanEnd" means
- // that the cursor is not at the end of the composing span, or there is a selection.
- // "mLastSelectionStart != newSelStart" means that the cursor is not in the same place
- // as last time we were called (if there is a selection, it means the start hasn't
- // changed, so it's the end that did).
- final boolean selectionChanged = (newSelStart != composingSpanEnd
- || newSelEnd != composingSpanEnd) && mLastSelectionStart != newSelStart;
+ final boolean selectionChanged = mLastSelectionStart != newSelStart
+ || mLastSelectionEnd != newSelEnd;
+
// if composingSpanStart and composingSpanEnd are -1, it means there is no composing
// span in the view - we can use that to narrow down whether the cursor was moved
// by us or not. If we are composing a word but there is no composing span, then
// we know for sure the cursor moved while we were composing and we should reset
- // the state.
+ // the state. TODO: rescind this policy: the framework never removes the composing
+ // span on its own accord while editing. This test is useless.
final boolean noComposingSpan = composingSpanStart == -1 && composingSpanEnd == -1;
+
// If the keyboard is not visible, we don't need to do all the housekeeping work, as it
// will be reset when the keyboard shows up anyway.
// TODO: revisit this when LatinIME supports hardware keyboards.
@@ -926,7 +975,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// state-related special processing to kick in.
mSpaceState = SPACE_STATE_NONE;
- if ((!mWordComposer.isComposingWord()) || selectionChanged || noComposingSpan) {
+ // TODO: is it still necessary to test for composingSpan related stuff?
+ final boolean selectionChangedOrSafeToReset = selectionChanged
+ || (!mWordComposer.isComposingWord()) || noComposingSpan;
+ final boolean hasOrHadSelection = (oldSelStart != oldSelEnd
+ || newSelStart != newSelEnd);
+ final int moveAmount = newSelStart - oldSelStart;
+ if (selectionChangedOrSafeToReset && (hasOrHadSelection
+ || !mWordComposer.moveCursorByAndReturnIfInsideComposingWord(moveAmount))) {
// If we are composing a word and moving the cursor, we would want to set a
// suggestion span for recorrection to work correctly. Unfortunately, that
// would involve the keyboard committing some new text, which would move the
@@ -937,6 +993,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// text, but that is probably too expensive to do, so we decided to leave things
// as is.
resetEntireInputState(newSelStart);
+ } else {
+ // resetEntireInputState calls resetCachesUponCursorMove, but with the second
+ // argument as true. But in all cases where we don't reset the entire input state,
+ // we still want to tell the rich input connection about the new cursor position so
+ // that it can update its caches.
+ mConnection.resetCachesUponCursorMove(newSelStart,
+ false /* shouldFinishComposition */);
}
// We moved the cursor. If we are touching a word, we need to resume suggestion,
@@ -1160,10 +1223,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private void resetEntireInputState(final int newCursorPosition) {
final boolean shouldFinishComposition = mWordComposer.isComposingWord();
resetComposingState(true /* alsoResetLastComposedWord */);
- if (mSettings.getCurrent().mBigramPredictionEnabled) {
+ final SettingsValues settingsValues = mSettings.getCurrent();
+ if (settingsValues.mBigramPredictionEnabled) {
clearSuggestionStrip();
} else {
- setSuggestedWords(mSettings.getCurrent().mSuggestPuncList, false);
+ setSuggestedWords(settingsValues.mSuggestPuncList, false);
}
mConnection.resetCachesUponCursorMove(newCursorPosition, shouldFinishComposition);
}
@@ -1237,8 +1301,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
private boolean maybeDoubleSpacePeriod() {
- if (!mSettings.getCurrent().mCorrectionEnabled) return false;
- if (!mSettings.getCurrent().mUseDoubleSpacePeriod) return false;
+ final SettingsValues settingsValues = mSettings.getCurrent();
+ if (!settingsValues.mCorrectionEnabled) return false;
+ if (!settingsValues.mUseDoubleSpacePeriod) return false;
if (!mHandler.isAcceptingDoubleSpacePeriod()) return false;
final CharSequence lastThree = mConnection.getTextBeforeCursor(3, 0);
if (lastThree != null && lastThree.length() == 3
@@ -1314,14 +1379,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
showSubtypeSelectorAndSettings();
}
- // Virtual codes representing custom requests. These are used in onCustomRequest() below.
- public static final int CODE_SHOW_INPUT_METHOD_PICKER = 1;
-
@Override
public boolean onCustomRequest(final int requestCode) {
if (isShowingOptionDialog()) return false;
switch (requestCode) {
- case CODE_SHOW_INPUT_METHOD_PICKER:
+ case Constants.CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER:
if (mRichImm.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) {
mRichImm.getInputMethodManager().showInputMethodPicker();
return true;
@@ -1418,8 +1480,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
LatinImeLogger.logOnDelete(x, y);
break;
case Constants.CODE_SHIFT:
- // Note: calling back to the keyboard on Shift key is handled in onPressKey()
- // and onReleaseKey().
+ // Note: Calling back to the keyboard on Shift key is handled in
+ // {@link #onPressKey(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
@@ -1427,9 +1489,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
handleRecapitalize();
}
break;
+ case Constants.CODE_CAPSLOCK:
+ // Note: Changing keyboard to shift lock state is handled in
+ // {@link KeyboardSwitcher#onCodeInput(int)}.
+ break;
case Constants.CODE_SWITCH_ALPHA_SYMBOL:
- // Note: calling back to the keyboard on symbol key is handled in onPressKey()
- // and onReleaseKey().
+ // Note: Calling back to the keyboard on symbol key is handled in
+ // {@link #onPressKey(int,boolean)} and {@link #onReleaseKey(int,boolean)}.
break;
case Constants.CODE_SETTINGS:
onSettingsKeyPressed();
@@ -1482,8 +1548,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
break;
}
switcher.onCodeInput(primaryCode);
- // Reset after any single keystroke, except shift and symbol-shift
+ // Reset after any single keystroke, except shift, capslock, and symbol-shift
if (!didAutoCorrect && primaryCode != Constants.CODE_SHIFT
+ && primaryCode != Constants.CODE_CAPSLOCK
&& primaryCode != Constants.CODE_SWITCH_ALPHA_SYMBOL)
mLastComposedWord.deactivate();
if (Constants.CODE_DELETE != primaryCode) {
@@ -1496,14 +1563,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final int spaceState) {
mSpaceState = SPACE_STATE_NONE;
final boolean didAutoCorrect;
- if (mSettings.getCurrent().isWordSeparator(primaryCode)) {
+ final SettingsValues settingsValues = mSettings.getCurrent();
+ if (settingsValues.isWordSeparator(primaryCode)) {
didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState);
} else {
didAutoCorrect = false;
if (SPACE_STATE_PHANTOM == spaceState) {
- if (mSettings.isInternal()) {
+ if (settingsValues.mIsInternal) {
if (mWordComposer.isComposingWord() && mWordComposer.isBatchMode()) {
- Stats.onAutoCorrection(
+ LatinImeLoggerUtils.onAutoCorrection(
"", mWordComposer.getTypedWord(), " ", mWordComposer);
}
}
@@ -1561,10 +1629,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
BatchInputUpdater.getInstance().onStartBatchInput(this);
mHandler.cancelUpdateSuggestionStrip();
mConnection.beginBatchEdit();
+ final SettingsValues settingsValues = mSettings.getCurrent();
if (mWordComposer.isComposingWord()) {
- if (mSettings.isInternal()) {
+ if (settingsValues.mIsInternal) {
if (mWordComposer.isBatchMode()) {
- Stats.onAutoCorrection("", mWordComposer.getTypedWord(), " ", mWordComposer);
+ LatinImeLoggerUtils.onAutoCorrection(
+ "", mWordComposer.getTypedWord(), " ", mWordComposer);
}
}
final int wordComposerSize = mWordComposer.size();
@@ -1590,7 +1660,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor();
if (Character.isLetterOrDigit(codePointBeforeCursor)
- || mSettings.getCurrent().isUsuallyFollowedBySpace(codePointBeforeCursor)) {
+ || settingsValues.isUsuallyFollowedBySpace(codePointBeforeCursor)) {
mSpaceState = SPACE_STATE_PHANTOM;
}
mConnection.endBatchEdit();
@@ -1635,8 +1705,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public void onStartBatchInput(final LatinIME latinIme) {
synchronized (mLock) {
mHandler.removeMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP);
- mLatinIme = latinIme;
mInBatchInput = true;
+ mLatinIme = latinIme;
+ mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip(
+ SuggestedWords.EMPTY, false /* dismissGestureFloatingPreviewText */);
}
}
@@ -1795,8 +1867,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
final String word = mWordComposer.getTypedWord();
ResearchLogger.latinIME_handleBackspace_batch(word, 1);
- ResearchLogger.getInstance().uncommitCurrentLogUnit(
- word, false /* dumpCurrentLogUnit */);
}
final String rejectedSuggestion = mWordComposer.getTypedWord();
mWordComposer.reset();
@@ -1810,9 +1880,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mConnection.deleteSurroundingText(1, 0);
}
} else {
+ final SettingsValues currentSettings = mSettings.getCurrent();
if (mLastComposedWord.canRevertCommit()) {
- if (mSettings.isInternal()) {
- Stats.onAutoCorrectionCancellation();
+ if (currentSettings.mIsInternal) {
+ LatinImeLoggerUtils.onAutoCorrectionCancellation();
}
revertCommit();
return;
@@ -1823,6 +1894,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// like the smiley key or the .com key.
final int length = mEnteredText.length();
mConnection.deleteSurroundingText(length, 0);
+ if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
+ ResearchLogger.latinIME_handleBackspace_cancelTextInput(mEnteredText);
+ }
mEnteredText = null;
// If we have mEnteredText, then we know that mHasUncommittedTypedChars == false.
// In addition we know that spaceState is false, and that we should not be
@@ -1856,7 +1930,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mLastSelectionEnd = mLastSelectionStart;
mConnection.deleteSurroundingText(numCharsDeleted, 0);
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
- ResearchLogger.latinIME_handleBackspace(numCharsDeleted);
+ ResearchLogger.latinIME_handleBackspace(numCharsDeleted,
+ false /* shouldUncommitLogUnit */);
}
} else {
// There is no selection, just delete one character.
@@ -1874,16 +1949,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mConnection.deleteSurroundingText(1, 0);
}
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
- ResearchLogger.latinIME_handleBackspace(1);
+ ResearchLogger.latinIME_handleBackspace(1, true /* shouldUncommitLogUnit */);
}
if (mDeleteCount > DELETE_ACCELERATE_AT) {
mConnection.deleteSurroundingText(1, 0);
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
- ResearchLogger.latinIME_handleBackspace(1);
+ ResearchLogger.latinIME_handleBackspace(1,
+ true /* shouldUncommitLogUnit */);
}
}
}
- if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) {
+ if (currentSettings.isSuggestionsRequested(mDisplayOrientation)) {
restartSuggestionsOnWordBeforeCursorIfAtEndOfWord();
}
}
@@ -1900,8 +1976,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
if ((SPACE_STATE_WEAK == spaceState || SPACE_STATE_SWAP_PUNCTUATION == spaceState)
&& isFromSuggestionStrip) {
- if (mSettings.getCurrent().isUsuallyPrecededBySpace(code)) return false;
- if (mSettings.getCurrent().isUsuallyFollowedBySpace(code)) return true;
+ final SettingsValues currentSettings = mSettings.getCurrent();
+ if (currentSettings.isUsuallyPrecededBySpace(code)) return false;
+ if (currentSettings.isUsuallyFollowedBySpace(code)) return true;
mConnection.removeTrailingSpace();
}
return false;
@@ -1913,8 +1990,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// TODO: remove isWordConnector() and use isUsuallyFollowedBySpace() instead.
// See onStartBatchInput() to see how to do it.
- if (SPACE_STATE_PHANTOM == spaceState &&
- !mSettings.getCurrent().isWordConnector(primaryCode)) {
+ final SettingsValues currentSettings = mSettings.getCurrent();
+ if (SPACE_STATE_PHANTOM == spaceState && !currentSettings.isWordConnector(primaryCode)) {
if (isComposingWord) {
// Sanity check
throw new RuntimeException("Should not be composing here");
@@ -1932,9 +2009,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// dozen milliseconds. Avoid calling it as much as possible, since we are on the UI
// thread here.
if (!isComposingWord && (isAlphabet(primaryCode)
- || mSettings.getCurrent().isWordConnector(primaryCode))
- && mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation) &&
- !mConnection.isCursorTouchingWord(mSettings.getCurrent())) {
+ || currentSettings.isWordConnector(primaryCode))
+ && currentSettings.isSuggestionsRequested(mDisplayOrientation) &&
+ !mConnection.isCursorTouchingWord(currentSettings)) {
// 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
@@ -1977,8 +2054,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (null != mSuggestionStripView) mSuggestionStripView.dismissAddToDictionaryHint();
}
mHandler.postUpdateSuggestionStrip();
- if (mSettings.isInternal()) {
- Utils.Stats.onNonSeparator((char)primaryCode, x, y);
+ if (currentSettings.mIsInternal) {
+ LatinImeLoggerUtils.onNonSeparator((char)primaryCode, x, y);
}
}
@@ -1990,9 +2067,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final CharSequence selectedText =
mConnection.getSelectedText(0 /* flags, 0 for no styles */);
if (TextUtils.isEmpty(selectedText)) return; // Race condition with the input connection
+ final SettingsValues currentSettings = mSettings.getCurrent();
mRecapitalizeStatus.initialize(mLastSelectionStart, mLastSelectionEnd,
- selectedText.toString(), mSettings.getCurrentLocale(),
- mSettings.getWordSeparators());
+ selectedText.toString(), currentSettings.mLocale,
+ currentSettings.mWordSeparators);
// We trim leading and trailing whitespace.
mRecapitalizeStatus.trim();
// Trimming the object may have changed the length of the string, and we need to
@@ -2020,17 +2098,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Returns true if we did an autocorrection, false otherwise.
private boolean handleSeparator(final int primaryCode, final int x, final int y,
final int spaceState) {
- if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
- ResearchLogger.latinIME_handleSeparator(primaryCode, mWordComposer.isComposingWord());
- }
boolean didAutoCorrect = false;
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 (mSettings.getCurrent().mCorrectionEnabled) {
+ if (currentSettings.mCorrectionEnabled) {
// TODO: maybe cache Strings in an <String> sparse array or something
commitCurrentAutoCorrection(new String(new int[]{primaryCode}, 0, 1));
didAutoCorrect = true;
@@ -2043,13 +2119,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
Constants.SUGGESTION_STRIP_COORDINATE == x);
if (SPACE_STATE_PHANTOM == spaceState &&
- mSettings.getCurrent().isUsuallyPrecededBySpace(primaryCode)) {
+ currentSettings.isUsuallyPrecededBySpace(primaryCode)) {
promotePhantomSpace();
}
+ if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
+ ResearchLogger.latinIME_handleSeparator(primaryCode, mWordComposer.isComposingWord());
+ }
sendKeyCodePoint(primaryCode);
if (Constants.CODE_SPACE == primaryCode) {
- if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) {
+ if (currentSettings.isSuggestionsRequested(mDisplayOrientation)) {
if (maybeDoubleSpacePeriod()) {
mSpaceState = SPACE_STATE_DOUBLE;
} else if (!isShowingPunctuationList()) {
@@ -2064,7 +2143,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
swapSwapperAndSpace();
mSpaceState = SPACE_STATE_SWAP_PUNCTUATION;
} else if (SPACE_STATE_PHANTOM == spaceState
- && mSettings.getCurrent().isUsuallyFollowedBySpace(primaryCode)) {
+ && currentSettings.isUsuallyFollowedBySpace(primaryCode)) {
// If we are in phantom space state, and the user presses a separator, we want to
// stay in phantom space state so that the next keypress has a chance to add the
// space. For example, if I type "Good dat", pick "day" from the suggestion strip
@@ -2082,8 +2161,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// already displayed or not, so it's okay.
setPunctuationSuggestions();
}
- if (mSettings.isInternal()) {
- Utils.Stats.onSeparator((char)primaryCode, x, y);
+ if (currentSettings.mIsInternal) {
+ LatinImeLoggerUtils.onSeparator((char)primaryCode, x, y);
}
mKeyboardSwitcher.updateShiftState();
@@ -2115,17 +2194,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
private boolean isSuggestionsStripVisible() {
+ final SettingsValues currentSettings = mSettings.getCurrent();
if (mSuggestionStripView == null)
return false;
if (mSuggestionStripView.isShowingAddToDictionaryHint())
return true;
- if (null == mSettings.getCurrent())
+ if (null == currentSettings)
return false;
- if (!mSettings.getCurrent().isSuggestionStripVisibleInOrientation(mDisplayOrientation))
+ if (!currentSettings.isSuggestionStripVisibleInOrientation(mDisplayOrientation))
return false;
- if (mSettings.getCurrent().isApplicationSpecifiedCompletionsOn())
+ if (currentSettings.isApplicationSpecifiedCompletionsOn())
return true;
- return mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation);
+ return currentSettings.isSuggestionsRequested(mDisplayOrientation);
}
private void clearSuggestionStrip() {
@@ -2158,10 +2238,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private void updateSuggestionStrip() {
mHandler.cancelUpdateSuggestionStrip();
+ final SettingsValues currentSettings = mSettings.getCurrent();
// Check if we have a suggestion engine attached.
if (mSuggest == null
- || !mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) {
+ || !currentSettings.isSuggestionsRequested(mDisplayOrientation)) {
if (mWordComposer.isComposingWord()) {
Log.w(TAG, "Called updateSuggestionsOrPredictions but suggestions were not "
+ "requested!");
@@ -2169,7 +2250,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return;
}
- if (!mWordComposer.isComposingWord() && !mSettings.getCurrent().mBigramPredictionEnabled) {
+ if (!mWordComposer.isComposingWord() && !currentSettings.mBigramPredictionEnabled) {
setPunctuationSuggestions();
return;
}
@@ -2182,19 +2263,21 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private SuggestedWords getSuggestedWords(final int sessionId) {
final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
- if (keyboard == null || mSuggest == null) {
+ final Suggest suggest = mSuggest;
+ if (keyboard == null || suggest == null) {
return SuggestedWords.EMPTY;
}
// 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(mSettings.getCurrent().mWordSeparators,
+ mConnection.getNthPreviousWord(currentSettings.mWordSeparators,
mWordComposer.isComposingWord() ? 2 : 1);
- return mSuggest.getSuggestedWords(mWordComposer, prevWord, keyboard.getProximityInfo(),
- mSettings.getBlockPotentiallyOffensive(),
- mSettings.getCurrent().mCorrectionEnabled, sessionId);
+ return suggest.getSuggestedWords(mWordComposer, prevWord, keyboard.getProximityInfo(),
+ currentSettings.mBlockPotentiallyOffensive,
+ currentSettings.mCorrectionEnabled, sessionId);
}
private SuggestedWords getSuggestedWordsOrOlderSuggestions(final int sessionId) {
@@ -2272,7 +2355,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
+ "is empty? Impossible! I must commit suicide.");
}
if (mSettings.isInternal()) {
- Stats.onAutoCorrection(typedWord, autoCorrection, separatorString, mWordComposer);
+ LatinImeLoggerUtils.onAutoCorrection(
+ typedWord, autoCorrection, separatorString, mWordComposer);
}
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
final SuggestedWords suggestedWords = mSuggestedWords;
@@ -2319,18 +2403,19 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
mConnection.beginBatchEdit();
+ final SettingsValues currentSettings = mSettings.getCurrent();
if (SPACE_STATE_PHANTOM == mSpaceState && suggestion.length() > 0
// In the batch input mode, a manually picked suggested word should just replace
// the current batch input text and there is no need for a phantom space.
&& !mWordComposer.isBatchMode()) {
final int firstChar = Character.codePointAt(suggestion, 0);
- if (!mSettings.getCurrent().isWordSeparator(firstChar)
- || mSettings.getCurrent().isUsuallyPrecededBySpace(firstChar)) {
+ if (!currentSettings.isWordSeparator(firstChar)
+ || currentSettings.isUsuallyPrecededBySpace(firstChar)) {
promotePhantomSpace();
}
}
- if (mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()
+ if (currentSettings.isApplicationSpecifiedCompletionsOn()
&& mApplicationSpecifiedCompletions != null
&& index >= 0 && index < mApplicationSpecifiedCompletions.length) {
mSuggestedWords = SuggestedWords.EMPTY;
@@ -2354,7 +2439,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
LastComposedWord.NOT_A_SEPARATOR);
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_pickSuggestionManually(replacedWord, index, suggestion,
- mWordComposer.isBatchMode());
+ mWordComposer.isBatchMode(), suggestionInfo.mScore, suggestionInfo.mKind,
+ suggestionInfo.mSourceDict);
}
mConnection.endBatchEdit();
// Don't allow cancellation of manual pick
@@ -2367,18 +2453,21 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// AND it's in none of our current dictionaries (main, user or otherwise).
// Please note that if mSuggest is null, it means that everything is off: suggestion
// and correction, so we shouldn't try to show the hint
+ final Suggest suggest = mSuggest;
final boolean showingAddToDictionaryHint =
- SuggestedWordInfo.KIND_TYPED == suggestionInfo.mKind && mSuggest != null
- // If the suggestion is not in the dictionary, the hint should be shown.
- && !AutoCorrection.isValidWord(mSuggest.getUnigramDictionaries(), suggestion, true);
-
- if (mSettings.isInternal()) {
- Stats.onSeparator((char)Constants.CODE_SPACE,
+ (SuggestedWordInfo.KIND_TYPED == suggestionInfo.mKind
+ || SuggestedWordInfo.KIND_OOV_CORRECTION == suggestionInfo.mKind)
+ && suggest != null
+ // If the suggestion is not in the dictionary, the hint should be shown.
+ && !AutoCorrectionUtils.isValidWord(suggest, suggestion, true);
+
+ if (currentSettings.mIsInternal) {
+ LatinImeLoggerUtils.onSeparator((char)Constants.CODE_SPACE,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
}
if (showingAddToDictionaryHint && mIsUserDictionaryAvailable) {
mSuggestionStripView.showAddToDictionaryHint(
- suggestion, mSettings.getCurrent().mHintToSaveText);
+ suggestion, currentSettings.mHintToSaveText);
} else {
// If we're not showing the "Touch again to save", then update the suggestion strip.
mHandler.postUpdateSuggestionStrip();
@@ -2404,10 +2493,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
private void setPunctuationSuggestions() {
- if (mSettings.getCurrent().mBigramPredictionEnabled) {
+ final SettingsValues currentSettings = mSettings.getCurrent();
+ if (currentSettings.mBigramPredictionEnabled) {
clearSuggestionStrip();
} else {
- setSuggestedWords(mSettings.getCurrent().mSuggestPuncList, false);
+ setSuggestedWords(currentSettings.mSuggestPuncList, false);
}
setAutoCorrectionIndicator(false);
setSuggestionStripShown(isSuggestionsStripVisible());
@@ -2415,21 +2505,20 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private String addToUserHistoryDictionary(final String suggestion) {
if (TextUtils.isEmpty(suggestion)) return null;
- if (mSuggest == null) return null;
+ final Suggest suggest = mSuggest;
+ if (suggest == null) return null;
// If correction is not enabled, we don't add words to the user history dictionary.
// That's to avoid unintended additions in some sensitive fields, or fields that
// expect to receive non-words.
- if (!mSettings.getCurrent().mCorrectionEnabled) return null;
+ final SettingsValues currentSettings = mSettings.getCurrent();
+ if (!currentSettings.mCorrectionEnabled) return null;
- final Suggest suggest = mSuggest;
- final UserHistoryDictionary userHistoryDictionary = mUserHistoryDictionary;
- if (suggest == null || userHistoryDictionary == null) {
- // Avoid concurrent issue
- return null;
- }
- final String prevWord
- = mConnection.getNthPreviousWord(mSettings.getCurrent().mWordSeparators, 2);
+ final UserHistoryPredictionDictionary userHistoryPredictionDictionary =
+ mUserHistoryPredictionDictionary;
+ if (userHistoryPredictionDictionary == null) return null;
+
+ final String prevWord = mConnection.getNthPreviousWord(currentSettings.mWordSeparators, 2);
final String secondWord;
if (mWordComposer.wasAutoCapitalized() && !mWordComposer.isMostlyCaps()) {
secondWord = suggestion.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale());
@@ -2438,10 +2527,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
// We demote unrecognized words (frequency < 0, below) by specifying them as "invalid".
// We don't add words with 0-frequency (assuming they would be profanity etc.).
- final int maxFreq = AutoCorrection.getMaxFrequency(
+ final int maxFreq = AutoCorrectionUtils.getMaxFrequency(
suggest.getUnigramDictionaries(), suggestion);
if (maxFreq == 0) return null;
- userHistoryDictionary.addToUserHistory(prevWord, secondWord, maxFreq > 0);
+ userHistoryPredictionDictionary.addToUserHistory(prevWord, secondWord, maxFreq > 0);
return prevWord;
}
@@ -2458,35 +2547,34 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (mLastSelectionStart != mLastSelectionEnd) return;
// If we don't know the cursor location, return.
if (mLastSelectionStart < 0) return;
- if (!mConnection.isCursorTouchingWord(mSettings.getCurrent())) return;
- final Range range = mConnection.getWordRangeAtCursor(mSettings.getWordSeparators(),
+ final SettingsValues currentSettings = mSettings.getCurrent();
+ if (!mConnection.isCursorTouchingWord(currentSettings)) return;
+ final TextRange range = mConnection.getWordRangeAtCursor(currentSettings.mWordSeparators,
0 /* additionalPrecedingWordsCount */);
if (null == range) return; // Happens if we don't have an input connection at all
// If for some strange reason (editor bug or so) we measure the text before the cursor as
// longer than what the entire text is supposed to be, the safe thing to do is bail out.
- if (range.mCharsBefore > mLastSelectionStart) return;
+ final int numberOfCharsInWordBeforeCursor = range.getNumberOfCharsInWordBeforeCursor();
+ if (numberOfCharsInWordBeforeCursor > mLastSelectionStart) return;
final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
final String typedWord = range.mWord.toString();
- if (range.mWord instanceof SpannableString) {
- final SpannableString spannableString = (SpannableString)range.mWord;
- int i = 0;
- for (Object object : spannableString.getSpans(0, spannableString.length(),
- SuggestionSpan.class)) {
- SuggestionSpan span = (SuggestionSpan)object;
- for (String s : span.getSuggestions()) {
- ++i;
- if (!TextUtils.equals(s, typedWord)) {
- suggestions.add(new SuggestedWordInfo(s,
- SuggestionStripView.MAX_SUGGESTIONS - i,
- SuggestedWordInfo.KIND_RESUMED, Dictionary.TYPE_RESUMED));
- }
+ int i = 0;
+ for (final SuggestionSpan span : range.getSuggestionSpansAtWord()) {
+ for (final String s : span.getSuggestions()) {
+ ++i;
+ if (!TextUtils.equals(s, typedWord)) {
+ suggestions.add(new SuggestedWordInfo(s,
+ SuggestionStripView.MAX_SUGGESTIONS - i,
+ SuggestedWordInfo.KIND_RESUMED, Dictionary.TYPE_RESUMED));
}
}
}
mWordComposer.setComposingWord(typedWord, mKeyboardSwitcher.getKeyboard());
- mWordComposer.setCursorPositionWithinWord(range.mCharsBefore);
- mConnection.setComposingRegion(mLastSelectionStart - range.mCharsBefore,
- mLastSelectionEnd + range.mCharsAfter);
+ // TODO: this is in chars but the callee expects code points!
+ mWordComposer.setCursorPositionWithinWord(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
@@ -2575,18 +2663,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
mConnection.deleteSurroundingText(deleteLength, 0);
if (!TextUtils.isEmpty(previousWord) && !TextUtils.isEmpty(committedWord)) {
- mUserHistoryDictionary.cancelAddingUserHistory(previousWord, committedWord);
+ mUserHistoryPredictionDictionary.cancelAddingUserHistory(previousWord, committedWord);
}
mConnection.commitText(originallyTypedWord + mLastComposedWord.mSeparatorString, 1);
if (mSettings.isInternal()) {
- Stats.onSeparator(mLastComposedWord.mSeparatorString,
+ LatinImeLoggerUtils.onSeparator(mLastComposedWord.mSeparatorString,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
}
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_revertCommit(committedWord, originallyTypedWord,
mWordComposer.isBatchMode(), mLastComposedWord.mSeparatorString);
- ResearchLogger.getInstance().uncommitCurrentLogUnit(committedWord,
- true /* dumpCurrentLogUnit */);
}
// Don't restart suggestion yet. We'll restart if the user deletes the
// separator.
@@ -2599,45 +2685,54 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public void promotePhantomSpace() {
if (mSettings.getCurrent().shouldInsertSpacesAutomatically()
&& !mConnection.textBeforeCursorLooksLikeURL()) {
- sendKeyCodePoint(Constants.CODE_SPACE);
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_promotePhantomSpace();
}
+ sendKeyCodePoint(Constants.CODE_SPACE);
}
}
- // Used by the RingCharBuffer
- public boolean isWordSeparator(final int code) {
- return mSettings.getCurrent().isWordSeparator(code);
- }
-
// TODO: Make this private
// Outside LatinIME, only used by the {@link InputTestsBase} test suite.
@UsedForTesting
void loadKeyboard() {
- // TODO: Why are we calling {@link #loadSettings()} and {@link #initSuggest()} in a
- // different order than in {@link #onStartInputView}?
- initSuggest();
+ // Since we are switching languages, the most urgent thing is to let the keyboard graphics
+ // update. LoadKeyboard does that, but we need to wait for buffer flip for it to be on
+ // the screen. Anything we do right now will delay this, so wait until the next frame
+ // before we do the rest, like reopening dictionaries and updating suggestions. So we
+ // post a message.
+ mHandler.postReopenDictionaries();
loadSettings();
if (mKeyboardSwitcher.getMainKeyboardView() != null) {
// Reload keyboard because the current language has been changed.
mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mSettings.getCurrent());
}
- // Since we just changed languages, we should re-evaluate suggestions with whatever word
- // we are currently composing. If we are not composing anything, we may want to display
- // predictions or punctuation signs (which is done by the updateSuggestionStrip anyway).
- mHandler.postUpdateSuggestionStrip();
}
- // Callback called by PointerTracker through the KeyboardActionListener. This is called when a
- // key is depressed; release matching call is onReleaseKey below.
+ private void hapticAndAudioFeedback(final int code, final boolean isRepeatKey) {
+ 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;
+ }
+ AudioAndHapticFeedbackManager.getInstance().hapticAndAudioFeedback(code, keyboardView);
+ }
+
+ // 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 isSinglePointer) {
+ public void onPressKey(final int primaryCode, final boolean isRepeatKey,
+ final boolean isSinglePointer) {
mKeyboardSwitcher.onPressKey(primaryCode, isSinglePointer);
+ hapticAndAudioFeedback(primaryCode, isRepeatKey);
}
- // Callback by PointerTracker through the KeyboardActionListener. This is called when a key
- // is released; press matching call is onPressKey above.
+ // Callback of the {@link KeyboardActionListener}. This is called when a key is released;
+ // press matching call is {@link #onPressKey(int,boolean,boolean)} above.
@Override
public void onReleaseKey(final int primaryCode, final boolean withSliding) {
mKeyboardSwitcher.onReleaseKey(primaryCode, withSliding);
@@ -2703,7 +2798,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
mSubtypeSwitcher.onNetworkStateChanged(intent);
} else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
- mKeyboardSwitcher.onRingerModeChanged();
+ AudioAndHapticFeedbackManager.getInstance().onRingerModeChanged();
}
}
};
@@ -2734,7 +2829,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final CharSequence[] items = new CharSequence[] {
// TODO: Should use new string "Select active input modes".
getString(R.string.language_selection_title),
- getString(Utils.getAcitivityTitleResId(this, SettingsActivity.class)),
+ getString(ApplicationUtils.getAcitivityTitleResId(this, SettingsActivity.class)),
};
final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
@Override
@@ -2787,6 +2882,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return mSuggestedWords.size() > 0 ? mSuggestedWords.getWord(0) : null;
}
+ // DO NOT USE THIS for any other purpose than testing. This is information private to LatinIME.
+ @UsedForTesting
+ /* package for test */ boolean isCurrentlyWaitingForMainDictionary() {
+ return mSuggest.isCurrentlyWaitingForMainDictionary();
+ }
+
+ // DO NOT USE THIS for any other purpose than testing. This is information private to LatinIME.
+ @UsedForTesting
+ /* package for test */ boolean hasMainDictionary() {
+ return mSuggest.hasMainDictionary();
+ }
+
public void debugDumpStateAndCrashWithException(final String context) {
final StringBuilder s = new StringBuilder(mAppWorkAroundsUtils.toString());
s.append("\nAttributes : ").append(mSettings.getCurrent().mInputAttributes)