mExpectingUpdateSelection was out of sync when nothing to delete.
This bug was leading to corrupted rendering of surrogate pairs in the following scenario. 1. Type some emojis 2. Move the cursor at the beginning of the text field 3. Hit backspace even though there's nothing to delete 4. Move the cursor after some emoji 5. Hit backspace The root cause of this issue was the out-of-sync mExpectingUpdateSelection if handleBackspace() gets called when the cursor reaches at the beginning of the TextView. In such case, mExpectingUpdateSelection shouldn't be set true because there's nothing to delete, so there will be no onUpdateSelection() calls associated with it. Due to this bug, the cache in RichInputConnection could get stale at step 4 described above. Then the following handleBackspace() that should delete a surrogate pair was not working correctly because of the stale cache. bug: 11181913 Change-Id: I9c6a948331726a821bd3ccec9c1d02dec2c4703amain
parent
c8383eda8b
commit
b9ce842142
|
@ -1622,8 +1622,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
case Constants.CODE_DELETE:
|
case Constants.CODE_DELETE:
|
||||||
mSpaceState = SPACE_STATE_NONE;
|
mSpaceState = SPACE_STATE_NONE;
|
||||||
handleBackspace(spaceState);
|
handleBackspace(spaceState);
|
||||||
mDeleteCount++;
|
|
||||||
mExpectingUpdateSelection = true;
|
|
||||||
LatinImeLogger.logOnDelete(x, y);
|
LatinImeLogger.logOnDelete(x, y);
|
||||||
break;
|
break;
|
||||||
case Constants.CODE_SHIFT:
|
case Constants.CODE_SHIFT:
|
||||||
|
@ -2051,6 +2049,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleBackspace(final int spaceState) {
|
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
|
// 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
|
// we want to wait a few milliseconds before doing it to avoid the keyboard flashing
|
||||||
// during key repeat.
|
// during key repeat.
|
||||||
|
@ -2140,8 +2142,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
// This should never happen.
|
// This should never happen.
|
||||||
Log.e(TAG, "Backspace when we don't know the selection position");
|
Log.e(TAG, "Backspace when we don't know the selection position");
|
||||||
}
|
}
|
||||||
final int lengthToDelete = Character.isSupplementaryCodePoint(
|
final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor();
|
||||||
mConnection.getCodePointBeforeCursor()) ? 2 : 1;
|
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() ||
|
if (mAppWorkAroundsUtils.isBeforeJellyBean() ||
|
||||||
currentSettings.mInputAttributes.isTypeNull()) {
|
currentSettings.mInputAttributes.isTypeNull()) {
|
||||||
// There are two possible reasons to send a key event: either the field has
|
// There are two possible reasons to send a key event: either the field has
|
||||||
|
@ -2160,8 +2170,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
true /* shouldUncommitLogUnit */);
|
true /* shouldUncommitLogUnit */);
|
||||||
}
|
}
|
||||||
if (mDeleteCount > DELETE_ACCELERATE_AT) {
|
if (mDeleteCount > DELETE_ACCELERATE_AT) {
|
||||||
|
final int codePointBeforeCursorToDeleteAgain =
|
||||||
|
mConnection.getCodePointBeforeCursor();
|
||||||
|
if (codePointBeforeCursorToDeleteAgain != Constants.NOT_A_CODE) {
|
||||||
final int lengthToDeleteAgain = Character.isSupplementaryCodePoint(
|
final int lengthToDeleteAgain = Character.isSupplementaryCodePoint(
|
||||||
mConnection.getCodePointBeforeCursor()) ? 2 : 1;
|
codePointBeforeCursorToDeleteAgain) ? 2 : 1;
|
||||||
mConnection.deleteSurroundingText(lengthToDeleteAgain, 0);
|
mConnection.deleteSurroundingText(lengthToDeleteAgain, 0);
|
||||||
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
|
||||||
ResearchLogger.latinIME_handleBackspace(lengthToDeleteAgain,
|
ResearchLogger.latinIME_handleBackspace(lengthToDeleteAgain,
|
||||||
|
@ -2169,6 +2182,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (currentSettings.isSuggestionsRequested(mDisplayOrientation)
|
if (currentSettings.isSuggestionsRequested(mDisplayOrientation)
|
||||||
&& currentSettings.mCurrentLanguageHasSpaces) {
|
&& currentSettings.mCurrentLanguageHasSpaces) {
|
||||||
restartSuggestionsOnWordBeforeCursorIfAtEndOfWord();
|
restartSuggestionsOnWordBeforeCursorIfAtEndOfWord();
|
||||||
|
|
Loading…
Reference in New Issue