Commit f99a48f6 authored by Jan Wilken Dörrie's avatar Jan Wilken Dörrie Committed by Commit Bot

[Passwords] Add autofill::mojom::FocusedFieldType Enum

This change introduces a new enum to autofill_types.mojom with the goal
to provide more information during FocusedNodeChanged. Eventually this
information will be used to show the TouchToFill feature for username
fields, but browser implementation will be left for a follow-up CL.

Bug: 957532
Change-Id: Iba9492a9ec2d612962898e43c02e8600925f98fc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1605901
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Reviewed-by: default avatarFriedrich [CET] <fhorschig@chromium.org>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#659428}
parent b9b69bc8
...@@ -83,8 +83,6 @@ void FakeMojoPasswordManagerDriver::HideManualFallbackForSaving() { ...@@ -83,8 +83,6 @@ void FakeMojoPasswordManagerDriver::HideManualFallbackForSaving() {
} }
void FakeMojoPasswordManagerDriver::FocusedInputChanged( void FakeMojoPasswordManagerDriver::FocusedInputChanged(
bool is_fillable, autofill::mojom::FocusedFieldType focused_field_type) {
bool is_password_field) { last_focused_field_type_ = focused_field_type;
last_focused_element_was_fillable_ = is_fillable;
last_focused_input_was_password_ = is_password_field;
} }
...@@ -127,12 +127,8 @@ class FakeMojoPasswordManagerDriver ...@@ -127,12 +127,8 @@ class FakeMojoPasswordManagerDriver
return called_show_manual_fallback_for_saving_count_; return called_show_manual_fallback_for_saving_count_;
} }
bool last_focused_input_was_password() const { autofill::mojom::FocusedFieldType last_focused_field_type() const {
return last_focused_input_was_password_; return last_focused_field_type_;
}
bool last_focused_element_was_fillable() const {
return last_focused_element_was_fillable_;
} }
private: private:
...@@ -165,7 +161,8 @@ class FakeMojoPasswordManagerDriver ...@@ -165,7 +161,8 @@ class FakeMojoPasswordManagerDriver
void ShowManualFallbackForSaving( void ShowManualFallbackForSaving(
const autofill::PasswordForm& password_form) override; const autofill::PasswordForm& password_form) override;
void HideManualFallbackForSaving() override; void HideManualFallbackForSaving() override;
void FocusedInputChanged(bool is_fillable, bool is_password_field) override; void FocusedInputChanged(
autofill::mojom::FocusedFieldType focused_field_type) override;
void LogFirstFillingResult(uint32_t form_renderer_id, void LogFirstFillingResult(uint32_t form_renderer_id,
int32_t result) override {} int32_t result) override {}
...@@ -209,13 +206,10 @@ class FakeMojoPasswordManagerDriver ...@@ -209,13 +206,10 @@ class FakeMojoPasswordManagerDriver
// If it is zero, the fallback is not available. // If it is zero, the fallback is not available.
int called_show_manual_fallback_for_saving_count_ = 0; int called_show_manual_fallback_for_saving_count_ = 0;
// Records wether a password field was the last input that InputChanged() was // Records the last focused field type that FocusedInputChanged() was called
// called for. // with.
bool last_focused_input_was_password_ = false; autofill::mojom::FocusedFieldType last_focused_field_type_ =
autofill::mojom::FocusedFieldType::kUnknown;
// Records wether the last input that InputChanged() was called for was
// fillable.
bool last_focused_element_was_fillable_ = false;
mojo::AssociatedBinding<autofill::mojom::PasswordManagerDriver> binding_; mojo::AssociatedBinding<autofill::mojom::PasswordManagerDriver> binding_;
}; };
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
using autofill::FillingStatus; using autofill::FillingStatus;
using autofill::FormTracker; using autofill::FormTracker;
using autofill::PasswordForm; using autofill::PasswordForm;
using autofill::mojom::FocusedFieldType;
using base::ASCIIToUTF16; using base::ASCIIToUTF16;
using base::UTF16ToUTF8; using base::UTF16ToUTF8;
using blink::WebAutofillState; using blink::WebAutofillState;
...@@ -3031,25 +3032,45 @@ TEST_F(PasswordAutofillAgentTest, ...@@ -3031,25 +3032,45 @@ TEST_F(PasswordAutofillAgentTest,
} }
TEST_F(PasswordAutofillAgentTest, DriverIsInformedAboutUnfillableField) { TEST_F(PasswordAutofillAgentTest, DriverIsInformedAboutUnfillableField) {
EXPECT_FALSE(fake_driver_.last_focused_element_was_fillable()); EXPECT_EQ(FocusedFieldType::kUnknown, fake_driver_.last_focused_field_type());
SimulateElementClick(kPasswordName); SimulateElementClick(kPasswordName);
fake_driver_.Flush(); fake_driver_.Flush();
EXPECT_TRUE(fake_driver_.last_focused_element_was_fillable()); EXPECT_EQ(FocusedFieldType::kFillablePasswordField,
fake_driver_.last_focused_field_type());
// Even though the focused element is a username field, it should be treated
// as unfillable, since it is read-only.
SetElementReadOnly(username_element_, true); SetElementReadOnly(username_element_, true);
FocusElement(kUsernameName); FocusElement(kUsernameName);
fake_driver_.Flush(); fake_driver_.Flush();
EXPECT_FALSE(fake_driver_.last_focused_element_was_fillable()); EXPECT_EQ(FocusedFieldType::kUnfillableElement,
fake_driver_.last_focused_field_type());
} }
TEST_F(PasswordAutofillAgentTest, DriverIsInformedAboutPasswordFields) { TEST_F(PasswordAutofillAgentTest, DriverIsInformedAboutFillableFields) {
SimulateElementClick("random_field");
fake_driver_.Flush();
EXPECT_EQ(FocusedFieldType::kFillableTextField,
fake_driver_.last_focused_field_type());
// A username field without fill data is indistinguishable from any other text
// field.
SimulateElementClick(kUsernameName); SimulateElementClick(kUsernameName);
fake_driver_.Flush(); fake_driver_.Flush();
EXPECT_FALSE(fake_driver_.last_focused_input_was_password()); EXPECT_EQ(FocusedFieldType::kFillableTextField,
fake_driver_.last_focused_field_type());
SimulateElementClick(kPasswordName); SimulateElementClick(kPasswordName);
fake_driver_.Flush(); fake_driver_.Flush();
EXPECT_TRUE(fake_driver_.last_focused_input_was_password()); EXPECT_EQ(FocusedFieldType::kFillablePasswordField,
fake_driver_.last_focused_field_type());
// A username field with fill data should be detected.
SimulateOnFillPasswordForm(fill_data_);
SimulateElementClick(kUsernameName);
fake_driver_.Flush();
EXPECT_EQ(FocusedFieldType::kFillableUsernameField,
fake_driver_.last_focused_field_type());
} }
// Tests that credential suggestions are autofilled on a password (and change // Tests that credential suggestions are autofilled on a password (and change
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "third_party/blink/public/web/web_widget.h" #include "third_party/blink/public/web/web_widget.h"
#include "ui/events/keycodes/keyboard_codes.h" #include "ui/events/keycodes/keyboard_codes.h"
using autofill::mojom::FocusedFieldType;
using base::ASCIIToUTF16; using base::ASCIIToUTF16;
using blink::WebDocument; using blink::WebDocument;
using blink::WebElement; using blink::WebElement;
...@@ -676,8 +677,8 @@ TEST_F(PasswordGenerationAgentTest, EditingEventsTest) { ...@@ -676,8 +677,8 @@ TEST_F(PasswordGenerationAgentTest, EditingEventsTest) {
SimulateUserTypingASCIICharacter(ui::VKEY_BACK, true); SimulateUserTypingASCIICharacter(ui::VKEY_BACK, true);
fake_pw_client_.Flush(); fake_pw_client_.Flush();
fake_driver_.Flush(); fake_driver_.Flush();
EXPECT_TRUE(fake_driver_.last_focused_element_was_fillable()); EXPECT_EQ(FocusedFieldType::kFillablePasswordField,
EXPECT_TRUE(fake_driver_.last_focused_input_was_password()); fake_driver_.last_focused_field_type());
testing::Mock::VerifyAndClearExpectations(&fake_pw_client_); testing::Mock::VerifyAndClearExpectations(&fake_pw_client_);
} }
...@@ -688,8 +689,8 @@ TEST_F(PasswordGenerationAgentTest, EditingEventsTest) { ...@@ -688,8 +689,8 @@ TEST_F(PasswordGenerationAgentTest, EditingEventsTest) {
fake_pw_client_.Flush(); fake_pw_client_.Flush();
// Last focused element shouldn't change while editing. // Last focused element shouldn't change while editing.
fake_driver_.Flush(); fake_driver_.Flush();
EXPECT_TRUE(fake_driver_.last_focused_element_was_fillable()); EXPECT_EQ(FocusedFieldType::kFillablePasswordField,
EXPECT_TRUE(fake_driver_.last_focused_input_was_password()); fake_driver_.last_focused_field_type());
} }
TEST_F(PasswordGenerationAgentTest, BlacklistedTest) { TEST_F(PasswordGenerationAgentTest, BlacklistedTest) {
......
...@@ -129,7 +129,7 @@ interface PasswordManagerDriver { ...@@ -129,7 +129,7 @@ interface PasswordManagerDriver {
// The focus changed to a different input in the same frame (e.g. tabbed from // The focus changed to a different input in the same frame (e.g. tabbed from
// email to password field). // email to password field).
FocusedInputChanged(bool is_fillable, bool is_password_field); FocusedInputChanged(FocusedFieldType focused_field_type);
// Sends the success state of filling credentials into a form. This happens // Sends the success state of filling credentials into a form. This happens
// only if the form being filled has a renderer_id. |result| is an // only if the form being filled has a renderer_id. |result| is an
......
...@@ -95,6 +95,14 @@ enum LabelSource { ...@@ -95,6 +95,14 @@ enum LabelSource {
VALUE, VALUE,
}; };
enum FocusedFieldType {
kUnknown,
kUnfillableElement,
kFillableTextField,
kFillableUsernameField,
kFillablePasswordField,
};
// autofill::FillingStatus // autofill::FillingStatus
enum FillingStatus { enum FillingStatus {
SUCCESS, SUCCESS,
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "components/autofill/content/common/autofill_types.mojom.h"
#include "components/autofill/content/renderer/form_autofill_util.h" #include "components/autofill/content/renderer/form_autofill_util.h"
#include "components/autofill/content/renderer/password_form_conversion_utils.h" #include "components/autofill/content/renderer/password_form_conversion_utils.h"
#include "components/autofill/content/renderer/password_generation_agent.h" #include "components/autofill/content/renderer/password_generation_agent.h"
...@@ -58,16 +59,20 @@ using blink::WebAutofillState; ...@@ -58,16 +59,20 @@ using blink::WebAutofillState;
using blink::WebDocument; using blink::WebDocument;
using blink::WebElement; using blink::WebElement;
using blink::WebElementCollection; using blink::WebElementCollection;
using blink::WebFormElement;
using blink::WebFormControlElement; using blink::WebFormControlElement;
using blink::WebFormElement;
using blink::WebFrame; using blink::WebFrame;
using blink::WebInputElement; using blink::WebInputElement;
using blink::WebLocalFrame; using blink::WebLocalFrame;
using blink::WebNode;
using blink::WebString; using blink::WebString;
using blink::WebVector; using blink::WebVector;
using blink::WebView; using blink::WebView;
namespace autofill { namespace autofill {
using mojom::FocusedFieldType;
namespace { namespace {
// The size above which we stop triggering autocomplete. // The size above which we stop triggering autocomplete.
...@@ -628,22 +633,21 @@ PasswordAutofillAgent::FormStructureInfo::operator=( ...@@ -628,22 +633,21 @@ PasswordAutofillAgent::FormStructureInfo::operator=(
PasswordAutofillAgent::FocusStateNotifier::FocusStateNotifier( PasswordAutofillAgent::FocusStateNotifier::FocusStateNotifier(
PasswordAutofillAgent* agent) PasswordAutofillAgent* agent)
: was_fillable_(false), was_password_field_(false), agent_(agent) {} : agent_(agent) {}
PasswordAutofillAgent::FocusStateNotifier::~FocusStateNotifier() = default; PasswordAutofillAgent::FocusStateNotifier::~FocusStateNotifier() = default;
void PasswordAutofillAgent::FocusStateNotifier::FocusedInputChanged( void PasswordAutofillAgent::FocusStateNotifier::FocusedInputChanged(
bool is_fillable, FocusedFieldType focused_field_type) {
bool is_password_field) { // Forward the request if the type changed or the field is fillable.
// Forward the request, if the field is valid or the request is different. if (focused_field_type != focused_field_type_ ||
if (!is_fillable && !was_fillable_ && !is_password_field && focused_field_type == FocusedFieldType::kFillableTextField ||
!was_password_field_) { focused_field_type == FocusedFieldType::kFillableUsernameField ||
return; // A previous request already reported this exact state. focused_field_type == FocusedFieldType::kFillablePasswordField) {
agent_->GetPasswordManagerDriver()->FocusedInputChanged(focused_field_type);
} }
was_fillable_ = is_fillable;
was_password_field_ = is_password_field; focused_field_type_ = focused_field_type;
agent_->GetPasswordManagerDriver()->FocusedInputChanged(is_fillable,
is_password_field);
} }
PasswordAutofillAgent::PasswordValueGatekeeper::PasswordValueGatekeeper() PasswordAutofillAgent::PasswordValueGatekeeper::PasswordValueGatekeeper()
...@@ -702,7 +706,7 @@ bool PasswordAutofillAgent::TextDidChangeInTextField( ...@@ -702,7 +706,7 @@ bool PasswordAutofillAgent::TextDidChangeInTextField(
} }
void PasswordAutofillAgent::DidEndTextFieldEditing() { void PasswordAutofillAgent::DidEndTextFieldEditing() {
focus_state_notifier_.FocusedInputChanged(false, false); focus_state_notifier_.FocusedInputChanged(FocusedFieldType::kUnknown);
} }
void PasswordAutofillAgent::UpdateStateForTextChange( void PasswordAutofillAgent::UpdateStateForTextChange(
...@@ -1531,34 +1535,36 @@ void PasswordAutofillAgent::GetFillableElementFromFormData( ...@@ -1531,34 +1535,36 @@ void PasswordAutofillAgent::GetFillableElementFromFormData(
} }
void PasswordAutofillAgent::FocusedNodeHasChanged(const blink::WebNode& node) { void PasswordAutofillAgent::FocusedNodeHasChanged(const blink::WebNode& node) {
DCHECK(!node.IsNull());
focused_input_element_.Reset(); focused_input_element_.Reset();
if (node.IsNull() || !node.IsElementNode()) { // Not a valid WebElement. if (!node.IsElementNode()) {
focus_state_notifier_.FocusedInputChanged( focus_state_notifier_.FocusedInputChanged(FocusedFieldType::kUnknown);
/*is_fillable=*/false, /*is_password_field=*/false);
return; return;
} }
WebElement web_element = node.ToConst<WebElement>(); auto element = node.ToConst<WebElement>();
const WebInputElement* input = ToWebInputElement(&web_element); auto* input_element = ToWebInputElement(&element);
if (!input) { if (!input_element) {
focus_state_notifier_.FocusedInputChanged( focus_state_notifier_.FocusedInputChanged(
/*is_fillable=*/false, /*is_password_field=*/false); FocusedFieldType::kUnfillableElement);
return; // If the node isn't an element, don't even try to convert. return;
} }
bool is_password = false;
bool is_fillable = input->IsTextField() && IsElementEditable(*input); auto focused_field_type = FocusedFieldType::kUnfillableElement;
if (is_fillable) { if (input_element->IsTextField() && IsElementEditable(*input_element)) {
focused_input_element_ = *input; focused_input_element_ = *input_element;
is_password = focused_input_element_.IsPasswordFieldForAutofill();
if (input_element->IsPasswordFieldForAutofill())
focused_field_type = FocusedFieldType::kFillablePasswordField;
else if (base::ContainsKey(web_input_to_password_info_, *input_element))
focused_field_type = FocusedFieldType::kFillableUsernameField;
else
focused_field_type = FocusedFieldType::kFillableTextField;
} }
focus_state_notifier_.FocusedInputChanged(is_fillable, is_password);
if (!web_element.IsFormControlElement()) focus_state_notifier_.FocusedInputChanged(focused_field_type);
return;
const WebFormControlElement control_element =
web_element.ToConst<WebFormControlElement>();
field_data_manager_.UpdateFieldDataMapWithNullValue( field_data_manager_.UpdateFieldDataMapWithNullValue(
control_element, FieldPropertiesFlags::HAD_FOCUS); *input_element, FieldPropertiesFlags::HAD_FOCUS);
} }
std::unique_ptr<PasswordForm> PasswordAutofillAgent::GetPasswordFormFromWebForm( std::unique_ptr<PasswordForm> PasswordAutofillAgent::GetPasswordFormFromWebForm(
......
...@@ -288,12 +288,12 @@ class PasswordAutofillAgent : public content::RenderFrameObserver, ...@@ -288,12 +288,12 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
explicit FocusStateNotifier(PasswordAutofillAgent* agent); explicit FocusStateNotifier(PasswordAutofillAgent* agent);
~FocusStateNotifier(); ~FocusStateNotifier();
void FocusedInputChanged(bool is_fillable, bool is_password_field); void FocusedInputChanged(mojom::FocusedFieldType focused_field_type);
private: private:
bool was_fillable_; mojom::FocusedFieldType focused_field_type_ =
bool was_password_field_; mojom::FocusedFieldType::kUnknown;
PasswordAutofillAgent* agent_; PasswordAutofillAgent* agent_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(FocusStateNotifier); DISALLOW_COPY_AND_ASSIGN(FocusStateNotifier);
}; };
......
...@@ -73,7 +73,8 @@ class FakeContentPasswordManagerDriver : public mojom::PasswordManagerDriver { ...@@ -73,7 +73,8 @@ class FakeContentPasswordManagerDriver : public mojom::PasswordManagerDriver {
void CheckSafeBrowsingReputation(const GURL& form_action, void CheckSafeBrowsingReputation(const GURL& form_action,
const GURL& frame_url) override {} const GURL& frame_url) override {}
void FocusedInputChanged(bool is_fillable, bool is_password_field) override {} void FocusedInputChanged(
autofill::mojom::FocusedFieldType focused_field_type) override {}
void LogFirstFillingResult(uint32_t form_renderer_id, void LogFirstFillingResult(uint32_t form_renderer_id,
int32_t result) override {} int32_t result) override {}
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "ui/base/page_transition_types.h" #include "ui/base/page_transition_types.h"
using autofill::mojom::FocusedFieldType;
namespace { namespace {
gfx::RectF TransformToRootCoordinates( gfx::RectF TransformToRootCoordinates(
...@@ -298,8 +300,14 @@ void ContentPasswordManagerDriver::CheckSafeBrowsingReputation( ...@@ -298,8 +300,14 @@ void ContentPasswordManagerDriver::CheckSafeBrowsingReputation(
#endif #endif
} }
void ContentPasswordManagerDriver::FocusedInputChanged(bool is_fillable, void ContentPasswordManagerDriver::FocusedInputChanged(
bool is_password_field) { FocusedFieldType focused_field_type) {
// TODO(crbug.com/957532): Forward the full focused field type to the client.
const bool is_fillable =
focused_field_type != FocusedFieldType::kUnknown &&
focused_field_type != FocusedFieldType::kUnfillableElement;
const bool is_password_field =
focused_field_type == FocusedFieldType::kFillablePasswordField;
client_->FocusedInputChanged(this, is_fillable, is_password_field); client_->FocusedInputChanged(this, is_fillable, is_password_field);
} }
......
...@@ -117,7 +117,8 @@ class ContentPasswordManagerDriver ...@@ -117,7 +117,8 @@ class ContentPasswordManagerDriver
void UserModifiedPasswordField() override; void UserModifiedPasswordField() override;
void CheckSafeBrowsingReputation(const GURL& form_action, void CheckSafeBrowsingReputation(const GURL& form_action,
const GURL& frame_url) override; const GURL& frame_url) override;
void FocusedInputChanged(bool is_fillable, bool is_password_field) override; void FocusedInputChanged(
autofill::mojom::FocusedFieldType focused_field_type) override;
void LogFirstFillingResult(uint32_t form_renderer_id, void LogFirstFillingResult(uint32_t form_renderer_id,
int32_t result) override; int32_t result) override;
......
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