Commit 7d24db75 authored by isherman@chromium.org's avatar isherman@chromium.org

Add metrics to track Autofill "user happiness"

BUG=none
TEST=TBD


Review URL: http://codereview.chromium.org/7747009

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@98397 0039d316-1c4b-4281-b951-d872f2087c98
parent fbc66010
...@@ -227,7 +227,11 @@ AutofillManager::AutofillManager(TabContentsWrapper* tab_contents) ...@@ -227,7 +227,11 @@ AutofillManager::AutofillManager(TabContentsWrapper* tab_contents)
disable_download_manager_requests_(false), disable_download_manager_requests_(false),
metric_logger_(new AutofillMetrics), metric_logger_(new AutofillMetrics),
has_logged_autofill_enabled_(false), has_logged_autofill_enabled_(false),
has_logged_address_suggestions_count_(false) { has_logged_address_suggestions_count_(false),
did_show_suggestions_(false),
user_did_type_(false),
user_did_autofill_(false),
user_did_edit_autofilled_field_(false) {
DCHECK(tab_contents); DCHECK(tab_contents);
// |personal_data_| is NULL when using TestTabContents. // |personal_data_| is NULL when using TestTabContents.
...@@ -278,12 +282,16 @@ bool AutofillManager::OnMessageReceived(const IPC::Message& message) { ...@@ -278,12 +282,16 @@ bool AutofillManager::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(AutofillManager, message) IPC_BEGIN_MESSAGE_MAP(AutofillManager, message)
IPC_MESSAGE_HANDLER(AutofillHostMsg_FormsSeen, OnFormsSeen) IPC_MESSAGE_HANDLER(AutofillHostMsg_FormsSeen, OnFormsSeen)
IPC_MESSAGE_HANDLER(AutofillHostMsg_FormSubmitted, OnFormSubmitted) IPC_MESSAGE_HANDLER(AutofillHostMsg_FormSubmitted, OnFormSubmitted)
IPC_MESSAGE_HANDLER(AutofillHostMsg_TextFieldDidChange,
OnTextFieldDidChange)
IPC_MESSAGE_HANDLER(AutofillHostMsg_QueryFormFieldAutofill, IPC_MESSAGE_HANDLER(AutofillHostMsg_QueryFormFieldAutofill,
OnQueryFormFieldAutofill) OnQueryFormFieldAutofill)
IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowAutofillDialog, IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowAutofillDialog,
OnShowAutofillDialog) OnShowAutofillDialog)
IPC_MESSAGE_HANDLER(AutofillHostMsg_FillAutofillFormData, IPC_MESSAGE_HANDLER(AutofillHostMsg_FillAutofillFormData,
OnFillAutofillFormData) OnFillAutofillFormData)
IPC_MESSAGE_HANDLER(AutofillHostMsg_DidPreviewAutofillFormData,
OnDidPreviewAutofillFormData)
IPC_MESSAGE_HANDLER(AutofillHostMsg_DidFillAutofillFormData, IPC_MESSAGE_HANDLER(AutofillHostMsg_DidFillAutofillFormData,
OnDidFillAutofillFormData) OnDidFillAutofillFormData)
IPC_MESSAGE_HANDLER(AutofillHostMsg_DidShowAutofillSuggestions, IPC_MESSAGE_HANDLER(AutofillHostMsg_DidShowAutofillSuggestions,
...@@ -352,6 +360,31 @@ void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms) { ...@@ -352,6 +360,31 @@ void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms) {
ParseForms(forms); ParseForms(forms);
} }
void AutofillManager::OnTextFieldDidChange(const FormData& form,
const FormField& field) {
FormStructure* form_structure = NULL;
AutofillField* autofill_field = NULL;
if (!FindCachedFormAndField(form, field, &form_structure, &autofill_field))
return;
if (!user_did_type_) {
user_did_type_ = true;
metric_logger_->LogUserHappinessMetric(AutofillMetrics::USER_DID_TYPE);
}
if (autofill_field->is_autofilled) {
autofill_field->is_autofilled = false;
metric_logger_->LogUserHappinessMetric(
AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD);
if (!user_did_edit_autofilled_field_) {
user_did_edit_autofilled_field_ = true;
metric_logger_->LogUserHappinessMetric(
AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD_ONCE);
}
}
}
void AutofillManager::OnQueryFormFieldAutofill( void AutofillManager::OnQueryFormFieldAutofill(
int query_id, int query_id,
const webkit_glue::FormData& form, const webkit_glue::FormData& form,
...@@ -508,6 +541,10 @@ void AutofillManager::OnFillAutofillFormData(int query_id, ...@@ -508,6 +541,10 @@ void AutofillManager::OnFillAutofillFormData(int query_id,
AutofillType(field_type).group()); AutofillType(field_type).group());
FillCreditCardFormField(*credit_card, field_type, &(*iter)); FillCreditCardFormField(*credit_card, field_type, &(*iter));
} }
// Mark the cached field as autofilled, so that we can detect when a
// user edits an autofilled field (for metrics).
autofill_field->is_autofilled = true;
break; break;
} }
} }
...@@ -559,6 +596,10 @@ void AutofillManager::OnFillAutofillFormData(int query_id, ...@@ -559,6 +596,10 @@ void AutofillManager::OnFillAutofillFormData(int query_id,
DCHECK_EQ(AutofillType::CREDIT_CARD, field_group_type); DCHECK_EQ(AutofillType::CREDIT_CARD, field_group_type);
FillCreditCardFormField(*credit_card, field_type, &result.fields[j]); FillCreditCardFormField(*credit_card, field_type, &result.fields[j]);
} }
// Mark the cached field as autofilled, so that we can detect when a user
// edits an autofilled field (for metrics).
form_structure->field(k)->is_autofilled = true;
} }
// We found a matching field in the |form_structure|, so on the next // We found a matching field in the |form_structure|, so on the next
...@@ -583,18 +624,43 @@ void AutofillManager::OnShowAutofillDialog() { ...@@ -583,18 +624,43 @@ void AutofillManager::OnShowAutofillDialog() {
browser->ShowOptionsTab(chrome::kAutofillSubPage); browser->ShowOptionsTab(chrome::kAutofillSubPage);
} }
void AutofillManager::OnDidPreviewAutofillFormData() {
NotificationService::current()->Notify(
chrome::NOTIFICATION_AUTOFILL_DID_FILL_FORM_DATA,
Source<RenderViewHost>(tab_contents()->render_view_host()),
NotificationService::NoDetails());
}
void AutofillManager::OnDidFillAutofillFormData() { void AutofillManager::OnDidFillAutofillFormData() {
NotificationService::current()->Notify( NotificationService::current()->Notify(
chrome::NOTIFICATION_AUTOFILL_DID_FILL_FORM_DATA, chrome::NOTIFICATION_AUTOFILL_DID_FILL_FORM_DATA,
Source<RenderViewHost>(tab_contents()->render_view_host()), Source<RenderViewHost>(tab_contents()->render_view_host()),
NotificationService::NoDetails()); NotificationService::NoDetails());
metric_logger_->LogUserHappinessMetric(AutofillMetrics::USER_DID_AUTOFILL);
if (!user_did_autofill_) {
user_did_autofill_ = true;
metric_logger_->LogUserHappinessMetric(
AutofillMetrics::USER_DID_AUTOFILL_ONCE);
}
} }
void AutofillManager::OnDidShowAutofillSuggestions() { void AutofillManager::OnDidShowAutofillSuggestions(bool is_new_popup) {
NotificationService::current()->Notify( NotificationService::current()->Notify(
chrome::NOTIFICATION_AUTOFILL_DID_SHOW_SUGGESTIONS, chrome::NOTIFICATION_AUTOFILL_DID_SHOW_SUGGESTIONS,
Source<RenderViewHost>(tab_contents()->render_view_host()), Source<RenderViewHost>(tab_contents()->render_view_host()),
NotificationService::NoDetails()); NotificationService::NoDetails());
if (is_new_popup) {
metric_logger_->LogUserHappinessMetric(AutofillMetrics::SUGGESTIONS_SHOWN);
if (!did_show_suggestions_) {
did_show_suggestions_ = true;
metric_logger_->LogUserHappinessMetric(
AutofillMetrics::SUGGESTIONS_SHOWN_ONCE);
}
}
} }
void AutofillManager::OnLoadedServerPredictions( void AutofillManager::OnLoadedServerPredictions(
...@@ -646,7 +712,7 @@ void AutofillManager::DeterminePossibleFieldTypesForUpload( ...@@ -646,7 +712,7 @@ void AutofillManager::DeterminePossibleFieldTypesForUpload(
// For each field in the |submitted_form|, extract the value. Then for each // For each field in the |submitted_form|, extract the value. Then for each
// profile or credit card, identify any stored types that match the value. // profile or credit card, identify any stored types that match the value.
for (size_t i = 0; i < submitted_form->field_count(); i++) { for (size_t i = 0; i < submitted_form->field_count(); i++) {
const AutofillField* field = submitted_form->field(i); AutofillField* field = submitted_form->field(i);
string16 value = CollapseWhitespace(field->value, false); string16 value = CollapseWhitespace(field->value, false);
FieldTypeSet matching_types; FieldTypeSet matching_types;
for (std::vector<FormGroup*>::const_iterator it = stored_data.begin(); for (std::vector<FormGroup*>::const_iterator it = stored_data.begin();
...@@ -657,7 +723,7 @@ void AutofillManager::DeterminePossibleFieldTypesForUpload( ...@@ -657,7 +723,7 @@ void AutofillManager::DeterminePossibleFieldTypesForUpload(
if (matching_types.empty()) if (matching_types.empty())
matching_types.insert(UNKNOWN_TYPE); matching_types.insert(UNKNOWN_TYPE);
submitted_form->set_possible_types(i, matching_types); field->set_possible_types(matching_types);
} }
} }
...@@ -704,6 +770,10 @@ void AutofillManager::Reset() { ...@@ -704,6 +770,10 @@ void AutofillManager::Reset() {
form_structures_.reset(); form_structures_.reset();
has_logged_autofill_enabled_ = false; has_logged_autofill_enabled_ = false;
has_logged_address_suggestions_count_ = false; has_logged_address_suggestions_count_ = false;
did_show_suggestions_ = false;
user_did_type_ = false;
user_did_autofill_ = false;
user_did_edit_autofilled_field_ = false;
} }
AutofillManager::AutofillManager(TabContentsWrapper* tab_contents, AutofillManager::AutofillManager(TabContentsWrapper* tab_contents,
...@@ -715,7 +785,11 @@ AutofillManager::AutofillManager(TabContentsWrapper* tab_contents, ...@@ -715,7 +785,11 @@ AutofillManager::AutofillManager(TabContentsWrapper* tab_contents,
disable_download_manager_requests_(true), disable_download_manager_requests_(true),
metric_logger_(new AutofillMetrics), metric_logger_(new AutofillMetrics),
has_logged_autofill_enabled_(false), has_logged_autofill_enabled_(false),
has_logged_address_suggestions_count_(false) { has_logged_address_suggestions_count_(false),
did_show_suggestions_(false),
user_did_type_(false),
user_did_autofill_(false),
user_did_edit_autofilled_field_(false) {
DCHECK(tab_contents); DCHECK(tab_contents);
} }
...@@ -1013,6 +1087,9 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) { ...@@ -1013,6 +1087,9 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) {
form_structures_.push_back(*iter); form_structures_.push_back(*iter);
} }
if (!form_structures_.empty())
metric_logger_->LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED);
CheckForPopularForms(form_structures_.get(), tab_contents_wrapper_, CheckForPopularForms(form_structures_.get(), tab_contents_wrapper_,
tab_contents()); tab_contents());
} }
......
...@@ -115,6 +115,8 @@ class AutofillManager : public TabContentsObserver, ...@@ -115,6 +115,8 @@ class AutofillManager : public TabContentsObserver,
private: private:
void OnFormSubmitted(const webkit_glue::FormData& form); void OnFormSubmitted(const webkit_glue::FormData& form);
void OnFormsSeen(const std::vector<webkit_glue::FormData>& forms); void OnFormsSeen(const std::vector<webkit_glue::FormData>& forms);
void OnTextFieldDidChange(const webkit_glue::FormData& form,
const webkit_glue::FormField& field);
void OnQueryFormFieldAutofill(int query_id, void OnQueryFormFieldAutofill(int query_id,
const webkit_glue::FormData& form, const webkit_glue::FormData& form,
const webkit_glue::FormField& field); const webkit_glue::FormField& field);
...@@ -123,8 +125,9 @@ class AutofillManager : public TabContentsObserver, ...@@ -123,8 +125,9 @@ class AutofillManager : public TabContentsObserver,
const webkit_glue::FormField& field, const webkit_glue::FormField& field,
int unique_id); int unique_id);
void OnShowAutofillDialog(); void OnShowAutofillDialog();
void OnDidPreviewAutofillFormData();
void OnDidFillAutofillFormData(); void OnDidFillAutofillFormData();
void OnDidShowAutofillSuggestions(); void OnDidShowAutofillSuggestions(bool is_new_popup);
// Fills |host| with the RenderViewHost for this tab. // Fills |host| with the RenderViewHost for this tab.
// Returns false if Autofill is disabled or if the host is unavailable. // Returns false if Autofill is disabled or if the host is unavailable.
...@@ -217,12 +220,19 @@ class AutofillManager : public TabContentsObserver, ...@@ -217,12 +220,19 @@ class AutofillManager : public TabContentsObserver,
// For logging UMA metrics. Overridden by metrics tests. // For logging UMA metrics. Overridden by metrics tests.
scoped_ptr<const AutofillMetrics> metric_logger_; scoped_ptr<const AutofillMetrics> metric_logger_;
// Have we logged whether Autofill is enabled for this page load? // Have we logged whether Autofill is enabled for this page load?
bool has_logged_autofill_enabled_; bool has_logged_autofill_enabled_;
// Have we logged an address suggestions count metric for this page? // Have we logged an address suggestions count metric for this page?
bool has_logged_address_suggestions_count_; bool has_logged_address_suggestions_count_;
// Have we shown Autofill suggestions at least once?
bool did_show_suggestions_;
// Has the user manually edited at least one form field among the autofillable
// ones?
bool user_did_type_;
// Has the user autofilled a form on this page?
bool user_did_autofill_;
// Has the user edited a field that was previously autofilled?
bool user_did_edit_autofilled_field_;
// Our copy of the form data. // Our copy of the form data.
ScopedVector<FormStructure> form_structures_; ScopedVector<FormStructure> form_structures_;
...@@ -264,6 +274,9 @@ class AutofillManager : public TabContentsObserver, ...@@ -264,6 +274,9 @@ class AutofillManager : public TabContentsObserver,
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, QualityMetricsForFailure); FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, QualityMetricsForFailure);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, QualityMetricsWithExperimentId); FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, QualityMetricsWithExperimentId);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, SaneMetricsWithCacheMismatch); FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, SaneMetricsWithCacheMismatch);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest,
UserHappinessFormLoadAndSubmission);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, UserHappinessFormInteraction);
DISALLOW_COPY_AND_ASSIGN(AutofillManager); DISALLOW_COPY_AND_ASSIGN(AutofillManager);
}; };
......
...@@ -288,6 +288,13 @@ void AutofillMetrics::LogServerQueryMetric(ServerQueryMetric metric) const { ...@@ -288,6 +288,13 @@ void AutofillMetrics::LogServerQueryMetric(ServerQueryMetric metric) const {
NUM_SERVER_QUERY_METRICS); NUM_SERVER_QUERY_METRICS);
} }
void AutofillMetrics::LogUserHappinessMetric(UserHappinessMetric metric) const {
DCHECK(metric < NUM_USER_HAPPINESS_METRICS);
UMA_HISTOGRAM_ENUMERATION("Autofill.UserHappiness", metric,
NUM_USER_HAPPINESS_METRICS);
}
void AutofillMetrics::LogIsAutofillEnabledAtStartup(bool enabled) const { void AutofillMetrics::LogIsAutofillEnabledAtStartup(bool enabled) const {
UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.Startup", enabled); UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.Startup", enabled);
} }
......
...@@ -79,6 +79,47 @@ class AutofillMetrics { ...@@ -79,6 +79,47 @@ class AutofillMetrics {
NUM_SERVER_QUERY_METRICS NUM_SERVER_QUERY_METRICS
}; };
// Each of these metrics is logged only for potentially autofillable forms,
// i.e. forms with at least three fields, etc.
// These are used to derive certain "user happiness" metrics. For example, we
// can compute the ratio (USER_DID_EDIT_AUTOFILLED_FIELD / USER_DID_AUTOFILL)
// to see how often users have to correct autofilled data.
enum UserHappinessMetric {
// Loaded a page containing forms.
FORMS_LOADED,
// Submitted a fillable form -- i.e. one with at least three field values
// that match the user's stored Autofill data -- and all matching fields
// were autofilled.
SUBMITTED_FILLABLE_FORM_AUTOFILLED_ALL,
// Submitted a fillable form and some (but not all) matching fields were
// autofilled.
SUBMITTED_FILLABLE_FORM_AUTOFILLED_SOME,
// Submitted a fillable form and no fields were autofilled.
SUBMITTED_FILLABLE_FORM_AUTOFILLED_NONE,
// Submitted a non-fillable form.
SUBMITTED_NON_FILLABLE_FORM,
// User manually filled one of the form fields.
USER_DID_TYPE,
// We showed a popup containing Autofill suggestions.
SUGGESTIONS_SHOWN,
// Same as above, but only logged once per page load.
SUGGESTIONS_SHOWN_ONCE,
// User autofilled at least part of the form.
USER_DID_AUTOFILL,
// Same as above, but only logged once per page load.
USER_DID_AUTOFILL_ONCE,
// User edited a previously autofilled field.
USER_DID_EDIT_AUTOFILLED_FIELD,
// Same as above, but only logged once per page load.
USER_DID_EDIT_AUTOFILLED_FIELD_ONCE,
NUM_USER_HAPPINESS_METRICS
};
// TODO(isherman): Add histograms to measure time elapsed between form load
// form submission, comparing autofilled and non-autofilled forms. So that we
// are measuring apples to apples, restrict just to fillable forms.
AutofillMetrics(); AutofillMetrics();
virtual ~AutofillMetrics(); virtual ~AutofillMetrics();
...@@ -101,6 +142,8 @@ class AutofillMetrics { ...@@ -101,6 +142,8 @@ class AutofillMetrics {
virtual void LogServerQueryMetric(ServerQueryMetric metric) const; virtual void LogServerQueryMetric(ServerQueryMetric metric) const;
virtual void LogUserHappinessMetric(UserHappinessMetric metric) const;
// This should be called each time a page containing forms is loaded. // This should be called each time a page containing forms is loaded.
virtual void LogIsAutofillEnabledAtPageLoad(bool enabled) const; virtual void LogIsAutofillEnabledAtPageLoad(bool enabled) const;
......
...@@ -650,6 +650,9 @@ void FormStructure::LogQualityMetrics( ...@@ -650,6 +650,9 @@ void FormStructure::LogQualityMetrics(
std::string experiment_id = server_experiment_id(); std::string experiment_id = server_experiment_id();
metric_logger.LogServerExperimentIdForUpload(experiment_id); metric_logger.LogServerExperimentIdForUpload(experiment_id);
size_t num_detected_field_types = 0;
bool did_autofill_all_possible_fields = true;
bool did_autofill_some_possible_fields = false;
for (size_t i = 0; i < field_count(); ++i) { for (size_t i = 0; i < field_count(); ++i) {
const AutofillField* field = this->field(i); const AutofillField* field = this->field(i);
metric_logger.LogQualityMetric(AutofillMetrics::FIELD_SUBMITTED, metric_logger.LogQualityMetric(AutofillMetrics::FIELD_SUBMITTED,
...@@ -662,6 +665,12 @@ void FormStructure::LogQualityMetrics( ...@@ -662,6 +665,12 @@ void FormStructure::LogQualityMetrics(
if (field_types.count(EMPTY_TYPE) || field_types.count(UNKNOWN_TYPE)) if (field_types.count(EMPTY_TYPE) || field_types.count(UNKNOWN_TYPE))
continue; continue;
++num_detected_field_types;
if (field->is_autofilled)
did_autofill_some_possible_fields = true;
else
did_autofill_all_possible_fields = false;
// Collapse field types that Chrome treats as identical, e.g. home and // Collapse field types that Chrome treats as identical, e.g. home and
// billing address fields. // billing address fields.
FieldTypeSet collapsed_field_types; FieldTypeSet collapsed_field_types;
...@@ -765,16 +774,20 @@ void FormStructure::LogQualityMetrics( ...@@ -765,16 +774,20 @@ void FormStructure::LogQualityMetrics(
} }
} }
} }
}
void FormStructure::set_possible_types(size_t index, if (num_detected_field_types < kRequiredFillableFields) {
const FieldTypeSet& types) { metric_logger.LogUserHappinessMetric(
if (index >= fields_.size()) { AutofillMetrics::SUBMITTED_NON_FILLABLE_FORM);
NOTREACHED(); } else if (did_autofill_all_possible_fields) {
return; metric_logger.LogUserHappinessMetric(
AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_ALL);
} else if (did_autofill_some_possible_fields) {
metric_logger.LogUserHappinessMetric(
AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_SOME);
} else {
metric_logger.LogUserHappinessMetric(
AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_NONE);
} }
fields_[index]->set_possible_types(types);
} }
const AutofillField* FormStructure::field(size_t index) const { const AutofillField* FormStructure::field(size_t index) const {
...@@ -786,6 +799,11 @@ const AutofillField* FormStructure::field(size_t index) const { ...@@ -786,6 +799,11 @@ const AutofillField* FormStructure::field(size_t index) const {
return fields_[index]; return fields_[index];
} }
AutofillField* FormStructure::field(size_t index) {
return const_cast<AutofillField*>(
static_cast<const FormStructure*>(this)->field(index));
}
size_t FormStructure::field_count() const { size_t FormStructure::field_count() const {
return fields_.size(); return fields_.size();
} }
......
...@@ -109,10 +109,8 @@ class FormStructure { ...@@ -109,10 +109,8 @@ class FormStructure {
// set for each field. // set for each field.
void LogQualityMetrics(const AutofillMetrics& metric_logger) const; void LogQualityMetrics(const AutofillMetrics& metric_logger) const;
// Sets the possible types for the field at |index|.
void set_possible_types(size_t index, const FieldTypeSet& types);
const AutofillField* field(size_t index) const; const AutofillField* field(size_t index) const;
AutofillField* field(size_t index);
size_t field_count() const; size_t field_count() const;
// Returns the number of fields that are able to be autofilled. // Returns the number of fields that are able to be autofilled.
......
...@@ -1504,7 +1504,7 @@ TEST(FormStructureTest, EncodeUploadRequest) { ...@@ -1504,7 +1504,7 @@ TEST(FormStructureTest, EncodeUploadRequest) {
ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
for (size_t i = 0; i < form_structure->field_count(); ++i) for (size_t i = 0; i < form_structure->field_count(); ++i)
form_structure->set_possible_types(i, possible_field_types[i]); form_structure->field(i)->set_possible_types(possible_field_types[i]);
FieldTypeSet available_field_types; FieldTypeSet available_field_types;
available_field_types.insert(NAME_FIRST); available_field_types.insert(NAME_FIRST);
...@@ -1564,7 +1564,7 @@ TEST(FormStructureTest, EncodeUploadRequest) { ...@@ -1564,7 +1564,7 @@ TEST(FormStructureTest, EncodeUploadRequest) {
form_structure.reset(new FormStructure(form)); form_structure.reset(new FormStructure(form));
ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
for (size_t i = 0; i < form_structure->field_count(); ++i) for (size_t i = 0; i < form_structure->field_count(); ++i)
form_structure->set_possible_types(i, possible_field_types[i]); form_structure->field(i)->set_possible_types(possible_field_types[i]);
EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, false, EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, false,
&encoded_xml)); &encoded_xml));
...@@ -1604,7 +1604,7 @@ TEST(FormStructureTest, EncodeUploadRequest) { ...@@ -1604,7 +1604,7 @@ TEST(FormStructureTest, EncodeUploadRequest) {
form_structure.reset(new FormStructure(form)); form_structure.reset(new FormStructure(form));
ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
for (size_t i = 0; i < form_structure->field_count(); ++i) for (size_t i = 0; i < form_structure->field_count(); ++i)
form_structure->set_possible_types(i, possible_field_types[i]); form_structure->field(i)->set_possible_types(possible_field_types[i]);
EXPECT_FALSE(form_structure->EncodeUploadRequest(available_field_types, false, EXPECT_FALSE(form_structure->EncodeUploadRequest(available_field_types, false,
&encoded_xml)); &encoded_xml));
} }
...@@ -1635,7 +1635,7 @@ TEST(FormStructureTest, CheckDataPresence) { ...@@ -1635,7 +1635,7 @@ TEST(FormStructureTest, CheckDataPresence) {
FieldTypeSet unknown_type; FieldTypeSet unknown_type;
unknown_type.insert(UNKNOWN_TYPE); unknown_type.insert(UNKNOWN_TYPE);
for (size_t i = 0; i < form_structure.field_count(); ++i) for (size_t i = 0; i < form_structure.field_count(); ++i)
form_structure.set_possible_types(i, unknown_type); form_structure.field(i)->set_possible_types(unknown_type);
// No available types. // No available types.
// datapresent should be "" == trimmmed(0x0000000000000000) == // datapresent should be "" == trimmmed(0x0000000000000000) ==
...@@ -1919,7 +1919,7 @@ TEST(FormStructureTest, CheckMultipleTypes) { ...@@ -1919,7 +1919,7 @@ TEST(FormStructureTest, CheckMultipleTypes) {
form_structure.reset(new FormStructure(form)); form_structure.reset(new FormStructure(form));
for (size_t i = 0; i < form_structure->field_count(); ++i) for (size_t i = 0; i < form_structure->field_count(); ++i)
form_structure->set_possible_types(i, possible_field_types[i]); form_structure->field(i)->set_possible_types(possible_field_types[i]);
std::string encoded_xml; std::string encoded_xml;
// Now we matched both fields singularly. // Now we matched both fields singularly.
...@@ -1937,7 +1937,7 @@ TEST(FormStructureTest, CheckMultipleTypes) { ...@@ -1937,7 +1937,7 @@ TEST(FormStructureTest, CheckMultipleTypes) {
encoded_xml); encoded_xml);
// Match third field as both first and last. // Match third field as both first and last.
possible_field_types[2].insert(NAME_FIRST); possible_field_types[2].insert(NAME_FIRST);
form_structure->set_possible_types(2, possible_field_types[2]); form_structure->field(2)->set_possible_types(possible_field_types[2]);
EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, false, EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, false,
&encoded_xml)); &encoded_xml));
EXPECT_EQ("<\?xml version=\"1.0\" encoding=\"UTF-8\"\?>" EXPECT_EQ("<\?xml version=\"1.0\" encoding=\"UTF-8\"\?>"
...@@ -1952,8 +1952,7 @@ TEST(FormStructureTest, CheckMultipleTypes) { ...@@ -1952,8 +1952,7 @@ TEST(FormStructureTest, CheckMultipleTypes) {
"</autofillupload>", "</autofillupload>",
encoded_xml); encoded_xml);
possible_field_types[3].insert(ADDRESS_HOME_LINE2); possible_field_types[3].insert(ADDRESS_HOME_LINE2);
form_structure->set_possible_types( form_structure->field(form_structure->field_count() - 1)->set_possible_types(
form_structure->field_count() - 1,
possible_field_types[form_structure->field_count() - 1]); possible_field_types[form_structure->field_count() - 1]);
EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, false, EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, false,
&encoded_xml)); &encoded_xml));
...@@ -1972,8 +1971,7 @@ TEST(FormStructureTest, CheckMultipleTypes) { ...@@ -1972,8 +1971,7 @@ TEST(FormStructureTest, CheckMultipleTypes) {
possible_field_types[3].clear(); possible_field_types[3].clear();
possible_field_types[3].insert(ADDRESS_HOME_LINE1); possible_field_types[3].insert(ADDRESS_HOME_LINE1);
possible_field_types[3].insert(COMPANY_NAME); possible_field_types[3].insert(COMPANY_NAME);
form_structure->set_possible_types( form_structure->field(form_structure->field_count() - 1)->set_possible_types(
form_structure->field_count() - 1,
possible_field_types[form_structure->field_count() - 1]); possible_field_types[form_structure->field_count() - 1]);
EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, false, EXPECT_TRUE(form_structure->EncodeUploadRequest(available_field_types, false,
&encoded_xml)); &encoded_xml));
......
...@@ -107,6 +107,11 @@ IPC_MESSAGE_ROUTED1(AutofillHostMsg_PasswordFormsVisible, ...@@ -107,6 +107,11 @@ IPC_MESSAGE_ROUTED1(AutofillHostMsg_PasswordFormsVisible,
IPC_MESSAGE_ROUTED1(AutofillHostMsg_FormSubmitted, IPC_MESSAGE_ROUTED1(AutofillHostMsg_FormSubmitted,
webkit_glue::FormData /* form */) webkit_glue::FormData /* form */)
// Notification that a form field's value has changed.
IPC_MESSAGE_ROUTED2(AutofillHostMsg_TextFieldDidChange,
webkit_glue::FormData /* the form */,
webkit_glue::FormField /* the form field */)
// Queries the browser for Autofill suggestions for a form input field. // Queries the browser for Autofill suggestions for a form input field.
IPC_MESSAGE_ROUTED3(AutofillHostMsg_QueryFormFieldAutofill, IPC_MESSAGE_ROUTED3(AutofillHostMsg_QueryFormFieldAutofill,
int /* id of this message */, int /* id of this message */,
...@@ -114,7 +119,8 @@ IPC_MESSAGE_ROUTED3(AutofillHostMsg_QueryFormFieldAutofill, ...@@ -114,7 +119,8 @@ IPC_MESSAGE_ROUTED3(AutofillHostMsg_QueryFormFieldAutofill,
webkit_glue::FormField /* the form field */) webkit_glue::FormField /* the form field */)
// Sent when the popup with Autofill suggestions for a form is shown. // Sent when the popup with Autofill suggestions for a form is shown.
IPC_MESSAGE_ROUTED0(AutofillHostMsg_DidShowAutofillSuggestions) IPC_MESSAGE_ROUTED1(AutofillHostMsg_DidShowAutofillSuggestions,
bool /* is this a new popup? */)
// Instructs the browser to fill in the values for a form using Autofill // Instructs the browser to fill in the values for a form using Autofill
// profile data. // profile data.
...@@ -124,7 +130,10 @@ IPC_MESSAGE_ROUTED4(AutofillHostMsg_FillAutofillFormData, ...@@ -124,7 +130,10 @@ IPC_MESSAGE_ROUTED4(AutofillHostMsg_FillAutofillFormData,
webkit_glue::FormField /* the form field */, webkit_glue::FormField /* the form field */,
int /* profile unique ID */) int /* profile unique ID */)
// Sent when a form is previewed or filled with Autofill suggestions. // Sent when a form is previewed with Autofill suggestions.
IPC_MESSAGE_ROUTED0(AutofillHostMsg_DidPreviewAutofillFormData)
// Sent when a form is filled with Autofill suggestions.
IPC_MESSAGE_ROUTED0(AutofillHostMsg_DidFillAutofillFormData) IPC_MESSAGE_ROUTED0(AutofillHostMsg_DidFillAutofillFormData)
// Instructs the browser to remove the specified Autocomplete entry from the // Instructs the browser to remove the specified Autocomplete entry from the
......
...@@ -179,6 +179,7 @@ void AutofillAgent::removeAutocompleteSuggestion(const WebString& name, ...@@ -179,6 +179,7 @@ void AutofillAgent::removeAutocompleteSuggestion(const WebString& name,
void AutofillAgent::textFieldDidEndEditing(const WebInputElement& element) { void AutofillAgent::textFieldDidEndEditing(const WebInputElement& element) {
password_autofill_manager_->TextFieldDidEndEditing(element); password_autofill_manager_->TextFieldDidEndEditing(element);
has_shown_autofill_popup_for_current_edit_ = false;
} }
void AutofillAgent::textFieldDidChange(const WebInputElement& element) { void AutofillAgent::textFieldDidChange(const WebInputElement& element) {
...@@ -197,6 +198,11 @@ void AutofillAgent::TextFieldDidChangeImpl(const WebInputElement& element) { ...@@ -197,6 +198,11 @@ void AutofillAgent::TextFieldDidChangeImpl(const WebInputElement& element) {
return; return;
ShowSuggestions(element, false, true, false); ShowSuggestions(element, false, true, false);
webkit_glue::FormData form;
webkit_glue::FormField field;
if (FindFormAndFieldForNode(element, &form, &field))
Send(new AutofillHostMsg_TextFieldDidChange(routing_id(), form, field));
} }
void AutofillAgent::textFieldDidReceiveKeyDown(const WebInputElement& element, void AutofillAgent::textFieldDidReceiveKeyDown(const WebInputElement& element,
...@@ -230,6 +236,7 @@ void AutofillAgent::OnSuggestionsReturned(int query_id, ...@@ -230,6 +236,7 @@ void AutofillAgent::OnSuggestionsReturned(int query_id,
std::vector<int> ids(unique_ids); std::vector<int> ids(unique_ids);
int separator_index = -1; int separator_index = -1;
DCHECK_GT(ids.size(), 0U);
if (!autofill_query_element_.isNull() && if (!autofill_query_element_.isNull() &&
!autofill_query_element_.autoComplete()) { !autofill_query_element_.autoComplete()) {
// If autofill is disabled and we had suggestions, show a warning instead. // If autofill is disabled and we had suggestions, show a warning instead.
...@@ -290,7 +297,10 @@ void AutofillAgent::OnSuggestionsReturned(int query_id, ...@@ -290,7 +297,10 @@ void AutofillAgent::OnSuggestionsReturned(int query_id,
autofill_query_element_, v, l, i, ids, separator_index); autofill_query_element_, v, l, i, ids, separator_index);
} }
Send(new AutofillHostMsg_DidShowAutofillSuggestions(routing_id())); Send(new AutofillHostMsg_DidShowAutofillSuggestions(
routing_id(),
has_autofill_item && !has_shown_autofill_popup_for_current_edit_));
has_shown_autofill_popup_for_current_edit_ |= has_autofill_item;
} }
void AutofillAgent::OnFormDataFilled(int query_id, void AutofillAgent::OnFormDataFilled(int query_id,
...@@ -301,15 +311,16 @@ void AutofillAgent::OnFormDataFilled(int query_id, ...@@ -301,15 +311,16 @@ void AutofillAgent::OnFormDataFilled(int query_id,
switch (autofill_action_) { switch (autofill_action_) {
case AUTOFILL_FILL: case AUTOFILL_FILL:
form_manager_.FillForm(form, autofill_query_element_); form_manager_.FillForm(form, autofill_query_element_);
Send(new AutofillHostMsg_DidFillAutofillFormData(routing_id()));
break; break;
case AUTOFILL_PREVIEW: case AUTOFILL_PREVIEW:
form_manager_.PreviewForm(form, autofill_query_element_); form_manager_.PreviewForm(form, autofill_query_element_);
Send(new AutofillHostMsg_DidPreviewAutofillFormData(routing_id()));
break; break;
default: default:
NOTREACHED(); NOTREACHED();
} }
autofill_action_ = AUTOFILL_NONE; autofill_action_ = AUTOFILL_NONE;
Send(new AutofillHostMsg_DidFillAutofillFormData(routing_id()));
} }
void AutofillAgent::OnFieldTypePredictionsAvailable( void AutofillAgent::OnFieldTypePredictionsAvailable(
......
...@@ -163,6 +163,10 @@ class AutofillAgent : public RenderViewObserver, ...@@ -163,6 +163,10 @@ class AutofillAgent : public RenderViewObserver,
// The menu index of the "Autofill options..." menu item. // The menu index of the "Autofill options..." menu item.
int suggestions_options_index_; int suggestions_options_index_;
// Have we already shown Autofill suggestions for the field the user is
// currently editing? Used to keep track of state for metrics logging.
bool has_shown_autofill_popup_for_current_edit_;
ScopedRunnableMethodFactory<AutofillAgent> method_factory_; ScopedRunnableMethodFactory<AutofillAgent> method_factory_;
DISALLOW_COPY_AND_ASSIGN(AutofillAgent); DISALLOW_COPY_AND_ASSIGN(AutofillAgent);
......
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