Don't distrust the cursor pos so much as to bug on IPC delay
When the cursor is moved by the user, the RichInputConnection is told about it. However, to work around a framework bug, it also looks at how many characters are in the buffer before the cursor, and if that's more than the value it's been passed, it deduces that's a framework bug and there are at least as many characters as seen before the cursor, so it puts the expected cursor position there. When you move the cursor, TextView calls onUpdateSelection, and when you move it fast, you'll get rapid-fire calls to onUpdateSelection. This is fine, the RIC is equipped to deal with that. However, these calls take some time to make it to the IME. In this instance, when the first call gets through and the IME calls TextView (synchronously) for text before the cursor, the cursor has already moved in the app, and TextView returns more characters than the cursor position was declared to be in this instance, so the RIC sets that as the expected cursor position. Sure enough, a split second later, the second call to onUpdateSelection arrives, with the new cursor position set where the RIC had found it too early. The RIC takes that as an "expected" cursor move, and the input does not get reset. Luckily, we have a way out. As far as we know, the framework bug only manifests itself upon rotation, which means we should only have to adjust for it in onStartInputView. Doing it in onUpdateSelection is too zealous (and probably too distrustful of the app to send the correct cursor positions). So we should just take care of the rotation case (by calling tryFixLyingCursorPosition in onStartInputView) and remove the compensating code in resetCachesUponCursorMoves. Bug: 12982502 Change-Id: Ic3c1408a1ec45deaea63b01d98376a79ae567d77main
parent
475f9f35b6
commit
3c84eb8822
|
@ -799,19 +799,22 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
|||
suggest = mInputLogic.mSuggest;
|
||||
}
|
||||
|
||||
// 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.
|
||||
// TODO[IL]: Can the following be moved to InputLogic#startInput?
|
||||
final boolean canReachInputConnection;
|
||||
if (!mInputLogic.mConnection.resetCachesUponCursorMoveAndReturnSuccess(
|
||||
editorInfo.initialSelStart, editorInfo.initialSelEnd,
|
||||
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.
|
||||
// We try resetting the caches up to 5 times before giving up.
|
||||
mHandler.postResetCaches(isDifferentTextField, 5 /* remainingTries */);
|
||||
// mLastSelection{Start,End} are reset later in this method, don't need to do it here
|
||||
canReachInputConnection = false;
|
||||
} else {
|
||||
// When rotating, initialSelStart and initialSelEnd sometimes are lying. Make a best
|
||||
// effort to work around this bug.
|
||||
mInputLogic.mConnection.tryFixLyingCursorPosition();
|
||||
if (isDifferentTextField) {
|
||||
mHandler.postResumeSuggestions();
|
||||
}
|
||||
|
|
|
@ -172,20 +172,6 @@ public final class RichInputConnection {
|
|||
Log.d(TAG, "Will try to retrieve text later.");
|
||||
return false;
|
||||
}
|
||||
final int lengthOfTextBeforeCursor = mCommittedTextBeforeComposingText.length();
|
||||
if (lengthOfTextBeforeCursor > newSelStart
|
||||
|| (newSelStart != lengthOfTextBeforeCursor
|
||||
&& lengthOfTextBeforeCursor < Constants.EDITOR_CONTENTS_CACHE_SIZE
|
||||
&& newSelStart < Constants.EDITOR_CONTENTS_CACHE_SIZE)) {
|
||||
// newSelStart and newSelEnd may be lying -- when rotating the device (probably a
|
||||
// framework bug). If the values don't agree and we have less chars than we asked
|
||||
// for, then we know how many chars we have. If we got more than newSelStart says, then
|
||||
// we also know it was lying. In both cases the length is more reliable. Note that we
|
||||
// only have to check newSelStart (not newSelEnd) since if newSelEnd is wrong, then
|
||||
// newSelStart will be wrong as well.
|
||||
mExpectedSelStart = lengthOfTextBeforeCursor;
|
||||
mExpectedSelEnd = lengthOfTextBeforeCursor;
|
||||
}
|
||||
if (null != mIC && shouldFinishComposition) {
|
||||
mIC.finishComposingText();
|
||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
||||
|
|
Loading…
Reference in New Issue