Commit 9e742fee authored by Ioana Pandele's avatar Ioana Pandele Committed by Commit Bot

[Android] Hide the KA when tapping outside of page

The KA relies on the FocusedNodeChanged event that it receives as a
RenderFrameObserver. This event however is not triggered when the focus
moves outside the frame (e.g. on the omnibox). In order to detect such
a focus change we use DidEndTextFieldEditing to hide the KA, same as
for the autofill popup.
When the user taps back onto the field DidCompleteFocusChangeInFrame is
called, which leads to the accessory being shown again.

TBR for 1 line in components/autofill/content/renderer/autofill_agent.cc
TBR=dvadym@chromium.org

Bug: 893695
Change-Id: I76a66ce43fad0a74c0abbc10c42d8916fd7e891a
Reviewed-on: https://chromium-review.googlesource.com/c/1268246Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Commit-Queue: Ioana Pandele <ioanap@chromium.org>
Cr-Commit-Position: refs/heads/master@{#598878}
parent 1cbd4653
......@@ -374,6 +374,13 @@ class PasswordAutofillAgentTest : public ChromeRenderViewTest {
base::Unretained(this)));
}
void FocusElement(std::string element_id) {
std::string script =
"document.getElementById('" + element_id + "').focus()";
ExecuteJavaScriptForTests(script.c_str());
GetMainFrame()->AutofillClient()->DidCompleteFocusChangeInFrame();
}
void SetFillOnAccountSelect() {
scoped_feature_list_.InitAndEnableFeature(
password_manager::features::kFillOnAccountSelect);
......@@ -1680,13 +1687,19 @@ TEST_F(PasswordAutofillAgentTest, FillIntoFocusedReadonlyTextField) {
}
// Tests that |FillIntoFocusedField| properly fills user-provided credentials.
TEST_F(PasswordAutofillAgentTest, FillIntoFocusedWritableTextField) {
// Leaks under ASan. Disabled due to https://crbug.com/855383.
#if defined(ADDRESS_SANITIZER)
#define MAYBE_FillIntoFocusedWritableTextField \
DISABLED_FillIntoFocusedWritableTextField
#else
#define MAYBE_FillIntoFocusedWritableTextField FillIntoFocusedWritableTextField
#endif
TEST_F(PasswordAutofillAgentTest, MAYBE_FillIntoFocusedWritableTextField) {
// Neither field should be autocompleted.
CheckTextFieldsDOMState(std::string(), false, std::string(), false);
// The same field should be filled if it is writable.
SetFocused(username_element_);
FocusElement(kUsernameName);
SetElementReadOnly(username_element_, false);
base::MockCallback<base::OnceCallback<void(FillingStatus)>> mock_callback;
......@@ -1727,7 +1740,7 @@ TEST_F(PasswordAutofillAgentTest, FillIntoFocusedFieldForNonClickFocus) {
// Click the username but shift the focus without click to the password.
SimulateElementClick(kUsernameName);
SetFocused(password_element_);
FocusElement(kPasswordName);
// The completion should now affect ONLY the password field. Don't fill a
// password so the error on failure shows where the filling happened.
// (see FillIntoFocusedFieldOnlyIntoPasswordFields).
......@@ -2906,7 +2919,7 @@ TEST_F(PasswordAutofillAgentTest, DriverIsInformedAboutUnfillableField) {
EXPECT_TRUE(fake_driver_.last_focused_element_was_fillable());
SetElementReadOnly(username_element_, true);
SetFocused(username_element_);
FocusElement(kUsernameName);
fake_driver_.Flush();
EXPECT_FALSE(fake_driver_.last_focused_element_was_fillable());
}
......
......@@ -312,6 +312,7 @@ void AutofillAgent::Shutdown() {
void AutofillAgent::TextFieldDidEndEditing(const WebInputElement& element) {
GetAutofillDriver()->DidEndTextFieldEditing();
password_autofill_agent_->DidEndTextFieldEditing();
}
void AutofillAgent::SetUserGestureRequired(bool required) {
......
......@@ -748,6 +748,10 @@ bool PasswordAutofillAgent::TextDidChangeInTextField(
return ShowSuggestions(element, false, false);
}
void PasswordAutofillAgent::DidEndTextFieldEditing() {
focus_state_notifier_.FocusedInputChanged(false, false);
}
void PasswordAutofillAgent::UpdateStateForTextChange(
const WebInputElement& element) {
// TODO(vabr): Get a mutable argument instead. http://crbug.com/397083
......@@ -1341,32 +1345,6 @@ void PasswordAutofillAgent::OnWillSubmitForm(const WebFormElement& form) {
}
}
void PasswordAutofillAgent::FocusedNodeChanged(const blink::WebNode& node) {
focused_input_element_.Reset();
if (node.IsNull() || // |node| is null <==> focus outside of frame.
!node.IsElementNode()) { // Not a valid WebElement.
focus_state_notifier_.FocusedInputChanged(
/*is_fillable=*/false, /*is_password_field=*/false);
return;
}
WebElement web_element = node.ToConst<WebElement>();
const WebInputElement* input = ToWebInputElement(&web_element);
if (!input) {
focus_state_notifier_.FocusedInputChanged(
/*is_fillable=*/false, /*is_password_field=*/false);
return; // If the node isn't an element, don't even try to convert.
}
bool is_password = false;
bool is_fillable = input->IsTextField() && IsElementEditable(*input);
if (is_fillable) {
focused_input_element_ = *input;
is_password = focused_input_element_.IsPasswordFieldForAutofill();
}
focus_state_notifier_.FocusedInputChanged(is_fillable, is_password);
}
void PasswordAutofillAgent::OnDestruct() {
binding_.Close();
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
......@@ -1551,9 +1529,28 @@ void PasswordAutofillAgent::GetFillableElementFromFormData(
}
void PasswordAutofillAgent::FocusedNodeHasChanged(const blink::WebNode& node) {
if (node.IsNull() || !node.IsElementNode())
focused_input_element_.Reset();
if (node.IsNull() || !node.IsElementNode()) { // Not a valid WebElement.
focus_state_notifier_.FocusedInputChanged(
/*is_fillable=*/false, /*is_password_field=*/false);
return;
const WebElement web_element = node.ToConst<WebElement>();
}
WebElement web_element = node.ToConst<WebElement>();
const WebInputElement* input = ToWebInputElement(&web_element);
if (!input) {
focus_state_notifier_.FocusedInputChanged(
/*is_fillable=*/false, /*is_password_field=*/false);
return; // If the node isn't an element, don't even try to convert.
}
bool is_password = false;
bool is_fillable = input->IsTextField() && IsElementEditable(*input);
if (is_fillable) {
focused_input_element_ = *input;
is_password = focused_input_element_.IsPasswordFieldForAutofill();
}
focus_state_notifier_.FocusedInputChanged(is_fillable, is_password);
if (!web_element.IsFormControlElement())
return;
const WebFormControlElement control_element =
......
......@@ -107,6 +107,11 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
// be used for any other autofill activity.
bool TextDidChangeInTextField(const blink::WebInputElement& element);
// Event forwarded by AutofillAgent from WebAutofillClient, informing that
// the text field editing has ended, which means that the field is not
// focused anymore.
void DidEndTextFieldEditing();
// Function that should be called whenever the value of |element| changes due
// to user input. This is separate from TextDidChangeInTextField() as that
// function may trigger UI and should only be called when other UI won't be
......@@ -167,7 +172,8 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
RendererSavePasswordProgressLogger* logger,
std::vector<blink::WebInputElement>* elements);
// Called when the focused node has changed.
// Called when the focused node has changed. This is not called if the focus
// moves outside the frame.
void FocusedNodeHasChanged(const blink::WebNode& node);
// Creates a |PasswordForm| from |web_form|.
......@@ -261,7 +267,6 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
void WillCommitProvisionalLoad() override;
void DidCommitProvisionalLoad(bool is_same_document_navigation,
ui::PageTransition transition) override;
void FocusedNodeChanged(const blink::WebNode& node) override;
void OnDestruct() override;
// Scans the given frame for password forms and sends them up to the browser.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment