diff --git a/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java b/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java index c5a4a3745c29b76ec5d07e8fc37aedeed1c55bc5..d3528a9ccc79d757807ddb223b1112af4bbc68d5 100644 --- a/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java +++ b/shell/platform/android/io/flutter/plugin/editing/InputConnectionAdaptor.java @@ -4,13 +4,11 @@ package io.flutter.plugin.editing; -import android.annotation.SuppressLint; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.os.Build; import android.os.Bundle; -import android.provider.Settings; import android.text.DynamicLayout; import android.text.Editable; import android.text.InputType; @@ -25,7 +23,6 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputMethodManager; -import android.view.inputmethod.InputMethodSubtype; import io.flutter.Log; import io.flutter.embedding.android.KeyboardManager; import io.flutter.embedding.engine.FlutterJNI; @@ -48,6 +45,7 @@ class InputConnectionAdaptor extends BaseInputConnection private final Layout mLayout; private FlutterTextUtils flutterTextUtils; private final KeyboardManager keyboardManager; + private int batchEditNestDepth = 0; @SuppressWarnings("deprecation") public InputConnectionAdaptor( @@ -135,12 +133,14 @@ class InputConnectionAdaptor extends BaseInputConnection @Override public boolean beginBatchEdit() { mEditable.beginBatchEdit(); + batchEditNestDepth += 1; return super.beginBatchEdit(); } @Override public boolean endBatchEdit() { boolean result = super.endBatchEdit(); + batchEditNestDepth -= 1; mEditable.endBatchEdit(); return result; } @@ -238,27 +238,9 @@ class InputConnectionAdaptor extends BaseInputConnection public void closeConnection() { super.closeConnection(); mEditable.removeEditingStateListener(this); - } - - // Detect if the keyboard is a Samsung keyboard, where we apply Samsung-specific hacks to - // fix critical bugs that make the keyboard otherwise unusable. See finishComposingText() for - // more details. - @SuppressLint("NewApi") // New API guard is inline, the linter can't see it. - @SuppressWarnings("deprecation") - private boolean isSamsung() { - InputMethodSubtype subtype = mImm.getCurrentInputMethodSubtype(); - // Impacted devices all shipped with Android Lollipop or newer. - if (subtype == null - || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP - || !Build.MANUFACTURER.equals("samsung")) { - return false; + for (; batchEditNestDepth > 0; batchEditNestDepth--) { + endBatchEdit(); } - String keyboardName = - Settings.Secure.getString( - mFlutterView.getContext().getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD); - // The Samsung keyboard is called "com.sec.android.inputmethod/.SamsungKeypad" but look - // for "Samsung" just in case Samsung changes the name of the keyboard. - return keyboardName.contains("Samsung"); } @Override diff --git a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java index f6fc6354152e8ae29f66e19b3445de181e7f2c7e..06951a8d64f33c744753176cc542cd4008e5a1a7 100644 --- a/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java +++ b/shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java @@ -433,9 +433,7 @@ public class TextInputPlugin implements ListenableEditingState.EditingStateWatch // to reset their internal states. mRestartInputPending = composingChanged(mLastKnownFrameworkTextEditingState, state); if (mRestartInputPending) { - Log.w( - TAG, - "Changing the content within the the composing region may cause the input method to behave strangely, and is therefore discouraged. See https://github.com/flutter/flutter/issues/78827 for more details"); + Log.i(TAG, "Composing region changed by the framework. Restarting the input method."); } } diff --git a/shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java b/shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java index 25c7106fbba72a44dd3faeeecb573b97bf09def3..04a19986750bde9ce317d455c8361c9c55058c5d 100644 --- a/shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java +++ b/shell/platform/android/test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java @@ -1163,6 +1163,19 @@ public class InputConnectionAdaptorTest { assertFalse(didConsume); } + @Test + public void testCleanUpBatchEndsOnCloseConnection() { + final ListenableEditingState editable = sampleEditable(0, 0); + InputConnectionAdaptor adaptor = spy(sampleInputConnectionAdaptor(editable)); + for (int i = 0; i < 5; i++) { + adaptor.beginBatchEdit(); + } + adaptor.endBatchEdit(); + verify(adaptor, times(1)).endBatchEdit(); + adaptor.closeConnection(); + verify(adaptor, times(4)).endBatchEdit(); + } + private static final String SAMPLE_TEXT = "Lorem ipsum dolor sit amet," + "\nconsectetur adipiscing elit.";