summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorisherman@chromium.org <isherman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-02 20:42:04 +0000
committerisherman@chromium.org <isherman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-02 20:42:04 +0000
commit1d14f58b753c59924cef2f5bb4a0f1cb88db07d5 (patch)
treea0bdee96486c4f0cbe4bb8e23ed5b890c8131587
parentfd346b76799059213d36109a799bc029f3a2ed1d (diff)
downloadchromium_src-1d14f58b753c59924cef2f5bb4a0f1cb88db07d5.zip
chromium_src-1d14f58b753c59924cef2f5bb4a0f1cb88db07d5.tar.gz
chromium_src-1d14f58b753c59924cef2f5bb4a0f1cb88db07d5.tar.bz2
Add metrics to measure time elapsed between form load and form submission with or without Autofill.
BUG=none TEST=unit_tests --gtest_filter=AutofillMetricsTest.* Review URL: http://codereview.chromium.org/7740070 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@99447 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/time.h18
-rw-r--r--chrome/browser/autofill/autofill_manager.cc32
-rw-r--r--chrome/browser/autofill/autofill_manager.h24
-rw-r--r--chrome/browser/autofill/autofill_manager_unittest.cc5
-rw-r--r--chrome/browser/autofill/autofill_metrics.cc39
-rw-r--r--chrome/browser/autofill/autofill_metrics.h30
-rw-r--r--chrome/browser/autofill/autofill_metrics_unittest.cc194
-rw-r--r--chrome/browser/autofill/autofill_type.cc40
-rw-r--r--chrome/browser/autofill/form_structure.cc53
-rw-r--r--chrome/browser/autofill/form_structure.h13
-rw-r--r--chrome/common/autofill_messages.h20
-rw-r--r--chrome/renderer/autofill/autofill_agent.cc19
-rw-r--r--chrome/renderer/autofill/form_autocomplete_browsertest.cc7
-rw-r--r--ipc/ipc_message_utils.cc25
-rw-r--r--ipc/ipc_message_utils.h9
15 files changed, 439 insertions, 89 deletions
diff --git a/base/time.h b/base/time.h
index aa97f0a..8590e99 100644
--- a/base/time.h
+++ b/base/time.h
@@ -60,9 +60,18 @@ class BASE_EXPORT TimeDelta {
static TimeDelta FromMilliseconds(int64 ms);
static TimeDelta FromMicroseconds(int64 us);
+ // Converts an integer value representing TimeDelta to a class. This is used
+ // when deserializing a |TimeDelta| structure, using a value known to be
+ // compatible. It is not provided as a constructor because the integer type
+ // may be unclear from the perspective of a caller.
+ static TimeDelta FromInternalValue(int64 delta) {
+ return TimeDelta(delta);
+ }
+
// Returns the internal numeric value of the TimeDelta object. Please don't
// use this and do arithmetic on it, as it is more error prone than using the
// provided operators.
+ // For serializing, use FromInternalValue to reconstitute.
int64 ToInternalValue() const {
return delta_;
}
@@ -487,7 +496,16 @@ class BASE_EXPORT TimeTicks {
return ticks_ == 0;
}
+ // Converts an integer value representing TimeTicks to a class. This is used
+ // when deserializing a |TimeTicks| structure, using a value known to be
+ // compatible. It is not provided as a constructor because the integer type
+ // may be unclear from the perspective of a caller.
+ static TimeTicks FromInternalValue(int64 ticks) {
+ return TimeTicks(ticks);
+ }
+
// Returns the internal numeric value of the TimeTicks object.
+ // For serializing, use FromInternalValue to reconstitute.
int64 ToInternalValue() const {
return ticks_;
}
diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc
index c5d4755..ce8e9df 100644
--- a/chrome/browser/autofill/autofill_manager.cc
+++ b/chrome/browser/autofill/autofill_manager.cc
@@ -52,6 +52,7 @@
#include "webkit/glue/form_data_predictions.h"
#include "webkit/glue/form_field.h"
+using base::TimeTicks;
using switches::kEnableAutofillFeedback;
using webkit_glue::FormData;
using webkit_glue::FormDataPredictions;
@@ -303,7 +304,8 @@ bool AutofillManager::OnMessageReceived(const IPC::Message& message) {
return handled;
}
-void AutofillManager::OnFormSubmitted(const FormData& form) {
+void AutofillManager::OnFormSubmitted(const FormData& form,
+ const TimeTicks& timestamp) {
// Let AutoComplete know as well.
tab_contents_wrapper_->autocomplete_history_manager()->OnFormSubmitted(form);
@@ -336,7 +338,10 @@ void AutofillManager::OnFormSubmitted(const FormData& form) {
if (!personal_data_->profiles().empty() ||
!personal_data_->credit_cards().empty()) {
DeterminePossibleFieldTypesForUpload(&submitted_form);
- submitted_form.LogQualityMetrics(*metric_logger_);
+ submitted_form.LogQualityMetrics(*metric_logger_,
+ forms_loaded_timestamp_,
+ initial_interaction_timestamp_,
+ timestamp);
if (submitted_form.ShouldBeCrowdsourced())
UploadFormData(submitted_form);
@@ -348,7 +353,8 @@ void AutofillManager::OnFormSubmitted(const FormData& form) {
ImportFormData(submitted_form);
}
-void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms) {
+void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms,
+ const TimeTicks& timestamp) {
bool enabled = IsAutofillEnabled();
if (!has_logged_autofill_enabled_) {
metric_logger_->LogIsAutofillEnabledAtPageLoad(enabled);
@@ -358,11 +364,13 @@ void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms) {
if (!enabled)
return;
+ forms_loaded_timestamp_ = timestamp;
ParseForms(forms);
}
void AutofillManager::OnTextFieldDidChange(const FormData& form,
- const FormField& field) {
+ const FormField& field,
+ const TimeTicks& timestamp) {
FormStructure* form_structure = NULL;
AutofillField* autofill_field = NULL;
if (!FindCachedFormAndField(form, field, &form_structure, &autofill_field))
@@ -384,6 +392,8 @@ void AutofillManager::OnTextFieldDidChange(const FormData& form,
AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD_ONCE);
}
}
+
+ UpdateInitialInteractionTimestamp(timestamp);
}
void AutofillManager::OnQueryFormFieldAutofill(
@@ -633,7 +643,7 @@ void AutofillManager::OnDidPreviewAutofillFormData() {
}
-void AutofillManager::OnDidFillAutofillFormData() {
+void AutofillManager::OnDidFillAutofillFormData(const TimeTicks& timestamp) {
NotificationService::current()->Notify(
chrome::NOTIFICATION_AUTOFILL_DID_FILL_FORM_DATA,
Source<RenderViewHost>(tab_contents()->render_view_host()),
@@ -645,6 +655,8 @@ void AutofillManager::OnDidFillAutofillFormData() {
metric_logger_->LogUserHappinessMetric(
AutofillMetrics::USER_DID_AUTOFILL_ONCE);
}
+
+ UpdateInitialInteractionTimestamp(timestamp);
}
void AutofillManager::OnDidShowAutofillSuggestions(bool is_new_popup) {
@@ -775,6 +787,8 @@ void AutofillManager::Reset() {
user_did_type_ = false;
user_did_autofill_ = false;
user_did_edit_autofilled_field_ = false;
+ forms_loaded_timestamp_ = TimeTicks();
+ initial_interaction_timestamp_ = TimeTicks();
}
AutofillManager::AutofillManager(TabContentsWrapper* tab_contents,
@@ -1151,3 +1165,11 @@ void AutofillManager::UnpackGUIDs(int id,
*cc_guid = IDToGUID(cc_id);
*profile_guid = IDToGUID(profile_id);
}
+
+void AutofillManager::UpdateInitialInteractionTimestamp(
+ const TimeTicks& interaction_timestamp) {
+ if (initial_interaction_timestamp_.is_null() ||
+ interaction_timestamp < initial_interaction_timestamp_) {
+ initial_interaction_timestamp_ = interaction_timestamp;
+ }
+}
diff --git a/chrome/browser/autofill/autofill_manager.h b/chrome/browser/autofill/autofill_manager.h
index d488a30..79dab88 100644
--- a/chrome/browser/autofill/autofill_manager.h
+++ b/chrome/browser/autofill/autofill_manager.h
@@ -17,6 +17,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/string16.h"
+#include "base/time.h"
#include "chrome/browser/autofill/autofill_download.h"
#include "chrome/browser/autofill/field_types.h"
#include "chrome/browser/autofill/form_structure.h"
@@ -113,10 +114,13 @@ class AutofillManager : public TabContentsObserver,
void UnpackGUIDs(int id, GUIDPair* cc_guid, GUIDPair* profile_guid);
private:
- void OnFormSubmitted(const webkit_glue::FormData& form);
- void OnFormsSeen(const std::vector<webkit_glue::FormData>& forms);
+ void OnFormSubmitted(const webkit_glue::FormData& form,
+ const base::TimeTicks& timestamp);
+ void OnFormsSeen(const std::vector<webkit_glue::FormData>& forms,
+ const base::TimeTicks& timestamp);
void OnTextFieldDidChange(const webkit_glue::FormData& form,
- const webkit_glue::FormField& field);
+ const webkit_glue::FormField& field,
+ const base::TimeTicks& timestamp);
void OnQueryFormFieldAutofill(int query_id,
const webkit_glue::FormData& form,
const webkit_glue::FormField& field);
@@ -126,7 +130,7 @@ class AutofillManager : public TabContentsObserver,
int unique_id);
void OnShowAutofillDialog();
void OnDidPreviewAutofillFormData();
- void OnDidFillAutofillFormData();
+ void OnDidFillAutofillFormData(const base::TimeTicks& timestamp);
void OnDidShowAutofillSuggestions(bool is_new_popup);
// Fills |host| with the RenderViewHost for this tab.
@@ -199,6 +203,12 @@ class AutofillManager : public TabContentsObserver,
// |submitted_form|.
void DeterminePossibleFieldTypesForUpload(FormStructure* submitted_form);
+ // If |initial_interaction_timestamp_| is unset or is set to a later time than
+ // |interaction_timestamp|, updates the cached timestamp. The latter check is
+ // needed because IPC messages can arrive out of order.
+ void UpdateInitialInteractionTimestamp(
+ const base::TimeTicks& interaction_timestamp);
+
// The owning TabContentsWrapper.
TabContentsWrapper* tab_contents_wrapper_;
@@ -233,6 +243,11 @@ class AutofillManager : public TabContentsObserver,
bool user_did_autofill_;
// Has the user edited a field that was previously autofilled?
bool user_did_edit_autofilled_field_;
+ // When the page finished loading.
+ base::TimeTicks forms_loaded_timestamp_;
+ // When the user first interacted with a potentially fillable form on this
+ // page.
+ base::TimeTicks initial_interaction_timestamp_;
// Our copy of the form data.
ScopedVector<FormStructure> form_structures_;
@@ -277,6 +292,7 @@ class AutofillManager : public TabContentsObserver,
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest,
UserHappinessFormLoadAndSubmission);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, UserHappinessFormInteraction);
+ FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, FormFillDuration);
DISALLOW_COPY_AND_ASSIGN(AutofillManager);
};
diff --git a/chrome/browser/autofill/autofill_manager_unittest.cc b/chrome/browser/autofill/autofill_manager_unittest.cc
index b850a41..8804aa7 100644
--- a/chrome/browser/autofill/autofill_manager_unittest.cc
+++ b/chrome/browser/autofill/autofill_manager_unittest.cc
@@ -10,6 +10,7 @@
#include "base/string16.h"
#include "base/string_number_conversions.h"
#include "base/stringprintf.h"
+#include "base/time.h"
#include "base/tuple.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete_history_manager.h"
@@ -512,11 +513,11 @@ class AutofillManagerTest : public TabContentsWrapperTestHarness {
}
void FormsSeen(const std::vector<webkit_glue::FormData>& forms) {
- autofill_manager_->OnFormsSeen(forms);
+ autofill_manager_->OnFormsSeen(forms, base::TimeTicks());
}
void FormSubmitted(const FormData& form) {
- autofill_manager_->OnFormSubmitted(form);
+ autofill_manager_->OnFormSubmitted(form, base::TimeTicks::Now());
}
void FillAutofillFormData(int query_id,
diff --git a/chrome/browser/autofill/autofill_metrics.cc b/chrome/browser/autofill/autofill_metrics.cc
index c3ad149..dae51a2 100644
--- a/chrome/browser/autofill/autofill_metrics.cc
+++ b/chrome/browser/autofill/autofill_metrics.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/metrics/histogram.h"
+#include "base/time.h"
#include "chrome/browser/autofill/autofill_type.h"
#include "chrome/browser/autofill/form_structure.h"
#include "webkit/glue/form_data.h"
@@ -298,6 +299,44 @@ void AutofillMetrics::LogUserHappinessMetric(UserHappinessMetric metric) const {
NUM_USER_HAPPINESS_METRICS);
}
+void AutofillMetrics::LogFormFillDurationFromLoadWithAutofill(
+ const base::TimeDelta& duration) const {
+ UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithAutofill",
+ duration,
+ base::TimeDelta::FromMilliseconds(100),
+ base::TimeDelta::FromMinutes(10),
+ 50);
+}
+
+void AutofillMetrics::LogFormFillDurationFromLoadWithoutAutofill(
+ const base::TimeDelta& duration) const {
+ UMA_HISTOGRAM_CUSTOM_TIMES("Autofill.FillDuration.FromLoad.WithoutAutofill",
+ duration,
+ base::TimeDelta::FromMilliseconds(100),
+ base::TimeDelta::FromMinutes(10),
+ 50);
+}
+
+void AutofillMetrics::LogFormFillDurationFromInteractionWithAutofill(
+ const base::TimeDelta& duration) const {
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "Autofill.FillDuration.FromInteraction.WithAutofill",
+ duration,
+ base::TimeDelta::FromMilliseconds(100),
+ base::TimeDelta::FromMinutes(10),
+ 50);
+}
+
+void AutofillMetrics::LogFormFillDurationFromInteractionWithoutAutofill(
+ const base::TimeDelta& duration) const {
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "Autofill.FillDuration.FromInteraction.WithoutAutofill",
+ duration,
+ base::TimeDelta::FromMilliseconds(100),
+ base::TimeDelta::FromMinutes(10),
+ 50);
+}
+
void AutofillMetrics::LogIsAutofillEnabledAtStartup(bool enabled) const {
UMA_HISTOGRAM_BOOLEAN("Autofill.IsEnabled.Startup", enabled);
}
diff --git a/chrome/browser/autofill/autofill_metrics.h b/chrome/browser/autofill/autofill_metrics.h
index 6e316e1..41d1351 100644
--- a/chrome/browser/autofill/autofill_metrics.h
+++ b/chrome/browser/autofill/autofill_metrics.h
@@ -12,6 +12,10 @@
#include "base/basictypes.h"
#include "chrome/browser/autofill/field_types.h"
+namespace base {
+class TimeDelta;
+}
+
class AutofillMetrics {
public:
enum InfoBarMetric {
@@ -116,10 +120,6 @@ class AutofillMetrics {
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();
virtual ~AutofillMetrics();
@@ -144,6 +144,28 @@ class AutofillMetrics {
virtual void LogUserHappinessMetric(UserHappinessMetric metric) const;
+ // This should be called when a form that has been Autofilled is submitted.
+ // |duration| should be the time elapsed between form load and submission.
+ virtual void LogFormFillDurationFromLoadWithAutofill(
+ const base::TimeDelta& duration) const;
+
+ // This should be called when a fillable form that has not been Autofilled is
+ // submitted. |duration| should be the time elapsed between form load and
+ // submission.
+ virtual void LogFormFillDurationFromLoadWithoutAutofill(
+ const base::TimeDelta& duration) const;
+
+ // This should be called when a form that has been Autofilled is submitted.
+ // |duration| should be the time elapsed between the initial form interaction
+ // and submission.
+ virtual void LogFormFillDurationFromInteractionWithAutofill(
+ const base::TimeDelta& duration) const;
+
+ // This should be called when a fillable form that has not been Autofilled is
+ // submitted. |duration| should be the time elapsed between the initial form
+ // interaction and submission.
+ virtual void LogFormFillDurationFromInteractionWithoutAutofill(
+ const base::TimeDelta& duration) const;
// This should be called each time a page containing forms is loaded.
virtual void LogIsAutofillEnabledAtPageLoad(bool enabled) const;
diff --git a/chrome/browser/autofill/autofill_metrics_unittest.cc b/chrome/browser/autofill/autofill_metrics_unittest.cc
index 76a953d..2015888 100644
--- a/chrome/browser/autofill/autofill_metrics_unittest.cc
+++ b/chrome/browser/autofill/autofill_metrics_unittest.cc
@@ -7,6 +7,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/string16.h"
+#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_cc_infobar_delegate.h"
#include "chrome/browser/autofill/autofill_common_test.h"
@@ -22,6 +23,11 @@
#include "webkit/glue/form_data.h"
#include "webkit/glue/form_field.h"
+using ::testing::_;
+using ::testing::AnyNumber;
+using ::testing::Mock;
+using base::TimeTicks;
+using base::TimeDelta;
using webkit_glue::FormData;
using webkit_glue::FormField;
@@ -47,6 +53,14 @@ class MockAutofillMetrics : public AutofillMetrics {
const std::string& experiment_id));
MOCK_CONST_METHOD1(LogServerQueryMetric, void(ServerQueryMetric metric));
MOCK_CONST_METHOD1(LogUserHappinessMetric, void(UserHappinessMetric metric));
+ MOCK_CONST_METHOD1(LogFormFillDurationFromLoadWithAutofill,
+ void(const TimeDelta& duration));
+ MOCK_CONST_METHOD1(LogFormFillDurationFromLoadWithoutAutofill,
+ void(const TimeDelta& duration));
+ MOCK_CONST_METHOD1(LogFormFillDurationFromInteractionWithAutofill,
+ void(const TimeDelta& duration));
+ MOCK_CONST_METHOD1(LogFormFillDurationFromInteractionWithoutAutofill,
+ void(const TimeDelta& duration));
MOCK_CONST_METHOD1(LogIsAutofillEnabledAtPageLoad, void(bool enabled));
MOCK_CONST_METHOD1(LogIsAutofillEnabledAtStartup, void(bool enabled));
MOCK_CONST_METHOD1(LogStoredProfileCount, void(size_t num_profiles));
@@ -169,9 +183,9 @@ class TestAutofillManager : public AutofillManager {
autofill_enabled_ = autofill_enabled;
}
- const MockAutofillMetrics* metric_logger() const {
- return static_cast<const MockAutofillMetrics*>(
- AutofillManager::metric_logger());
+ MockAutofillMetrics* metric_logger() {
+ return static_cast<MockAutofillMetrics*>(const_cast<AutofillMetrics*>(
+ AutofillManager::metric_logger()));
}
void AddSeenForm(const FormData& form,
@@ -395,7 +409,8 @@ TEST_F(AutofillMetricsTest, QualityMetrics) {
AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_SOME));
// Simulate form submission.
- EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form));
+ EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form,
+ TimeTicks::Now()));
}
// Test that we log the appropriate additional metrics when Autofill failed.
@@ -512,7 +527,8 @@ TEST_F(AutofillMetricsTest, QualityMetricsForFailure) {
}
// Simulate form submission.
- EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form));
+ EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form,
+ TimeTicks::Now()));
}
// Test that we behave sanely when the cached form differs from the submitted
@@ -669,7 +685,8 @@ TEST_F(AutofillMetricsTest, SaneMetricsWithCacheMismatch) {
std::string()));
// Simulate form submission.
- EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form));
+ EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form,
+ TimeTicks::Now()));
}
// Test that we don't log quality metrics for non-autofillable forms.
@@ -695,7 +712,8 @@ TEST_F(AutofillMetricsTest, NoQualityMetricsForNonAutofillableForms) {
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogQualityMetric(AutofillMetrics::FIELD_SUBMITTED,
std::string())).Times(0);
- EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form));
+ EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form,
+ TimeTicks::Now()));
// Search forms are not auto-fillable.
form.action = GURL("http://example.com/search?q=Elvis%20Presley");
@@ -707,7 +725,8 @@ TEST_F(AutofillMetricsTest, NoQualityMetricsForNonAutofillableForms) {
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogQualityMetric(AutofillMetrics::FIELD_SUBMITTED,
std::string())).Times(0);
- EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form));
+ EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form,
+ TimeTicks::Now()));
}
// Test that we recored the experiment id appropriately.
@@ -832,7 +851,8 @@ TEST_F(AutofillMetricsTest, QualityMetricsWithExperimentId) {
ADDRESS_HOME_COUNTRY, experiment_id));
// Simulate form submission.
- EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form));
+ EXPECT_NO_FATAL_FAILURE(autofill_manager_->OnFormSubmitted(form,
+ TimeTicks::Now()));
}
// Test that the profile count is logged correctly.
@@ -937,7 +957,7 @@ TEST_F(AutofillMetricsTest, AutofillIsEnabledAtPageLoad) {
LogIsAutofillEnabledAtPageLoad(true)).Times(1);
autofill_manager_->set_autofill_enabled(true);
- autofill_manager_->OnFormsSeen(std::vector<FormData>());
+ autofill_manager_->OnFormsSeen(std::vector<FormData>(), TimeTicks());
// Reset the autofill manager state.
autofill_manager_->Reset();
@@ -947,7 +967,7 @@ TEST_F(AutofillMetricsTest, AutofillIsEnabledAtPageLoad) {
LogIsAutofillEnabledAtPageLoad(false)).Times(1);
autofill_manager_->set_autofill_enabled(false);
- autofill_manager_->OnFormsSeen(std::vector<FormData>());
+ autofill_manager_->OnFormsSeen(std::vector<FormData>(), TimeTicks());
}
// Test that credit card infobar metrics are logged correctly.
@@ -1054,7 +1074,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) {
{
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED)).Times(0);
- autofill_manager_->OnFormsSeen(forms);
+ autofill_manager_->OnFormsSeen(forms, TimeTicks());
}
@@ -1076,7 +1096,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) {
*autofill_manager_->metric_logger(),
LogUserHappinessMetric(
AutofillMetrics::SUBMITTED_NON_FILLABLE_FORM)).Times(0);
- autofill_manager_->OnFormSubmitted(form);
+ autofill_manager_->OnFormSubmitted(form, TimeTicks::Now());
}
// Add more fields to the form.
@@ -1090,7 +1110,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) {
{
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED));
- autofill_manager_->OnFormsSeen(forms);
+ autofill_manager_->OnFormsSeen(forms, TimeTicks());
}
// Expect a notification when the form is submitted.
@@ -1098,7 +1118,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) {
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogUserHappinessMetric(
AutofillMetrics::SUBMITTED_NON_FILLABLE_FORM));
- autofill_manager_->OnFormSubmitted(form);
+ autofill_manager_->OnFormSubmitted(form, TimeTicks::Now());
}
// Fill in two of the fields.
@@ -1111,7 +1131,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) {
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogUserHappinessMetric(
AutofillMetrics::SUBMITTED_NON_FILLABLE_FORM));
- autofill_manager_->OnFormSubmitted(form);
+ autofill_manager_->OnFormSubmitted(form, TimeTicks::Now());
}
// Fill in the third field.
@@ -1123,7 +1143,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) {
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogUserHappinessMetric(
AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_NONE));
- autofill_manager_->OnFormSubmitted(form);
+ autofill_manager_->OnFormSubmitted(form, TimeTicks::Now());
}
@@ -1136,7 +1156,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) {
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogUserHappinessMetric(
AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_SOME));
- autofill_manager_->OnFormSubmitted(form);
+ autofill_manager_->OnFormSubmitted(form, TimeTicks::Now());
}
// Mark all of the fillable fields as autofilled.
@@ -1149,7 +1169,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) {
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogUserHappinessMetric(
AutofillMetrics::SUBMITTED_FILLABLE_FORM_AUTOFILLED_ALL));
- autofill_manager_->OnFormSubmitted(form);
+ autofill_manager_->OnFormSubmitted(form, TimeTicks::Now());
}
// Clear out the third field's value.
@@ -1161,7 +1181,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormLoadAndSubmission) {
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogUserHappinessMetric(
AutofillMetrics::SUBMITTED_NON_FILLABLE_FORM));
- autofill_manager_->OnFormSubmitted(form);
+ autofill_manager_->OnFormSubmitted(form, TimeTicks::Now());
}
}
@@ -1190,14 +1210,15 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) {
{
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogUserHappinessMetric(AutofillMetrics::FORMS_LOADED));
- autofill_manager_->OnFormsSeen(forms);
+ autofill_manager_->OnFormsSeen(forms, TimeTicks());
}
// Simulate typing.
{
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogUserHappinessMetric(AutofillMetrics::USER_DID_TYPE));
- autofill_manager_->OnTextFieldDidChange(form, form.fields.front());
+ autofill_manager_->OnTextFieldDidChange(form, form.fields.front(),
+ TimeTicks());
}
// Simulate suggestions shown twice for a single edit (i.e. multiple
@@ -1230,7 +1251,7 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) {
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogUserHappinessMetric(
AutofillMetrics::USER_DID_AUTOFILL_ONCE));
- autofill_manager_->OnDidFillAutofillFormData();
+ autofill_manager_->OnDidFillAutofillFormData(TimeTicks());
}
// Simulate editing an autofilled field.
@@ -1246,9 +1267,11 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) {
autofill_manager_->OnFillAutofillFormData(
0, form, form.fields.front(),
autofill_manager_->PackGUIDs(empty, guid));
- autofill_manager_->OnTextFieldDidChange(form, form.fields.front());
+ autofill_manager_->OnTextFieldDidChange(form, form.fields.front(),
+ TimeTicks());
// Simulate a second keystroke; make sure we don't log the metric twice.
- autofill_manager_->OnTextFieldDidChange(form, form.fields.front());
+ autofill_manager_->OnTextFieldDidChange(form, form.fields.front(),
+ TimeTicks());
}
// Simulate invoking autofill again.
@@ -1257,13 +1280,130 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction) {
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogUserHappinessMetric(
AutofillMetrics::USER_DID_AUTOFILL_ONCE)).Times(0);
- autofill_manager_->OnDidFillAutofillFormData();
+ autofill_manager_->OnDidFillAutofillFormData(TimeTicks());
// Simulate editing another autofilled field.
{
EXPECT_CALL(*autofill_manager_->metric_logger(),
LogUserHappinessMetric(
AutofillMetrics::USER_DID_EDIT_AUTOFILLED_FIELD));
- autofill_manager_->OnTextFieldDidChange(form, form.fields[1]);
+ autofill_manager_->OnTextFieldDidChange(form, form.fields[1], TimeTicks());
}
}
+
+// Verify that we correctly log metrics tracking the duration of form fill.
+TEST_F(AutofillMetricsTest, FormFillDuration) {
+ // Load a fillable form.
+ FormData form;
+ form.name = ASCIIToUTF16("TestForm");
+ form.method = ASCIIToUTF16("POST");
+ form.origin = GURL("http://example.com/form.html");
+ form.action = GURL("http://example.com/submit.html");
+ form.user_submitted = true;
+
+ FormField field;
+ autofill_test::CreateTestFormField("Name", "name", "", "text", &field);
+ form.fields.push_back(field);
+ autofill_test::CreateTestFormField("Email", "email", "", "text", &field);
+ form.fields.push_back(field);
+ autofill_test::CreateTestFormField("Phone", "phone", "", "text", &field);
+ form.fields.push_back(field);
+
+ std::vector<FormData> forms(1, form);
+
+ // Fill the field values for form submission.
+ form.fields[0].value = ASCIIToUTF16("Elvis Aaron Presley");
+ form.fields[1].value = ASCIIToUTF16("theking@gmail.com");
+ form.fields[2].value = ASCIIToUTF16("12345678901");
+
+ // Ignore any non-timing metrics.
+ // CAUTION: This is a global variable. So as to not affect other tests, this
+ // _must_ be restored to "warning" at the end of the test.
+ ::testing::FLAGS_gmock_verbose = "error";
+
+ // Expect only form load metrics to be logged if the form is submitted without
+ // user interaction.
+ {
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ LogFormFillDurationFromLoadWithAutofill(_)).Times(0);
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ LogFormFillDurationFromLoadWithoutAutofill(
+ TimeDelta::FromInternalValue(16)));
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ LogFormFillDurationFromInteractionWithAutofill(_)).Times(0);
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ LogFormFillDurationFromInteractionWithoutAutofill(_)).Times(0);
+ autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1));
+ autofill_manager_->OnFormSubmitted(form, TimeTicks::FromInternalValue(17));
+ autofill_manager_->Reset();
+ Mock::VerifyAndClearExpectations(autofill_manager_->metric_logger());
+ }
+
+ // Expect metric to be logged if the user manually edited a form field.
+ {
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ LogFormFillDurationFromLoadWithAutofill(_)).Times(0);
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ LogFormFillDurationFromLoadWithoutAutofill(
+ TimeDelta::FromInternalValue(16)));
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ LogFormFillDurationFromInteractionWithAutofill(_)).Times(0);
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ LogFormFillDurationFromInteractionWithoutAutofill(
+ TimeDelta::FromInternalValue(14)));
+ autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1));
+ autofill_manager_->OnTextFieldDidChange(form, form.fields.front(),
+ TimeTicks::FromInternalValue(3));
+ autofill_manager_->OnFormSubmitted(form, TimeTicks::FromInternalValue(17));
+ autofill_manager_->Reset();
+ Mock::VerifyAndClearExpectations(autofill_manager_->metric_logger());
+ }
+
+ // Expect metric to be logged if the user autofilled the form.
+ form.fields[0].is_autofilled = true;
+ {
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ LogFormFillDurationFromLoadWithAutofill(
+ TimeDelta::FromInternalValue(16)));
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ LogFormFillDurationFromLoadWithoutAutofill(_)).Times(0);
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ LogFormFillDurationFromInteractionWithAutofill(
+ TimeDelta::FromInternalValue(12)));
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ LogFormFillDurationFromInteractionWithoutAutofill(_)).Times(0);
+ autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1));
+ autofill_manager_->OnDidFillAutofillFormData(
+ TimeTicks::FromInternalValue(5));
+ autofill_manager_->OnFormSubmitted(form, TimeTicks::FromInternalValue(17));
+ autofill_manager_->Reset();
+ Mock::VerifyAndClearExpectations(autofill_manager_->metric_logger());
+ }
+
+ // Expect metric to be logged if the user both manually filled some fields
+ // and autofilled others. Messages can arrive out of order, so make sure they
+ // take precedence appropriately.
+ {
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ LogFormFillDurationFromLoadWithAutofill(
+ TimeDelta::FromInternalValue(16)));
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ LogFormFillDurationFromLoadWithoutAutofill(_)).Times(0);
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ LogFormFillDurationFromInteractionWithAutofill(
+ TimeDelta::FromInternalValue(14)));
+ EXPECT_CALL(*autofill_manager_->metric_logger(),
+ LogFormFillDurationFromInteractionWithoutAutofill(_)).Times(0);
+ autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1));
+ autofill_manager_->OnDidFillAutofillFormData(
+ TimeTicks::FromInternalValue(5));
+ autofill_manager_->OnTextFieldDidChange(form, form.fields.front(),
+ TimeTicks::FromInternalValue(3));
+ autofill_manager_->OnFormSubmitted(form, TimeTicks::FromInternalValue(17));
+ autofill_manager_->Reset();
+ Mock::VerifyAndClearExpectations(autofill_manager_->metric_logger());
+ }
+
+ // Restore the global Gmock verbosity level to its default value.
+ ::testing::FLAGS_gmock_verbose = "warning";
+}
diff --git a/chrome/browser/autofill/autofill_type.cc b/chrome/browser/autofill/autofill_type.cc
index b53d997..4ee6350 100644
--- a/chrome/browser/autofill/autofill_type.cc
+++ b/chrome/browser/autofill/autofill_type.cc
@@ -10,11 +10,15 @@
namespace {
+const AutofillType::AutofillTypeDefinition kUnknownAutofillTypeDefinition = {
+ /* UNKNOWN_TYPE */ AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP
+};
+
AutofillType::AutofillTypeDefinition kAutofillTypeDefinitions[] = {
// NO_SERVER_DATA
{ AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
// UNKNOWN_TYPE
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
+ kUnknownAutofillTypeDefinition,
// EMPTY_TYPE
{ AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
@@ -46,11 +50,11 @@ AutofillType::AutofillTypeDefinition kAutofillTypeDefinitions[] = {
{ AutofillType::PHONE_HOME, AutofillType::PHONE_WHOLE_NUMBER },
// Work phone numbers (values [15,19]) are deprecated.
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
+ kUnknownAutofillTypeDefinition,
+ kUnknownAutofillTypeDefinition,
+ kUnknownAutofillTypeDefinition,
+ kUnknownAutofillTypeDefinition,
+ kUnknownAutofillTypeDefinition,
// PHONE_FAX_NUMBER
{ AutofillType::PHONE_FAX, AutofillType::PHONE_NUMBER },
@@ -64,11 +68,11 @@ AutofillType::AutofillTypeDefinition kAutofillTypeDefinitions[] = {
{ AutofillType::PHONE_FAX, AutofillType::PHONE_WHOLE_NUMBER },
// Cell phone numbers (values [25, 29]) are deprecated.
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
+ kUnknownAutofillTypeDefinition,
+ kUnknownAutofillTypeDefinition,
+ kUnknownAutofillTypeDefinition,
+ kUnknownAutofillTypeDefinition,
+ kUnknownAutofillTypeDefinition,
// ADDRESS_HOME_LINE1
{ AutofillType::ADDRESS_HOME, AutofillType::ADDRESS_LINE1 },
@@ -101,13 +105,13 @@ AutofillType::AutofillTypeDefinition kAutofillTypeDefinitions[] = {
{ AutofillType::ADDRESS_BILLING, AutofillType::ADDRESS_COUNTRY },
// ADDRESS_SHIPPING values [44,50] are deprecated.
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
- { AutofillType::NO_GROUP, AutofillType::NO_SUBGROUP },
+ kUnknownAutofillTypeDefinition,
+ kUnknownAutofillTypeDefinition,
+ kUnknownAutofillTypeDefinition,
+ kUnknownAutofillTypeDefinition,
+ kUnknownAutofillTypeDefinition,
+ kUnknownAutofillTypeDefinition,
+ kUnknownAutofillTypeDefinition,
// CREDIT_CARD_NAME
{ AutofillType::CREDIT_CARD, AutofillType::NO_SUBGROUP },
diff --git a/chrome/browser/autofill/form_structure.cc b/chrome/browser/autofill/form_structure.cc
index 97e706d..90250bf 100644
--- a/chrome/browser/autofill/form_structure.cc
+++ b/chrome/browser/autofill/form_structure.cc
@@ -12,6 +12,7 @@
#include "base/stringprintf.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
+#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_metrics.h"
#include "chrome/browser/autofill/autofill_type.h"
@@ -646,7 +647,10 @@ void FormStructure::UpdateFromCache(const FormStructure& cached_form) {
}
void FormStructure::LogQualityMetrics(
- const AutofillMetrics& metric_logger) const {
+ const AutofillMetrics& metric_logger,
+ const base::TimeTicks& load_time,
+ const base::TimeTicks& interaction_time,
+ const base::TimeTicks& submission_time) const {
std::string experiment_id = server_experiment_id();
metric_logger.LogServerExperimentIdForUpload(experiment_id);
@@ -778,15 +782,46 @@ void FormStructure::LogQualityMetrics(
if (num_detected_field_types < kRequiredFillableFields) {
metric_logger.LogUserHappinessMetric(
AutofillMetrics::SUBMITTED_NON_FILLABLE_FORM);
- } else if (did_autofill_all_possible_fields) {
- 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);
+ if (did_autofill_all_possible_fields) {
+ 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);
+ }
+
+ // Unlike the other times, the |submission_time| should always be available.
+ DCHECK(!submission_time.is_null());
+
+ // The |load_time| might be unset, in the case that the form was dynamically
+ // added to the DOM.
+ if (!load_time.is_null()) {
+ // Submission should always chronologically follow form load.
+ DCHECK(submission_time > load_time);
+ base::TimeDelta elapsed = submission_time - load_time;
+ if (did_autofill_some_possible_fields)
+ metric_logger.LogFormFillDurationFromLoadWithAutofill(elapsed);
+ else
+ metric_logger.LogFormFillDurationFromLoadWithoutAutofill(elapsed);
+ }
+
+ // The |interaction_time| might be unset, in the case that the user
+ // submitted a blank form.
+ if (!interaction_time.is_null()) {
+ // Submission should always chronologically follow interaction.
+ DCHECK(submission_time > interaction_time);
+ base::TimeDelta elapsed = submission_time - interaction_time;
+ if (did_autofill_some_possible_fields) {
+ metric_logger.LogFormFillDurationFromInteractionWithAutofill(elapsed);
+ } else {
+ metric_logger.LogFormFillDurationFromInteractionWithoutAutofill(
+ elapsed);
+ }
+ }
}
}
diff --git a/chrome/browser/autofill/form_structure.h b/chrome/browser/autofill/form_structure.h
index 4f154d4..9824c36 100644
--- a/chrome/browser/autofill/form_structure.h
+++ b/chrome/browser/autofill/form_structure.h
@@ -30,6 +30,10 @@ enum UploadRequired {
class AutofillMetrics;
+namespace base {
+class TimeTicks;
+}
+
namespace buzz {
class XmlElement;
}
@@ -106,8 +110,13 @@ class FormStructure {
// Logs quality metrics for |this|, which should be a user-submitted form.
// This method should only be called after the possible field types have been
- // set for each field.
- void LogQualityMetrics(const AutofillMetrics& metric_logger) const;
+ // set for each field. |interaction_time| should be a timestamp corresponding
+ // to the user's first interaction with the form. |submission_time| should be
+ // a timestamp corresponding to the form's submission.
+ void LogQualityMetrics(const AutofillMetrics& metric_logger,
+ const base::TimeTicks& load_time,
+ const base::TimeTicks& interaction_time,
+ const base::TimeTicks& submission_time) const;
const AutofillField* field(size_t index) const;
AutofillField* field(size_t index);
diff --git a/chrome/common/autofill_messages.h b/chrome/common/autofill_messages.h
index 75cc2fb..213f081 100644
--- a/chrome/common/autofill_messages.h
+++ b/chrome/common/autofill_messages.h
@@ -6,8 +6,10 @@
#include <string>
+#include "base/time.h"
#include "content/common/webkit_param_traits.h"
#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_message_utils.h"
#include "webkit/glue/form_data.h"
#include "webkit/glue/form_data_predictions.h"
#include "webkit/glue/form_field.h"
@@ -90,8 +92,9 @@ IPC_MESSAGE_ROUTED1(
// Notification that forms have been seen that are candidates for
// filling/submitting by the AutofillManager.
-IPC_MESSAGE_ROUTED1(AutofillHostMsg_FormsSeen,
- std::vector<webkit_glue::FormData> /* forms */)
+IPC_MESSAGE_ROUTED2(AutofillHostMsg_FormsSeen,
+ std::vector<webkit_glue::FormData> /* forms */,
+ base::TimeTicks /* timestamp */)
// Notification that password forms have been seen that are candidates for
// filling/submitting by the password manager.
@@ -104,13 +107,15 @@ IPC_MESSAGE_ROUTED1(AutofillHostMsg_PasswordFormsVisible,
std::vector<webkit_glue::PasswordForm> /* forms */)
// Notification that a form has been submitted. The user hit the button.
-IPC_MESSAGE_ROUTED1(AutofillHostMsg_FormSubmitted,
- webkit_glue::FormData /* form */)
+IPC_MESSAGE_ROUTED2(AutofillHostMsg_FormSubmitted,
+ webkit_glue::FormData /* form */,
+ base::TimeTicks /* timestamp */)
// Notification that a form field's value has changed.
-IPC_MESSAGE_ROUTED2(AutofillHostMsg_TextFieldDidChange,
+IPC_MESSAGE_ROUTED3(AutofillHostMsg_TextFieldDidChange,
webkit_glue::FormData /* the form */,
- webkit_glue::FormField /* the form field */)
+ webkit_glue::FormField /* the form field */,
+ base::TimeTicks /* timestamp */)
// Queries the browser for Autofill suggestions for a form input field.
IPC_MESSAGE_ROUTED3(AutofillHostMsg_QueryFormFieldAutofill,
@@ -134,7 +139,8 @@ IPC_MESSAGE_ROUTED4(AutofillHostMsg_FillAutofillFormData,
IPC_MESSAGE_ROUTED0(AutofillHostMsg_DidPreviewAutofillFormData)
// Sent when a form is filled with Autofill suggestions.
-IPC_MESSAGE_ROUTED0(AutofillHostMsg_DidFillAutofillFormData)
+IPC_MESSAGE_ROUTED1(AutofillHostMsg_DidFillAutofillFormData,
+ base::TimeTicks /* timestamp */)
// Instructs the browser to remove the specified Autocomplete entry from the
// database.
diff --git a/chrome/renderer/autofill/autofill_agent.cc b/chrome/renderer/autofill/autofill_agent.cc
index 9b55fcc..98334d7 100644
--- a/chrome/renderer/autofill/autofill_agent.cc
+++ b/chrome/renderer/autofill/autofill_agent.cc
@@ -5,6 +5,7 @@
#include "chrome/renderer/autofill/autofill_agent.h"
#include "base/message_loop.h"
+#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/autofill_messages.h"
#include "chrome/common/chrome_constants.h"
@@ -79,8 +80,10 @@ void AutofillAgent::DidFinishDocumentLoad(WebFrame* frame) {
std::vector<webkit_glue::FormData> forms;
form_manager_.ExtractForms(frame, &forms);
- if (!forms.empty())
- Send(new AutofillHostMsg_FormsSeen(routing_id(), forms));
+ if (!forms.empty()) {
+ Send(new AutofillHostMsg_FormsSeen(routing_id(), forms,
+ base::TimeTicks::Now()));
+ }
}
void AutofillAgent::FrameDetached(WebFrame* frame) {
@@ -100,7 +103,8 @@ void AutofillAgent::WillSubmitForm(WebFrame* frame,
static_cast<FormManager::ExtractMask>(
FormManager::EXTRACT_VALUE | FormManager::EXTRACT_OPTION_TEXT),
&form_data)) {
- Send(new AutofillHostMsg_FormSubmitted(routing_id(), form_data));
+ Send(new AutofillHostMsg_FormSubmitted(routing_id(), form_data,
+ base::TimeTicks::Now()));
}
}
@@ -201,8 +205,10 @@ void AutofillAgent::TextFieldDidChangeImpl(const WebInputElement& element) {
webkit_glue::FormData form;
webkit_glue::FormField field;
- if (FindFormAndFieldForNode(element, &form, &field))
- Send(new AutofillHostMsg_TextFieldDidChange(routing_id(), form, field));
+ if (FindFormAndFieldForNode(element, &form, &field)) {
+ Send(new AutofillHostMsg_TextFieldDidChange(routing_id(), form, field,
+ base::TimeTicks::Now()));
+ }
}
void AutofillAgent::textFieldDidReceiveKeyDown(const WebInputElement& element,
@@ -311,7 +317,8 @@ void AutofillAgent::OnFormDataFilled(int query_id,
switch (autofill_action_) {
case AUTOFILL_FILL:
form_manager_.FillForm(form, autofill_query_element_);
- Send(new AutofillHostMsg_DidFillAutofillFormData(routing_id()));
+ Send(new AutofillHostMsg_DidFillAutofillFormData(routing_id(),
+ base::TimeTicks::Now()));
break;
case AUTOFILL_PREVIEW:
form_manager_.PreviewForm(form, autofill_query_element_);
diff --git a/chrome/renderer/autofill/form_autocomplete_browsertest.cc b/chrome/renderer/autofill/form_autocomplete_browsertest.cc
index 9d58e94..101b812 100644
--- a/chrome/renderer/autofill/form_autocomplete_browsertest.cc
+++ b/chrome/renderer/autofill/form_autocomplete_browsertest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/time.h"
#include "chrome/common/autofill_messages.h"
#include "chrome/test/base/render_view_test.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -35,7 +36,8 @@ TEST_F(FormAutocompleteTest, NormalFormSubmit) {
AutofillHostMsg_FormSubmitted::ID);
ASSERT_TRUE(message != NULL);
- Tuple1<FormData> forms;
+ // The tuple also includes a timestamp, which is ignored.
+ Tuple2<FormData, base::TimeTicks> forms;
AutofillHostMsg_FormSubmitted::Read(message, &forms);
ASSERT_EQ(2U, forms.a.fields.size());
@@ -83,7 +85,8 @@ TEST_F(FormAutocompleteTest, AutoCompleteOffInputSubmit) {
AutofillHostMsg_FormSubmitted::ID);
ASSERT_TRUE(message != NULL);
- Tuple1<FormData> forms;
+ // The tuple also includes a timestamp, which is ignored.
+ Tuple2<FormData, base::TimeTicks> forms;
AutofillHostMsg_FormSubmitted::Read(message, &forms);
ASSERT_EQ(1U, forms.a.fields.size());
diff --git a/ipc/ipc_message_utils.cc b/ipc/ipc_message_utils.cc
index 6ef03f4..dcbde0b 100644
--- a/ipc/ipc_message_utils.cc
+++ b/ipc/ipc_message_utils.cc
@@ -269,7 +269,7 @@ void ParamTraits<base::Time>::Log(const param_type& p, std::string* l) {
}
void ParamTraits<base::TimeDelta> ::Write(Message* m, const param_type& p) {
- ParamTraits<int64> ::Write(m, p.InMicroseconds());
+ ParamTraits<int64> ::Write(m, p.ToInternalValue());
}
bool ParamTraits<base::TimeDelta> ::Read(const Message* m,
@@ -278,13 +278,32 @@ bool ParamTraits<base::TimeDelta> ::Read(const Message* m,
int64 value;
bool ret = ParamTraits<int64> ::Read(m, iter, &value);
if (ret)
- *r = base::TimeDelta::FromMicroseconds(value);
+ *r = base::TimeDelta::FromInternalValue(value);
return ret;
}
void ParamTraits<base::TimeDelta> ::Log(const param_type& p, std::string* l) {
- ParamTraits<int64> ::Log(p.InMicroseconds(), l);
+ ParamTraits<int64> ::Log(p.ToInternalValue(), l);
+}
+
+void ParamTraits<base::TimeTicks> ::Write(Message* m, const param_type& p) {
+ ParamTraits<int64> ::Write(m, p.ToInternalValue());
+}
+
+bool ParamTraits<base::TimeTicks> ::Read(const Message* m,
+ void** iter,
+ param_type* r) {
+ int64 value;
+ bool ret = ParamTraits<int64> ::Read(m, iter, &value);
+ if (ret)
+ *r = base::TimeTicks::FromInternalValue(value);
+
+ return ret;
+}
+
+void ParamTraits<base::TimeTicks> ::Log(const param_type& p, std::string* l) {
+ ParamTraits<int64> ::Log(p.ToInternalValue(), l);
}
void ParamTraits<DictionaryValue>::Write(Message* m, const param_type& p) {
diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h
index e7bbe34..7c46f90 100644
--- a/ipc/ipc_message_utils.h
+++ b/ipc/ipc_message_utils.h
@@ -105,6 +105,7 @@ class DictionaryValue;
class ListValue;
class Time;
class TimeDelta;
+class TimeTicks;
struct FileDescriptor;
}
@@ -332,6 +333,14 @@ struct IPC_EXPORT ParamTraits<base::TimeDelta> {
static void Log(const param_type& p, std::string* l);
};
+template <>
+struct IPC_EXPORT ParamTraits<base::TimeTicks> {
+ typedef base::TimeTicks param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
#if defined(OS_WIN)
template <>
struct ParamTraits<LOGFONT> {