-
Notifications
You must be signed in to change notification settings - Fork 6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[iOS] Fix view removal process for AutofillContextAction.cancel
#57209
Conversation
@@ -2675,8 +2675,7 @@ - (void)hideTextInput { | |||
[self removeEnableFlutterTextInputViewAccessibilityTimer]; | |||
_activeView.accessibilityEnabled = NO; | |||
[_activeView resignFirstResponder]; | |||
[_activeView removeFromSuperview]; | |||
[_inputHider removeFromSuperview]; | |||
[self cleanUpViewHierarchy:YES clearText:NO delayRemoval:NO]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the comment here my assumption is that we should be setting clearText:YES
in this case.
@LongCatIsLooong can you confirm?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's been a while since I looked at this. Is there a quick explanation of what is supposed to happen here? I think this will be called when the framework dismisses the software keyboard?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not making a lot sense to me right now that cleanUpViewHierarchy
needs to be called when the framework dismisses the keyboard. A bit explanation as to why the bug is happening (is the framework dismissing the keyboard before the autofill group cleans up the view hierarchy?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the apps I put in the description,
- push from screen1 to screen2
- focus on TextField (password)
- pop from screen2 to screen1
then MethodChannel is called as follows.
TextInput.setClient
TextInput.setEditableSizeAndTransform
TextInput.setMarkedTextRect
TextInput.setStyle
TextInput.setEditingState
TextInput.show
TextInput.requestAutofill
TextInput.setCaretRect
TextInput.clearClient
TextInput.hide
TextInput.finishAutofillContext
I noticed that in TextInput.finishAutofillContext
the auto fill process is expected to be performed, but is actually performed in TextInput.hide
. When either _activeView
or _inputHider
was removeFromSuperview
, the process would run.
removeFromSuperView
has been added at #23776, but if it is not needed I will add a commit to remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explanation!
@chunhtai do you remember why the active field is removed from the view hierarchy when the keyboard is dismissed? iOS autofill will try to save the password if the active field is a password field so we should probably keep the field in the view hierarchy if possible so iOS doesn't think it's the best time to show the "save password" prompt.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the late reply, still this fix doesn't feel right. IIRC hideTextInput
is called when a framework input field tries to dismiss the software keyboard. I don't think this should be tied to autofill at all. With the current implementation in the PR, dismissing the input field will destroy the current autofill context, so if the developer wants to show the "save password" prompt after the keyboard is dismissed, they wouldn't be able to because the autofill context is already destroyed at that point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the case @LongCatIsLooong are pointing out the behavior of this video?
request_after_hide.mp4
It works on the simulator, but it looks like even if I hide the keyboard or move to the next screen, I can still call the password manager by requesting finishAutofillContext
. Could you please let me know if I may have missed any edge cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the video, sorry i wasn't clear, by "dismissing the input field" I meant the framework sending a TextInput.hide
message to the text input plugin (users dismissing the keyboard doesn't trigger hideTextInput
). I looked into the EditableText
implementation it seems TextInput.hide
is sent to the text input plugin in EditableTextState.dispose
, and in clearConnection
(which means the field loses focus, and the new focus is not an input field).
So hypothetically, if the user enters their credentials, and moves the focus to something that is not a text field (to reproduce this you can add a button that calls FocusNode.unfocus()
on the password field's focus node), they won't be able to save passwords after that. If someone implements their own TextInputClient
, then their users won't be able to save password after the custom TextInputClient
implementation calls TextInput.hide
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated sample app and tested.
https://github.com/koji-1009/autofill_cancel_issue/blob/d0537895cea743cc7544083690e2497b8e007e3b/lib/main.dart
Movie "primaryFocus" is called primaryFocus?.unfocus()
with StatelessWidget, "focusNode" is called FocusNode.unfocus()
with StatefulWidget. Please let me know if there is a different implementation that should be tested.
primaryFocus.mp4
focusNode.mp4
In the master branch, calling primaryFocus?.unfocus()
invokes password manager. So perhaps there is a problem with the current implementation, but I believe this fix will solve the problem described in the issue.
master.mp4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created a PR on flutter/flutter. flutter/flutter#160653
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @koji-1009 thanks for your contribution. To avoid a future regression, please add a test. If you need suggestions on how to write it or where it should be wired up, please let us know and we'll be glad to point you in the right direction! Take a look at shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm for examples.
@cbracken |
The results of the test run are shown here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding the test!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh wait. Just noticed this is open against the flutter/engine repo. @koji-1009 in late December, we merged the engine repo into the flutter/flutter repo. Would you mind re-opening this patch against that repo, link to this one in the description, and I can re-approve over there. Apologies for the confusion! |
@cbracken |
Monorepo Migration Completed
The
This is a canned message |
The
removeFromSuperview
in thehideTextInput
method was triggering the save password, so I changed it tocleanUpViewHierarchy
.fix flutter/flutter#145681
sample app code
https://github.com/koji-1009/autofill_cancel_issue
before
before.mp4
after
after.mp4
Pre-launch Checklist
///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.