Skip to content

Commit

Permalink
[Android Text Input] Remove Samsung restart input workaround for newe…
Browse files Browse the repository at this point in the history
…r Samsung keyboards (flutter#24288)
  • Loading branch information
LongCatIsLooong authored Feb 16, 2021
1 parent e1f03cd commit 1687040
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
Expand Down Expand Up @@ -497,7 +498,27 @@ private boolean isRestartAlwaysRequired() {
mView.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");
if (!keyboardName.contains("Samsung")) {
return false;
}

final long versionCode;
try {
versionCode =
mView
.getContext()
.getPackageManager()
.getPackageInfo("com.sec.android.inputmethod", 0)
.getLongVersionCode();
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "com.sec.android.inputmethod is not installed.");
return false;
}

// 3.3.23.33 is a known version that's free of the aforementioned bug.
// 3.0.24.96 still has this bug.
// TODO(LongCatIsLooong): Find the minimum version that has the fix.
return versionCode < 332333999;
}

@VisibleForTesting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.res.AssetManager;
import android.graphics.Insets;
import android.graphics.Rect;
Expand Down Expand Up @@ -64,13 +65,15 @@
import org.mockito.Mock;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowAutofillManager;
import org.robolectric.shadows.ShadowBuild;
import org.robolectric.shadows.ShadowInputMethodManager;
import org.robolectric.shadows.ShadowPackageManager;

@Config(
manifest = Config.NONE,
Expand Down Expand Up @@ -339,14 +342,21 @@ public void setTextInputEditingState_alwaysSetEditableWhenDifferent() {
assertTrue(textInputPlugin.getEditable().toString().equals("Shibuyawoo"));
}

// See https://github.com/flutter/flutter/issues/29341 and
// https://github.com/flutter/flutter/issues/31512
// All modern Samsung keybords are affected including non-korean languages and thus
// need the restart.
// See also: https://github.com/flutter/flutter/issues/29341 and
// https://github.com/flutter/flutter/issues/31512.
// Some recent versions of Samsung keybords are affected including non-korean
// languages and thus needed the restart.
@Test
public void setTextInputEditingState_alwaysRestartsOnAffectedDevices2() {
// Initialize a TextInputPlugin that needs to be always restarted.
public void setTextInputEditingState_alwaysRestartsOnAffectedDevices() {
// Initialize a TextInputPlugin with a Samsung keypad.
ShadowBuild.setManufacturer("samsung");
final ShadowPackageManager packageManager =
Shadows.shadowOf(
RuntimeEnvironment.application.getApplicationContext().getPackageManager());
final PackageInfo info = new PackageInfo();
info.packageName = "com.sec.android.inputmethod";
info.versionCode = 200000000;
packageManager.addPackage(info);
InputMethodSubtype inputMethodSubtype =
new InputMethodSubtype(0, 0, /*locale=*/ "en", "", "", false, false);
Settings.Secure.putString(
Expand Down Expand Up @@ -386,6 +396,59 @@ public void setTextInputEditingState_alwaysRestartsOnAffectedDevices2() {
assertEquals(2, testImm.getRestartCount(testView));
}

// Regression test for https://github.com/flutter/flutter/issues/73433.
// The restart workaround seems to have caused #73433 and it's no longer
// needed on newer versions of Samsung keyboard.
@Test
public void setTextInputEditingState_DontForceRestartOnNewSamsungKeyboard() {
// Initialize a TextInputPlugin with a Samsung keypad.
ShadowBuild.setManufacturer("samsung");
final ShadowPackageManager packageManager =
Shadows.shadowOf(
RuntimeEnvironment.application.getApplicationContext().getPackageManager());
final PackageInfo info = new PackageInfo();
info.packageName = "com.sec.android.inputmethod";
info.versionCode = 333183070;
packageManager.addPackage(info);
InputMethodSubtype inputMethodSubtype =
new InputMethodSubtype(0, 0, /*locale=*/ "en", "", "", false, false);
Settings.Secure.putString(
RuntimeEnvironment.application.getContentResolver(),
Settings.Secure.DEFAULT_INPUT_METHOD,
"com.sec.android.inputmethod/.SamsungKeypad");
TestImm testImm =
Shadow.extract(
RuntimeEnvironment.application.getSystemService(Context.INPUT_METHOD_SERVICE));
testImm.setCurrentInputMethodSubtype(inputMethodSubtype);
View testView = new View(RuntimeEnvironment.application);
TextInputChannel textInputChannel = new TextInputChannel(mock(DartExecutor.class));
TextInputPlugin textInputPlugin =
new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
textInputPlugin.setTextInputClient(
0,
new TextInputChannel.Configuration(
false,
false,
true,
TextInputChannel.TextCapitalization.NONE,
null,
null,
null,
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, -1, -1));

// Move the cursor.
assertEquals(1, testImm.getRestartCount(testView));
textInputPlugin.setTextInputEditingState(
testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));

// Verify that we've NOT restarted the input.
assertEquals(1, testImm.getRestartCount(testView));
}

@Test
public void setTextInputEditingState_doesNotRestartOnUnaffectedDevices() {
// Initialize a TextInputPlugin that needs to be always restarted.
Expand Down Expand Up @@ -425,7 +488,7 @@ public void setTextInputEditingState_doesNotRestartOnUnaffectedDevices() {
textInputPlugin.setTextInputEditingState(
testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));

// Verify that we've restarted the input.
// Verify that we've NOT restarted the input.
assertEquals(1, testImm.getRestartCount(testView));
}

Expand Down

0 comments on commit 1687040

Please sign in to comment.