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.java139
1 files changed, 120 insertions, 19 deletions
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 094ccd77f..0e1c4dc31 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -161,6 +161,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
mPositionalInfoForUserDictPendingAddition = null;
private final WordComposer mWordComposer = new WordComposer();
private final RichInputConnection mConnection = new RichInputConnection(this);
+ private final RecapitalizeStatus mRecapitalizeStatus = new RecapitalizeStatus();
// 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;
@@ -741,6 +742,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
resetComposingState(true /* alsoResetLastComposedWord */);
mDeleteCount = 0;
mSpaceState = SPACE_STATE_NONE;
+ mRecapitalizeStatus.deactivate();
mCurrentlyPressedHardwareKeys.clear();
if (mSuggestionStripView != null) {
@@ -923,7 +925,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// We moved the cursor. If we are touching a word, we need to resume suggestion.
mHandler.postResumeSuggestions();
-
+ // Reset the last recapitalization.
+ mRecapitalizeStatus.deactivate();
mKeyboardSwitcher.updateShiftState();
}
mExpectingUpdateSelection = false;
@@ -993,8 +996,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
}
if (!mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()) return;
- mApplicationSpecifiedCompletions =
- CompletionInfoUtils.removeNulls(applicationSpecifiedCompletions);
if (applicationSpecifiedCompletions == null) {
clearSuggestionStrip();
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
@@ -1002,6 +1003,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
return;
}
+ mApplicationSpecifiedCompletions =
+ CompletionInfoUtils.removeNulls(applicationSpecifiedCompletions);
final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords =
SuggestedWords.getFromApplicationSpecifiedCompletions(
@@ -1177,6 +1180,15 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
SPACE_STATE_PHANTOM == mSpaceState);
}
+ public int getCurrentRecapitalizeState() {
+ if (!mRecapitalizeStatus.isActive()
+ || !mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) {
+ // Not recapitalizing at the moment
+ return RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE;
+ }
+ return mRecapitalizeStatus.getCurrentMode();
+ }
+
// Factor in auto-caps and manual caps and compute the current caps mode.
private int getActualCapsMode() {
final int keyboardShiftMode = mKeyboardSwitcher.getKeyboardShiftMode();
@@ -1387,8 +1399,18 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
LatinImeLogger.logOnDelete(x, y);
break;
case Constants.CODE_SHIFT:
+ // Note: calling back to the keyboard on Shift key is handled in onPressKey()
+ // and onReleaseKey().
+ final Keyboard currentKeyboard = switcher.getKeyboard();
+ if (null != currentKeyboard && currentKeyboard.mId.isAlphabetKeyboard()) {
+ // TODO: Instead of checking for alphabetic keyboard here, separate keycodes for
+ // alphabetic shift and shift while in symbol layout.
+ handleRecapitalize();
+ }
+ break;
case Constants.CODE_SWITCH_ALPHA_SYMBOL:
- // Shift and symbol key is handled in onPressKey() and onReleaseKey().
+ // Note: calling back to the keyboard on symbol key is handled in onPressKey()
+ // and onReleaseKey().
break;
case Constants.CODE_SETTINGS:
onSettingsKeyPressed();
@@ -1466,7 +1488,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
"", mWordComposer.getTypedWord(), " ", mWordComposer);
}
}
- commitTyped(LastComposedWord.NOT_A_SEPARATOR);
+ 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 character at the current cursor position.
+ resetEntireInputState(mLastSelectionStart);
+ } else {
+ commitTyped(LastComposedWord.NOT_A_SEPARATOR);
+ }
}
final int keyX, keyY;
final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
@@ -1522,8 +1550,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
final int wordComposerSize = mWordComposer.size();
// Since isComposingWord() is true, the size is at least 1.
- final int lastChar = mWordComposer.getCodeAt(wordComposerSize - 1);
- if (wordComposerSize <= 1) {
+ final int lastChar = mWordComposer.getCodeBeforeCursor();
+ 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 batch input at the current cursor position.
+ resetEntireInputState(mLastSelectionStart);
+ } else if (wordComposerSize <= 1) {
// We auto-correct the previous (typed, not gestured) string iff it's one character
// long. The reason for this is, even in the middle of gesture typing, you'll still
// tap one-letter words and you want them auto-corrected (typically, "i" in English
@@ -1734,8 +1766,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// during key repeat.
mHandler.postUpdateShiftState();
- if (mWordComposer.isComposingWord() && !mWordComposer.isCursorAtEndOfComposingWord()) {
+ if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) {
+ // If we are in the middle of a recorrection, we need to commit the recorrection
+ // first so that we can remove the character at the current cursor position.
resetEntireInputState(mLastSelectionStart);
+ // When we exit this if-clause, mWordComposer.isComposingWord() will return false.
}
if (mWordComposer.isComposingWord()) {
final int length = mWordComposer.size();
@@ -1747,7 +1782,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
ResearchLogger.getInstance().uncommitCurrentLogUnit(
word, false /* dumpCurrentLogUnit */);
}
+ final String rejectedSuggestion = mWordComposer.getTypedWord();
mWordComposer.reset();
+ mWordComposer.setRejectedBatchModeSuggestion(rejectedSuggestion);
} else {
mWordComposer.deleteLast();
}
@@ -1868,7 +1905,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
promotePhantomSpace();
}
- if (mWordComposer.isComposingWord() && !mWordComposer.isCursorAtEndOfComposingWord()) {
+ 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 character at the current cursor position.
resetEntireInputState(mLastSelectionStart);
isComposingWord = false;
}
@@ -1926,6 +1965,38 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
}
+ private void handleRecapitalize() {
+ if (mLastSelectionStart == mLastSelectionEnd) return; // No selection
+ // If we have a recapitalize in progress, use it; otherwise, create a new one.
+ if (!mRecapitalizeStatus.isActive()
+ || !mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) {
+ mRecapitalizeStatus.initialize(mLastSelectionStart, mLastSelectionEnd,
+ mConnection.getSelectedText(0 /* flags, 0 for no styles */).toString(),
+ mSettings.getCurrentLocale(), mSettings.getWordSeparators());
+ // We trim leading and trailing whitespace.
+ mRecapitalizeStatus.trim();
+ // Trimming the object may have changed the length of the string, and we need to
+ // reposition the selection handles accordingly. As this result in an IPC call,
+ // only do it if it's actually necessary, in other words if the recapitalize status
+ // is not set at the same place as before.
+ if (!mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) {
+ mLastSelectionStart = mRecapitalizeStatus.getNewCursorStart();
+ mLastSelectionEnd = mRecapitalizeStatus.getNewCursorEnd();
+ mConnection.setSelection(mLastSelectionStart, mLastSelectionEnd);
+ }
+ }
+ mRecapitalizeStatus.rotate();
+ final int numCharsDeleted = mLastSelectionEnd - mLastSelectionStart;
+ mConnection.setSelection(mLastSelectionEnd, mLastSelectionEnd);
+ mConnection.deleteSurroundingText(numCharsDeleted, 0);
+ mConnection.commitText(mRecapitalizeStatus.getRecapitalizedString(), 0);
+ mLastSelectionStart = mRecapitalizeStatus.getNewCursorStart();
+ mLastSelectionEnd = mRecapitalizeStatus.getNewCursorEnd();
+ mConnection.setSelection(mLastSelectionStart, mLastSelectionEnd);
+ // Match the keyboard to the new state.
+ mKeyboardSwitcher.updateShiftState();
+ }
+
// Returns true if we did an autocorrection, false otherwise.
private boolean handleSeparator(final int primaryCode, final int x, final int y,
final int spaceState) {
@@ -1933,7 +2004,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
ResearchLogger.latinIME_handleSeparator(primaryCode, mWordComposer.isComposingWord());
}
boolean didAutoCorrect = false;
- // Handle separator
+ 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);
+ }
if (mWordComposer.isComposingWord()) {
if (mSettings.getCurrent().mCorrectionEnabled) {
// TODO: maybe cache Strings in an <String> sparse array or something
@@ -2354,10 +2429,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
if (!mConnection.isCursorTouchingWord(mSettings.getCurrent())) return;
final Range range = mConnection.getWordRangeAtCursor(mSettings.getWordSeparators(),
0 /* additionalPrecedingWordsCount */);
+ if (null == range) return; // Happens if we don't have an input connection at all
final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
+ final String typedWord = range.mWord.toString();
if (range.mWord instanceof SpannableString) {
final SpannableString spannableString = (SpannableString)range.mWord;
- final String typedWord = spannableString.toString();
int i = 0;
for (Object object : spannableString.getSpans(0, spannableString.length(),
SuggestionSpan.class)) {
@@ -2372,18 +2448,42 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
}
}
}
- mWordComposer.setComposingWord(range.mWord, mKeyboardSwitcher.getKeyboard());
+ mWordComposer.setComposingWord(typedWord, mKeyboardSwitcher.getKeyboard());
mWordComposer.setCursorPositionWithinWord(range.mCharsBefore);
mConnection.setComposingRegion(mLastSelectionStart - range.mCharsBefore,
mLastSelectionEnd + range.mCharsAfter);
+ final SuggestedWords suggestedWords;
if (suggestions.isEmpty()) {
- suggestions.add(new SuggestedWordInfo(range.mWord.toString(), 1,
- SuggestedWordInfo.KIND_TYPED, Dictionary.TYPE_RESUMED));
+ // We come here if there weren't any suggestion spans on this word. We will try to
+ // compute suggestions for it instead.
+ final SuggestedWords suggestedWordsIncludingTypedWord =
+ getSuggestedWords(Suggest.SESSION_TYPING);
+ if (suggestedWordsIncludingTypedWord.size() > 1) {
+ // We were able to compute new suggestions for this word.
+ // Remove the typed word, since we don't want to display it in this case.
+ // The #getSuggestedWordsExcludingTypedWord() method sets willAutoCorrect to false.
+ suggestedWords =
+ suggestedWordsIncludingTypedWord.getSuggestedWordsExcludingTypedWord();
+ } else {
+ // No saved suggestions, and we were unable to compute any good one either.
+ // Rather than displaying an empty suggestion strip, we'll display the original
+ // word alone in the middle.
+ // Since there is only one word, willAutoCorrect is false.
+ suggestedWords = suggestedWordsIncludingTypedWord;
+ }
+ } else {
+ // We found suggestion spans in the word. We'll create the SuggestedWords out of
+ // them, and make willAutoCorrect false.
+ suggestedWords = new SuggestedWords(suggestions,
+ true /* typedWordValid */, false /* willAutoCorrect */,
+ false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */,
+ false /* isPrediction */);
}
- showSuggestionStrip(new SuggestedWords(suggestions,
- true /* typedWordValid */, false /* willAutoCorrect */,
- false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */,
- false /* isPrediction */), range.mWord.toString());
+
+ // Note that it's very important here that suggestedWords.mWillAutoCorrect is false.
+ // We never want to auto-correct on a resumed suggestion. Please refer to the three
+ // places above where suggestedWords is affected.
+ showSuggestionStrip(suggestedWords, typedWord);
}
/**
@@ -2459,7 +2559,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
// This essentially inserts a space, and that's it.
public void promotePhantomSpace() {
- if (mSettings.getCurrent().shouldInsertSpacesAutomatically()) {
+ if (mSettings.getCurrent().shouldInsertSpacesAutomatically()
+ && !mConnection.textBeforeCursorLooksLikeURL()) {
sendKeyCodePoint(Constants.CODE_SPACE);
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.latinIME_promotePhantomSpace();