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.java1121
1 files changed, 405 insertions, 716 deletions
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 97e898af9..6d902b89a 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -48,15 +48,12 @@ import android.util.Printer;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
-import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
-import android.view.ViewParent;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.accessibility.AccessibilityUtils;
@@ -64,6 +61,7 @@ import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
import com.android.inputmethod.compat.CompatUtils;
import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
import com.android.inputmethod.compat.SuggestionSpanUtils;
+import com.android.inputmethod.keyboard.KeyDetector;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardActionListener;
import com.android.inputmethod.keyboard.KeyboardId;
@@ -103,27 +101,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
*/
private static final String SCHEME_PACKAGE = "package";
- /** Whether to use the binary version of the contacts dictionary */
- public static final boolean USE_BINARY_CONTACTS_DICTIONARY = true;
-
- /** Whether to use the binary version of the user dictionary */
- public static final boolean USE_BINARY_USER_DICTIONARY = true;
-
- // TODO: migrate this to SettingsValues
- private int mSuggestionVisibility;
- private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE
- = R.string.prefs_suggestion_visibility_show_value;
- private static final int SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
- = R.string.prefs_suggestion_visibility_show_only_portrait_value;
- private static final int SUGGESTION_VISIBILILTY_HIDE_VALUE
- = R.string.prefs_suggestion_visibility_hide_value;
-
- private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] {
- SUGGESTION_VISIBILILTY_SHOW_VALUE,
- SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE,
- SUGGESTION_VISIBILILTY_HIDE_VALUE
- };
-
private static final int SPACE_STATE_NONE = 0;
// Double space: the state where the user pressed space twice quickly, which LatinIME
// resolved as period-space. Undoing this converts the period to a space.
@@ -143,8 +120,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Current space state of the input method. This can be any of the above constants.
private int mSpaceState;
- private SettingsValues mSettingsValues;
- private InputAttributes mInputAttributes;
+ private SettingsValues mCurrentSettings;
private View mExtractArea;
private View mKeyPreviewBackingView;
@@ -162,15 +138,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private boolean mShouldSwitchToLastSubtype = true;
private boolean mIsMainDictionaryAvailable;
- // TODO: revert this back to the concrete class after transition.
- private Dictionary mUserDictionary;
+ private UserBinaryDictionary mUserDictionary;
private UserHistoryDictionary mUserHistoryDictionary;
private boolean mIsUserDictionaryAvailable;
private LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
private WordComposer mWordComposer = new WordComposer();
-
- private int mCorrectionMode;
+ private RichInputConnection mConnection = new RichInputConnection(this);
// Keep track of the last selection range to decide if we need to show word alternatives
private static final int NOT_A_CURSOR_POSITION = -1;
@@ -203,14 +177,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public static class UIHandler extends StaticInnerHandlerWrapper<LatinIME> {
private static final int MSG_UPDATE_SHIFT_STATE = 1;
- private static final int MSG_SPACE_TYPED = 4;
- private static final int MSG_SET_BIGRAM_PREDICTIONS = 5;
private static final int MSG_PENDING_IMS_CALLBACK = 6;
- private static final int MSG_UPDATE_SUGGESTIONS = 7;
+ private static final int MSG_UPDATE_SUGGESTION_STRIP = 7;
private int mDelayUpdateSuggestions;
private int mDelayUpdateShiftState;
private long mDoubleSpacesTurnIntoPeriodTimeout;
+ private long mDoubleSpaceTimerStart;
public UIHandler(LatinIME outerInstance) {
super(outerInstance);
@@ -231,29 +204,25 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final LatinIME latinIme = getOuterInstance();
final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher;
switch (msg.what) {
- case MSG_UPDATE_SUGGESTIONS:
- latinIme.updateSuggestions();
+ case MSG_UPDATE_SUGGESTION_STRIP:
+ latinIme.updateSuggestionsOrPredictions();
break;
case MSG_UPDATE_SHIFT_STATE:
switcher.updateShiftState();
break;
- case MSG_SET_BIGRAM_PREDICTIONS:
- latinIme.updateBigramPredictions();
- break;
}
}
- public void postUpdateSuggestions() {
- removeMessages(MSG_UPDATE_SUGGESTIONS);
- sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTIONS), mDelayUpdateSuggestions);
+ public void postUpdateSuggestionStrip() {
+ sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION_STRIP), mDelayUpdateSuggestions);
}
- public void cancelUpdateSuggestions() {
- removeMessages(MSG_UPDATE_SUGGESTIONS);
+ public void cancelUpdateSuggestionStrip() {
+ removeMessages(MSG_UPDATE_SUGGESTION_STRIP);
}
public boolean hasPendingUpdateSuggestions() {
- return hasMessages(MSG_UPDATE_SUGGESTIONS);
+ return hasMessages(MSG_UPDATE_SUGGESTION_STRIP);
}
public void postUpdateShiftState() {
@@ -265,26 +234,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
removeMessages(MSG_UPDATE_SHIFT_STATE);
}
- public void postUpdateBigramPredictions() {
- removeMessages(MSG_SET_BIGRAM_PREDICTIONS);
- sendMessageDelayed(obtainMessage(MSG_SET_BIGRAM_PREDICTIONS), mDelayUpdateSuggestions);
- }
-
- public void cancelUpdateBigramPredictions() {
- removeMessages(MSG_SET_BIGRAM_PREDICTIONS);
- }
-
public void startDoubleSpacesTimer() {
- removeMessages(MSG_SPACE_TYPED);
- sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED), mDoubleSpacesTurnIntoPeriodTimeout);
+ mDoubleSpaceTimerStart = SystemClock.uptimeMillis();
}
public void cancelDoubleSpacesTimer() {
- removeMessages(MSG_SPACE_TYPED);
+ mDoubleSpaceTimerStart = 0;
}
public boolean isAcceptingDoubleSpaces() {
- return hasMessages(MSG_SPACE_TYPED);
+ return SystemClock.uptimeMillis() - mDoubleSpaceTimerStart
+ < mDoubleSpacesTurnIntoPeriodTimeout;
}
// Working variables for the following methods.
@@ -393,7 +353,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mPrefs = prefs;
LatinImeLogger.init(this, prefs);
if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.init(this, prefs);
+ ResearchLogger.getInstance().init(this, prefs);
}
InputMethodManagerCompatWrapper.init(this);
SubtypeSwitcher.init(this);
@@ -411,14 +371,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
loadSettings();
- ImfUtils.setAdditionalInputMethodSubtypes(this, mSettingsValues.getAdditionalSubtypes());
-
- // TODO: remove the following when it's not needed by updateCorrectionMode() any more
- mInputAttributes = new InputAttributes(null, false /* isFullscreenMode */);
- updateCorrectionMode();
+ ImfUtils.setAdditionalInputMethodSubtypes(this, mCurrentSettings.getAdditionalSubtypes());
Utils.GCUtils.getInstance().reset();
boolean tryGC = true;
+ // Shouldn't this be removed? I think that from Honeycomb on, the GC is now actually working
+ // as expected and this code is useless.
for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
try {
initSuggest();
@@ -454,14 +412,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged()
// is not guaranteed. It may even be called at the same time on a different thread.
if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+ final InputAttributes inputAttributes =
+ new InputAttributes(getCurrentInputEditorInfo(), isFullscreenMode());
final RunInLocale<SettingsValues> job = new RunInLocale<SettingsValues>() {
@Override
protected SettingsValues job(Resources res) {
- return new SettingsValues(mPrefs, LatinIME.this);
+ return new SettingsValues(mPrefs, inputAttributes, LatinIME.this);
}
};
- mSettingsValues = job.runInLocale(mResources, mSubtypeSwitcher.getCurrentSubtypeLocale());
- mFeedbackManager = new AudioAndHapticFeedbackManager(this, mSettingsValues);
+ mCurrentSettings = job.runInLocale(mResources, mSubtypeSwitcher.getCurrentSubtypeLocale());
+ mFeedbackManager = new AudioAndHapticFeedbackManager(this, mCurrentSettings);
resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary());
}
@@ -469,7 +429,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
final String localeStr = subtypeLocale.toString();
- final Dictionary oldContactsDictionary;
+ final ContactsBinaryDictionary oldContactsDictionary;
if (mSuggest != null) {
oldContactsDictionary = mSuggest.getContactsDictionary();
mSuggest.close();
@@ -477,19 +437,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
oldContactsDictionary = null;
}
mSuggest = new Suggest(this, subtypeLocale);
- if (mSettingsValues.mAutoCorrectEnabled) {
- mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
+ if (mCurrentSettings.mCorrectionEnabled) {
+ mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold);
}
mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale);
-
- if (USE_BINARY_USER_DICTIONARY) {
- mUserDictionary = new UserBinaryDictionary(this, localeStr);
- mIsUserDictionaryAvailable = ((UserBinaryDictionary)mUserDictionary).isEnabled();
- } else {
- mUserDictionary = new UserDictionary(this, localeStr);
- mIsUserDictionaryAvailable = ((UserDictionary)mUserDictionary).isEnabled();
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.getInstance().initSuggest(mSuggest);
}
+
+ mUserDictionary = new UserBinaryDictionary(this, localeStr);
+ mIsUserDictionaryAvailable = mUserDictionary.isEnabled();
mSuggest.setUserDictionary(mUserDictionary);
resetContactsDictionary(oldContactsDictionary);
@@ -497,44 +455,43 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged()
// is not guaranteed. It may even be called at the same time on a different thread.
if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
- mUserHistoryDictionary = UserHistoryDictionary.getInstance(
- this, localeStr, Suggest.DIC_USER_HISTORY, mPrefs);
+ mUserHistoryDictionary = UserHistoryDictionary.getInstance(this, localeStr, mPrefs);
mSuggest.setUserHistoryDictionary(mUserHistoryDictionary);
}
/**
* Resets the contacts dictionary in mSuggest according to the user settings.
*
- * This method takes an optional contacts dictionary to use. Since the contacts dictionary
- * does not depend on the locale, it can be reused across different instances of Suggest.
- * The dictionary will also be opened or closed as necessary depending on the settings.
+ * This method takes an optional contacts dictionary to use when the locale hasn't changed
+ * since the contacts dictionary can be opened or closed as necessary depending on the settings.
*
* @param oldContactsDictionary an optional dictionary to use, or null
*/
- private void resetContactsDictionary(final Dictionary oldContactsDictionary) {
- final boolean shouldSetDictionary = (null != mSuggest && mSettingsValues.mUseContactsDict);
+ private void resetContactsDictionary(final ContactsBinaryDictionary oldContactsDictionary) {
+ final boolean shouldSetDictionary = (null != mSuggest && mCurrentSettings.mUseContactsDict);
- final Dictionary dictionaryToUse;
+ final ContactsBinaryDictionary dictionaryToUse;
if (!shouldSetDictionary) {
// Make sure the dictionary is closed. If it is already closed, this is a no-op,
// so it's safe to call it anyways.
if (null != oldContactsDictionary) oldContactsDictionary.close();
dictionaryToUse = null;
- } else if (null != oldContactsDictionary) {
- // Make sure the old contacts dictionary is opened. If it is already open, this is a
- // no-op, so it's safe to call it anyways.
- if (USE_BINARY_CONTACTS_DICTIONARY) {
- ((ContactsBinaryDictionary)oldContactsDictionary).reopen(this);
- } else {
- ((ContactsDictionary)oldContactsDictionary).reopen(this);
- }
- dictionaryToUse = oldContactsDictionary;
} else {
- if (USE_BINARY_CONTACTS_DICTIONARY) {
- dictionaryToUse = new ContactsBinaryDictionary(this, Suggest.DIC_CONTACTS,
- mSubtypeSwitcher.getCurrentSubtypeLocale());
+ final Locale locale = mSubtypeSwitcher.getCurrentSubtypeLocale();
+ if (null != oldContactsDictionary) {
+ if (!oldContactsDictionary.mLocale.equals(locale)) {
+ // If the locale has changed then recreate the contacts dictionary. This
+ // allows locale dependent rules for handling bigram name predictions.
+ oldContactsDictionary.close();
+ dictionaryToUse = new ContactsBinaryDictionary(this, locale);
+ } else {
+ // Make sure the old contacts dictionary is opened. If it is already open,
+ // this is a no-op, so it's safe to call it anyways.
+ oldContactsDictionary.reopen(this);
+ dictionaryToUse = oldContactsDictionary;
+ }
} else {
- dictionaryToUse = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
+ dictionaryToUse = new ContactsBinaryDictionary(this, locale);
}
}
@@ -569,9 +526,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (mDisplayOrientation != conf.orientation) {
mDisplayOrientation = conf.orientation;
mHandler.startOrientationChanging();
- final InputConnection ic = getCurrentInputConnection();
- commitTyped(ic, LastComposedWord.NOT_A_SEPARATOR);
- if (ic != null) ic.finishComposingText(); // For voice input
+ mConnection.beginBatchEdit();
+ commitTyped(LastComposedWord.NOT_A_SEPARATOR);
+ mConnection.finishComposingText();
+ mConnection.endBatchEdit();
if (isShowingOptionDialog())
mOptionsDialog.dismiss();
}
@@ -660,6 +618,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
+ ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS) != 0));
}
if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.getInstance().start();
ResearchLogger.latinIME_onStartInputViewInternal(editorInfo, mPrefs);
}
if (InputAttributes.inPrivateImeOptions(null, NO_MICROPHONE_COMPAT, editorInfo)) {
@@ -699,7 +658,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
updateFullscreenMode();
mLastSelectionStart = editorInfo.initialSelStart;
mLastSelectionEnd = editorInfo.initialSelEnd;
- mInputAttributes = new InputAttributes(editorInfo, isFullscreenMode());
mApplicationSpecifiedCompletions = null;
inputView.closing();
@@ -709,36 +667,40 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mSpaceState = SPACE_STATE_NONE;
loadSettings();
- updateCorrectionMode();
- updateSuggestionVisibility(mResources);
- if (mSuggest != null && mSettingsValues.mAutoCorrectEnabled) {
- mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
+ if (mSuggest != null && mCurrentSettings.mCorrectionEnabled) {
+ mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold);
}
- switcher.loadKeyboard(editorInfo, mSettingsValues);
+ switcher.loadKeyboard(editorInfo, mCurrentSettings);
if (mSuggestionsView != null)
mSuggestionsView.clear();
setSuggestionStripShownInternal(
isSuggestionsStripVisible(), /* needsInputViewShown */ false);
- // Delay updating suggestions because keyboard input view may not be shown at this point.
- mHandler.postUpdateSuggestions();
+
+ mHandler.cancelUpdateSuggestionStrip();
mHandler.cancelDoubleSpacesTimer();
- inputView.setKeyPreviewPopupEnabled(mSettingsValues.mKeyPreviewPopupOn,
- mSettingsValues.mKeyPreviewPopupDismissDelay);
+ inputView.setKeyPreviewPopupEnabled(mCurrentSettings.mKeyPreviewPopupOn,
+ mCurrentSettings.mKeyPreviewPopupDismissDelay);
inputView.setProximityCorrectionEnabled(true);
if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
}
+ // Callback for the TargetApplicationGetter
+ @Override
public void onTargetApplicationKnown(final ApplicationInfo info) {
mTargetApplicationInfo = info;
}
@Override
public void onWindowHidden() {
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_onWindowHidden(mLastSelectionStart, mLastSelectionEnd,
+ getCurrentInputConnection());
+ }
super.onWindowHidden();
KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
if (inputView != null) inputView.closing();
@@ -748,6 +710,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
super.onFinishInput();
LatinImeLogger.commit();
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.getInstance().stop();
+ }
KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
if (inputView != null) inputView.closing();
@@ -759,7 +724,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
if (inputView != null) inputView.cancelAllMessages();
// Remove pending messages related to update suggestions
- mHandler.cancelUpdateSuggestions();
+ mHandler.cancelUpdateSuggestionStrip();
}
@Override
@@ -768,7 +733,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
int composingSpanStart, int composingSpanEnd) {
super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
composingSpanStart, composingSpanEnd);
-
if (DEBUG) {
Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart
+ ", ose=" + oldSelEnd
@@ -780,9 +744,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
+ ", ce=" + composingSpanEnd);
}
if (ProductionFlag.IS_EXPERIMENTAL) {
+ final boolean expectingUpdateSelectionFromLogger =
+ ResearchLogger.getAndClearLatinIMEExpectingUpdateSelection();
ResearchLogger.latinIME_onUpdateSelection(mLastSelectionStart, mLastSelectionEnd,
oldSelStart, oldSelEnd, newSelStart, newSelEnd, composingSpanStart,
- composingSpanEnd);
+ composingSpanEnd, mExpectingUpdateSelection,
+ expectingUpdateSelectionFromLogger, mConnection);
+ if (expectingUpdateSelectionFromLogger) {
+ // TODO: Investigate. Quitting now sounds wrong - we won't do the resetting work
+ return;
+ }
}
// TODO: refactor the following code to be less contrived.
@@ -841,7 +812,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
*/
@Override
public void onExtractedTextClicked() {
- if (isSuggestionsRequested()) return;
+ if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) return;
super.onExtractedTextClicked();
}
@@ -857,7 +828,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
*/
@Override
public void onExtractedCursorMovement(int dx, int dy) {
- if (isSuggestionsRequested()) return;
+ if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) return;
super.onExtractedCursorMovement(dx, dy);
}
@@ -888,33 +859,31 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions);
}
- if (mInputAttributes.mApplicationSpecifiedCompletionOn) {
- mApplicationSpecifiedCompletions = applicationSpecifiedCompletions;
- if (applicationSpecifiedCompletions == null) {
- clearSuggestions();
- return;
- }
-
- final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords =
- SuggestedWords.getFromApplicationSpecifiedCompletions(
- applicationSpecifiedCompletions);
- final SuggestedWords suggestedWords = new SuggestedWords(
- applicationSuggestedWords,
- false /* typedWordValid */,
- false /* hasAutoCorrectionCandidate */,
- false /* allowsToBeAutoCorrected */,
- false /* isPunctuationSuggestions */,
- false /* isObsoleteSuggestions */,
- false /* isPrediction */);
- // When in fullscreen mode, show completions generated by the application
- final boolean isAutoCorrection = false;
- setSuggestions(suggestedWords, isAutoCorrection);
- setAutoCorrectionIndicator(isAutoCorrection);
- // TODO: is this the right thing to do? What should we auto-correct to in
- // this case? This says to keep whatever the user typed.
- mWordComposer.setAutoCorrection(mWordComposer.getTypedWord());
- setSuggestionStripShown(true);
+ if (!mCurrentSettings.isApplicationSpecifiedCompletionsOn()) return;
+ mApplicationSpecifiedCompletions = applicationSpecifiedCompletions;
+ if (applicationSpecifiedCompletions == null) {
+ clearSuggestions();
+ return;
}
+
+ final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords =
+ SuggestedWords.getFromApplicationSpecifiedCompletions(
+ applicationSpecifiedCompletions);
+ final SuggestedWords suggestedWords = new SuggestedWords(
+ applicationSuggestedWords,
+ false /* typedWordValid */,
+ false /* hasAutoCorrectionCandidate */,
+ false /* isPunctuationSuggestions */,
+ false /* isObsoleteSuggestions */,
+ false /* isPrediction */);
+ // When in fullscreen mode, show completions generated by the application
+ final boolean isAutoCorrection = false;
+ setSuggestions(suggestedWords, isAutoCorrection);
+ setAutoCorrectionIndicator(isAutoCorrection);
+ // TODO: is this the right thing to do? What should we auto-correct to in
+ // this case? This says to keep whatever the user typed.
+ mWordComposer.setAutoCorrection(mWordComposer.getTypedWord());
+ setSuggestionStripShown(true);
}
private void setSuggestionStripShownInternal(boolean shown, boolean needsInputViewShown) {
@@ -1001,7 +970,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public boolean onEvaluateFullscreenMode() {
// Reread resource value here, because this method is called by framework anytime as needed.
final boolean isFullscreenModeAllowed =
- mSettingsValues.isFullscreenModeAllowed(getResources());
+ mCurrentSettings.isFullscreenModeAllowed(getResources());
return super.onEvaluateFullscreenMode() && isFullscreenModeAllowed;
}
@@ -1016,15 +985,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
// This will reset the whole input state to the starting state. It will clear
- // the composing word, reset the last composed word, tell the inputconnection
- // and the composingStateManager about it.
+ // the composing word, reset the last composed word, tell the inputconnection about it.
private void resetEntireInputState() {
resetComposingState(true /* alsoResetLastComposedWord */);
- updateSuggestions();
- final InputConnection ic = getCurrentInputConnection();
- if (ic != null) {
- ic.finishComposingText();
- }
+ clearSuggestions();
+ mConnection.finishComposingText();
}
private void resetComposingState(final boolean alsoResetLastComposedWord) {
@@ -1033,26 +998,26 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
}
- public void commitTyped(final InputConnection ic, final int separatorCode) {
+ private void commitTyped(final int separatorCode) {
if (!mWordComposer.isComposingWord()) return;
final CharSequence typedWord = mWordComposer.getTypedWord();
if (typedWord.length() > 0) {
- if (ic != null) {
- ic.commitText(typedWord, 1);
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_commitText(typedWord);
- }
+ mConnection.commitText(typedWord, 1);
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_commitText(typedWord);
}
final CharSequence prevWord = addToUserHistoryDictionary(typedWord);
mLastComposedWord = mWordComposer.commitWord(
LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, typedWord.toString(),
separatorCode, prevWord);
}
- updateSuggestions();
+ updateSuggestionsOrPredictions();
}
+ // Called from the KeyboardSwitcher which needs to know auto caps state to display
+ // the right layout.
public int getCurrentAutoCapsState() {
- if (!mSettingsValues.mAutoCap) return Constants.TextUtils.CAP_MODE_OFF;
+ if (!mCurrentSettings.mAutoCap) return Constants.TextUtils.CAP_MODE_OFF;
final EditorInfo ei = getCurrentInputEditorInfo();
if (ei == null) return Constants.TextUtils.CAP_MODE_OFF;
@@ -1070,27 +1035,23 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// unless needed.
if (mWordComposer.isComposingWord()) return Constants.TextUtils.CAP_MODE_OFF;
- final InputConnection ic = getCurrentInputConnection();
- if (ic == null) return Constants.TextUtils.CAP_MODE_OFF;
// TODO: This blocking IPC call is heavy. Consider doing this without using IPC calls.
// Note: getCursorCapsMode() returns the current capitalization mode that is any
// combination of CAP_MODE_CHARACTERS, CAP_MODE_WORDS, and CAP_MODE_SENTENCES. 0 means none
// of them.
- return ic.getCursorCapsMode(inputType);
+ return mConnection.getCursorCapsMode(inputType);
}
- // "ic" may be null
- private void swapSwapperAndSpaceWhileInBatchEdit(final InputConnection ic) {
- if (null == ic) return;
- CharSequence lastTwo = ic.getTextBeforeCursor(2, 0);
+ private void swapSwapperAndSpace() {
+ CharSequence lastTwo = mConnection.getTextBeforeCursor(2, 0);
// It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called.
if (lastTwo != null && lastTwo.length() == 2
&& lastTwo.charAt(0) == Keyboard.CODE_SPACE) {
- ic.deleteSurroundingText(2, 0);
+ mConnection.deleteSurroundingText(2, 0);
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_deleteSurroundingText(2);
}
- ic.commitText(lastTwo.charAt(1) + " ", 1);
+ mConnection.commitText(lastTwo.charAt(1) + " ", 1);
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_swapSwapperAndSpaceWhileInBatchEdit();
}
@@ -1098,18 +1059,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
- private boolean maybeDoubleSpaceWhileInBatchEdit(final InputConnection ic) {
- if (mCorrectionMode == Suggest.CORRECTION_NONE) return false;
- if (ic == null) return false;
- final CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
+ private boolean maybeDoubleSpace() {
+ if (!mCurrentSettings.mCorrectionEnabled) return false;
+ if (!mHandler.isAcceptingDoubleSpaces()) return false;
+ final CharSequence lastThree = mConnection.getTextBeforeCursor(3, 0);
if (lastThree != null && lastThree.length() == 3
&& canBeFollowedByPeriod(lastThree.charAt(0))
&& lastThree.charAt(1) == Keyboard.CODE_SPACE
- && lastThree.charAt(2) == Keyboard.CODE_SPACE
- && mHandler.isAcceptingDoubleSpaces()) {
+ && lastThree.charAt(2) == Keyboard.CODE_SPACE) {
mHandler.cancelDoubleSpacesTimer();
- ic.deleteSurroundingText(2, 0);
- ic.commitText(". ", 1);
+ mConnection.deleteSurroundingText(2, 0);
+ mConnection.commitText(". ", 1);
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_doubleSpaceAutoPeriod();
}
@@ -1131,29 +1091,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|| codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET;
}
- // "ic" may be null
- private static void removeTrailingSpaceWhileInBatchEdit(final InputConnection ic) {
- if (ic == null) return;
- final CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
- if (lastOne != null && lastOne.length() == 1
- && lastOne.charAt(0) == Keyboard.CODE_SPACE) {
- ic.deleteSurroundingText(1, 0);
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_deleteSurroundingText(1);
- }
- }
- }
-
+ // Callback for the SuggestionsView, to call when the "add to dictionary" hint is pressed.
@Override
- public boolean addWordToDictionary(String word) {
- if (USE_BINARY_USER_DICTIONARY) {
- ((UserBinaryDictionary)mUserDictionary).addWordToUserDictionary(word, 128);
- } else {
- ((UserDictionary)mUserDictionary).addWordToUserDictionary(word, 128);
- }
- // Suggestion strip should be updated after the operation of adding word to the
- // user dictionary
- mHandler.postUpdateSuggestions();
+ public boolean addWordToUserDictionary(String word) {
+ mUserDictionary.addWordToUserDictionary(word, 128);
return true;
}
@@ -1193,17 +1134,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
private void performEditorAction(int actionId) {
- final InputConnection ic = getCurrentInputConnection();
- if (ic != null) {
- ic.performEditorAction(actionId);
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_performEditorAction(actionId);
- }
+ mConnection.performEditorAction(actionId);
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_performEditorAction(actionId);
}
}
private void handleLanguageSwitchKey() {
- final boolean includesOtherImes = mSettingsValues.mIncludesOtherImesInLanguageSwitchList;
+ final boolean includesOtherImes = mCurrentSettings.mIncludesOtherImesInLanguageSwitchList;
final IBinder token = getWindow().getWindow().getAttributes().token;
if (mShouldSwitchToLastSubtype) {
final InputMethodSubtype lastSubtype = mImm.getLastInputMethodSubtype();
@@ -1221,12 +1159,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
- static private void sendUpDownEnterOrBackspace(final int code, final InputConnection ic) {
+ private void sendUpDownEnterOrBackspace(final int code) {
final long eventTime = SystemClock.uptimeMillis();
- ic.sendKeyEvent(new KeyEvent(eventTime, eventTime,
+ mConnection.sendKeyEvent(new KeyEvent(eventTime, eventTime,
KeyEvent.ACTION_DOWN, code, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE));
- ic.sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
+ mConnection.sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
KeyEvent.ACTION_UP, code, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE));
}
@@ -1239,24 +1177,21 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return;
}
- final InputConnection ic = getCurrentInputConnection();
- if (ic != null) {
- // 16 is android.os.Build.VERSION_CODES.JELLY_BEAN but we can't write it because
- // we want to be able to compile against the Ice Cream Sandwich SDK.
- if (Keyboard.CODE_ENTER == code && mTargetApplicationInfo != null
- && mTargetApplicationInfo.targetSdkVersion < 16) {
- // Backward compatibility mode. Before Jelly bean, the keyboard would simulate
- // a hardware keyboard event on pressing enter or delete. This is bad for many
- // reasons (there are race conditions with commits) but some applications are
- // relying on this behavior so we continue to support it for older apps.
- sendUpDownEnterOrBackspace(KeyEvent.KEYCODE_ENTER, ic);
- } else {
- final String text = new String(new int[] { code }, 0, 1);
- ic.commitText(text, text.length());
- }
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_sendKeyCodePoint(code);
- }
+ // 16 is android.os.Build.VERSION_CODES.JELLY_BEAN but we can't write it because
+ // we want to be able to compile against the Ice Cream Sandwich SDK.
+ if (Keyboard.CODE_ENTER == code && mTargetApplicationInfo != null
+ && mTargetApplicationInfo.targetSdkVersion < 16) {
+ // Backward compatibility mode. Before Jelly bean, the keyboard would simulate
+ // a hardware keyboard event on pressing enter or delete. This is bad for many
+ // reasons (there are race conditions with commits) but some applications are
+ // relying on this behavior so we continue to support it for older apps.
+ sendUpDownEnterOrBackspace(KeyEvent.KEYCODE_ENTER);
+ } else {
+ final String text = new String(new int[] { code }, 0, 1);
+ mConnection.commitText(text, text.length());
+ }
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_sendKeyCodePoint(code);
}
}
@@ -1268,11 +1203,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mDeleteCount = 0;
}
mLastKeyTime = when;
+ mConnection.beginBatchEdit();
if (ProductionFlag.IS_EXPERIMENTAL) {
- if (ResearchLogger.sIsLogging) {
- ResearchLogger.getInstance().logKeyEvent(primaryCode, x, y);
- }
+ ResearchLogger.latinIME_onCodeInput(primaryCode, x, y);
}
final KeyboardSwitcher switcher = mKeyboardSwitcher;
@@ -1321,16 +1255,19 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
case Keyboard.CODE_LANGUAGE_SWITCH:
handleLanguageSwitchKey();
break;
- default:
- if (primaryCode == Keyboard.CODE_TAB
- && mInputAttributes.mEditorAction == EditorInfo.IME_ACTION_NEXT) {
- performEditorAction(EditorInfo.IME_ACTION_NEXT);
- break;
+ case Keyboard.CODE_RESEARCH:
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.getInstance().presentResearchDialog(this);
}
+ break;
+ default:
mSpaceState = SPACE_STATE_NONE;
- if (mSettingsValues.isWordSeparator(primaryCode)) {
+ if (mCurrentSettings.isWordSeparator(primaryCode)) {
didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState);
} else {
+ if (SPACE_STATE_PHANTOM == spaceState) {
+ commitTyped(LastComposedWord.NOT_A_SEPARATOR);
+ }
final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
if (keyboard != null && keyboard.hasProximityCharsCorrection(primaryCode)) {
handleCharacter(primaryCode, x, y, spaceState);
@@ -1349,23 +1286,23 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
&& primaryCode != Keyboard.CODE_SWITCH_ALPHA_SYMBOL)
mLastComposedWord.deactivate();
mEnteredText = null;
+ mConnection.endBatchEdit();
}
+ // Called from PointerTracker through the KeyboardActionListener interface
@Override
public void onTextInput(CharSequence text) {
- final InputConnection ic = getCurrentInputConnection();
- if (ic == null) return;
- ic.beginBatchEdit();
- commitTyped(ic, LastComposedWord.NOT_A_SEPARATOR);
- text = specificTldProcessingOnTextInput(ic, text);
+ mConnection.beginBatchEdit();
+ commitTyped(LastComposedWord.NOT_A_SEPARATOR);
+ text = specificTldProcessingOnTextInput(text);
if (SPACE_STATE_PHANTOM == mSpaceState) {
sendKeyCodePoint(Keyboard.CODE_SPACE);
}
- ic.commitText(text, 1);
+ mConnection.commitText(text, 1);
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_commitText(text);
}
- ic.endBatchEdit();
+ mConnection.endBatchEdit();
mKeyboardSwitcher.updateShiftState();
mKeyboardSwitcher.onCodeInput(Keyboard.CODE_OUTPUT_TEXT);
mSpaceState = SPACE_STATE_NONE;
@@ -1373,9 +1310,32 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
resetComposingState(true /* alsoResetLastComposedWord */);
}
- // ic may not be null
- private CharSequence specificTldProcessingOnTextInput(final InputConnection ic,
- final CharSequence text) {
+ @Override
+ public void onStartBatchInput() {
+ mConnection.beginBatchEdit();
+ if (mWordComposer.isComposingWord()) {
+ commitTyped(LastComposedWord.NOT_A_SEPARATOR);
+ mExpectingUpdateSelection = true;
+ // TODO: Can we remove this?
+ mSpaceState = SPACE_STATE_PHANTOM;
+ }
+ mConnection.endBatchEdit();
+ }
+
+ @Override
+ public void onEndBatchInput(CharSequence text) {
+ mConnection.beginBatchEdit();
+ if (SPACE_STATE_PHANTOM == mSpaceState) {
+ sendKeyCodePoint(Keyboard.CODE_SPACE);
+ }
+ mConnection.setComposingText(text, 1);
+ mExpectingUpdateSelection = true;
+ mConnection.endBatchEdit();
+ mKeyboardSwitcher.updateShiftState();
+ mSpaceState = SPACE_STATE_PHANTOM;
+ }
+
+ private CharSequence specificTldProcessingOnTextInput(final CharSequence text) {
if (text.length() <= 1 || text.charAt(0) != Keyboard.CODE_PERIOD
|| !Character.isLetter(text.charAt(1))) {
// Not a tld: do nothing.
@@ -1384,7 +1344,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// We have a TLD (or something that looks like this): make sure we don't add
// a space even if currently in phantom mode.
mSpaceState = SPACE_STATE_NONE;
- final CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
+ final CharSequence lastOne = mConnection.getTextBeforeCursor(1, 0);
if (lastOne != null && lastOne.length() == 1
&& lastOne.charAt(0) == Keyboard.CODE_PERIOD) {
return text.subSequence(1, text.length());
@@ -1393,6 +1353,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
+ // Called from PointerTracker through the KeyboardActionListener interface
@Override
public void onCancelInput() {
// User released a finger outside any key
@@ -1400,24 +1361,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
private void handleBackspace(final int spaceState) {
- final InputConnection ic = getCurrentInputConnection();
- if (ic == null) return;
- ic.beginBatchEdit();
- handleBackspaceWhileInBatchEdit(spaceState, ic);
- ic.endBatchEdit();
- }
-
- // "ic" may not be null.
- private void handleBackspaceWhileInBatchEdit(final int spaceState, final InputConnection ic) {
// In many cases, we may have to put the keyboard in auto-shift state again.
mHandler.postUpdateShiftState();
- if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
+ if (mEnteredText != null && mConnection.sameAsTextBeforeCursor(mEnteredText)) {
// 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();
- ic.deleteSurroundingText(length, 0);
+ mConnection.deleteSurroundingText(length, 0);
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_deleteSurroundingText(length);
}
@@ -1430,19 +1382,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (mWordComposer.isComposingWord()) {
final int length = mWordComposer.size();
if (length > 0) {
- mWordComposer.deleteLast();
- ic.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1);
- // If we have deleted the last remaining character of a word, then we are not
- // isComposingWord() any more.
- if (!mWordComposer.isComposingWord()) {
- // Not composing word any more, so we can show bigrams.
- mHandler.postUpdateBigramPredictions();
+ // Immediately after a batch input.
+ if (SPACE_STATE_PHANTOM == spaceState) {
+ mWordComposer.reset();
} else {
- // Still composing a word, so we still have letters to deduce a suggestion from.
- mHandler.postUpdateSuggestions();
+ mWordComposer.deleteLast();
}
+ mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1);
+ mHandler.postUpdateSuggestionStrip();
} else {
- ic.deleteSurroundingText(1, 0);
+ mConnection.deleteSurroundingText(1, 0);
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_deleteSurroundingText(1);
}
@@ -1450,17 +1399,18 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} else {
if (mLastComposedWord.canRevertCommit()) {
Utils.Stats.onAutoCorrectionCancellation();
- revertCommit(ic);
+ revertCommit();
return;
}
if (SPACE_STATE_DOUBLE == spaceState) {
- if (revertDoubleSpaceWhileInBatchEdit(ic)) {
+ mHandler.cancelDoubleSpacesTimer();
+ if (mConnection.revertDoubleSpace()) {
// No need to reset mSpaceState, it has already be done (that's why we
// receive it as a parameter)
return;
}
} else if (SPACE_STATE_SWAP_PUNCTUATION == spaceState) {
- if (revertSwapPunctuation(ic)) {
+ if (mConnection.revertSwapPunctuation()) {
// Likewise
return;
}
@@ -1471,8 +1421,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (mLastSelectionStart != mLastSelectionEnd) {
// If there is a selection, remove it.
final int lengthToDelete = mLastSelectionEnd - mLastSelectionStart;
- ic.setSelection(mLastSelectionEnd, mLastSelectionEnd);
- ic.deleteSurroundingText(lengthToDelete, 0);
+ mConnection.setSelection(mLastSelectionEnd, mLastSelectionEnd);
+ mConnection.deleteSurroundingText(lengthToDelete, 0);
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_deleteSurroundingText(lengthToDelete);
}
@@ -1490,40 +1440,39 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// a hardware keyboard event on pressing enter or delete. This is bad for many
// reasons (there are race conditions with commits) but some applications are
// relying on this behavior so we continue to support it for older apps.
- sendUpDownEnterOrBackspace(KeyEvent.KEYCODE_DEL, ic);
+ sendUpDownEnterOrBackspace(KeyEvent.KEYCODE_DEL);
} else {
- ic.deleteSurroundingText(1, 0);
+ mConnection.deleteSurroundingText(1, 0);
}
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_deleteSurroundingText(1);
}
if (mDeleteCount > DELETE_ACCELERATE_AT) {
- ic.deleteSurroundingText(1, 0);
+ mConnection.deleteSurroundingText(1, 0);
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_deleteSurroundingText(1);
}
}
}
- if (isSuggestionsRequested()) {
- restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(ic);
+ if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) {
+ restartSuggestionsOnWordBeforeCursorIfAtEndOfWord();
}
}
}
- // ic may be null
- private boolean maybeStripSpaceWhileInBatchEdit(final InputConnection ic, final int code,
+ private boolean maybeStripSpace(final int code,
final int spaceState, final boolean isFromSuggestionStrip) {
if (Keyboard.CODE_ENTER == code && SPACE_STATE_SWAP_PUNCTUATION == spaceState) {
- removeTrailingSpaceWhileInBatchEdit(ic);
+ mConnection.removeTrailingSpace();
return false;
} else if ((SPACE_STATE_WEAK == spaceState
|| SPACE_STATE_SWAP_PUNCTUATION == spaceState)
&& isFromSuggestionStrip) {
- if (mSettingsValues.isWeakSpaceSwapper(code)) {
+ if (mCurrentSettings.isWeakSpaceSwapper(code)) {
return true;
} else {
- if (mSettingsValues.isWeakSpaceStripper(code)) {
- removeTrailingSpaceWhileInBatchEdit(ic);
+ if (mCurrentSettings.isWeakSpaceStripper(code)) {
+ mConnection.removeTrailingSpace();
}
return false;
}
@@ -1534,20 +1483,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private void handleCharacter(final int primaryCode, final int x,
final int y, final int spaceState) {
- final InputConnection ic = getCurrentInputConnection();
- if (null != ic) ic.beginBatchEdit();
- // TODO: if ic is null, does it make any sense to call this?
- handleCharacterWhileInBatchEdit(primaryCode, x, y, spaceState, ic);
- if (null != ic) ic.endBatchEdit();
- }
-
- // "ic" may be null without this crashing, but the behavior will be really strange
- private void handleCharacterWhileInBatchEdit(final int primaryCode,
- final int x, final int y, final int spaceState, final InputConnection ic) {
boolean isComposingWord = mWordComposer.isComposingWord();
if (SPACE_STATE_PHANTOM == spaceState &&
- !mSettingsValues.isSymbolExcludedFromWordSeparators(primaryCode)) {
+ !mCurrentSettings.isSymbolExcludedFromWordSeparators(primaryCode)) {
if (isComposingWord) {
// Sanity check
throw new RuntimeException("Should not be composing here");
@@ -1559,8 +1498,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)
- || mSettingsValues.isSymbolExcludedFromWordSeparators(primaryCode))
- && isSuggestionsRequested() && !isCursorTouchingWord()) {
+ || mCurrentSettings.isSymbolExcludedFromWordSeparators(primaryCode))
+ && mCurrentSettings.isSuggestionsRequested(mDisplayOrientation) &&
+ !mConnection.isCursorTouchingWord(mCurrentSettings)) {
// 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
@@ -1571,85 +1511,73 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// it entirely and resume suggestions on the previous word, we'd like to still
// have touch coordinates for it.
resetComposingState(false /* alsoResetLastComposedWord */);
- clearSuggestions();
}
if (isComposingWord) {
- mWordComposer.add(
- primaryCode, x, y, mKeyboardSwitcher.getKeyboardView().getKeyDetector());
- if (ic != null) {
- // If it's the first letter, make note of auto-caps state
- if (mWordComposer.size() == 1) {
- mWordComposer.setAutoCapitalized(
- getCurrentAutoCapsState() != Constants.TextUtils.CAP_MODE_OFF);
- }
- ic.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1);
- }
- mHandler.postUpdateSuggestions();
+ final int keyX, keyY;
+ if (KeyboardActionListener.Adapter.isInvalidCoordinate(x)
+ || KeyboardActionListener.Adapter.isInvalidCoordinate(y)) {
+ keyX = x;
+ keyY = y;
+ } else {
+ final KeyDetector keyDetector =
+ mKeyboardSwitcher.getKeyboardView().getKeyDetector();
+ keyX = keyDetector.getTouchX(x);
+ keyY = keyDetector.getTouchY(y);
+ }
+ mWordComposer.add(primaryCode, keyX, keyY);
+ // If it's the first letter, make note of auto-caps state
+ if (mWordComposer.size() == 1) {
+ mWordComposer.setAutoCapitalized(
+ getCurrentAutoCapsState() != Constants.TextUtils.CAP_MODE_OFF);
+ }
+ mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1);
} else {
- final boolean swapWeakSpace = maybeStripSpaceWhileInBatchEdit(ic, primaryCode,
+ final boolean swapWeakSpace = maybeStripSpace(primaryCode,
spaceState, KeyboardActionListener.SUGGESTION_STRIP_COORDINATE == x);
sendKeyCodePoint(primaryCode);
if (swapWeakSpace) {
- swapSwapperAndSpaceWhileInBatchEdit(ic);
+ swapSwapperAndSpace();
mSpaceState = SPACE_STATE_WEAK;
}
- // Some characters are not word separators, yet they don't start a new
- // composing span. For these, we haven't changed the suggestion strip, and
- // if the "add to dictionary" hint is shown, we should do so now. Examples of
- // such characters include single quote, dollar, and others; the exact list is
- // the list of characters for which we enter handleCharacterWhileInBatchEdit
- // that don't match the test if ((isAlphabet...)) at the top of this method.
- if (null != mSuggestionsView && mSuggestionsView.dismissAddToDictionaryHint()) {
- mHandler.postUpdateBigramPredictions();
- }
+ // In case the "add to dictionary" hint was still displayed.
+ if (null != mSuggestionsView) mSuggestionsView.dismissAddToDictionaryHint();
}
+ mHandler.postUpdateSuggestionStrip();
Utils.Stats.onNonSeparator((char)primaryCode, x, y);
}
// Returns true if we did an autocorrection, false otherwise.
private boolean handleSeparator(final int primaryCode, final int x, final int y,
final int spaceState) {
- // Should dismiss the "Touch again to save" message when handling separator
- if (mSuggestionsView != null && mSuggestionsView.dismissAddToDictionaryHint()) {
- mHandler.cancelUpdateBigramPredictions();
- mHandler.postUpdateSuggestions();
- }
-
boolean didAutoCorrect = false;
// Handle separator
- final InputConnection ic = getCurrentInputConnection();
- if (ic != null) {
- ic.beginBatchEdit();
- }
if (mWordComposer.isComposingWord()) {
// In certain languages where single quote is a separator, it's better
// not to auto correct, but accept the typed word. For instance,
// in Italian dov' should not be expanded to dove' because the elision
// requires the last vowel to be removed.
- final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled
- && !mInputAttributes.mInputTypeNoAutoCorrect;
- if (shouldAutoCorrect && primaryCode != Keyboard.CODE_SINGLE_QUOTE) {
- commitCurrentAutoCorrection(primaryCode, ic);
+ if (mCurrentSettings.mCorrectionEnabled && primaryCode != Keyboard.CODE_SINGLE_QUOTE) {
+ commitCurrentAutoCorrection(primaryCode);
didAutoCorrect = true;
} else {
- commitTyped(ic, primaryCode);
+ commitTyped(primaryCode);
}
}
- final boolean swapWeakSpace = maybeStripSpaceWhileInBatchEdit(ic, primaryCode, spaceState,
+ final boolean swapWeakSpace = maybeStripSpace(primaryCode, spaceState,
KeyboardActionListener.SUGGESTION_STRIP_COORDINATE == x);
if (SPACE_STATE_PHANTOM == spaceState &&
- mSettingsValues.isPhantomSpacePromotingSymbol(primaryCode)) {
+ mCurrentSettings.isPhantomSpacePromotingSymbol(primaryCode)) {
sendKeyCodePoint(Keyboard.CODE_SPACE);
}
sendKeyCodePoint(primaryCode);
if (Keyboard.CODE_SPACE == primaryCode) {
- if (isSuggestionsRequested()) {
- if (maybeDoubleSpaceWhileInBatchEdit(ic)) {
+ if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) {
+ if (maybeDoubleSpace()) {
mSpaceState = SPACE_STATE_DOUBLE;
} else if (!isShowingPunctuationList()) {
mSpaceState = SPACE_STATE_WEAK;
@@ -1657,13 +1585,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
mHandler.startDoubleSpacesTimer();
- if (!isCursorTouchingWord()) {
- mHandler.cancelUpdateSuggestions();
- mHandler.postUpdateBigramPredictions();
+ if (!mConnection.isCursorTouchingWord(mCurrentSettings)) {
+ mHandler.postUpdateSuggestionStrip();
}
} else {
if (swapWeakSpace) {
- swapSwapperAndSpaceWhileInBatchEdit(ic);
+ swapSwapperAndSpace();
mSpaceState = SPACE_STATE_SWAP_PUNCTUATION;
} else if (SPACE_STATE_PHANTOM == spaceState) {
// If we are in phantom space state, and the user presses a separator, we want to
@@ -1682,9 +1609,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
Utils.Stats.onSeparator((char)primaryCode, x, y);
- if (ic != null) {
- ic.endBatchEdit();
- }
return didAutoCorrect;
}
@@ -1695,63 +1619,33 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
private void handleClose() {
- commitTyped(getCurrentInputConnection(), LastComposedWord.NOT_A_SEPARATOR);
+ commitTyped(LastComposedWord.NOT_A_SEPARATOR);
requestHideSelf(0);
LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
if (inputView != null)
inputView.closing();
}
- public boolean isSuggestionsRequested() {
- return mInputAttributes.mIsSettingsSuggestionStripOn
- && (mCorrectionMode > 0 || isShowingSuggestionsStrip());
- }
-
- public boolean isShowingPunctuationList() {
+ // TODO: make this private
+ // Outside LatinIME, only used by the test suite.
+ /* package for tests */ boolean isShowingPunctuationList() {
if (mSuggestionsView == null) return false;
- return mSettingsValues.mSuggestPuncList == mSuggestionsView.getSuggestions();
- }
-
- public boolean isShowingSuggestionsStrip() {
- return (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_VALUE)
- || (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
- && mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT);
+ return mCurrentSettings.mSuggestPuncList == mSuggestionsView.getSuggestions();
}
- public boolean isSuggestionsStripVisible() {
+ private boolean isSuggestionsStripVisible() {
if (mSuggestionsView == null)
return false;
if (mSuggestionsView.isShowingAddToDictionaryHint())
return true;
- if (!isShowingSuggestionsStrip())
+ if (!mCurrentSettings.isSuggestionStripVisibleInOrientation(mDisplayOrientation))
return false;
- if (mInputAttributes.mApplicationSpecifiedCompletionOn)
+ if (mCurrentSettings.isApplicationSpecifiedCompletionsOn())
return true;
- return isSuggestionsRequested();
+ return mCurrentSettings.isSuggestionsRequested(mDisplayOrientation);
}
- public void switchToKeyboardView() {
- if (DEBUG) {
- Log.d(TAG, "Switch to keyboard view.");
- }
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_switchToKeyboardView();
- }
- View v = mKeyboardSwitcher.getKeyboardView();
- if (v != null) {
- // Confirms that the keyboard view doesn't have parent view.
- ViewParent p = v.getParent();
- if (p != null && p instanceof ViewGroup) {
- ((ViewGroup) p).removeView(v);
- }
- setInputView(v);
- }
- setSuggestionStripShown(isSuggestionsStripVisible());
- updateInputViewShown();
- mHandler.postUpdateSuggestions();
- }
-
- public void clearSuggestions() {
+ private void clearSuggestions() {
setSuggestions(SuggestedWords.EMPTY, false);
setAutoCorrectionIndicator(false);
}
@@ -1765,83 +1659,89 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private void setAutoCorrectionIndicator(final boolean newAutoCorrectionIndicator) {
// Put a blue underline to a word in TextView which will be auto-corrected.
- final InputConnection ic = getCurrentInputConnection();
- if (ic == null) return;
if (mIsAutoCorrectionIndicatorOn != newAutoCorrectionIndicator
&& mWordComposer.isComposingWord()) {
mIsAutoCorrectionIndicatorOn = newAutoCorrectionIndicator;
final CharSequence textWithUnderline =
getTextWithUnderline(mWordComposer.getTypedWord());
- ic.setComposingText(textWithUnderline, 1);
+ mConnection.setComposingText(textWithUnderline, 1);
}
}
- public void updateSuggestions() {
+ private void updateSuggestionsOrPredictions() {
+ mHandler.cancelUpdateSuggestionStrip();
+
// Check if we have a suggestion engine attached.
- if ((mSuggest == null || !isSuggestionsRequested())) {
+ if (mSuggest == null || !mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) {
if (mWordComposer.isComposingWord()) {
- Log.w(TAG, "Called updateSuggestions but suggestions were not requested!");
+ Log.w(TAG, "Called updateSuggestionsOrPredictions but suggestions were not "
+ + "requested!");
mWordComposer.setAutoCorrection(mWordComposer.getTypedWord());
}
return;
}
- mHandler.cancelUpdateSuggestions();
- mHandler.cancelUpdateBigramPredictions();
-
- if (!mWordComposer.isComposingWord()) {
+ final String typedWord = mWordComposer.getTypedWord();
+ if (!mWordComposer.isComposingWord() && !mCurrentSettings.mBigramPredictionEnabled) {
setPunctuationSuggestions();
return;
}
- // TODO: May need a better way of retrieving previous word
- final InputConnection ic = getCurrentInputConnection();
- final CharSequence prevWord;
- if (null == ic) {
- prevWord = null;
+ // 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 CharSequence prevWord =
+ mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators,
+ mWordComposer.isComposingWord() ? 2 : 1);
+ SuggestedWords suggestedWords = mSuggest.getSuggestedWords(mWordComposer,
+ prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(),
+ mCurrentSettings.mCorrectionEnabled);
+ suggestedWords = maybeRetrieveOlderSuggestions(typedWord, suggestedWords);
+
+ if (null != suggestedWords && suggestedWords.size() > 0) {
+ showSuggestions(suggestedWords, typedWord);
} else {
- prevWord = EditingUtils.getPreviousWord(ic, mSettingsValues.mWordSeparators);
+ clearSuggestions();
}
+ }
- final CharSequence typedWord = mWordComposer.getTypedWord();
- // getSuggestedWords handles gracefully a null value of prevWord
- final SuggestedWords suggestedWords = mSuggest.getSuggestedWords(mWordComposer,
- prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(), mCorrectionMode);
-
- // Basically, we update the suggestion strip only when suggestion count > 1. However,
- // there is an exception: We update the suggestion strip whenever typed word's length
- // is 1 or typed word is found in dictionary, regardless of suggestion count. Actually,
- // in most cases, suggestion count is 1 when typed word's length is 1, but we do always
- // need to clear the previous state when the user starts typing a word (i.e. typed word's
- // length == 1).
- if (suggestedWords.size() > 1 || typedWord.length() == 1
- || !suggestedWords.mAllowsToBeAutoCorrected
+ private SuggestedWords maybeRetrieveOlderSuggestions(final CharSequence typedWord,
+ final SuggestedWords suggestedWords) {
+ // TODO: consolidate this into getSuggestedWords
+ // We update the suggestion strip only when we have some suggestions to show, i.e. when
+ // the suggestion count is > 1; else, we leave the old suggestions, with the typed word
+ // replaced with the new one. However, when the word is a dictionary word, or when the
+ // length of the typed word is 1 or 0 (after a deletion typically), we do want to remove the
+ // old suggestions. Also, if we are showing the "add to dictionary" hint, we need to
+ // revert to suggestions - although it is unclear how we can come here if it's displayed.
+ if (suggestedWords.size() > 1 || typedWord.length() <= 1
+ || !suggestedWords.mTypedWordValid
|| mSuggestionsView.isShowingAddToDictionaryHint()) {
- showSuggestions(suggestedWords, typedWord);
+ return suggestedWords;
} else {
SuggestedWords previousSuggestions = mSuggestionsView.getSuggestions();
- if (previousSuggestions == mSettingsValues.mSuggestPuncList) {
+ if (previousSuggestions == mCurrentSettings.mSuggestPuncList) {
previousSuggestions = SuggestedWords.EMPTY;
}
final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions =
SuggestedWords.getTypedWordAndPreviousSuggestions(
typedWord, previousSuggestions);
- final SuggestedWords obsoleteSuggestedWords =
- new SuggestedWords(typedWordAndPreviousSuggestions,
+ return new SuggestedWords(typedWordAndPreviousSuggestions,
false /* typedWordValid */,
false /* hasAutoCorrectionCandidate */,
- false /* allowsToBeAutoCorrected */,
false /* isPunctuationSuggestions */,
true /* isObsoleteSuggestions */,
false /* isPrediction */);
- showSuggestions(obsoleteSuggestedWords, typedWord);
}
}
- public void showSuggestions(final SuggestedWords suggestedWords, final CharSequence typedWord) {
+ private void showSuggestions(final SuggestedWords suggestedWords,
+ final CharSequence typedWord) {
+ // This method is only ever called by updateSuggestions or updateBigramPredictions.
final CharSequence autoCorrection;
if (suggestedWords.size() > 0) {
- if (suggestedWords.hasAutoCorrectionWord()) {
+ if (suggestedWords.mWillAutoCorrect) {
autoCorrection = suggestedWords.getWord(1);
} else {
autoCorrection = typedWord;
@@ -1856,12 +1756,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
setSuggestionStripShown(isSuggestionsStripVisible());
}
- private void commitCurrentAutoCorrection(final int separatorCodePoint,
- final InputConnection ic) {
+ private void commitCurrentAutoCorrection(final int separatorCodePoint) {
// Complete any pending suggestions query first
if (mHandler.hasPendingUpdateSuggestions()) {
- mHandler.cancelUpdateSuggestions();
- updateSuggestions();
+ updateSuggestionsOrPredictions();
}
final CharSequence autoCorrection = mWordComposer.getAutoCorrectionOrNull();
if (autoCorrection != null) {
@@ -1878,26 +1776,20 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mExpectingUpdateSelection = true;
commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD,
separatorCodePoint);
- if (!typedWord.equals(autoCorrection) && null != ic) {
+ if (!typedWord.equals(autoCorrection)) {
// This will make the correction flash for a short while as a visual clue
// to the user that auto-correction happened.
- ic.commitCorrection(new CorrectionInfo(mLastSelectionEnd - typedWord.length(),
+ mConnection.commitCorrection(
+ new CorrectionInfo(mLastSelectionEnd - typedWord.length(),
typedWord, autoCorrection));
}
}
}
+ // Called from SuggestionsView through the SuggestionsView.Listener interface
@Override
public void pickSuggestionManually(final int index, final CharSequence suggestion,
- int x, int y) {
- final InputConnection ic = getCurrentInputConnection();
- if (null != ic) ic.beginBatchEdit();
- pickSuggestionManuallyWhileInBatchEdit(index, suggestion, x, y, ic);
- if (null != ic) ic.endBatchEdit();
- }
-
- public void pickSuggestionManuallyWhileInBatchEdit(final int index,
- final CharSequence suggestion, final int x, final int y, final InputConnection ic) {
+ final int x, final int y) {
final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions();
// If this is a punctuation picked from the suggestion strip, pass it to onCodeInput
if (suggestion.length() == 1 && isShowingPunctuationList()) {
@@ -1915,15 +1807,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return;
}
+ mConnection.beginBatchEdit();
if (SPACE_STATE_PHANTOM == mSpaceState && suggestion.length() > 0) {
int firstChar = Character.codePointAt(suggestion, 0);
- if ((!mSettingsValues.isWeakSpaceStripper(firstChar))
- && (!mSettingsValues.isWeakSpaceSwapper(firstChar))) {
+ if ((!mCurrentSettings.isWeakSpaceStripper(firstChar))
+ && (!mCurrentSettings.isWeakSpaceSwapper(firstChar))) {
sendKeyCodePoint(Keyboard.CODE_SPACE);
}
}
- if (mInputAttributes.mApplicationSpecifiedCompletionOn
+ if (mCurrentSettings.isApplicationSpecifiedCompletionsOn()
&& mApplicationSpecifiedCompletions != null
&& index >= 0 && index < mApplicationSpecifiedCompletions.length) {
if (mSuggestionsView != null) {
@@ -1931,13 +1824,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
mKeyboardSwitcher.updateShiftState();
resetComposingState(true /* alsoResetLastComposedWord */);
- if (ic != null) {
- final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index];
- ic.commitCompletion(completionInfo);
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_pickApplicationSpecifiedCompletion(index,
- completionInfo.getText(), x, y);
- }
+ final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index];
+ mConnection.commitCompletion(completionInfo);
+ mConnection.endBatchEdit();
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_pickApplicationSpecifiedCompletion(index,
+ completionInfo.getText(), x, y);
}
return;
}
@@ -1953,6 +1845,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mExpectingUpdateSelection = true;
commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK,
LastComposedWord.NOT_A_SEPARATOR);
+ mConnection.endBatchEdit();
// Don't allow cancellation of manual pick
mLastComposedWord.deactivate();
mSpaceState = SPACE_STATE_PHANTOM;
@@ -1966,8 +1859,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// - There is a dictionary and the word is not in it
// 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
- // We used to look at mCorrectionMode here, but showing the hint should have nothing
- // to do with the autocorrection setting.
final boolean showingAddToDictionaryHint = index == 0 && mSuggest != null
// If there is no dictionary the hint should be shown.
&& (!mSuggest.hasMainDictionary()
@@ -1977,20 +1868,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
Utils.Stats.onSeparator((char)Keyboard.CODE_SPACE, WordComposer.NOT_A_COORDINATE,
WordComposer.NOT_A_COORDINATE);
- if (!showingAddToDictionaryHint) {
- // If we're not showing the "Touch again to save", then show corrections again.
- // In case the cursor position doesn't change, make sure we show the suggestions again.
- updateBigramPredictions();
- // Updating the predictions right away may be slow and feel unresponsive on slower
- // terminals. On the other hand if we just postUpdateBigramPredictions() it will
- // take a noticeable delay to update them which may feel uneasy.
+ if (showingAddToDictionaryHint && mIsUserDictionaryAvailable) {
+ mSuggestionsView.showAddToDictionaryHint(suggestion, mCurrentSettings.mHintToSaveText);
} else {
- if (mIsUserDictionaryAvailable) {
- mSuggestionsView.showAddToDictionaryHint(
- suggestion, mSettingsValues.mHintToSaveText);
- } else {
- mHandler.postUpdateSuggestions();
- }
+ // If we're not showing the "Touch again to save", then update the suggestion strip.
+ mHandler.postUpdateSuggestionStrip();
}
}
@@ -1999,22 +1881,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
*/
private void commitChosenWord(final CharSequence chosenWord, final int commitType,
final int separatorCode) {
- final InputConnection ic = getCurrentInputConnection();
- if (ic != null) {
- if (mSettingsValues.mEnableSuggestionSpanInsertion) {
- final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions();
- ic.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan(
- this, chosenWord, suggestedWords, mIsMainDictionaryAvailable),
- 1);
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_commitText(chosenWord);
- }
- } else {
- ic.commitText(chosenWord, 1);
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_commitText(chosenWord);
- }
- }
+ final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions();
+ mConnection.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan(
+ this, chosenWord, suggestedWords, mIsMainDictionaryAvailable), 1);
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.latinIME_commitText(chosenWord);
}
// Add the word to the user history dictionary
final CharSequence prevWord = addToUserHistoryDictionary(chosenWord);
@@ -2026,42 +1897,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
separatorCode, prevWord);
}
- public void updateBigramPredictions() {
- if (mSuggest == null || !isSuggestionsRequested())
- return;
-
- if (!mSettingsValues.mBigramPredictionEnabled) {
- setPunctuationSuggestions();
- return;
- }
-
- final SuggestedWords suggestedWords;
- if (mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
- final CharSequence prevWord = EditingUtils.getThisWord(getCurrentInputConnection(),
- mSettingsValues.mWordSeparators);
- if (!TextUtils.isEmpty(prevWord)) {
- suggestedWords = mSuggest.getBigramPredictions(prevWord);
- } else {
- suggestedWords = null;
- }
- } else {
- suggestedWords = null;
- }
-
- if (null != suggestedWords && suggestedWords.size() > 0) {
- // Explicitly supply an empty typed word (the no-second-arg version of
- // showSuggestions will retrieve the word near the cursor, we don't want that here)
- showSuggestions(suggestedWords, "");
- } else {
- clearSuggestions();
- }
- }
-
- public void setPunctuationSuggestions() {
- if (mSettingsValues.mBigramPredictionEnabled) {
+ private void setPunctuationSuggestions() {
+ if (mCurrentSettings.mBigramPredictionEnabled) {
clearSuggestions();
} else {
- setSuggestions(mSettingsValues.mSuggestPuncList, false);
+ setSuggestions(mCurrentSettings.mSuggestPuncList, false);
}
setAutoCorrectionIndicator(false);
setSuggestionStripShown(isSuggestionsStripVisible());
@@ -2070,22 +1910,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private CharSequence addToUserHistoryDictionary(final CharSequence suggestion) {
if (TextUtils.isEmpty(suggestion)) return null;
- // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be
- // adding words in situations where the user or application really didn't
- // want corrections enabled or learned.
- if (!(mCorrectionMode == Suggest.CORRECTION_FULL
- || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) {
- 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 (!mCurrentSettings.mCorrectionEnabled) return null;
- if (mUserHistoryDictionary != null) {
- final InputConnection ic = getCurrentInputConnection();
- final CharSequence prevWord;
- if (null != ic) {
- prevWord = EditingUtils.getPreviousWord(ic, mSettingsValues.mWordSeparators);
- } else {
- prevWord = null;
- }
+ final UserHistoryDictionary userHistoryDictionary = mUserHistoryDictionary;
+ if (userHistoryDictionary != null) {
+ final CharSequence prevWord
+ = mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators, 2);
final String secondWord;
if (mWordComposer.isAutoCapitalized() && !mWordComposer.isMostlyCaps()) {
secondWord = suggestion.toString().toLowerCase(
@@ -2098,95 +1931,36 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final int maxFreq = AutoCorrection.getMaxFrequency(
mSuggest.getUnigramDictionaries(), suggestion);
if (maxFreq == 0) return null;
- mUserHistoryDictionary.addToUserHistory(null == prevWord ? null : prevWord.toString(),
+ userHistoryDictionary.addToUserHistory(null == prevWord ? null : prevWord.toString(),
secondWord, maxFreq > 0);
return prevWord;
}
return null;
}
- public boolean isCursorTouchingWord() {
- final InputConnection ic = getCurrentInputConnection();
- if (ic == null) return false;
- CharSequence before = ic.getTextBeforeCursor(1, 0);
- CharSequence after = ic.getTextAfterCursor(1, 0);
- if (!TextUtils.isEmpty(before) && !mSettingsValues.isWordSeparator(before.charAt(0))
- && !mSettingsValues.isSymbolExcludedFromWordSeparators(before.charAt(0))) {
- return true;
- }
- if (!TextUtils.isEmpty(after) && !mSettingsValues.isWordSeparator(after.charAt(0))
- && !mSettingsValues.isSymbolExcludedFromWordSeparators(after.charAt(0))) {
- return true;
- }
- return false;
- }
-
- // "ic" must not be null
- private static boolean sameAsTextBeforeCursor(final InputConnection ic,
- final CharSequence text) {
- final CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0);
- return TextUtils.equals(text, beforeText);
- }
-
- // "ic" must not be null
/**
* Check if the cursor is actually at the end of a word. If so, restart suggestions on this
* word, else do nothing.
*/
- private void restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(
- final InputConnection ic) {
- // Bail out if the cursor is not at the end of a word (cursor must be preceded by
- // non-whitespace, non-separator, non-start-of-text)
- // Example ("|" is the cursor here) : <SOL>"|a" " |a" " | " all get rejected here.
- final CharSequence textBeforeCursor = ic.getTextBeforeCursor(1, 0);
- if (TextUtils.isEmpty(textBeforeCursor)
- || mSettingsValues.isWordSeparator(textBeforeCursor.charAt(0))) return;
-
- // Bail out if the cursor is in the middle of a word (cursor must be followed by whitespace,
- // separator or end of line/text)
- // Example: "test|"<EOL> "te|st" get rejected here
- final CharSequence textAfterCursor = ic.getTextAfterCursor(1, 0);
- if (!TextUtils.isEmpty(textAfterCursor)
- && !mSettingsValues.isWordSeparator(textAfterCursor.charAt(0))) return;
-
- // Bail out if word before cursor is 0-length or a single non letter (like an apostrophe)
- // Example: " -|" gets rejected here but "e-|" and "e|" are okay
- CharSequence word = EditingUtils.getWordAtCursor(ic, mSettingsValues.mWordSeparators);
- // We don't suggest on leading single quotes, so we have to remove them from the word if
- // it starts with single quotes.
- while (!TextUtils.isEmpty(word) && Keyboard.CODE_SINGLE_QUOTE == word.charAt(0)) {
- word = word.subSequence(1, word.length());
- }
- if (TextUtils.isEmpty(word)) return;
- final char firstChar = word.charAt(0); // we just tested that word is not empty
- if (word.length() == 1 && !Character.isLetter(firstChar)) return;
-
- // We only suggest on words that start with a letter or a symbol that is excluded from
- // word separators (see #handleCharacterWhileInBatchEdit).
- if (!(isAlphabet(firstChar)
- || mSettingsValues.isSymbolExcludedFromWordSeparators(firstChar))) {
- return;
+ private void restartSuggestionsOnWordBeforeCursorIfAtEndOfWord() {
+ final CharSequence word = mConnection.getWordBeforeCursorIfAtEndOfWord(mCurrentSettings);
+ if (null != word) {
+ restartSuggestionsOnWordBeforeCursor(word);
}
-
- // Okay, we are at the end of a word. Restart suggestions.
- restartSuggestionsOnWordBeforeCursor(ic, word);
}
- // "ic" must not be null
- private void restartSuggestionsOnWordBeforeCursor(final InputConnection ic,
- final CharSequence word) {
+ private void restartSuggestionsOnWordBeforeCursor(final CharSequence word) {
mWordComposer.setComposingWord(word, mKeyboardSwitcher.getKeyboard());
final int length = word.length();
- ic.deleteSurroundingText(length, 0);
+ mConnection.deleteSurroundingText(length, 0);
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_deleteSurroundingText(length);
}
- ic.setComposingText(word, 1);
- mHandler.postUpdateSuggestions();
+ mConnection.setComposingText(word, 1);
+ mHandler.postUpdateSuggestionStrip();
}
- // "ic" must not be null
- private void revertCommit(final InputConnection ic) {
+ private void revertCommit() {
final CharSequence previousWord = mLastComposedWord.mPrevWord;
final String originallyTypedWord = mLastComposedWord.mTypedWord;
final CharSequence committedWord = mLastComposedWord.mCommittedWord;
@@ -2200,7 +1974,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
throw new RuntimeException("revertCommit, but we are composing a word");
}
final String wordBeforeCursor =
- ic.getTextBeforeCursor(deleteLength, 0)
+ mConnection.getTextBeforeCursor(deleteLength, 0)
.subSequence(0, cancelLength).toString();
if (!TextUtils.equals(committedWord, wordBeforeCursor)) {
throw new RuntimeException("revertCommit check failed: we thought we were "
@@ -2208,7 +1982,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
+ "\", but before the cursor we found \"" + wordBeforeCursor + "\"");
}
}
- ic.deleteSurroundingText(deleteLength, 0);
+ mConnection.deleteSurroundingText(deleteLength, 0);
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_deleteSurroundingText(deleteLength);
}
@@ -2216,122 +1990,58 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mUserHistoryDictionary.cancelAddingUserHistory(
previousWord.toString(), committedWord.toString());
}
- if (0 == separatorLength || mLastComposedWord.didCommitTypedWord()) {
- // This is the case when we cancel a manual pick.
- // We should restart suggestion on the word right away.
- mWordComposer.resumeSuggestionOnLastComposedWord(mLastComposedWord);
- ic.setComposingText(originallyTypedWord, 1);
- } else {
- ic.commitText(originallyTypedWord, 1);
- // Re-insert the separator
- sendKeyCodePoint(mLastComposedWord.mSeparatorCode);
- Utils.Stats.onSeparator(mLastComposedWord.mSeparatorCode, WordComposer.NOT_A_COORDINATE,
- WordComposer.NOT_A_COORDINATE);
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_revertCommit(originallyTypedWord);
- }
- // Don't restart suggestion yet. We'll restart if the user deletes the
- // separator.
- }
- mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
- mHandler.cancelUpdateBigramPredictions();
- mHandler.postUpdateSuggestions();
- }
-
- // "ic" must not be null
- private boolean revertDoubleSpaceWhileInBatchEdit(final InputConnection ic) {
- mHandler.cancelDoubleSpacesTimer();
- // Here we test whether we indeed have a period and a space before us. This should not
- // be needed, but it's there just in case something went wrong.
- final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0);
- if (!". ".equals(textBeforeCursor)) {
- // Theoretically we should not be coming here if there isn't ". " before the
- // cursor, but the application may be changing the text while we are typing, so
- // anything goes. We should not crash.
- Log.d(TAG, "Tried to revert double-space combo but we didn't find "
- + "\". \" just before the cursor.");
- return false;
- }
- ic.deleteSurroundingText(2, 0);
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_deleteSurroundingText(2);
- }
- ic.commitText(" ", 1);
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_revertDoubleSpaceWhileInBatchEdit();
- }
- return true;
- }
-
- private static boolean revertSwapPunctuation(final InputConnection ic) {
- // Here we test whether we indeed have a space and something else before us. This should not
- // be needed, but it's there just in case something went wrong.
- final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0);
- // NOTE: This does not work with surrogate pairs. Hopefully when the keyboard is able to
- // enter surrogate pairs this code will have been removed.
- if (TextUtils.isEmpty(textBeforeCursor)
- || (Keyboard.CODE_SPACE != textBeforeCursor.charAt(1))) {
- // We may only come here if the application is changing the text while we are typing.
- // This is quite a broken case, but not logically impossible, so we shouldn't crash,
- // but some debugging log may be in order.
- Log.d(TAG, "Tried to revert a swap of punctuation but we didn't "
- + "find a space just before the cursor.");
- return false;
- }
- ic.beginBatchEdit();
- ic.deleteSurroundingText(2, 0);
- if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_deleteSurroundingText(2);
- }
- ic.commitText(" " + textBeforeCursor.subSequence(0, 1), 1);
+ mConnection.commitText(originallyTypedWord, 1);
+ // Re-insert the separator
+ sendKeyCodePoint(mLastComposedWord.mSeparatorCode);
+ Utils.Stats.onSeparator(mLastComposedWord.mSeparatorCode, WordComposer.NOT_A_COORDINATE,
+ WordComposer.NOT_A_COORDINATE);
if (ProductionFlag.IS_EXPERIMENTAL) {
- ResearchLogger.latinIME_revertSwapPunctuation();
+ ResearchLogger.latinIME_revertCommit(originallyTypedWord);
}
- ic.endBatchEdit();
- return true;
+ // Don't restart suggestion yet. We'll restart if the user deletes the
+ // separator.
+ mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
+ // We have a separator between the word and the cursor: we should show predictions.
+ mHandler.postUpdateSuggestionStrip();
}
+ // Used by the RingCharBuffer
public boolean isWordSeparator(int code) {
- return mSettingsValues.isWordSeparator(code);
- }
-
- public boolean preferCapitalization() {
- return mWordComposer.isFirstCharCapitalized();
+ return mCurrentSettings.isWordSeparator(code);
}
// Notify that language or mode have been changed and toggleLanguage will update KeyboardID
- // according to new language or mode.
+ // according to new language or mode. Called from SubtypeSwitcher.
public void onRefreshKeyboard() {
// When the device locale is changed in SetupWizard etc., this method may get called via
// onConfigurationChanged before SoftInputWindow is shown.
if (mKeyboardSwitcher.getKeyboardView() != null) {
// Reload keyboard because the current language has been changed.
- mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mSettingsValues);
+ mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mCurrentSettings);
}
initSuggest();
- updateCorrectionMode();
loadSettings();
// 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 updateBigramPredictions anyway).
- if (isCursorTouchingWord()) {
- mHandler.postUpdateSuggestions();
- } else {
- mHandler.postUpdateBigramPredictions();
- }
+ // predictions or punctuation signs (which is done by the updateSuggestionStrip anyway).
+ mHandler.postUpdateSuggestionStrip();
}
// TODO: Remove this method from {@link LatinIME} and move {@link FeedbackManager} to
- // {@link KeyboardSwitcher}.
+ // {@link KeyboardSwitcher}. Called from KeyboardSwitcher
public void hapticAndAudioFeedback(final int primaryCode) {
mFeedbackManager.hapticAndAudioFeedback(primaryCode, mKeyboardSwitcher.getKeyboardView());
}
+ // Callback called by PointerTracker through the KeyboardActionListener. This is called when a
+ // key is depressed; release matching call is onReleaseKey below.
@Override
public void onPressKey(int primaryCode) {
mKeyboardSwitcher.onPressKey(primaryCode);
}
+ // Callback by PointerTracker through the KeyboardActionListener. This is called when a key
+ // is released; press matching call is onPressKey above.
@Override
public void onReleaseKey(int primaryCode, boolean withSliding) {
mKeyboardSwitcher.onReleaseKey(primaryCode, withSliding);
@@ -2352,12 +2062,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// 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.
- final InputConnection ic = getCurrentInputConnection();
- if (null != ic) {
- final CharSequence lastChar = ic.getTextBeforeCursor(1, 0);
- if (!TextUtils.isEmpty(lastChar) && Character.isHighSurrogate(lastChar.charAt(0))) {
- ic.deleteSurroundingText(1, 0);
- }
+ final CharSequence lastChar = mConnection.getTextBeforeCursor(1, 0);
+ if (!TextUtils.isEmpty(lastChar) && Character.isHighSurrogate(lastChar.charAt(0))) {
+ mConnection.deleteSurroundingText(1, 0);
}
}
}
@@ -2375,29 +2082,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
};
- private void updateCorrectionMode() {
- // TODO: cleanup messy flags
- final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled
- && !mInputAttributes.mInputTypeNoAutoCorrect;
- mCorrectionMode = shouldAutoCorrect ? Suggest.CORRECTION_FULL : Suggest.CORRECTION_NONE;
- mCorrectionMode = (mSettingsValues.mBigramSuggestionEnabled && shouldAutoCorrect)
- ? Suggest.CORRECTION_FULL_BIGRAM : mCorrectionMode;
- }
-
- private void updateSuggestionVisibility(final Resources res) {
- final String suggestionVisiblityStr = mSettingsValues.mShowSuggestionsSetting;
- for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) {
- if (suggestionVisiblityStr.equals(res.getString(visibility))) {
- mSuggestionVisibility = visibility;
- break;
- }
- }
- }
-
private void launchSettings() {
launchSettingsClass(SettingsActivity.class);
}
+ // Called from debug code only
public void launchDebugSettings() {
launchSettingsClass(DebugSettingsActivity.class);
}
@@ -2440,10 +2129,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setItems(items, listener)
.setTitle(title);
- showOptionDialogInternal(builder.create());
+ showOptionDialog(builder.create());
}
- private void showOptionDialogInternal(AlertDialog dialog) {
+ /* package */ void showOptionDialog(AlertDialog dialog) {
final IBinder windowToken = mKeyboardSwitcher.getKeyboardView().getWindowToken();
if (windowToken == null) return;
@@ -2470,13 +2159,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1;
p.println(" Keyboard mode = " + keyboardMode);
- p.println(" mIsSuggestionsRequested=" + mInputAttributes.mIsSettingsSuggestionStripOn);
- p.println(" mCorrectionMode=" + mCorrectionMode);
+ p.println(" mIsSuggestionsSuggestionsRequested = "
+ + mCurrentSettings.isSuggestionsRequested(mDisplayOrientation));
+ p.println(" mCorrectionEnabled=" + mCurrentSettings.mCorrectionEnabled);
p.println(" isComposingWord=" + mWordComposer.isComposingWord());
- p.println(" mAutoCorrectEnabled=" + mSettingsValues.mAutoCorrectEnabled);
- p.println(" mSoundOn=" + mSettingsValues.mSoundOn);
- p.println(" mVibrateOn=" + mSettingsValues.mVibrateOn);
- p.println(" mKeyPreviewPopupOn=" + mSettingsValues.mKeyPreviewPopupOn);
- p.println(" mInputAttributes=" + mInputAttributes.toString());
+ p.println(" mSoundOn=" + mCurrentSettings.mSoundOn);
+ p.println(" mVibrateOn=" + mCurrentSettings.mVibrateOn);
+ p.println(" mKeyPreviewPopupOn=" + mCurrentSettings.mKeyPreviewPopupOn);
+ p.println(" inputAttributes=" + mCurrentSettings.getInputAttributesDebugString());
}
}