diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin')
6 files changed, 156 insertions, 200 deletions
diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java index f34cb5ff9..bc0792434 100644 --- a/java/src/com/android/inputmethod/latin/LastComposedWord.java +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -40,26 +40,31 @@ public class LastComposedWord { // an auto-correction. public static final int COMMIT_TYPE_CANCEL_AUTO_CORRECT = 3; + public static final int NOT_A_SEPARATOR = -1; + public final ArrayList<int[]> mCodes; public final int[] mXCoordinates; public final int[] mYCoordinates; public final String mTypedWord; - public final String mAutoCorrection; + public final String mCommittedWord; + public final int mSeparatorCode; private boolean mActive; public static final LastComposedWord NOT_A_COMPOSED_WORD = - new LastComposedWord(null, null, null, "", ""); + new LastComposedWord(null, null, null, "", "", NOT_A_SEPARATOR); // Warning: this is using the passed objects as is and fully expects them to be // immutable. Do not fiddle with their contents after you passed them to this constructor. public LastComposedWord(final ArrayList<int[]> codes, final int[] xCoordinates, - final int[] yCoordinates, final String typedWord, final String autoCorrection) { + final int[] yCoordinates, final String typedWord, final String committedWord, + final int separatorCode) { mCodes = codes; mXCoordinates = xCoordinates; mYCoordinates = yCoordinates; mTypedWord = typedWord; - mAutoCorrection = autoCorrection; + mCommittedWord = committedWord; + mSeparatorCode = separatorCode; mActive = true; } @@ -67,8 +72,15 @@ public class LastComposedWord { mActive = false; } - public boolean canCancelAutoCorrect() { - return mActive && !TextUtils.isEmpty(mAutoCorrection) - && !TextUtils.equals(mTypedWord, mAutoCorrection); + public boolean canRevertCommit() { + return mActive && !TextUtils.isEmpty(mCommittedWord); + } + + public boolean didCommitTypedWord() { + return TextUtils.equals(mTypedWord, mCommittedWord); + } + + public static int getSeparatorLength(final int separatorCode) { + return NOT_A_SEPARATOR == separatorCode ? 0 : 1; } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index ce306eaad..47ec40f99 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -165,8 +165,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // 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. private static final int SPACE_STATE_DOUBLE = 1; - // Swap punctuation: the state where a (weak or magic) space and a punctuation from the - // suggestion strip have just been swapped. Undoing this swaps them back. + // Swap punctuation: the state where a weak space and a punctuation from the suggestion strip + // have just been swapped. Undoing this swaps them back; the space is still considered weak. private static final int SPACE_STATE_SWAP_PUNCTUATION = 2; // Weak space: a space that should be swapped only by suggestion strip punctuation. Weak // spaces happen when the user presses space, accepting the current suggestion (whether @@ -658,7 +658,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mDisplayOrientation = conf.orientation; mHandler.startOrientationChanging(); final InputConnection ic = getCurrentInputConnection(); - commitTyped(ic); + commitTyped(ic, LastComposedWord.NOT_A_SEPARATOR); if (ic != null) ic.finishComposingText(); // For voice input if (isShowingOptionDialog()) mOptionsDialog.dismiss(); @@ -887,26 +887,16 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // the second one - the first call successfully avoids this test, but the second one // enters. For the moment we rely on noComposingSpan to further reduce the impact. + // TODO: the following is probably better done in resetEntireInputState(). + // it should only happen when the cursor moved, and the very purpose of the + // test below is to narrow down whether this happened or not. Likewise with + // the call to postUpdateShiftState. // We set this to NONE because after a cursor move, we don't want the space // state-related special processing to kick in. mSpaceState = SPACE_STATE_NONE; - if (((mWordComposer.isComposingWord()) - || mVoiceProxy.isVoiceInputHighlighted()) - && (selectionChanged || noComposingSpan)) { - resetComposingState(true /* alsoResetLastComposedWord */); - updateSuggestions(); - final InputConnection ic = getCurrentInputConnection(); - if (ic != null) { - ic.finishComposingText(); - } - mComposingStateManager.onFinishComposingText(); - mVoiceProxy.setVoiceInputHighlighted(false); - } else if (!mWordComposer.isComposingWord()) { - // TODO: is the following reset still needed, given that we are not composing - // a word? - resetComposingState(true /* alsoResetLastComposedWord */); - updateSuggestions(); + if ((!mWordComposer.isComposingWord()) || selectionChanged || noComposingSpan) { + resetEntireInputState(); } mHandler.postUpdateShiftState(); @@ -1116,17 +1106,33 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return super.onKeyUp(keyCode, event); } + // 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. + private void resetEntireInputState() { + resetComposingState(true /* alsoResetLastComposedWord */); + updateSuggestions(); + final InputConnection ic = getCurrentInputConnection(); + if (ic != null) { + ic.finishComposingText(); + } + mComposingStateManager.onFinishComposingText(); + mVoiceProxy.setVoiceInputHighlighted(false); + } + private void resetComposingState(final boolean alsoResetLastComposedWord) { mWordComposer.reset(); if (alsoResetLastComposedWord) mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; } - public void commitTyped(final InputConnection ic) { + public void commitTyped(final InputConnection ic, final int separatorCode) { if (!mWordComposer.isComposingWord()) return; final CharSequence typedWord = mWordComposer.getTypedWord(); - mLastComposedWord = mWordComposer.commitWord(LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD); if (typedWord.length() > 0) { + mLastComposedWord = mWordComposer.commitWord( + LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, typedWord.toString(), + separatorCode); if (ic != null) { ic.commitText(typedWord, 1); } @@ -1242,11 +1248,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar KeyboardActionListener.SUGGESTION_STRIP_COORDINATE); } - private static int getEditorActionId(EditorInfo editorInfo) { - if (editorInfo == null) return 0; - return (editorInfo.actionLabel != null) - ? editorInfo.actionId - : (editorInfo.imeOptions & EditorInfo.IME_MASK_ACTION); + private static int getActionId(Keyboard keyboard) { + return keyboard != null ? keyboard.mId.imeActionId() : EditorInfo.IME_ACTION_NONE; } private void performeEditorAction(int actionId) { @@ -1312,18 +1315,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mSubtypeSwitcher.switchToShortcutIME(); break; case Keyboard.CODE_ACTION_ENTER: - performeEditorAction(getEditorActionId(getCurrentInputEditorInfo())); + performeEditorAction(getActionId(switcher.getKeyboard())); + break; + case Keyboard.CODE_ACTION_NEXT: + performeEditorAction(EditorInfo.IME_ACTION_NEXT); break; - case Keyboard.CODE_TAB: - handleTab(); - // There are two cases for tab. Either we send a "next" event, that may change the - // focus but will never move the cursor. Or, we send a real tab keycode, which some - // applications may accept or ignore, and we don't know whether this will move the - // cursor or not. So actually, we don't really know. - // So to go with the safer option, we'd rather behave as if the user moved the - // cursor when they didn't than the opposite. We also expect that most applications - // will actually use tab only for focus movement. - // To sum it up: do not update mExpectingUpdateSelection here. + case Keyboard.CODE_ACTION_PREVIOUS: + EditorInfoCompatUtils.performEditorActionPrevious(getCurrentInputConnection()); break; default: mSpaceState = SPACE_STATE_NONE; @@ -1348,7 +1346,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final InputConnection ic = getCurrentInputConnection(); if (ic == null) return; ic.beginBatchEdit(); - commitTyped(ic); + commitTyped(ic, LastComposedWord.NOT_A_SEPARATOR); text = specificTldProcessingOnTextInput(ic, text); if (SPACE_STATE_PHANTOM == mSpaceState) { sendKeyCodePoint(Keyboard.CODE_SPACE); @@ -1433,16 +1431,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar ic.deleteSurroundingText(1, 0); } } else { - // We should be very careful about auto-correction cancellation and suggestion - // resuming here. The behavior needs to be different according to text field types, - // and it would be much clearer to test for them explicitly here rather than - // relying on implicit values like "whether the suggestion strip is displayed". - if (mLastComposedWord.canCancelAutoCorrect()) { + if (mLastComposedWord.canRevertCommit()) { Utils.Stats.onAutoCorrectionCancellation(); - cancelAutoCorrect(ic); + revertCommit(ic); return; } - if (SPACE_STATE_DOUBLE == spaceState) { if (revertDoubleSpaceWhileInBatchEdit(ic)) { // No need to reset mSpaceState, it has already be done (that's why we @@ -1456,61 +1449,27 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } - // See the comment above: must be careful about resuming auto-suggestion. - if (mSuggestionsView != null && mSuggestionsView.dismissAddToDictionaryHint()) { - // Go back to the suggestion mode if the user canceled the - // "Touch again to save". - // NOTE: In general, we don't revert the word when backspacing - // from a manual suggestion pick. We deliberately chose a - // different behavior only in the case of picking the first - // suggestion (typed word). It's intentional to have made this - // inconsistent with backspacing after selecting other suggestions. - restartSuggestionsOnManuallyPickedTypedWord(ic); + // No cancelling of commit/double space/swap: we have a regular backspace. + // We should backspace one char and restart suggestion if at the end of a word. + if (mLastSelectionStart != mLastSelectionEnd) { + // If there is a selection, remove it. + final int lengthToDelete = mLastSelectionEnd - mLastSelectionStart; + ic.setSelection(mLastSelectionEnd, mLastSelectionEnd); + ic.deleteSurroundingText(lengthToDelete, 0); } else { - // Here we must check whether there is a selection. If so we should remove the - // selected text, otherwise we should just delete the character before the cursor. - if (mLastSelectionStart != mLastSelectionEnd) { - final int lengthToDelete = mLastSelectionEnd - mLastSelectionStart; - ic.setSelection(mLastSelectionEnd, mLastSelectionEnd); - ic.deleteSurroundingText(lengthToDelete, 0); - } else { - if (NOT_A_CURSOR_POSITION == mLastSelectionEnd) { - // This should never happen. - Log.e(TAG, "Backspace when we don't know the selection position"); - } - ic.deleteSurroundingText(1, 0); - if (mDeleteCount > DELETE_ACCELERATE_AT) { - ic.deleteSurroundingText(1, 0); - } + // There is no selection, just delete one character. + if (NOT_A_CURSOR_POSITION == mLastSelectionEnd) { + // This should never happen. + Log.e(TAG, "Backspace when we don't know the selection position"); } - if (isSuggestionsRequested()) { - restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(ic); + ic.deleteSurroundingText(1, 0); + if (mDeleteCount > DELETE_ACCELERATE_AT) { + ic.deleteSurroundingText(1, 0); } } - } - } - - // TODO: Implement next and previous actions using other key code than tab's code. - private void handleTab() { - final int imeOptions = getCurrentInputEditorInfo().imeOptions; - if (!EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions) - && !EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)) { - // TODO: This should be {@link #sendKeyCodePoint(int)}. - sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB); - return; - } - - final InputConnection ic = getCurrentInputConnection(); - if (ic == null) - return; - - final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); - // True if keyboard is in either shift chording or manual shifted state. - final boolean isManualShifted = (keyboard != null && keyboard.isManualShifted()); - if (EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions) && !isManualShifted) { - EditorInfoCompatUtils.performEditorActionNext(ic); - } else if (EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions) && isManualShifted) { - EditorInfoCompatUtils.performEditorActionPrevious(ic); + if (isSuggestionsRequested()) { + restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(ic); + } } } @@ -1523,10 +1482,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } else if ((SPACE_STATE_WEAK == spaceState || SPACE_STATE_SWAP_PUNCTUATION == spaceState) && isFromSuggestionStrip) { - if (mSettingsValues.isMagicSpaceSwapper(code)) { + if (mSettingsValues.isWeakSpaceSwapper(code)) { return true; } else { - if (mSettingsValues.isMagicSpaceStripper(code)) { + if (mSettingsValues.isWeakSpaceStripper(code)) { removeTrailingSpaceWhileInBatchEdit(ic); } return false; @@ -1599,6 +1558,15 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar swapSwapperAndSpaceWhileInBatchEdit(ic); 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(); + } } Utils.Stats.onNonSeparator((char)primaryCode, x, y); } @@ -1632,7 +1600,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar commitCurrentAutoCorrection(primaryCode, ic); didAutoCorrect = true; } else { - commitTyped(ic); + commitTyped(ic, primaryCode); } } @@ -1689,7 +1657,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } private void handleClose() { - commitTyped(getCurrentInputConnection()); + commitTyped(getCurrentInputConnection(), LastComposedWord.NOT_A_SEPARATOR); mVoiceProxy.handleClose(); requestHideSelf(0); LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); @@ -1900,7 +1868,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCodePoint); mExpectingUpdateSelection = true; - commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD); + commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD, + separatorCodePoint); // Add the word to the user unigram dictionary if it's not a known word addToUserUnigramAndBigramDictionaries(autoCorrection, UserUnigramDictionary.FREQUENCY_FOR_TYPED); @@ -1955,7 +1924,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar LatinImeLogger.logOnManualSuggestion(mWordComposer.getTypedWord().toString(), suggestion.toString(), index, suggestions.mWords); mExpectingUpdateSelection = true; - commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK); + commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK, + LastComposedWord.NOT_A_SEPARATOR); // Add the word to the auto dictionary if it's not a known word if (index == 0) { addToUserUnigramAndBigramDictionaries(suggestion, @@ -2005,7 +1975,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar /** * Commits the chosen word to the text field and saves it for later retrieval. */ - private void commitChosenWord(final CharSequence bestWord, final int commitType) { + private void commitChosenWord(final CharSequence bestWord, final int commitType, + final int separatorCode) { final InputConnection ic = getCurrentInputConnection(); if (ic != null) { mVoiceProxy.rememberReplacedWord(bestWord, mSettingsValues.mWordSeparators); @@ -2019,9 +1990,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } // TODO: figure out here if this is an auto-correct or if the best word is actually // what user typed. Note: currently this is done much later in - // LastComposedWord#canCancelAutoCorrect by string equality of the remembered + // LastComposedWord#didCommitTypedWord by string equality of the remembered // strings. - mLastComposedWord = mWordComposer.commitWord(commitType); + mLastComposedWord = mWordComposer.commitWord(commitType, bestWord.toString(), + separatorCode); } private static final WordComposer sEmptyWordComposer = new WordComposer(); @@ -2183,66 +2155,43 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } // "ic" must not be null - private void cancelAutoCorrect(final InputConnection ic) { + private void revertCommit(final InputConnection ic) { final String originallyTypedWord = mLastComposedWord.mTypedWord; - final CharSequence autoCorrectedTo = mLastComposedWord.mAutoCorrection; - final int cancelLength = autoCorrectedTo.length(); - final CharSequence separator = ic.getTextBeforeCursor(1, 0); + final CharSequence committedWord = mLastComposedWord.mCommittedWord; + final int cancelLength = committedWord.length(); + final int separatorLength = mLastComposedWord.getSeparatorLength( + mLastComposedWord.mSeparatorCode); + // TODO: should we check our saved separator against the actual contents of the text view? if (DEBUG) { if (mWordComposer.isComposingWord()) { - throw new RuntimeException("cancelAutoCorrect, but we are composing a word"); + throw new RuntimeException("revertCommit, but we are composing a word"); } final String wordBeforeCursor = - ic.getTextBeforeCursor(cancelLength + 1, 0).subSequence(0, cancelLength) - .toString(); - if (!TextUtils.equals(autoCorrectedTo, wordBeforeCursor)) { - throw new RuntimeException("cancelAutoCorrect check failed: we thought we were " - + "reverting \"" + autoCorrectedTo + ic.getTextBeforeCursor(cancelLength + separatorLength, 0) + .subSequence(0, cancelLength).toString(); + if (!TextUtils.equals(committedWord, wordBeforeCursor)) { + throw new RuntimeException("revertCommit check failed: we thought we were " + + "reverting \"" + committedWord + "\", but before the cursor we found \"" + wordBeforeCursor + "\""); } - if (TextUtils.equals(originallyTypedWord, wordBeforeCursor)) { - throw new RuntimeException("cancelAutoCorrect check failed: we wanted to cancel " - + "auto correction and revert to \"" + originallyTypedWord - + "\" but we found this very string before the cursor"); - } } - ic.deleteSurroundingText(cancelLength + 1, 0); - ic.commitText(originallyTypedWord, 1); - // Re-insert the separator - ic.commitText(separator, 1); - mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; - Utils.Stats.onSeparator(separator.charAt(0), WordComposer.NOT_A_COORDINATE, - WordComposer.NOT_A_COORDINATE); - mHandler.cancelUpdateBigramPredictions(); - mHandler.postUpdateSuggestions(); - } - - // "ic" must not be null - private void restartSuggestionsOnManuallyPickedTypedWord(final InputConnection ic) { - // Note: this relies on the last word still being held in the WordComposer, in - // the field for suggestion resuming. - // Note: in the interest of code simplicity, we may want to just call - // restartSuggestionsOnWordBeforeCursorIfAtEndOfWord instead, but retrieving - // the old WordComposer allows to reuse the actual typed coordinates. - mWordComposer.resumeSuggestionOnLastComposedWord(mLastComposedWord); - // We resume suggestion, and then we want to set the composing text to the content - // of the word composer again. But since we just manually picked a word, there is - // no composing text at the moment, so we have to delete the word before we set a - // new composing text. - final int restartLength = mWordComposer.size(); - if (DEBUG) { - final String wordBeforeCursor = ic.getTextBeforeCursor(restartLength, 0).toString(); - if (!TextUtils.equals(mWordComposer.getTypedWord(), wordBeforeCursor)) { - throw new RuntimeException("restartSuggestionsOnManuallyPickedTypedWord " - + "check failed: we thought we were reverting \"" - + mWordComposer.getTypedWord() - + "\", but before the cursor we found \"" - + wordBeforeCursor + "\""); - } + ic.deleteSurroundingText(cancelLength + separatorLength, 0); + 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); + mComposingStateManager.onStartComposingText(); + 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); + // Don't restart suggestion yet. We'll restart if the user deletes the + // separator. } - ic.deleteSurroundingText(restartLength, 0); - mComposingStateManager.onStartComposingText(); - ic.setComposingText(mWordComposer.getTypedWord(), 1); + mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; mHandler.cancelUpdateBigramPredictions(); mHandler.postUpdateSuggestions(); } diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 7a43cb827..d123b608f 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -35,8 +35,8 @@ public class SettingsValues { // From resources: public final int mDelayUpdateOldSuggestions; - public final String mMagicSpaceStrippers; - public final String mMagicSpaceSwappers; + public final String mWeakSpaceStrippers; + public final String mWeakSpaceSwappers; private final String mSuggestPuncs; public final SuggestedWords mSuggestPuncList; public final SuggestedWords mSuggestPuncOutputTextList; @@ -89,14 +89,14 @@ public class SettingsValues { // Get the resources mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions); - mMagicSpaceStrippers = res.getString(R.string.magic_space_stripping_symbols); - mMagicSpaceSwappers = res.getString(R.string.magic_space_swapping_symbols); + mWeakSpaceStrippers = res.getString(R.string.weak_space_stripping_symbols); + mWeakSpaceSwappers = res.getString(R.string.weak_space_swapping_symbols); if (LatinImeLogger.sDBG) { - final int length = mMagicSpaceStrippers.length(); - for (int i = 0; i < length; i = mMagicSpaceStrippers.offsetByCodePoints(i, 1)) { - if (isMagicSpaceSwapper(mMagicSpaceStrippers.codePointAt(i))) { - throw new RuntimeException("Char code " + mMagicSpaceStrippers.codePointAt(i) - + " is both a magic space swapper and stripper."); + final int length = mWeakSpaceStrippers.length(); + for (int i = 0; i < length; i = mWeakSpaceStrippers.offsetByCodePoints(i, 1)) { + if (isWeakSpaceSwapper(mWeakSpaceStrippers.codePointAt(i))) { + throw new RuntimeException("Char code " + mWeakSpaceStrippers.codePointAt(i) + + " is both a weak space swapper and stripper."); } } } @@ -107,7 +107,7 @@ public class SettingsValues { mSuggestPuncOutputTextList = createSuggestPuncOutputTextList(suggestPuncsSpec); mSymbolsExcludedFromWordSeparators = res.getString(R.string.symbols_excluded_from_word_separators); - mWordSeparators = createWordSeparators(mMagicSpaceStrippers, mMagicSpaceSwappers, + mWordSeparators = createWordSeparators(mWeakSpaceStrippers, mWeakSpaceSwappers, mSymbolsExcludedFromWordSeparators, res); mHintToSaveText = context.getText(R.string.hint_add_to_dictionary); @@ -188,11 +188,11 @@ public class SettingsValues { return builder.setIsPunctuationSuggestions().build(); } - private static String createWordSeparators(final String magicSpaceStrippers, - final String magicSpaceSwappers, final String symbolsExcludedFromWordSeparators, + private static String createWordSeparators(final String weakSpaceStrippers, + final String weakSpaceSwappers, final String symbolsExcludedFromWordSeparators, final Resources res) { - String wordSeparators = magicSpaceStrippers + magicSpaceSwappers - + res.getString(R.string.magic_space_promoting_symbols); + String wordSeparators = weakSpaceStrippers + weakSpaceSwappers + + res.getString(R.string.weak_space_promoting_symbols); for (int i = symbolsExcludedFromWordSeparators.length() - 1; i >= 0; --i) { wordSeparators = wordSeparators.replace( symbolsExcludedFromWordSeparators.substring(i, i + 1), ""); @@ -215,14 +215,14 @@ public class SettingsValues { return mSymbolsExcludedFromWordSeparators.contains(String.valueOf((char)code)); } - public boolean isMagicSpaceStripper(int code) { + public boolean isWeakSpaceStripper(int code) { // TODO: this does not work if the code does not fit in a char - return mMagicSpaceStrippers.contains(String.valueOf((char)code)); + return mWeakSpaceStrippers.contains(String.valueOf((char)code)); } - public boolean isMagicSpaceSwapper(int code) { + public boolean isWeakSpaceSwapper(int code) { // TODO: this does not work if the code does not fit in a char - return mMagicSpaceSwappers.contains(String.valueOf((char)code)); + return mWeakSpaceSwappers.contains(String.valueOf((char)code)); } private static boolean isAutoCorrectEnabled(final Resources resources, diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 3975dddeb..6d63e95f6 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -264,6 +264,7 @@ public class Utils { int ret = in % BUFSIZE; return ret < 0 ? ret + BUFSIZE : ret; } + // TODO: accept code points public void push(char c, int x, int y) { if (!mEnabled) return; if (mUsabilityStudy) { @@ -777,9 +778,10 @@ public class Utils { LatinImeLogger.logOnInputChar(); } - public static void onSeparator(final char code, final int x, + public static void onSeparator(final int code, final int x, final int y) { - RingCharBuffer.getInstance().push(code, x, y); + // TODO: accept code points + RingCharBuffer.getInstance().push((char)code, x, y); LatinImeLogger.logOnInputSeparator(); } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index a1a329a8d..8121ada7f 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -308,17 +308,11 @@ public class WordComposer { } // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. - public LastComposedWord commitWord(final int type) { - // Note: currently, we come here whenever we commit a word. If it's any *other* kind than - // DECIDED_WORD, we should reset mAutoCorrection so that we don't attempt to cancel later. - // If it's a DECIDED_WORD, it may be an actual auto-correction by the IME, or what the user - // typed because the IME decided *not* to auto-correct for whatever reason. - // Ideally we would also null it when it was a DECIDED_WORD that was not an auto-correct. - // As it happens these two cases should behave differently, because the former can be - // canceled while the latter can't. Currently, we figure this out in - // LastComposedWord#didAutoCorrectToAnotherWord with #equals(). It would be marginally - // cleaner to do it here, but it would be slower (since we would #equals() for each commit, - // instead of only on cancel), and ultimately we want to figure it out even earlier anyway. + public LastComposedWord commitWord(final int type, final String committedWord, + final int separatorCode) { + // Note: currently, we come here whenever we commit a word. If it's a MANUAL_PICK + // or a DECIDED_WORD we may cancel the commit later; otherwise, we should deactivate + // the last composed word to ensure this does not happen. final ArrayList<int[]> codes = mCodes; final int[] xCoordinates = mXCoordinates; final int[] yCoordinates = mYCoordinates; @@ -326,9 +320,9 @@ public class WordComposer { mXCoordinates = new int[N]; mYCoordinates = new int[N]; final LastComposedWord lastComposedWord = new LastComposedWord(codes, - xCoordinates, yCoordinates, mTypedWord.toString(), - null == mAutoCorrection ? null : mAutoCorrection.toString()); - if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD) { + xCoordinates, yCoordinates, mTypedWord.toString(), committedWord, separatorCode); + if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD + && type != LastComposedWord.COMMIT_TYPE_MANUAL_PICK) { lastComposedWord.deactivate(); } mTypedWord.setLength(0); @@ -342,6 +336,6 @@ public class WordComposer { mYCoordinates = lastComposedWord.mYCoordinates; mTypedWord.setLength(0); mTypedWord.append(lastComposedWord.mTypedWord); - mAutoCorrection = lastComposedWord.mAutoCorrection; + mAutoCorrection = null; // This will be filled by the next call to updateSuggestion. } } diff --git a/java/src/com/android/inputmethod/latin/XmlParseUtils.java b/java/src/com/android/inputmethod/latin/XmlParseUtils.java index d747a024c..e14c71cb5 100644 --- a/java/src/com/android/inputmethod/latin/XmlParseUtils.java +++ b/java/src/com/android/inputmethod/latin/XmlParseUtils.java @@ -27,8 +27,7 @@ public class XmlParseUtils { @SuppressWarnings("serial") public static class ParseException extends XmlPullParserException { public ParseException(String msg, XmlPullParser parser) { - super(msg + " at line " + parser.getLineNumber() - + ", column " + parser.getColumnNumber()); + super(msg + " at " + parser.getPositionDescription()); } } |