Loading java/src/com/android/inputmethod/latin/Constants.java +3 −0 Original line number Diff line number Diff line Loading @@ -138,6 +138,9 @@ public final class Constants { public static final int SPELL_CHECKER_COORDINATE = -3; public static final int EXTERNAL_KEYBOARD_COORDINATE = -4; // A hint on how many characters to cache from the TextView. A good value of this is given by // how many characters we need to be able to almost always find the caps mode. public static final int EDITOR_CONTENTS_CACHE_SIZE = 1024; // Must be equal to MAX_WORD_LENGTH in native/jni/src/defines.h public static final int DICTIONARY_MAX_WORD_LENGTH = 48; Loading java/src/com/android/inputmethod/latin/LatinIME.java +77 −5 Original line number Diff line number Diff line Loading @@ -233,6 +233,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private static final int MSG_RESUME_SUGGESTIONS = 4; private static final int MSG_REOPEN_DICTIONARIES = 5; private static final int MSG_ON_END_BATCH_INPUT = 6; private static final int MSG_RESET_CACHES = 7; private static final int ARG1_NOT_GESTURE_INPUT = 0; private static final int ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1; Loading Loading @@ -297,6 +298,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen case MSG_ON_END_BATCH_INPUT: latinIme.onEndBatchInputAsyncInternal((SuggestedWords) msg.obj); break; case MSG_RESET_CACHES: latinIme.retryResetCaches(msg.arg1 == 1 /* tryResumeSuggestions */, msg.arg2 /* remainingTries */); break; } } Loading @@ -313,6 +318,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen sendMessageDelayed(obtainMessage(MSG_RESUME_SUGGESTIONS), mDelayUpdateSuggestions); } public void postResetCaches(final boolean tryResumeSuggestions, final int remainingTries) { removeMessages(MSG_RESET_CACHES); sendMessage(obtainMessage(MSG_RESET_CACHES, tryResumeSuggestions ? 1 : 0, remainingTries, null)); } public void cancelUpdateSuggestionStrip() { removeMessages(MSG_UPDATE_SUGGESTION_STRIP); } Loading Loading @@ -852,7 +863,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // span, so we should reset our state unconditionally, even if restarting is true. mEnteredText = null; resetComposingState(true /* alsoResetLastComposedWord */); if (isDifferentTextField) mHandler.postResumeSuggestions(); mDeleteCount = 0; mSpaceState = SPACE_STATE_NONE; mRecapitalizeStatus.deactivate(); Loading @@ -871,8 +881,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } mSuggestedWords = SuggestedWords.EMPTY; mConnection.resetCachesUponCursorMove(editorInfo.initialSelStart, false /* shouldFinishComposition */); // Sometimes, while rotating, for some reason the framework tells the app we are not // connected to it and that means we can't refresh the cache. In this case, schedule a // refresh later. if (!mConnection.resetCachesUponCursorMoveAndReturnSuccess(editorInfo.initialSelStart, false /* shouldFinishComposition */)) { // We try resetting the caches up to 5 times before giving up. mHandler.postResetCaches(isDifferentTextField, 5 /* remainingTries */); } else { if (isDifferentTextField) mHandler.postResumeSuggestions(); } if (isDifferentTextField) { mainKeyboardView.closing(); Loading @@ -899,6 +917,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mLastSelectionStart = editorInfo.initialSelStart; mLastSelectionEnd = editorInfo.initialSelEnd; // In some cases (namely, after rotation of the device) editorInfo.initialSelStart is lying // so we try using some heuristics to find out about these and fix them. tryFixLyingCursorPosition(); mHandler.cancelUpdateSuggestionStrip(); mHandler.cancelDoubleSpacePeriodTimer(); Loading @@ -918,6 +939,35 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); } /** * Try to get the text from the editor to expose lies the framework may have been * telling us. Concretely, when the device rotates, the frameworks tells us about where the * cursor used to be initially in the editor at the time it first received the focus; this * may be completely different from the place it is upon rotation. Since we don't have any * means to get the real value, try at least to ask the text view for some characters and * detect the most damaging cases: when the cursor position is declared to be much smaller * than it really is. */ private void tryFixLyingCursorPosition() { final CharSequence textBeforeCursor = mConnection.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0); if (null == textBeforeCursor) { mLastSelectionStart = mLastSelectionEnd = NOT_A_CURSOR_POSITION; } else { final int textLength = textBeforeCursor.length(); if (textLength > mLastSelectionStart || (textLength < Constants.EDITOR_CONTENTS_CACHE_SIZE && mLastSelectionStart < Constants.EDITOR_CONTENTS_CACHE_SIZE)) { mLastSelectionStart = textLength; // We can't figure out the value of mLastSelectionEnd :( // But at least if it's smaller than mLastSelectionStart something is wrong if (mLastSelectionStart > mLastSelectionEnd) { mLastSelectionEnd = mLastSelectionStart; } } } } // Initialization of personalization debug settings. This must be called inside // onStartInputView. private void initPersonalizationDebugSettings(SettingsValues currentSettingsValues) { Loading Loading @@ -1072,7 +1122,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // argument as true. But in all cases where we don't reset the entire input state, // we still want to tell the rich input connection about the new cursor position so // that it can update its caches. mConnection.resetCachesUponCursorMove(newSelStart, mConnection.resetCachesUponCursorMoveAndReturnSuccess(newSelStart, false /* shouldFinishComposition */); } Loading Loading @@ -1308,7 +1358,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } else { setSuggestedWords(settingsValues.mSuggestPuncList, false); } mConnection.resetCachesUponCursorMove(newCursorPosition, shouldFinishComposition); mConnection.resetCachesUponCursorMoveAndReturnSuccess(newCursorPosition, shouldFinishComposition); } private void resetComposingState(final boolean alsoResetLastComposedWord) { Loading Loading @@ -2853,6 +2904,27 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mHandler.postUpdateSuggestionStrip(); } /** * Retry resetting caches in the rich input connection. * * When the editor can't be accessed we can't reset the caches, so we schedule a retry. * This method handles the retry, and re-schedules a new retry if we still can't access. * We only retry up to 5 times before giving up. * * @param tryResumeSuggestions Whether we should resume suggestions or not. * @param remainingTries How many times we may try again before giving up. */ private void retryResetCaches(final boolean tryResumeSuggestions, final int remainingTries) { if (!mConnection.resetCachesUponCursorMoveAndReturnSuccess(mLastSelectionStart, false)) { if (0 < remainingTries) { mHandler.postResetCaches(tryResumeSuggestions, remainingTries - 1); } return; } tryFixLyingCursorPosition(); if (tryResumeSuggestions) mHandler.postResumeSuggestions(); } private void revertCommit() { final String previousWord = mLastComposedWord.mPrevWord; final String originallyTypedWord = mLastComposedWord.mTypedWord; Loading java/src/com/android/inputmethod/latin/RichInputConnection.java +49 −12 Original line number Diff line number Diff line Loading @@ -73,9 +73,6 @@ public final class RichInputConnection { * This contains the currently composing text, as LatinIME thinks the TextView is seeing it. */ private final StringBuilder mComposingText = new StringBuilder(); // A hint on how many characters to cache from the TextView. A good value of this is given by // how many characters we need to be able to almost always find the caps mode. private static final int DEFAULT_TEXT_CACHE_SIZE = 100; private final InputMethodService mParent; InputConnection mIC; Loading @@ -93,7 +90,8 @@ public final class RichInputConnection { r.token = 1; r.flags = 0; final ExtractedText et = mIC.getExtractedText(r, 0); final CharSequence beforeCursor = getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE, 0); final CharSequence beforeCursor = getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0); final StringBuilder internal = new StringBuilder().append(mCommittedTextBeforeComposingText) .append(mComposingText); if (null == et || null == beforeCursor) return; Loading Loading @@ -142,19 +140,56 @@ public final class RichInputConnection { if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); } public void resetCachesUponCursorMove(final int newCursorPosition, /** * Reset the cached text and retrieve it again from the editor. * * This should be called when the cursor moved. It's possible that we can't connect to * the application when doing this; notably, this happens sometimes during rotation, probably * because of a race condition in the framework. In this case, we just can't retrieve the * data, so we empty the cache and note that we don't know the new cursor position, and we * return false so that the caller knows about this and can retry later. * * @param newCursorPosition The new position of the cursor, as received from the system. * @param shouldFinishComposition Whether we should finish the composition in progress. * @return true if we were able to connect to the editor successfully, false otherwise. When * this method returns false, the caches could not be correctly refreshed so they were only * reset: the caller should try again later to return to normal operation. */ public boolean resetCachesUponCursorMoveAndReturnSuccess(final int newCursorPosition, final boolean shouldFinishComposition) { mExpectedCursorPosition = newCursorPosition; mComposingText.setLength(0); mCommittedTextBeforeComposingText.setLength(0); final CharSequence textBeforeCursor = getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE, 0); if (null != textBeforeCursor) mCommittedTextBeforeComposingText.append(textBeforeCursor); mIC = mParent.getCurrentInputConnection(); // Call upon the inputconnection directly since our own method is using the cache, and // we want to refresh it. final CharSequence textBeforeCursor = null == mIC ? null : mIC.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0); if (null == textBeforeCursor) { // For some reason the app thinks we are not connected to it. This looks like a // framework bug... Fall back to ground state and return false. mExpectedCursorPosition = INVALID_CURSOR_POSITION; Log.e(TAG, "Unable to connect to the editor to retrieve text... will retry later"); return false; } mCommittedTextBeforeComposingText.append(textBeforeCursor); final int lengthOfTextBeforeCursor = textBeforeCursor.length(); if (lengthOfTextBeforeCursor > newCursorPosition || (lengthOfTextBeforeCursor < Constants.EDITOR_CONTENTS_CACHE_SIZE && newCursorPosition < Constants.EDITOR_CONTENTS_CACHE_SIZE)) { // newCursorPosition may be lying -- when rotating the device (probably a framework // bug). If we have less chars than we asked for, then we know how many chars we have, // and if we got more than newCursorPosition says, then we know it was lying. In both // cases the length is more reliable mExpectedCursorPosition = lengthOfTextBeforeCursor; } if (null != mIC && shouldFinishComposition) { mIC.finishComposingText(); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.richInputConnection_finishComposingText(); } } return true; } private void checkBatchEdit() { Loading Loading @@ -233,7 +268,8 @@ public final class RichInputConnection { // getCapsMode should be updated to be able to return a "not enough info" result so that // we can get more context only when needed. if (TextUtils.isEmpty(mCommittedTextBeforeComposingText) && 0 != mExpectedCursorPosition) { final CharSequence textBeforeCursor = getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE, 0); final CharSequence textBeforeCursor = getTextBeforeCursor( Constants.EDITOR_CONTENTS_CACHE_SIZE, 0); if (!TextUtils.isEmpty(textBeforeCursor)) { mCommittedTextBeforeComposingText.append(textBeforeCursor); } Loading Loading @@ -364,7 +400,7 @@ public final class RichInputConnection { if (DEBUG_BATCH_NESTING) checkBatchEdit(); if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); final CharSequence textBeforeCursor = getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE + (end - start), 0); getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE + (end - start), 0); mCommittedTextBeforeComposingText.setLength(0); if (!TextUtils.isEmpty(textBeforeCursor)) { final int indexOfStartOfComposingText = Loading Loading @@ -406,7 +442,8 @@ public final class RichInputConnection { } mExpectedCursorPosition = start; mCommittedTextBeforeComposingText.setLength(0); mCommittedTextBeforeComposingText.append(getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE, 0)); mCommittedTextBeforeComposingText.append( getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0)); } public void commitCorrection(final CorrectionInfo correctionInfo) { Loading Loading @@ -525,9 +562,9 @@ public final class RichInputConnection { if (mIC == null || sep == null) { return null; } final CharSequence before = mIC.getTextBeforeCursor(1000, final CharSequence before = mIC.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, InputConnection.GET_TEXT_WITH_STYLES); final CharSequence after = mIC.getTextAfterCursor(1000, final CharSequence after = mIC.getTextAfterCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, InputConnection.GET_TEXT_WITH_STYLES); if (before == null || after == null) { return null; Loading Loading
java/src/com/android/inputmethod/latin/Constants.java +3 −0 Original line number Diff line number Diff line Loading @@ -138,6 +138,9 @@ public final class Constants { public static final int SPELL_CHECKER_COORDINATE = -3; public static final int EXTERNAL_KEYBOARD_COORDINATE = -4; // A hint on how many characters to cache from the TextView. A good value of this is given by // how many characters we need to be able to almost always find the caps mode. public static final int EDITOR_CONTENTS_CACHE_SIZE = 1024; // Must be equal to MAX_WORD_LENGTH in native/jni/src/defines.h public static final int DICTIONARY_MAX_WORD_LENGTH = 48; Loading
java/src/com/android/inputmethod/latin/LatinIME.java +77 −5 Original line number Diff line number Diff line Loading @@ -233,6 +233,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private static final int MSG_RESUME_SUGGESTIONS = 4; private static final int MSG_REOPEN_DICTIONARIES = 5; private static final int MSG_ON_END_BATCH_INPUT = 6; private static final int MSG_RESET_CACHES = 7; private static final int ARG1_NOT_GESTURE_INPUT = 0; private static final int ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1; Loading Loading @@ -297,6 +298,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen case MSG_ON_END_BATCH_INPUT: latinIme.onEndBatchInputAsyncInternal((SuggestedWords) msg.obj); break; case MSG_RESET_CACHES: latinIme.retryResetCaches(msg.arg1 == 1 /* tryResumeSuggestions */, msg.arg2 /* remainingTries */); break; } } Loading @@ -313,6 +318,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen sendMessageDelayed(obtainMessage(MSG_RESUME_SUGGESTIONS), mDelayUpdateSuggestions); } public void postResetCaches(final boolean tryResumeSuggestions, final int remainingTries) { removeMessages(MSG_RESET_CACHES); sendMessage(obtainMessage(MSG_RESET_CACHES, tryResumeSuggestions ? 1 : 0, remainingTries, null)); } public void cancelUpdateSuggestionStrip() { removeMessages(MSG_UPDATE_SUGGESTION_STRIP); } Loading Loading @@ -852,7 +863,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // span, so we should reset our state unconditionally, even if restarting is true. mEnteredText = null; resetComposingState(true /* alsoResetLastComposedWord */); if (isDifferentTextField) mHandler.postResumeSuggestions(); mDeleteCount = 0; mSpaceState = SPACE_STATE_NONE; mRecapitalizeStatus.deactivate(); Loading @@ -871,8 +881,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } mSuggestedWords = SuggestedWords.EMPTY; mConnection.resetCachesUponCursorMove(editorInfo.initialSelStart, false /* shouldFinishComposition */); // Sometimes, while rotating, for some reason the framework tells the app we are not // connected to it and that means we can't refresh the cache. In this case, schedule a // refresh later. if (!mConnection.resetCachesUponCursorMoveAndReturnSuccess(editorInfo.initialSelStart, false /* shouldFinishComposition */)) { // We try resetting the caches up to 5 times before giving up. mHandler.postResetCaches(isDifferentTextField, 5 /* remainingTries */); } else { if (isDifferentTextField) mHandler.postResumeSuggestions(); } if (isDifferentTextField) { mainKeyboardView.closing(); Loading @@ -899,6 +917,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mLastSelectionStart = editorInfo.initialSelStart; mLastSelectionEnd = editorInfo.initialSelEnd; // In some cases (namely, after rotation of the device) editorInfo.initialSelStart is lying // so we try using some heuristics to find out about these and fix them. tryFixLyingCursorPosition(); mHandler.cancelUpdateSuggestionStrip(); mHandler.cancelDoubleSpacePeriodTimer(); Loading @@ -918,6 +939,35 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); } /** * Try to get the text from the editor to expose lies the framework may have been * telling us. Concretely, when the device rotates, the frameworks tells us about where the * cursor used to be initially in the editor at the time it first received the focus; this * may be completely different from the place it is upon rotation. Since we don't have any * means to get the real value, try at least to ask the text view for some characters and * detect the most damaging cases: when the cursor position is declared to be much smaller * than it really is. */ private void tryFixLyingCursorPosition() { final CharSequence textBeforeCursor = mConnection.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0); if (null == textBeforeCursor) { mLastSelectionStart = mLastSelectionEnd = NOT_A_CURSOR_POSITION; } else { final int textLength = textBeforeCursor.length(); if (textLength > mLastSelectionStart || (textLength < Constants.EDITOR_CONTENTS_CACHE_SIZE && mLastSelectionStart < Constants.EDITOR_CONTENTS_CACHE_SIZE)) { mLastSelectionStart = textLength; // We can't figure out the value of mLastSelectionEnd :( // But at least if it's smaller than mLastSelectionStart something is wrong if (mLastSelectionStart > mLastSelectionEnd) { mLastSelectionEnd = mLastSelectionStart; } } } } // Initialization of personalization debug settings. This must be called inside // onStartInputView. private void initPersonalizationDebugSettings(SettingsValues currentSettingsValues) { Loading Loading @@ -1072,7 +1122,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // argument as true. But in all cases where we don't reset the entire input state, // we still want to tell the rich input connection about the new cursor position so // that it can update its caches. mConnection.resetCachesUponCursorMove(newSelStart, mConnection.resetCachesUponCursorMoveAndReturnSuccess(newSelStart, false /* shouldFinishComposition */); } Loading Loading @@ -1308,7 +1358,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } else { setSuggestedWords(settingsValues.mSuggestPuncList, false); } mConnection.resetCachesUponCursorMove(newCursorPosition, shouldFinishComposition); mConnection.resetCachesUponCursorMoveAndReturnSuccess(newCursorPosition, shouldFinishComposition); } private void resetComposingState(final boolean alsoResetLastComposedWord) { Loading Loading @@ -2853,6 +2904,27 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mHandler.postUpdateSuggestionStrip(); } /** * Retry resetting caches in the rich input connection. * * When the editor can't be accessed we can't reset the caches, so we schedule a retry. * This method handles the retry, and re-schedules a new retry if we still can't access. * We only retry up to 5 times before giving up. * * @param tryResumeSuggestions Whether we should resume suggestions or not. * @param remainingTries How many times we may try again before giving up. */ private void retryResetCaches(final boolean tryResumeSuggestions, final int remainingTries) { if (!mConnection.resetCachesUponCursorMoveAndReturnSuccess(mLastSelectionStart, false)) { if (0 < remainingTries) { mHandler.postResetCaches(tryResumeSuggestions, remainingTries - 1); } return; } tryFixLyingCursorPosition(); if (tryResumeSuggestions) mHandler.postResumeSuggestions(); } private void revertCommit() { final String previousWord = mLastComposedWord.mPrevWord; final String originallyTypedWord = mLastComposedWord.mTypedWord; Loading
java/src/com/android/inputmethod/latin/RichInputConnection.java +49 −12 Original line number Diff line number Diff line Loading @@ -73,9 +73,6 @@ public final class RichInputConnection { * This contains the currently composing text, as LatinIME thinks the TextView is seeing it. */ private final StringBuilder mComposingText = new StringBuilder(); // A hint on how many characters to cache from the TextView. A good value of this is given by // how many characters we need to be able to almost always find the caps mode. private static final int DEFAULT_TEXT_CACHE_SIZE = 100; private final InputMethodService mParent; InputConnection mIC; Loading @@ -93,7 +90,8 @@ public final class RichInputConnection { r.token = 1; r.flags = 0; final ExtractedText et = mIC.getExtractedText(r, 0); final CharSequence beforeCursor = getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE, 0); final CharSequence beforeCursor = getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0); final StringBuilder internal = new StringBuilder().append(mCommittedTextBeforeComposingText) .append(mComposingText); if (null == et || null == beforeCursor) return; Loading Loading @@ -142,19 +140,56 @@ public final class RichInputConnection { if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); } public void resetCachesUponCursorMove(final int newCursorPosition, /** * Reset the cached text and retrieve it again from the editor. * * This should be called when the cursor moved. It's possible that we can't connect to * the application when doing this; notably, this happens sometimes during rotation, probably * because of a race condition in the framework. In this case, we just can't retrieve the * data, so we empty the cache and note that we don't know the new cursor position, and we * return false so that the caller knows about this and can retry later. * * @param newCursorPosition The new position of the cursor, as received from the system. * @param shouldFinishComposition Whether we should finish the composition in progress. * @return true if we were able to connect to the editor successfully, false otherwise. When * this method returns false, the caches could not be correctly refreshed so they were only * reset: the caller should try again later to return to normal operation. */ public boolean resetCachesUponCursorMoveAndReturnSuccess(final int newCursorPosition, final boolean shouldFinishComposition) { mExpectedCursorPosition = newCursorPosition; mComposingText.setLength(0); mCommittedTextBeforeComposingText.setLength(0); final CharSequence textBeforeCursor = getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE, 0); if (null != textBeforeCursor) mCommittedTextBeforeComposingText.append(textBeforeCursor); mIC = mParent.getCurrentInputConnection(); // Call upon the inputconnection directly since our own method is using the cache, and // we want to refresh it. final CharSequence textBeforeCursor = null == mIC ? null : mIC.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0); if (null == textBeforeCursor) { // For some reason the app thinks we are not connected to it. This looks like a // framework bug... Fall back to ground state and return false. mExpectedCursorPosition = INVALID_CURSOR_POSITION; Log.e(TAG, "Unable to connect to the editor to retrieve text... will retry later"); return false; } mCommittedTextBeforeComposingText.append(textBeforeCursor); final int lengthOfTextBeforeCursor = textBeforeCursor.length(); if (lengthOfTextBeforeCursor > newCursorPosition || (lengthOfTextBeforeCursor < Constants.EDITOR_CONTENTS_CACHE_SIZE && newCursorPosition < Constants.EDITOR_CONTENTS_CACHE_SIZE)) { // newCursorPosition may be lying -- when rotating the device (probably a framework // bug). If we have less chars than we asked for, then we know how many chars we have, // and if we got more than newCursorPosition says, then we know it was lying. In both // cases the length is more reliable mExpectedCursorPosition = lengthOfTextBeforeCursor; } if (null != mIC && shouldFinishComposition) { mIC.finishComposingText(); if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.richInputConnection_finishComposingText(); } } return true; } private void checkBatchEdit() { Loading Loading @@ -233,7 +268,8 @@ public final class RichInputConnection { // getCapsMode should be updated to be able to return a "not enough info" result so that // we can get more context only when needed. if (TextUtils.isEmpty(mCommittedTextBeforeComposingText) && 0 != mExpectedCursorPosition) { final CharSequence textBeforeCursor = getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE, 0); final CharSequence textBeforeCursor = getTextBeforeCursor( Constants.EDITOR_CONTENTS_CACHE_SIZE, 0); if (!TextUtils.isEmpty(textBeforeCursor)) { mCommittedTextBeforeComposingText.append(textBeforeCursor); } Loading Loading @@ -364,7 +400,7 @@ public final class RichInputConnection { if (DEBUG_BATCH_NESTING) checkBatchEdit(); if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); final CharSequence textBeforeCursor = getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE + (end - start), 0); getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE + (end - start), 0); mCommittedTextBeforeComposingText.setLength(0); if (!TextUtils.isEmpty(textBeforeCursor)) { final int indexOfStartOfComposingText = Loading Loading @@ -406,7 +442,8 @@ public final class RichInputConnection { } mExpectedCursorPosition = start; mCommittedTextBeforeComposingText.setLength(0); mCommittedTextBeforeComposingText.append(getTextBeforeCursor(DEFAULT_TEXT_CACHE_SIZE, 0)); mCommittedTextBeforeComposingText.append( getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0)); } public void commitCorrection(final CorrectionInfo correctionInfo) { Loading Loading @@ -525,9 +562,9 @@ public final class RichInputConnection { if (mIC == null || sep == null) { return null; } final CharSequence before = mIC.getTextBeforeCursor(1000, final CharSequence before = mIC.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, InputConnection.GET_TEXT_WITH_STYLES); final CharSequence after = mIC.getTextAfterCursor(1000, final CharSequence after = mIC.getTextAfterCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, InputConnection.GET_TEXT_WITH_STYLES); if (before == null || after == null) { return null; Loading