Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 98221a2

Browse files
Clean up text input configuration in clearTextInputClient (#34209)
1 parent 54867f3 commit 98221a2

File tree

2 files changed

+60
-13
lines changed

2 files changed

+60
-13
lines changed

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

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public class TextInputPlugin implements ListenableEditingState.EditingStateWatch
4343
@NonNull private final TextInputChannel textInputChannel;
4444
@NonNull private InputTarget inputTarget = new InputTarget(InputTarget.Type.NO_TARGET, 0);
4545
@Nullable private TextInputChannel.Configuration configuration;
46-
@Nullable private SparseArray<TextInputChannel.Configuration> mAutofillConfigurations;
46+
@Nullable private SparseArray<TextInputChannel.Configuration> autofillConfiguration;
4747
@NonNull private ListenableEditingState mEditable;
4848
private boolean mRestartInputPending;
4949
@Nullable private InputConnection lastInputConnection;
@@ -556,6 +556,7 @@ void clearTextInputClient() {
556556
}
557557
mEditable.removeEditingStateListener(this);
558558
notifyViewExited();
559+
configuration = null;
559560
updateAutofillConfigurationIfNeeded(null);
560561
inputTarget = new InputTarget(InputTarget.Type.NO_TARGET, 0);
561562
unlockPlatformViewInputConnection();
@@ -679,7 +680,7 @@ public void didChangeEditingState(
679680
// have changed. However if the value of an unfocused EditableText is changed in the framework,
680681
// such change will not be sent to the text input plugin until the next TextInput.attach call.
681682
private boolean needsAutofill() {
682-
return mAutofillConfigurations != null;
683+
return autofillConfiguration != null;
683684
}
684685

685686
private void notifyViewEntered() {
@@ -724,21 +725,20 @@ private void updateAutofillConfigurationIfNeeded(TextInputChannel.Configuration
724725

725726
if (configuration == null || configuration.autofill == null) {
726727
// Disables autofill if the configuration doesn't have an autofill field.
727-
mAutofillConfigurations = null;
728+
autofillConfiguration = null;
728729
return;
729730
}
730731

731732
final TextInputChannel.Configuration[] configurations = configuration.fields;
732-
mAutofillConfigurations = new SparseArray<>();
733+
autofillConfiguration = new SparseArray<>();
733734

734735
if (configurations == null) {
735-
mAutofillConfigurations.put(
736-
configuration.autofill.uniqueIdentifier.hashCode(), configuration);
736+
autofillConfiguration.put(configuration.autofill.uniqueIdentifier.hashCode(), configuration);
737737
} else {
738738
for (TextInputChannel.Configuration config : configurations) {
739739
TextInputChannel.Configuration.Autofill autofill = config.autofill;
740740
if (autofill != null) {
741-
mAutofillConfigurations.put(autofill.uniqueIdentifier.hashCode(), config);
741+
autofillConfiguration.put(autofill.uniqueIdentifier.hashCode(), config);
742742
afm.notifyValueChanged(
743743
mView,
744744
autofill.uniqueIdentifier.hashCode(),
@@ -755,9 +755,9 @@ public void onProvideAutofillVirtualStructure(@NonNull ViewStructure structure,
755755

756756
final String triggerIdentifier = configuration.autofill.uniqueIdentifier;
757757
final AutofillId parentId = structure.getAutofillId();
758-
for (int i = 0; i < mAutofillConfigurations.size(); i++) {
759-
final int autofillId = mAutofillConfigurations.keyAt(i);
760-
final TextInputChannel.Configuration config = mAutofillConfigurations.valueAt(i);
758+
for (int i = 0; i < autofillConfiguration.size(); i++) {
759+
final int autofillId = autofillConfiguration.keyAt(i);
760+
final TextInputChannel.Configuration config = autofillConfiguration.valueAt(i);
761761
final TextInputChannel.Configuration.Autofill autofill = config.autofill;
762762
if (autofill == null) {
763763
continue;
@@ -801,16 +801,16 @@ public void autofill(@NonNull SparseArray<AutofillValue> values) {
801801
return;
802802
}
803803

804-
final TextInputChannel.Configuration.Autofill currentAutofill = configuration.autofill;
805-
if (currentAutofill == null) {
804+
if (configuration == null || autofillConfiguration == null || configuration.autofill == null) {
806805
return;
807806
}
808807

808+
final TextInputChannel.Configuration.Autofill currentAutofill = configuration.autofill;
809809
final HashMap<String, TextInputChannel.TextEditState> editingValues = new HashMap<>();
810810
for (int i = 0; i < values.size(); i++) {
811811
int virtualId = values.keyAt(i);
812812

813-
final TextInputChannel.Configuration config = mAutofillConfigurations.get(virtualId);
813+
final TextInputChannel.Configuration config = autofillConfiguration.get(virtualId);
814814
if (config == null || config.autofill == null) {
815815
continue;
816816
}

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

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1781,6 +1781,53 @@ public void autofill_testAutofillUpdatesTheFramework() {
17811781
assertEquals(editState.text, "unfocused field");
17821782
}
17831783

1784+
@Test
1785+
public void autofill_doesNotCrashAfterClearClientCall() {
1786+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
1787+
return;
1788+
}
1789+
FlutterView testView = new FlutterView(ctx);
1790+
TextInputChannel textInputChannel = spy(new TextInputChannel(mock(DartExecutor.class)));
1791+
TextInputPlugin textInputPlugin =
1792+
new TextInputPlugin(testView, textInputChannel, mock(PlatformViewsController.class));
1793+
// Set up an autofill scenario with 2 fields.
1794+
final TextInputChannel.Configuration.Autofill autofillConfig =
1795+
new TextInputChannel.Configuration.Autofill(
1796+
"1",
1797+
new String[] {"HINT1"},
1798+
"placeholder1",
1799+
new TextInputChannel.TextEditState("", 0, 0, -1, -1));
1800+
final TextInputChannel.Configuration config =
1801+
new TextInputChannel.Configuration(
1802+
false,
1803+
false,
1804+
true,
1805+
true,
1806+
false,
1807+
TextInputChannel.TextCapitalization.NONE,
1808+
null,
1809+
null,
1810+
null,
1811+
autofillConfig,
1812+
null);
1813+
1814+
textInputPlugin.setTextInputClient(0, config);
1815+
textInputPlugin.setTextInputEditingState(
1816+
testView, new TextInputChannel.TextEditState("", 0, 0, -1, -1));
1817+
textInputPlugin.clearTextInputClient();
1818+
1819+
final SparseArray<AutofillValue> autofillValues = new SparseArray();
1820+
autofillValues.append("1".hashCode(), AutofillValue.forText("focused field"));
1821+
autofillValues.append("2".hashCode(), AutofillValue.forText("unfocused field"));
1822+
1823+
// Autofill both fields.
1824+
textInputPlugin.autofill(autofillValues);
1825+
1826+
verify(textInputChannel, never()).updateEditingStateWithTag(anyInt(), any());
1827+
verify(textInputChannel, never())
1828+
.updateEditingState(anyInt(), any(), anyInt(), anyInt(), anyInt(), anyInt());
1829+
}
1830+
17841831
@Test
17851832
public void autofill_testSetTextIpnutClientUpdatesSideFields() {
17861833
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {

0 commit comments

Comments
 (0)