Samsung fix duplication on punctuation: Update keyboard on finish compose. (flutter/engine#15701)

This commit is contained in:
Gary Qian 2020-01-16 18:04:58 -08:00 committed by GitHub
parent a4db366459
commit a6de6785ef
2 changed files with 58 additions and 0 deletions

View File

@ -5,6 +5,7 @@
package io.flutter.plugin.editing;
import android.content.Context;
import android.os.Build;
import android.text.DynamicLayout;
import android.text.Editable;
import android.text.Layout;
@ -14,6 +15,7 @@ import android.text.TextPaint;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CursorAnchorInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
@ -133,6 +135,24 @@ class InputConnectionAdaptor extends BaseInputConnection {
return result;
}
@Override
public boolean finishComposingText() {
boolean result = super.finishComposingText();
if (Build.VERSION.SDK_INT >= 21) {
// Update the keyboard with a reset/empty composing region. Critical on
// Samsung keyboards to prevent punctuation duplication.
CursorAnchorInfo.Builder builder = new CursorAnchorInfo.Builder();
builder.setComposingText(-1, "");
CursorAnchorInfo anchorInfo = builder.build();
mImm.updateCursorAnchorInfo(mFlutterView, anchorInfo);
}
updateEditingState();
return result;
}
@Override
public boolean setSelection(int start, int end) {
boolean result = super.setSelection(start, end);

View File

@ -2,8 +2,10 @@ package io.flutter.plugin.editing;
import android.content.Context;
import android.content.res.AssetManager;
import android.os.Build;
import android.provider.Settings;
import android.util.SparseIntArray;
import android.view.inputmethod.CursorAnchorInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
@ -219,10 +221,37 @@ public class TextInputPluginTest {
verifyMethodCall(bufferCaptor.getValue(), "TextInputClient.performAction", new String[] {"0", "TextInputAction.done"});
}
@Test
public void inputConnection_finishComposingTextUpdatesIMM() throws JSONException {
TestImm testImm = Shadow.extract(RuntimeEnvironment.application.getSystemService(Context.INPUT_METHOD_SERVICE));
FlutterJNI mockFlutterJni = mock(FlutterJNI.class);
View testView = new View(RuntimeEnvironment.application);
DartExecutor dartExecutor = spy(new DartExecutor(mockFlutterJni, mock(AssetManager.class)));
TextInputPlugin textInputPlugin = new TextInputPlugin(testView, dartExecutor, mock(PlatformViewsController.class));
textInputPlugin.setTextInputClient(
0,
new TextInputChannel.Configuration(
false, false, true, TextInputChannel.TextCapitalization.NONE,
new TextInputChannel.InputType(TextInputChannel.TextInputType.TEXT, false, false), null, null));
// There's a pending restart since we initialized the text input client. Flush that now.
textInputPlugin.setTextInputEditingState(testView, new TextInputChannel.TextEditState("", 0, 0));
InputConnection connection = textInputPlugin.createInputConnection(testView, new EditorInfo());
connection.finishComposingText();
if (Build.VERSION.SDK_INT >= 21) {
CursorAnchorInfo.Builder builder = new CursorAnchorInfo.Builder();
builder.setComposingText(-1, "");
CursorAnchorInfo anchorInfo = builder.build();
assertEquals(testImm.getLastCursorAnchorInfo(), anchorInfo);
}
}
@Implements(InputMethodManager.class)
public static class TestImm extends ShadowInputMethodManager {
private InputMethodSubtype currentInputMethodSubtype;
private SparseIntArray restartCounter = new SparseIntArray();
private CursorAnchorInfo cursorAnchorInfo;
public TestImm() {
}
@ -245,5 +274,14 @@ public class TextInputPluginTest {
public int getRestartCount(View view) {
return restartCounter.get(view.hashCode(), /*defaultValue=*/0);
}
@Implementation
public void updateCursorAnchorInfo(View view, CursorAnchorInfo cursorAnchorInfo) {
this.cursorAnchorInfo = cursorAnchorInfo;
}
public CursorAnchorInfo getLastCursorAnchorInfo() {
return cursorAnchorInfo;
}
}
}