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

Commit d96371e

Browse files
Add autofill save for iOS and Android (#18643)
1 parent db8c40b commit d96371e

File tree

5 files changed

+718
-144
lines changed

5 files changed

+718
-144
lines changed

shell/platform/android/io/flutter/embedding/engine/systemchannels/TextInputChannel.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result
112112
textInputMethodHandler.clearClient();
113113
result.success(null);
114114
break;
115+
case "TextInput.finishAutofillContext":
116+
textInputMethodHandler.finishAutofillContext((boolean) args);
117+
result.success(null);
118+
break;
115119
default:
116120
result.notImplemented();
117121
break;
@@ -284,6 +288,18 @@ public interface TextInputMethodHandler {
284288
*/
285289
void requestAutofill();
286290

291+
/**
292+
* Requests that the {@link AutofillManager} cancel or commit the current autofill context.
293+
*
294+
* <p>The method calls {@link android.view.autofill.AutofillManager#commit()} when {@code
295+
* shouldSave} is true, and calls {@link android.view.autofill.AutofillManager#cancel()}
296+
* otherwise.
297+
*
298+
* @param shouldSave whether the active autofill service should save the current user input for
299+
* future use.
300+
*/
301+
void finishAutofillContext(boolean shouldSave);
302+
287303
// TODO(mattcarroll): javadoc
288304
void setClient(int textInputClientId, @NonNull Configuration configuration);
289305

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,18 @@ public void requestAutofill() {
8282
notifyViewEntered();
8383
}
8484

85+
@Override
86+
public void finishAutofillContext(boolean shouldSave) {
87+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || afm == null) {
88+
return;
89+
}
90+
if (shouldSave) {
91+
afm.commit();
92+
} else {
93+
afm.cancel();
94+
}
95+
}
96+
8597
@Override
8698
public void setClient(
8799
int textInputClientId, TextInputChannel.Configuration configuration) {

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ private void verifyMethodCall(ByteBuffer buffer, String methodName, String[] exp
7070
}
7171
}
7272

73+
private static void sendToBinaryMessageHandler(
74+
BinaryMessenger.BinaryMessageHandler binaryMessageHandler, String method, Object args) {
75+
MethodCall methodCall = new MethodCall(method, args);
76+
ByteBuffer encodedMethodCall = JSONMethodCodec.INSTANCE.encodeMethodCall(methodCall);
77+
binaryMessageHandler.onMessage(
78+
(ByteBuffer) encodedMethodCall.flip(), mock(BinaryMessenger.BinaryReply.class));
79+
}
80+
7381
@Test
7482
public void textInputPlugin_RequestsReattachOnCreation() throws JSONException {
7583
// Initialize a general TextInputPlugin.
@@ -531,6 +539,33 @@ public void autofill_onProvideVirtualViewStructure_single() {
531539
verify(children[0]).setDimens(anyInt(), anyInt(), anyInt(), anyInt(), geq(0), geq(0));
532540
}
533541

542+
@Test
543+
public void respondsToInputChannelMessages() {
544+
ArgumentCaptor<BinaryMessenger.BinaryMessageHandler> binaryMessageHandlerCaptor =
545+
ArgumentCaptor.forClass(BinaryMessenger.BinaryMessageHandler.class);
546+
DartExecutor mockBinaryMessenger = mock(DartExecutor.class);
547+
TextInputChannel.TextInputMethodHandler mockHandler =
548+
mock(TextInputChannel.TextInputMethodHandler.class);
549+
TextInputChannel textInputChannel = new TextInputChannel(mockBinaryMessenger);
550+
551+
textInputChannel.setTextInputMethodHandler(mockHandler);
552+
553+
verify(mockBinaryMessenger, times(1))
554+
.setMessageHandler(any(String.class), binaryMessageHandlerCaptor.capture());
555+
556+
BinaryMessenger.BinaryMessageHandler binaryMessageHandler =
557+
binaryMessageHandlerCaptor.getValue();
558+
559+
sendToBinaryMessageHandler(binaryMessageHandler, "TextInput.requestAutofill", null);
560+
verify(mockHandler, times(1)).requestAutofill();
561+
562+
sendToBinaryMessageHandler(binaryMessageHandler, "TextInput.finishAutofillContext", true);
563+
verify(mockHandler, times(1)).finishAutofillContext(true);
564+
565+
sendToBinaryMessageHandler(binaryMessageHandler, "TextInput.finishAutofillContext", false);
566+
verify(mockHandler, times(1)).finishAutofillContext(false);
567+
}
568+
534569
@Implements(InputMethodManager.class)
535570
public static class TestImm extends ShadowInputMethodManager {
536571
private InputMethodSubtype currentInputMethodSubtype;

0 commit comments

Comments
 (0)