diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin/LatinIME.java')
-rw-r--r-- | java/src/com/android/inputmethod/latin/LatinIME.java | 180 |
1 files changed, 109 insertions, 71 deletions
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index ccdbd0d4d..608bb3cea 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -99,6 +99,7 @@ import com.android.inputmethod.latin.utils.JniUtils; import com.android.inputmethod.latin.utils.LatinImeLoggerUtils; import com.android.inputmethod.latin.utils.RecapitalizeStatus; import com.android.inputmethod.latin.utils.StaticInnerHandlerWrapper; +import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.TargetPackageInfoGetterTask; import com.android.inputmethod.latin.utils.TextRange; import com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils; @@ -1261,9 +1262,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final boolean needsInputViewShown) { // TODO: Modify this if we support suggestions with hard keyboard if (onEvaluateInputViewShown() && mSuggestionStripView != null) { - final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); - final boolean inputViewShown = (mainKeyboardView != null) - ? mainKeyboardView.isShown() : false; + final boolean inputViewShown = mKeyboardSwitcher.isShowingMainKeyboardOrEmojiPalettes(); final boolean shouldShowSuggestions = shown && (needsInputViewShown ? inputViewShown : true); if (isFullscreenMode()) { @@ -1329,7 +1328,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (visibleKeyboardView.isShown()) { // Note that the height of Emoji layout is the same as the height of the main keyboard // and the suggestion strip - if (mKeyboardSwitcher.isShowingEmojiKeyboard() + if (mKeyboardSwitcher.isShowingEmojiPalettes() || mSuggestionStripView.getVisibility() == View.VISIBLE) { visibleTopY -= suggestionsHeight; } @@ -1588,8 +1587,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // relying on this behavior so we continue to support it for older apps. sendDownUpKeyEvent(KeyEvent.KEYCODE_ENTER); } else { - final String text = new String(new int[] { code }, 0, 1); - mConnection.commitText(text, text.length()); + mConnection.commitText(StringUtils.newSingleCodePointString(code), 1); } } @@ -1624,8 +1622,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen case Constants.CODE_DELETE: mSpaceState = SPACE_STATE_NONE; handleBackspace(spaceState); - mDeleteCount++; - mExpectingUpdateSelection = true; LatinImeLogger.logOnDelete(x, y); break; case Constants.CODE_SHIFT: @@ -1712,7 +1708,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mSpaceState = SPACE_STATE_NONE; final boolean didAutoCorrect; final SettingsValues settingsValues = mSettings.getCurrent(); - if (settingsValues.isWordSeparator(primaryCode)) { + if (settingsValues.isWordSeparator(primaryCode) + || Character.getType(primaryCode) == Character.OTHER_SYMBOL) { didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState); } else { didAutoCorrect = false; @@ -1838,12 +1835,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public boolean handleMessage(final Message msg) { + // TODO: straighten message passing - we don't need two kinds of messages calling + // each other. switch (msg.what) { case MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP: - updateBatchInput((InputPointers)msg.obj); + updateBatchInput((InputPointers)msg.obj, msg.arg2 /* sequenceNumber */); break; case MSG_GET_SUGGESTED_WORDS: - mLatinIme.getSuggestedWords(msg.arg1, (OnGetSuggestedWordsCallback) msg.obj); + mLatinIme.getSuggestedWords(msg.arg1 /* sessionId */, + msg.arg2 /* sequenceNumber */, (OnGetSuggestedWordsCallback) msg.obj); break; } return true; @@ -1860,14 +1860,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } // Run in the Handler thread. - private void updateBatchInput(final InputPointers batchPointers) { + private void updateBatchInput(final InputPointers batchPointers, final int sequenceNumber) { synchronized (mLock) { if (!mInBatchInput) { // Batch input has ended or canceled while the message was being delivered. return; } - getSuggestedWordsGestureLocked(batchPointers, new OnGetSuggestedWordsCallback() { + getSuggestedWordsGestureLocked(batchPointers, sequenceNumber, + new OnGetSuggestedWordsCallback() { @Override public void onGetSuggestedWords(final SuggestedWords suggestedWords) { mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip( @@ -1878,13 +1879,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } // Run in the UI thread. - public void onUpdateBatchInput(final InputPointers batchPointers) { + public void onUpdateBatchInput(final InputPointers batchPointers, + final int sequenceNumber) { if (mHandler.hasMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP)) { return; } - mHandler.obtainMessage( - MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP, batchPointers) - .sendToTarget(); + mHandler.obtainMessage(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP, 0 /* arg1 */, + sequenceNumber /* arg2 */, batchPointers /* obj */).sendToTarget(); } public void onCancelBatchInput() { @@ -1898,7 +1899,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Run in the UI thread. public void onEndBatchInput(final InputPointers batchPointers) { synchronized(mLock) { - getSuggestedWordsGestureLocked(batchPointers, new OnGetSuggestedWordsCallback() { + getSuggestedWordsGestureLocked(batchPointers, SuggestedWords.NOT_A_SEQUENCE_NUMBER, + new OnGetSuggestedWordsCallback() { @Override public void onGetSuggestedWords(final SuggestedWords suggestedWords) { mInBatchInput = false; @@ -1913,10 +1915,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // {@link LatinIME#getSuggestedWords(int)} method calls with same session id have to // be synchronized. private void getSuggestedWordsGestureLocked(final InputPointers batchPointers, - final OnGetSuggestedWordsCallback callback) { + final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { mLatinIme.mWordComposer.setBatchInputPointers(batchPointers); mLatinIme.getSuggestedWordsOrOlderSuggestionsAsync(Suggest.SESSION_GESTURE, - new OnGetSuggestedWordsCallback() { + sequenceNumber, new OnGetSuggestedWordsCallback() { @Override public void onGetSuggestedWords(SuggestedWords suggestedWords) { final int suggestionCount = suggestedWords.size(); @@ -1931,9 +1933,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen }); } - public void getSuggestedWords(final int sessionId, + public void getSuggestedWords(final int sessionId, final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { - mHandler.obtainMessage(MSG_GET_SUGGESTED_WORDS, sessionId, 0, callback).sendToTarget(); + mHandler.obtainMessage(MSG_GET_SUGGESTED_WORDS, sessionId, sequenceNumber, callback) + .sendToTarget(); } private void onDestroy() { @@ -1954,11 +1957,28 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } + /* The sequence number member is only used in onUpdateBatchInput. It is increased each time + * auto-commit happens. The reason we need this is, when auto-commit happens we trim the + * input pointers that are held in a singleton, and to know how much to trim we rely on the + * results of the suggestion process that is held in mSuggestedWords. + * However, the suggestion process is asynchronous, and sometimes we may enter the + * onUpdateBatchInput method twice without having recomputed suggestions yet, or having + * received new suggestions generated from not-yet-trimmed input pointers. In this case, the + * mIndexOfTouchPointOfSecondWords member will be out of date, and we must not use it lest we + * remove an unrelated number of pointers (possibly even more than are left in the input + * pointers, leading to a crash). + * To avoid that, we increase the sequence number each time we auto-commit and trim the + * input pointers, and we do not use any suggested words that have been generated with an + * earlier sequence number. + */ + private int mAutoCommitSequenceNumber = 1; @Override public void onUpdateBatchInput(final InputPointers batchPointers) { if (mSettings.getCurrent().mPhraseGestureEnabled) { final SuggestedWordInfo candidate = mSuggestedWords.getAutoCommitCandidate(); - if (null != candidate) { + // If these suggested words have been generated with out of date input pointers, then + // we skip auto-commit (see comments above on the mSequenceNumber member). + if (null != candidate && mSuggestedWords.mSequenceNumber >= mAutoCommitSequenceNumber) { if (candidate.mSourceDict.shouldAutoCommit(candidate)) { final String[] commitParts = candidate.mWord.split(" ", 2); batchPointers.shift(candidate.mIndexOfTouchPointOfSecondWord); @@ -1967,10 +1987,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mSpaceState = SPACE_STATE_PHANTOM; mKeyboardSwitcher.updateShiftState(); mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode()); + ++mAutoCommitSequenceNumber; } } } - mInputUpdater.onUpdateBatchInput(batchPointers); + mInputUpdater.onUpdateBatchInput(batchPointers, mAutoCommitSequenceNumber); } // This method must run in UI Thread. @@ -2052,6 +2073,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } private void handleBackspace(final int spaceState) { + // We revert these in this method if the deletion doesn't happen. + mDeleteCount++; + mExpectingUpdateSelection = true; + // In many cases, we may have to put the keyboard in auto-shift state again. However // we want to wait a few milliseconds before doing it to avoid the keyboard flashing // during key repeat. @@ -2141,8 +2166,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // This should never happen. Log.e(TAG, "Backspace when we don't know the selection position"); } - final int lengthToDelete = Character.isSupplementaryCodePoint( - mConnection.getCodePointBeforeCursor()) ? 2 : 1; + final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor(); + if (codePointBeforeCursor == Constants.NOT_A_CODE) { + // Nothing to delete before the cursor. We have to revert the deletion states + // that were updated at the beginning of this method. + mDeleteCount--; + mExpectingUpdateSelection = false; + return; + } + final int lengthToDelete = + Character.isSupplementaryCodePoint(codePointBeforeCursor) ? 2 : 1; if (mAppWorkAroundsUtils.isBeforeJellyBean() || currentSettings.mInputAttributes.isTypeNull()) { // There are two possible reasons to send a key event: either the field has @@ -2161,12 +2194,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen true /* shouldUncommitLogUnit */); } if (mDeleteCount > DELETE_ACCELERATE_AT) { - final int lengthToDeleteAgain = Character.isSupplementaryCodePoint( - mConnection.getCodePointBeforeCursor()) ? 2 : 1; - mConnection.deleteSurroundingText(lengthToDeleteAgain, 0); - if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { - ResearchLogger.latinIME_handleBackspace(lengthToDeleteAgain, - true /* shouldUncommitLogUnit */); + final int codePointBeforeCursorToDeleteAgain = + mConnection.getCodePointBeforeCursor(); + if (codePointBeforeCursorToDeleteAgain != Constants.NOT_A_CODE) { + final int lengthToDeleteAgain = Character.isSupplementaryCodePoint( + codePointBeforeCursorToDeleteAgain) ? 2 : 1; + mConnection.deleteSurroundingText(lengthToDeleteAgain, 0); + if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { + ResearchLogger.latinIME_handleBackspace(lengthToDeleteAgain, + true /* shouldUncommitLogUnit */); + } } } } @@ -2336,11 +2373,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (mWordComposer.isComposingWord()) { // May have changed since we stored wasComposing if (currentSettings.mCorrectionEnabled) { final String separator = shouldAvoidSendingCode ? LastComposedWord.NOT_A_SEPARATOR - : new String(new int[] { primaryCode }, 0, 1); + : StringUtils.newSingleCodePointString(primaryCode); commitCurrentAutoCorrection(separator); didAutoCorrect = true; } else { - commitTyped(new String(new int[]{primaryCode}, 0, 1)); + commitTyped(StringUtils.newSingleCodePointString(primaryCode)); } } @@ -2489,7 +2526,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final AsyncResultHolder<SuggestedWords> holder = new AsyncResultHolder<SuggestedWords>(); getSuggestedWordsOrOlderSuggestionsAsync(Suggest.SESSION_TYPING, - new OnGetSuggestedWordsCallback() { + SuggestedWords.NOT_A_SEQUENCE_NUMBER, new OnGetSuggestedWordsCallback() { @Override public void onGetSuggestedWords(final SuggestedWords suggestedWords) { holder.set(suggestedWords); @@ -2504,7 +2541,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } - private void getSuggestedWords(final int sessionId, + private void getSuggestedWords(final int sessionId, final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); final Suggest suggest = mSuggest; @@ -2529,18 +2566,19 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } suggest.getSuggestedWords(mWordComposer, prevWord, keyboard.getProximityInfo(), currentSettings.mBlockPotentiallyOffensive, currentSettings.mCorrectionEnabled, - additionalFeaturesOptions, sessionId, callback); + additionalFeaturesOptions, sessionId, sequenceNumber, callback); } private void getSuggestedWordsOrOlderSuggestionsAsync(final int sessionId, - final OnGetSuggestedWordsCallback callback) { - mInputUpdater.getSuggestedWords(sessionId, new OnGetSuggestedWordsCallback() { - @Override - public void onGetSuggestedWords(SuggestedWords suggestedWords) { - callback.onGetSuggestedWords(maybeRetrieveOlderSuggestions( - mWordComposer.getTypedWord(), suggestedWords)); - } - }); + final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { + mInputUpdater.getSuggestedWords(sessionId, sequenceNumber, + new OnGetSuggestedWordsCallback() { + @Override + public void onGetSuggestedWords(SuggestedWords suggestedWords) { + callback.onGetSuggestedWords(maybeRetrieveOlderSuggestions( + mWordComposer.getTypedWord(), suggestedWords)); + } + }); } private SuggestedWords maybeRetrieveOlderSuggestions(final String typedWord, @@ -2875,30 +2913,30 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // We come here if there weren't any suggestion spans on this word. We will try to // compute suggestions for it instead. mInputUpdater.getSuggestedWords(Suggest.SESSION_TYPING, - new OnGetSuggestedWordsCallback() { - @Override - public void onGetSuggestedWords( - final SuggestedWords suggestedWordsIncludingTypedWord) { - final SuggestedWords suggestedWords; - if (suggestedWordsIncludingTypedWord.size() > 1) { - // We were able to compute new suggestions for this word. - // Remove the typed word, since we don't want to display it in this case. - // The #getSuggestedWordsExcludingTypedWord() method sets willAutoCorrect to - // false. - suggestedWords = suggestedWordsIncludingTypedWord - .getSuggestedWordsExcludingTypedWord(); - } else { - // No saved suggestions, and we were unable to compute any good one either. - // Rather than displaying an empty suggestion strip, we'll display the - // original word alone in the middle. - // Since there is only one word, willAutoCorrect is false. - suggestedWords = suggestedWordsIncludingTypedWord; - } - // We need to pass typedWord because mWordComposer.mTypedWord may differ from - // typedWord. - unsetIsAutoCorrectionIndicatorOnAndCallShowSuggestionStrip(suggestedWords, - typedWord); - }}); + SuggestedWords.NOT_A_SEQUENCE_NUMBER, new OnGetSuggestedWordsCallback() { + @Override + public void onGetSuggestedWords( + final SuggestedWords suggestedWordsIncludingTypedWord) { + final SuggestedWords suggestedWords; + if (suggestedWordsIncludingTypedWord.size() > 1) { + // We were able to compute new suggestions for this word. + // Remove the typed word, since we don't want to display it in this + // case. The #getSuggestedWordsExcludingTypedWord() method sets + // willAutoCorrect to false. + suggestedWords = suggestedWordsIncludingTypedWord + .getSuggestedWordsExcludingTypedWord(); + } else { + // No saved suggestions, and we were unable to compute any good one + // either. Rather than displaying an empty suggestion strip, we'll + // display the original word alone in the middle. + // Since there is only one word, willAutoCorrect is false. + suggestedWords = suggestedWordsIncludingTypedWord; + } + // We need to pass typedWord because mWordComposer.mTypedWord may + // differ from typedWord. + unsetIsAutoCorrectionIndicatorOnAndCallShowSuggestionStrip( + suggestedWords, typedWord); + }}); } else { // We found suggestion spans in the word. We'll create the SuggestedWords out of // them, and make willAutoCorrect false. @@ -2979,8 +3017,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final String originallyTypedWord = mLastComposedWord.mTypedWord; final String committedWord = mLastComposedWord.mCommittedWord; final int cancelLength = committedWord.length(); - final int separatorLength = LastComposedWord.getSeparatorLength( - mLastComposedWord.mSeparatorString); + // We want java chars, not codepoints for the following. + final int separatorLength = mLastComposedWord.mSeparatorString.length(); // TODO: should we check our saved separator against the actual contents of the text view? final int deleteLength = cancelLength + separatorLength; if (DEBUG) { |