From 035e3885ac5db4944f3b244019ee73208a88fd39 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 19 Dec 2013 17:57:10 +0900 Subject: [PATCH] [IL8] Move handleNonSeparator to InputLogic Also move getActualCapsMode and getNthPreviousWordForSuggestion Bug: 8636060 Change-Id: I1ee9162d0b7a517070c4b7420b084c973f061533 --- .../android/inputmethod/latin/LatinIME.java | 144 +++--------------- .../latin/inputlogic/InputLogic.java | 138 ++++++++++++++++- 2 files changed, 154 insertions(+), 128 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 035cec453..2fff8d25e 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1269,6 +1269,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Called from the KeyboardSwitcher which needs to know auto caps state to display // the right layout. + // TODO[IL]: Move this to InputLogic. public int getCurrentAutoCapsState() { final SettingsValues currentSettingsValues = mSettings.getCurrent(); if (!currentSettingsValues.mAutoCap) return Constants.TextUtils.CAP_MODE_OFF; @@ -1292,20 +1293,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return mInputLogic.mRecapitalizeStatus.getCurrentMode(); } - // Factor in auto-caps and manual caps and compute the current caps mode. - private int getActualCapsMode() { - final int keyboardShiftMode = mKeyboardSwitcher.getKeyboardShiftMode(); - if (keyboardShiftMode != WordComposer.CAPS_MODE_AUTO_SHIFTED) return keyboardShiftMode; - final int auto = getCurrentAutoCapsState(); - if (0 != (auto & TextUtils.CAP_MODE_CHARACTERS)) { - return WordComposer.CAPS_MODE_AUTO_SHIFT_LOCKED; - } - if (0 != auto) { - return WordComposer.CAPS_MODE_AUTO_SHIFTED; - } - return WordComposer.CAPS_MODE_OFF; - } - // Callback for the {@link SuggestionStripView}, to call when the "add to dictionary" hint is // pressed. @Override @@ -1447,9 +1434,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } mInputLogic.mConnection.endBatchEdit(); mInputLogic.mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( - getActualCapsMode(), + mInputLogic.getActualCapsMode(mKeyboardSwitcher), // Prev word is 1st word before cursor - getNthPreviousWordForSuggestion(currentSettingsValues, 1 /* nthPreviousWord */)); + mInputLogic.getNthPreviousWordForSuggestion(currentSettingsValues, + 1 /* nthPreviousWord */)); } static final class InputUpdater implements Handler.Callback { @@ -1626,7 +1614,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mKeyboardSwitcher.updateShiftState(); mInputLogic.mWordComposer. setCapitalizedModeAndPreviousWordAtStartComposingTime( - getActualCapsMode(), commitParts[0]); + mInputLogic.getActualCapsMode(mKeyboardSwitcher), commitParts[0]); ++mAutoCommitSequenceNumber; } } @@ -1711,94 +1699,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mInputUpdater.onCancelBatchInput(); } - // TODO[IL]: Move to InputLogic and make private again. - public void handleCharacter(final int primaryCode, final int x, final int y, - final int spaceState) { - // TODO: refactor this method to stop flipping isComposingWord around all the time, and - // make it shorter (possibly cut into several pieces). Also factor handleNonSpecialCharacter - // which has the same name as other handle* methods but is not the same. - boolean isComposingWord = mInputLogic.mWordComposer.isComposingWord(); - - // TODO: remove isWordConnector() and use isUsuallyFollowedBySpace() instead. - // See onStartBatchInput() to see how to do it. - final SettingsValues currentSettings = mSettings.getCurrent(); - if (SpaceState.PHANTOM == spaceState && !currentSettings.isWordConnector(primaryCode)) { - if (isComposingWord) { - // Sanity check - throw new RuntimeException("Should not be composing here"); - } - mInputLogic.promotePhantomSpace(currentSettings); - } - - if (mInputLogic.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. - mInputLogic.resetEntireInputState(currentSettings, mInputLogic.mLastSelectionStart, - mInputLogic.mLastSelectionEnd); - isComposingWord = false; - } - // We want to find out whether to start composing a new word with this character. If so, - // we need to reset the composing state and switch isComposingWord. The order of the - // tests is important for good performance. - // We only start composing if we're not already composing. - if (!isComposingWord - // We only start composing if this is a word code point. Essentially that means it's a - // a letter or a word connector. - && currentSettings.isWordCodePoint(primaryCode) - // We never go into composing state if suggestions are not requested. - && currentSettings.isSuggestionsRequested(mDisplayOrientation) && - // In languages with spaces, we only start composing a word when we are not already - // touching a word. In languages without spaces, the above conditions are sufficient. - (!mInputLogic.mConnection.isCursorTouchingWord(currentSettings) - || !currentSettings.mCurrentLanguageHasSpaces)) { - // Reset entirely the composing state anyway, then start composing a new word unless - // the character is a single quote or a dash. The idea here is, single quote and dash - // are not separators and they should be treated as normal characters, except in the - // first position where they should not start composing a word. - isComposingWord = (Constants.CODE_SINGLE_QUOTE != primaryCode - && Constants.CODE_DASH != primaryCode); - // Here we don't need to reset the last composed word. It will be reset - // when we commit this one, if we ever do; if on the other hand we backspace - // it entirely and resume suggestions on the previous word, we'd like to still - // have touch coordinates for it. - mInputLogic.resetComposingState(false /* alsoResetLastComposedWord */); - } - if (isComposingWord) { - final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); - // TODO: We should reconsider which coordinate system should be used to represent - // keyboard event. - final int keyX = mainKeyboardView.getKeyX(x); - final int keyY = mainKeyboardView.getKeyY(y); - mInputLogic.mWordComposer.add(primaryCode, keyX, keyY); - // If it's the first letter, make note of auto-caps state - if (mInputLogic.mWordComposer.size() == 1) { - // We pass 1 to getPreviousWordForSuggestion because we were not composing a word - // yet, so the word we want is the 1st word before the cursor. - mInputLogic.mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( - getActualCapsMode(), - getNthPreviousWordForSuggestion(currentSettings, 1 /* nthPreviousWord */)); - } - mInputLogic.mConnection.setComposingText(mInputLogic.getTextWithUnderline( - mInputLogic.mWordComposer.getTypedWord()), 1); - } else { - final boolean swapWeakSpace = mInputLogic.maybeStripSpace(currentSettings, - primaryCode, spaceState, Constants.SUGGESTION_STRIP_COORDINATE == x); - - mInputLogic.sendKeyCodePoint(primaryCode); - - if (swapWeakSpace) { - mInputLogic.swapSwapperAndSpace(mKeyboardSwitcher); - mInputLogic.mSpaceState = SpaceState.WEAK; - } - // In case the "add to dictionary" hint was still displayed. - if (null != mSuggestionStripView) mSuggestionStripView.dismissAddToDictionaryHint(); - } - mHandler.postUpdateSuggestionStrip(); - if (currentSettings.mIsInternal) { - LatinImeLoggerUtils.onNonSeparator((char)primaryCode, x, y); - } - } - // TODO[IL]: Rename this to avoid using handle* private void handleClose() { // TODO: Verify that words are logged properly when IME is closed. @@ -1833,6 +1733,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return currentSettings.isSuggestionsRequested(mDisplayOrientation); } + public void dismissAddToDictionaryHint() { + if (null != mSuggestionStripView) { + mSuggestionStripView.dismissAddToDictionaryHint(); + } + } + // TODO[IL]: Define a clear interface for this public void clearSuggestionStrip() { setSuggestedWords(SuggestedWords.EMPTY, false); @@ -1900,24 +1806,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } - /** - * Get the nth previous word before the cursor as context for the suggestion process. - * @param currentSettings the current settings values. - * @param nthPreviousWord reverse index of the word to get (1-indexed) - * @return the nth previous word before the cursor. - */ - private String getNthPreviousWordForSuggestion(final SettingsValues currentSettings, - final int nthPreviousWord) { - if (currentSettings.mCurrentLanguageHasSpaces) { - // If we are typing in a language with spaces we can just look up the previous - // word from textview. - return mInputLogic.mConnection.getNthPreviousWord(currentSettings, nthPreviousWord); - } else { - return LastComposedWord.NOT_A_COMPOSED_WORD == mInputLogic.mLastComposedWord ? null - : mInputLogic.mLastComposedWord.mCommittedWord; - } - } - private void getSuggestedWords(final int sessionId, final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); @@ -1942,8 +1830,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // We're checking the previous word in the text field against the memorized previous // word. If we are composing a word we should have the second word before the cursor // memorized, otherwise we should have the first. - final String rereadPrevWord = getNthPreviousWordForSuggestion(currentSettings, - mInputLogic.mWordComposer.isComposingWord() ? 2 : 1); + final String rereadPrevWord = mInputLogic.getNthPreviousWordForSuggestion( + currentSettings, mInputLogic.mWordComposer.isComposingWord() ? 2 : 1); if (!TextUtils.equals(previousWord, rereadPrevWord)) { throw new RuntimeException("Unexpected previous word: " + previousWord + " <> " + rereadPrevWord); @@ -2308,7 +2196,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } mInputLogic.mWordComposer.setComposingWord(typedWord, - getNthPreviousWordForSuggestion(currentSettings, + mInputLogic.getNthPreviousWordForSuggestion(currentSettings, // We want the previous word for suggestion. If we have chars in the word // before the cursor, then we want the word before that, hence 2; otherwise, // we want the word immediately before the cursor, hence 1. @@ -2391,11 +2279,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } + // TODO[IL]: Move this to InputLogic private void restartSuggestionsOnWordBeforeCursor(final String word) { mInputLogic.mWordComposer.setComposingWord(word, // Previous word is the 2nd word before cursor because we are restarting on the // 1st word before cursor. - getNthPreviousWordForSuggestion(mSettings.getCurrent(), 2 /* nthPreviousWord */), + mInputLogic.getNthPreviousWordForSuggestion(mSettings.getCurrent(), + 2 /* nthPreviousWord */), mKeyboardSwitcher.getKeyboard()); final int length = word.length(); mInputLogic.mConnection.deleteSurroundingText(length, 0); diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 5fa084def..33ca25c00 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -27,6 +27,7 @@ import com.android.inputmethod.compat.SuggestionSpanUtils; import com.android.inputmethod.event.EventInterpreter; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardSwitcher; +import com.android.inputmethod.keyboard.MainKeyboardView; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.LastComposedWord; import com.android.inputmethod.latin.LatinIME; @@ -228,6 +229,7 @@ public final class InputLogic { * manage keyboard-related stuff like shift, language switch, settings, layout switch, or * any key that results in multiple code points like the ".com" key. * + * @param settingsValues The current settings values. * @param codePoint the code point associated with the key. * @param x the x-coordinate of the key press, or Contants.NOT_A_COORDINATE if not applicable. * @param y the y-coordinate of the key press, or Contants.NOT_A_COORDINATE if not applicable. @@ -270,11 +272,107 @@ public final class InputLogic { keyX = Constants.NOT_A_COORDINATE; keyY = Constants.NOT_A_COORDINATE; } - mLatinIME.handleCharacter(codePoint, keyX, keyY, spaceState); + handleNonSeparator(settingsValues, codePoint, keyX, keyY, spaceState, + keyboardSwitcher, handler); } return didAutoCorrect; } + /** + * Handle a non-separator. + * @param settingsValues The current settings values. + * @param codePoint the code point associated with the key. + * @param x the x-coordinate of the key press, or Contants.NOT_A_COORDINATE if not applicable. + * @param y the y-coordinate of the key press, or Contants.NOT_A_COORDINATE if not applicable. + * @param spaceState the space state at start of the batch input. + */ + private void handleNonSeparator(final SettingsValues settingsValues, + final int codePoint, final int x, final int y, final int spaceState, + // TODO: Remove these arguments + final KeyboardSwitcher keyboardSwitcher, final LatinIME.UIHandler handler) { + // TODO: refactor this method to stop flipping isComposingWord around all the time, and + // make it shorter (possibly cut into several pieces). Also factor handleNonSpecialCharacter + // which has the same name as other handle* methods but is not the same. + boolean isComposingWord = mWordComposer.isComposingWord(); + + // TODO: remove isWordConnector() and use isUsuallyFollowedBySpace() instead. + // See onStartBatchInput() to see how to do it. + if (SpaceState.PHANTOM == spaceState && !settingsValues.isWordConnector(codePoint)) { + if (isComposingWord) { + // Sanity check + throw new RuntimeException("Should not be composing here"); + } + promotePhantomSpace(settingsValues); + } + + 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(settingsValues, mLastSelectionStart, mLastSelectionEnd); + isComposingWord = false; + } + // We want to find out whether to start composing a new word with this character. If so, + // we need to reset the composing state and switch isComposingWord. The order of the + // tests is important for good performance. + // We only start composing if we're not already composing. + if (!isComposingWord + // We only start composing if this is a word code point. Essentially that means it's a + // a letter or a word connector. + && settingsValues.isWordCodePoint(codePoint) + // We never go into composing state if suggestions are not requested. + && settingsValues.isSuggestionsRequested(mLatinIME.mDisplayOrientation) && + // In languages with spaces, we only start composing a word when we are not already + // touching a word. In languages without spaces, the above conditions are sufficient. + (!mConnection.isCursorTouchingWord(settingsValues) + || !settingsValues.mCurrentLanguageHasSpaces)) { + // Reset entirely the composing state anyway, then start composing a new word unless + // the character is a single quote or a dash. The idea here is, single quote and dash + // are not separators and they should be treated as normal characters, except in the + // first position where they should not start composing a word. + isComposingWord = (Constants.CODE_SINGLE_QUOTE != codePoint + && Constants.CODE_DASH != codePoint); + // Here we don't need to reset the last composed word. It will be reset + // when we commit this one, if we ever do; if on the other hand we backspace + // it entirely and resume suggestions on the previous word, we'd like to still + // have touch coordinates for it. + resetComposingState(false /* alsoResetLastComposedWord */); + } + if (isComposingWord) { + final MainKeyboardView mainKeyboardView = keyboardSwitcher.getMainKeyboardView(); + // TODO: We should reconsider which coordinate system should be used to represent + // keyboard event. + final int keyX = mainKeyboardView.getKeyX(x); + final int keyY = mainKeyboardView.getKeyY(y); + mWordComposer.add(codePoint, keyX, keyY); + // If it's the first letter, make note of auto-caps state + if (mWordComposer.size() == 1) { + // We pass 1 to getPreviousWordForSuggestion because we were not composing a word + // yet, so the word we want is the 1st word before the cursor. + mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( + getActualCapsMode(keyboardSwitcher), + getNthPreviousWordForSuggestion(settingsValues, 1 /* nthPreviousWord */)); + } + mConnection.setComposingText(getTextWithUnderline( + mWordComposer.getTypedWord()), 1); + } else { + final boolean swapWeakSpace = maybeStripSpace(settingsValues, + codePoint, spaceState, Constants.SUGGESTION_STRIP_COORDINATE == x); + + sendKeyCodePoint(codePoint); + + if (swapWeakSpace) { + swapSwapperAndSpace(keyboardSwitcher); + mSpaceState = SpaceState.WEAK; + } + // In case the "add to dictionary" hint was still displayed. + mLatinIME.dismissAddToDictionaryHint(); + } + handler.postUpdateSuggestionStrip(); + if (settingsValues.mIsInternal) { + LatinImeLoggerUtils.onNonSeparator((char)codePoint, x, y); + } + } + /** * Handle input of a separator code point. * @param settingsValues The current settings values. @@ -657,6 +755,25 @@ public final class InputLogic { keyboardSwitcher.updateShiftState(); } + /** + * Factor in auto-caps and manual caps and compute the current caps mode. + * @param keyboardSwitcher the keyboard switcher. Caps mode depends on its mode. + * @return the actual caps mode the keyboard is in right now. + */ + // TODO: Make this private + public int getActualCapsMode(final KeyboardSwitcher keyboardSwitcher) { + final int keyboardShiftMode = keyboardSwitcher.getKeyboardShiftMode(); + if (keyboardShiftMode != WordComposer.CAPS_MODE_AUTO_SHIFTED) return keyboardShiftMode; + final int auto = mLatinIME.getCurrentAutoCapsState(); + if (0 != (auto & TextUtils.CAP_MODE_CHARACTERS)) { + return WordComposer.CAPS_MODE_AUTO_SHIFT_LOCKED; + } + if (0 != auto) { + return WordComposer.CAPS_MODE_AUTO_SHIFTED; + } + return WordComposer.CAPS_MODE_OFF; + } + /** * @return the editor info for the current editor */ @@ -664,6 +781,25 @@ public final class InputLogic { return mLatinIME.getCurrentInputEditorInfo(); } + /** + * Get the nth previous word before the cursor as context for the suggestion process. + * @param currentSettings the current settings values. + * @param nthPreviousWord reverse index of the word to get (1-indexed) + * @return the nth previous word before the cursor. + */ + // TODO: Make this private + public String getNthPreviousWordForSuggestion(final SettingsValues currentSettings, + final int nthPreviousWord) { + if (currentSettings.mCurrentLanguageHasSpaces) { + // If we are typing in a language with spaces we can just look up the previous + // word from textview. + return mConnection.getNthPreviousWord(currentSettings, nthPreviousWord); + } else { + return LastComposedWord.NOT_A_COMPOSED_WORD == mLastComposedWord ? null + : mLastComposedWord.mCommittedWord; + } + } + /** * @param actionId the action to perform */