Skip to content

Commit 1687040

Browse files
[Android Text Input] Remove Samsung restart input workaround for newer Samsung keyboards (flutter#24288)
1 parent e1f03cd commit 1687040

2 files changed

Lines changed: 92 additions & 8 deletions

File tree

shell/platform/android/io/flutter/plugin/editing/TextInputPlugin.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import android.annotation.SuppressLint;
88
import android.content.Context;
9+
import android.content.pm.PackageManager;
910
import android.graphics.Rect;
1011
import android.os.Build;
1112
import android.os.Bundle;
@@ -497,7 +498,27 @@ private boolean isRestartAlwaysRequired() {
497498
mView.getContext().getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
498499
// The Samsung keyboard is called "com.sec.android.inputmethod/.SamsungKeypad" but look
499500
// for "Samsung" just in case Samsung changes the name of the keyboard.
500-
return keyboardName.contains("Samsung");
501+
if (!keyboardName.contains("Samsung")) {
502+
return false;
503+
}
504+
505+
final long versionCode;
506+
try {
507+
versionCode =
508+
mView
509+
.getContext()
510+
.getPackageManager()
511+
.getPackageInfo("com.sec.android.inputmethod", 0)
512+
.getLongVersionCode();
513+
} catch (PackageManager.NameNotFoundException e) {
514+
Log.w(TAG, "com.sec.android.inputmethod is not installed.");
515+
return false;
516+
}
517+
518+
// 3.3.23.33 is a known version that's free of the aforementioned bug.
519+
// 3.0.24.96 still has this bug.
520+
// TODO(LongCatIsLooong): Find the minimum version that has the fix.
521+
return versionCode < 332333999;
501522
}
502523

503524
@VisibleForTesting

shell/platform/android/test/io/flutter/plugin/editing/TextInputPluginTest.java

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import android.annotation.TargetApi;
2020
import android.content.Context;
21+
import android.content.pm.PackageInfo;
2122
import android.content.res.AssetManager;
2223
import android.graphics.Insets;
2324
import android.graphics.Rect;
@@ -64,13 +65,15 @@
6465
import org.mockito.Mock;
6566
import org.robolectric.RobolectricTestRunner;
6667
import org.robolectric.RuntimeEnvironment;
68+
import org.robolectric.Shadows;
6769
import org.robolectric.annotation.Config;
6870
import org.robolectric.annotation.Implementation;
6971
import org.robolectric.annotation.Implements;
7072
import org.robolectric.shadow.api.Shadow;
7173
import org.robolectric.shadows.ShadowAutofillManager;
7274
import org.robolectric.shadows.ShadowBuild;
7375
import org.robolectric.shadows.ShadowInputMethodManager;
76+
import org.robolectric.shadows.ShadowPackageManager;
7477

7578
@Config(
7679
manifest = Config.NONE,
@@ -339,14 +342,21 @@ public void setTextInputEditingState_alwaysSetEditableWhenDifferent() {
339342
assertTrue(textInputPlugin.getEditable().toString().equals("Shibuyawoo"));
340343
}
341344

342-
// See https://github.com/flutter/flutter/issues/29341 and
343-
// https://github.com/flutter/flutter/issues/31512
344-
// All modern Samsung keybords are affected including non-korean languages and thus
345-
// need the restart.
345+
// See also: https://github.com/flutter/flutter/issues/29341 and
346+
// https://github.com/flutter/flutter/issues/31512.
347+
// Some recent versions of Samsung keybords are affected including non-korean
348+
// languages and thus needed the restart.
346349
@Test
347-
public void setTextInputEditingState_alwaysRestartsOnAffectedDevices2() {
348-
// Initialize a TextInputPlugin that needs to be always restarted.
350+
public void setTextInputEditingState_alwaysRestartsOnAffectedDevices() {
351+
// Initialize a TextInputPlugin with a Samsung keypad.
349352
ShadowBuild.setManufacturer("samsung");
353+
final ShadowPackageManager packageManager =
354+
Shadows.shadowOf(
355+
RuntimeEnvironment.application.getApplicationContext().getPackageManager());
356+
final PackageInfo info = new PackageInfo();
357+
info.packageName = "com.sec.android.inputmethod";
358+
info.versionCode = 200000000;
359+
packageManager.addPackage(info);
350360
InputMethodSubtype inputMethodSubtype =
351361
new InputMethodSubtype(0, 0, /*locale=*/ "en", "", "", false, false);
352362
Settings.Secure.putString(
@@ -386,6 +396,59 @@ public void setTextInputEditingState_alwaysRestartsOnAffectedDevices2() {
386396
assertEquals(2, testImm.getRestartCount(testView));
387397
}
388398

399+
// Regression test for https://github.com/flutter/flutter/issues/73433.
400+
// The restart workaround seems to have caused #73433 and it's no longer
401+
// needed on newer versions of Samsung keyboard.
402+
@Test
403+
public void setTextInputEditingState_DontForceRestartOnNewSamsungKeyboard() {
404+
// Initialize a TextInputPlugin with a Samsung keypad.
405+
ShadowBuild.setManufacturer("samsung");
406+
final ShadowPackageManager packageManager =
407+
Shadows.shadowOf(
408+
RuntimeEnvironment.application.getApplicationContext().getPackageManager());
409+
final PackageInfo info = new PackageInfo();
410+
info.packageName = "com.sec.android.inputmethod";
411+
info.versionCode = 333183070;
412+
packageManager.addPackage(info);
413+
InputMethodSubtype inputMethodSubtype =
414+
new InputMethodSubtype(0, 0, /*locale=*/ "en", "", "", false, false);
415+
Settings.Secure.putString(
416+
RuntimeEnvironment.application.getContentResolver(),
417+
Settings.Secure.DEFAULT_INPUT_METHOD,
418+
"com.sec.android.inputmethod/.SamsungKeypad");
419+
TestImm testImm =
420+
Shadow.extract(
421+
RuntimeEnvironment.application.getSystemService(Context.INPUT_METHOD_SERVICE));
422+
testImm.setCurrentInputMethodSubtype(inputMethodSubtype);
423+
View testView = new View(RuntimeEnvironment.application);
424+
TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
425+
TextInputPlugin textInputPlugin =
426+
new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
427+
textInputPlugin.setTextInputClient(
428+
0,
429+
new TextInputChannel.Configuration(
430+
false,
431+
false,
432+
true,
433+
TextInputChannel.TextCapitalization.NONE,
434+
null,
435+
null,
436+
null,
437+
null,
438+
null));
439+
// There's a pending restart since we initialized the text input client. Flush that now.
440+
textInputPlugin.setTextInputEditingState(
441+
testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));
442+
443+
// Move the cursor.
444+
assertEquals(1, testImm.getRestartCount(testView));
445+
textInputPlugin.setTextInputEditingState(
446+
testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));
447+
448+
// Verify that we've NOT restarted the input.
449+
assertEquals(1, testImm.getRestartCount(testView));
450+
}
451+
389452
@Test
390453
public void setTextInputEditingState_doesNotRestartOnUnaffectedDevices() {
391454
// Initialize a TextInputPlugin that needs to be always restarted.
@@ -425,7 +488,7 @@ public void setTextInputEditingState_doesNotRestartOnUnaffectedDevices() {
425488
textInputPlugin.setTextInputEditingState(
426489
testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));
427490

428-
// Verify that we've restarted the input.
491+
// Verify that we've NOT restarted the input.
429492
assertEquals(1, testImm.getRestartCount(testView));
430493
}
431494

0 commit comments

Comments
 (0)