Commit 7a17c138 authored by dbeam@chromium.org's avatar dbeam@chromium.org

Sync Promo: Add more UMA metrics.

R=estade@chromium.org
BUG=103822
TEST=+1 action in SyncPromo.UserFlowAction and +2 new histograms.


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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@110354 0039d316-1c4b-4281-b951-d872f2087c98
parent ec014b55
...@@ -36,6 +36,7 @@ cr.define('sync_promo', function() { ...@@ -36,6 +36,7 @@ cr.define('sync_promo', function() {
CONFIRMED_AFTER_SIGN_IN: i++, CONFIRMED_AFTER_SIGN_IN: i++,
CLOSED_TAB: i++, CLOSED_TAB: i++,
CLOSED_WINDOW: i++, CLOSED_WINDOW: i++,
LEFT_DURING_THROBBER: i++,
}; };
}()); }());
...@@ -69,7 +70,7 @@ cr.define('sync_promo', function() { ...@@ -69,7 +70,7 @@ cr.define('sync_promo', function() {
var self = this; var self = this;
$('promo-skip-button').addEventListener('click', function() { $('promo-skip-button').addEventListener('click', function() {
chrome.send('SyncPromo:UserFlowAction', [actions.SKIP_CLICKED]); chrome.send('SyncPromo:UserSkipped');
self.closeOverlay_(); self.closeOverlay_();
}); });
...@@ -109,6 +110,7 @@ cr.define('sync_promo', function() { ...@@ -109,6 +110,7 @@ cr.define('sync_promo', function() {
// we also track users that use the keyboard and press enter. // we also track users that use the keyboard and press enter.
var signInAttemptedAlready = false; var signInAttemptedAlready = false;
$('gaia-login-form').addEventListener('submit', function() { $('gaia-login-form').addEventListener('submit', function() {
++self.signInAttempts_;
if (!signInAttemptedAlready) if (!signInAttemptedAlready)
chrome.send('SyncPromo:UserFlowAction', [actions.SIGN_IN_ATTEMPTED]); chrome.send('SyncPromo:UserFlowAction', [actions.SIGN_IN_ATTEMPTED]);
signInAttemptedAlready = true; signInAttemptedAlready = true;
...@@ -146,6 +148,17 @@ cr.define('sync_promo', function() { ...@@ -146,6 +148,17 @@ cr.define('sync_promo', function() {
this.toggleHidden_.bind(this)); this.toggleHidden_.bind(this));
}, },
/**
* Called when the page is unloading to record number of times a user tried
* to sign in and if they left while a throbber was running.
* @private
*/
recordPageViewActions_: function() {
chrome.send('SyncPromo:RecordSignInAttempts', [this.signInAttempts_]);
if (this.throbberStart_)
chrome.send('SyncPromo:UserFlowAction', [actions.LEFT_DURING_THROBBER]);
},
/** /**
* Remove the [hidden] attribute from the node that was not previously * Remove the [hidden] attribute from the node that was not previously
* transitioning. * transitioning.
...@@ -193,7 +206,36 @@ cr.define('sync_promo', function() { ...@@ -193,7 +206,36 @@ cr.define('sync_promo', function() {
*/ */
setPromoTitleVisible_: function(visible) { setPromoTitleVisible_: function(visible) {
$('promo-title').hidden = !visible; $('promo-title').hidden = !visible;
} },
/** @inheritDoc */
setThrobbersVisible_: function(visible) {
if (visible) {
this.throbberStart_ = Date.now();
} else {
if (this.throbberStart_) {
chrome.send('SyncPromo:RecordThrobberTime',
[Date.now() - this.throbberStart_]);
}
this.throbberStart_ = 0;
}
// Pass through to SyncSetupOverlay to handle display logic.
options.SyncSetupOverlay.prototype.setThrobbersVisible_.apply(
this, arguments);
},
/**
* Number of times a user attempted to sign in to GAIA during this page
* view.
* @private
*/
signInAttempts_: 0,
/**
* The start time of a throbber on the page.
* @private
*/
throbberStart_: 0,
}; };
SyncPromo.showErrorUI = function() { SyncPromo.showErrorUI = function() {
...@@ -227,14 +269,20 @@ cr.define('sync_promo', function() { ...@@ -227,14 +269,20 @@ cr.define('sync_promo', function() {
SyncPromo.setPromoTitleVisible = function(visible) { SyncPromo.setPromoTitleVisible = function(visible) {
SyncPromo.getInstance().setPromoTitleVisible_(visible); SyncPromo.getInstance().setPromoTitleVisible_(visible);
} };
SyncPromo.recordPageViewActions = function() {
SyncPromo.getInstance().recordPageViewActions_();
};
// Export // Export
return { return {
SyncPromo : SyncPromo SyncPromo: SyncPromo
}; };
}); });
var OptionsPage = options.OptionsPage; var OptionsPage = options.OptionsPage;
var SyncSetupOverlay = sync_promo.SyncPromo; var SyncSetupOverlay = sync_promo.SyncPromo;
window.addEventListener('DOMContentLoaded', sync_promo.SyncPromo.initialize); window.addEventListener('DOMContentLoaded', sync_promo.SyncPromo.initialize);
window.addEventListener('beforeunload',
sync_promo.SyncPromo.recordPageViewActions.bind(sync_promo.SyncPromo));
...@@ -538,10 +538,15 @@ cr.define('options', function() { ...@@ -538,10 +538,15 @@ cr.define('options', function() {
this.showOverlay_(); this.showOverlay_();
}, },
/**
* Changes the visibility of throbbers on this page.
* @param {boolean} visible Whether or not to set all throbber nodes
* visible.
*/
setThrobbersVisible_: function(visible) { setThrobbersVisible_: function(visible) {
var throbbers = document.getElementsByClassName("throbber"); var throbbers = document.getElementsByClassName("throbber");
for (var i = 0; i < throbbers.length; i++) for (var i = 0; i < throbbers.length; i++)
throbbers[i].style.visibility = visible ? "visible" : "hidden"; throbbers[i].style.visibility = visible ? "visible" : "hidden";
}, },
loginSetFocus_: function() { loginSetFocus_: function() {
...@@ -771,7 +776,7 @@ cr.define('options', function() { ...@@ -771,7 +776,7 @@ cr.define('options', function() {
$('captcha-value').disabled = true; $('captcha-value').disabled = true;
$('access-code').disabled = true; $('access-code').disabled = true;
$('logging-in-throbber').style.visibility = "visible"; this.setThrobbersVisible_(true);
var f = $('gaia-login-form'); var f = $('gaia-login-form');
var email = $('gaia-email'); var email = $('gaia-email');
......
...@@ -33,6 +33,8 @@ class MetricsHandler : public WebUIMessageHandler { ...@@ -33,6 +33,8 @@ class MetricsHandler : public WebUIMessageHandler {
// user action. // user action.
void HandleRecordAction(const base::ListValue* args); void HandleRecordAction(const base::ListValue* args);
// TODO(dbeam): http://crbug.com/104338
// Callback for the "metricsHandler:recordInHistogram" message. This records // Callback for the "metricsHandler:recordInHistogram" message. This records
// into a histogram. |args| contains the histogram name, the value to record, // into a histogram. |args| contains the histogram name, the value to record,
// and the maximum allowed value, which can be at most 4000. The histogram // and the maximum allowed value, which can be at most 4000. The histogram
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/bind_helpers.h" #include "base/bind_helpers.h"
#include "base/metrics/histogram.h" #include "base/metrics/histogram.h"
#include "base/time.h"
#include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/profile_sync_service.h" #include "chrome/browser/sync/profile_sync_service.h"
...@@ -20,8 +21,42 @@ ...@@ -20,8 +21,42 @@
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h" #include "chrome/common/url_constants.h"
#include "content/browser/tab_contents/tab_contents.h" #include "content/browser/tab_contents/tab_contents.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_details.h" #include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
namespace {
// User actions on the sync promo (aka "Sign in to Chrome").
enum SyncPromoUserFlowActionEnums {
SYNC_PROMO_VIEWED,
SYNC_PROMO_LEARN_MORE_CLICKED,
SYNC_PROMO_ACCOUNT_HELP_CLICKED,
SYNC_PROMO_CREATE_ACCOUNT_CLICKED,
SYNC_PROMO_SKIP_CLICKED,
SYNC_PROMO_SIGN_IN_ATTEMPTED,
SYNC_PROMO_SIGNED_IN_SUCCESSFULLY,
SYNC_PROMO_ADVANCED_CLICKED,
SYNC_PROMO_ENCRYPTION_HELP_CLICKED,
SYNC_PROMO_CANCELLED_AFTER_SIGN_IN,
SYNC_PROMO_CONFIRMED_AFTER_SIGN_IN,
SYNC_PROMO_CLOSED_TAB,
SYNC_PROMO_CLOSED_WINDOW,
SYNC_PROMO_LEFT_DURING_THROBBER,
SYNC_PROMO_BUCKET_BOUNDARY,
SYNC_PROMO_FIRST_VALID_JS_ACTION = SYNC_PROMO_LEARN_MORE_CLICKED,
SYNC_PROMO_LAST_VALID_JS_ACTION = SYNC_PROMO_CONFIRMED_AFTER_SIGN_IN,
};
// This was added because of the need to change the existing UMA enum for the
// sync promo mid-flight. Ideally these values would be contiguous, but the
// real world is not always ideal.
static bool IsValidUserFlowAction(int action) {
return (action >= SYNC_PROMO_FIRST_VALID_JS_ACTION &&
action <= SYNC_PROMO_LAST_VALID_JS_ACTION) ||
action == SYNC_PROMO_LEFT_DURING_THROBBER;
}
} // namespace
SyncPromoHandler::SyncPromoHandler(ProfileManager* profile_manager) SyncPromoHandler::SyncPromoHandler(ProfileManager* profile_manager)
: SyncSetupHandler(profile_manager), : SyncSetupHandler(profile_manager),
...@@ -67,12 +102,21 @@ void SyncPromoHandler::RegisterMessages() { ...@@ -67,12 +102,21 @@ void SyncPromoHandler::RegisterMessages() {
web_ui_->RegisterMessageCallback("SyncPromo:Initialize", web_ui_->RegisterMessageCallback("SyncPromo:Initialize",
base::Bind(&SyncPromoHandler::HandleInitializeSyncPromo, base::Bind(&SyncPromoHandler::HandleInitializeSyncPromo,
base::Unretained(this))); base::Unretained(this)));
web_ui_->RegisterMessageCallback("SyncPromo:UserFlowAction", web_ui_->RegisterMessageCallback("SyncPromo:RecordSignInAttempts",
base::Bind(&SyncPromoHandler::HandleUserFlowAction, base::Bind(&SyncPromoHandler::HandleRecordSignInAttempts,
base::Unretained(this)));
web_ui_->RegisterMessageCallback("SyncPromo:RecordThrobberTime",
base::Bind(&SyncPromoHandler::HandleRecordThrobberTime,
base::Unretained(this))); base::Unretained(this)));
web_ui_->RegisterMessageCallback("SyncPromo:ShowAdvancedSettings", web_ui_->RegisterMessageCallback("SyncPromo:ShowAdvancedSettings",
base::Bind(&SyncPromoHandler::HandleShowAdvancedSettings, base::Bind(&SyncPromoHandler::HandleShowAdvancedSettings,
base::Unretained(this))); base::Unretained(this)));
web_ui_->RegisterMessageCallback("SyncPromo:UserFlowAction",
base::Bind(&SyncPromoHandler::HandleUserFlowAction,
base::Unretained(this)));
web_ui_->RegisterMessageCallback("SyncPromo:UserSkipped",
base::Bind(&SyncPromoHandler::HandleUserSkipped,
base::Unretained(this)));
SyncSetupHandler::RegisterMessages(); SyncSetupHandler::RegisterMessages();
} }
...@@ -101,7 +145,7 @@ void SyncPromoHandler::Observe(int type, ...@@ -101,7 +145,7 @@ void SyncPromoHandler::Observe(int type,
switch (type) { switch (type) {
case content::NOTIFICATION_TAB_CLOSING: { case content::NOTIFICATION_TAB_CLOSING: {
if (!window_already_closed_) if (!window_already_closed_)
RecordUserFlowAction(extension_misc::SYNC_PROMO_CLOSED_TAB); RecordUserFlowAction(SYNC_PROMO_CLOSED_TAB);
break; break;
} }
case chrome::NOTIFICATION_BROWSER_CLOSING: { case chrome::NOTIFICATION_BROWSER_CLOSING: {
...@@ -109,7 +153,7 @@ void SyncPromoHandler::Observe(int type, ...@@ -109,7 +153,7 @@ void SyncPromoHandler::Observe(int type,
Browser* browser = content::Source<Browser>(source).ptr(); Browser* browser = content::Source<Browser>(source).ptr();
if (browser->tabstrip_model()->GetWrapperIndex( if (browser->tabstrip_model()->GetWrapperIndex(
web_ui_->tab_contents()) != TabStripModel::kNoTab) { web_ui_->tab_contents()) != TabStripModel::kNoTab) {
RecordUserFlowAction(extension_misc::SYNC_PROMO_CLOSED_WINDOW); RecordUserFlowAction(SYNC_PROMO_CLOSED_WINDOW);
window_already_closed_ = true; window_already_closed_ = true;
} }
break; break;
...@@ -149,7 +193,7 @@ void SyncPromoHandler::HandleInitializeSyncPromo(const base::ListValue* args) { ...@@ -149,7 +193,7 @@ void SyncPromoHandler::HandleInitializeSyncPromo(const base::ListValue* args) {
OpenSyncSetup(); OpenSyncSetup();
// We don't need to compute anything for this, just do this every time. // We don't need to compute anything for this, just do this every time.
RecordUserFlowAction(extension_misc::SYNC_PROMO_VIEWED); RecordUserFlowAction(SYNC_PROMO_VIEWED);
// Increment view count first and show natural numbers in stats rather than 0 // Increment view count first and show natural numbers in stats rather than 0
// based starting point (if it happened to be our first time showing this). // based starting point (if it happened to be our first time showing this).
IncrementViewCountBy(1); IncrementViewCountBy(1);
...@@ -165,22 +209,38 @@ void SyncPromoHandler::HandleShowAdvancedSettings( ...@@ -165,22 +209,38 @@ void SyncPromoHandler::HandleShowAdvancedSettings(
url += chrome::kSyncSetupSubPage; url += chrome::kSyncSetupSubPage;
web_ui_->tab_contents()->OpenURL(GURL(url), GURL(), CURRENT_TAB, web_ui_->tab_contents()->OpenURL(GURL(url), GURL(), CURRENT_TAB,
content::PAGE_TRANSITION_LINK); content::PAGE_TRANSITION_LINK);
RecordUserFlowAction(extension_misc::SYNC_PROMO_ADVANCED_CLICKED); RecordUserFlowAction(SYNC_PROMO_ADVANCED_CLICKED);
}
// TODO(dbeam): Replace with metricsHandler:recordHistogramTime when it exists.
void SyncPromoHandler::HandleRecordThrobberTime(const base::ListValue* args) {
double time_double;
CHECK(args->GetDouble(0, &time_double));
UMA_HISTOGRAM_TIMES("SyncPromo.ThrobberTime",
base::TimeDelta::FromMilliseconds(time_double));
}
// TODO(dbeam): Replace with metricsHandler:recordHistogramCount when it exists.
void SyncPromoHandler::HandleRecordSignInAttempts(const base::ListValue* args) {
double count_double;
CHECK(args->GetDouble(0, &count_double));
UMA_HISTOGRAM_COUNTS("SyncPromo.SignInAttempts", count_double);
} }
void SyncPromoHandler::HandleUserFlowAction(const base::ListValue* args) { void SyncPromoHandler::HandleUserFlowAction(const base::ListValue* args) {
double action_double; double action_double;
CHECK(args->GetDouble(0, &action_double)); CHECK(args->GetDouble(0, &action_double));
int action = static_cast<int>(action_double); int action = static_cast<int>(action_double);
if (action >= extension_misc::SYNC_PROMO_FIRST_VALID_JS_ACTION &&
action <= extension_misc::SYNC_PROMO_LAST_VALID_JS_ACTION) { if (IsValidUserFlowAction(action))
RecordUserFlowAction(action); RecordUserFlowAction(action);
} else { else
NOTREACHED() << "Attempt to record invalid user flow action on sync promo."; NOTREACHED() << "Attempt to record invalid user flow action on sync promo.";
} }
if (action == extension_misc::SYNC_PROMO_SKIP_CLICKED) void SyncPromoHandler::HandleUserSkipped(const base::ListValue* args) {
SyncPromoUI::SetUserSkippedSyncPromo(Profile::FromWebUI(web_ui_)); SyncPromoUI::SetUserSkippedSyncPromo(Profile::FromWebUI(web_ui_));
RecordUserFlowAction(SYNC_PROMO_SKIP_CLICKED);
} }
int SyncPromoHandler::GetViewCount() const { int SyncPromoHandler::GetViewCount() const {
...@@ -199,5 +259,5 @@ int SyncPromoHandler::IncrementViewCountBy(unsigned int amount) { ...@@ -199,5 +259,5 @@ int SyncPromoHandler::IncrementViewCountBy(unsigned int amount) {
void SyncPromoHandler::RecordUserFlowAction(int action) { void SyncPromoHandler::RecordUserFlowAction(int action) {
// Send an enumeration to our single user flow histogram. // Send an enumeration to our single user flow histogram.
UMA_HISTOGRAM_ENUMERATION("SyncPromo.UserFlow", action, UMA_HISTOGRAM_ENUMERATION("SyncPromo.UserFlow", action,
extension_misc::SYNC_PROMO_BUCKET_BOUNDARY); SYNC_PROMO_BUCKET_BOUNDARY);
} }
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
class PrefService; class PrefService;
// The handler for Javascript messages related to the "sync promo" page. // The handler for JavaScript messages related to the "sync promo" page.
class SyncPromoHandler : public SyncSetupHandler { class SyncPromoHandler : public SyncSetupHandler {
public: public:
explicit SyncPromoHandler(ProfileManager* profile_manager); explicit SyncPromoHandler(ProfileManager* profile_manager);
...@@ -36,19 +36,30 @@ class SyncPromoHandler : public SyncSetupHandler { ...@@ -36,19 +36,30 @@ class SyncPromoHandler : public SyncSetupHandler {
virtual void ShowSetupUI() OVERRIDE; virtual void ShowSetupUI() OVERRIDE;
private: private:
// Javascript callback handler to close the sync promo. // JavaScript callback handler to close the sync promo.
void HandleCloseSyncPromo(const base::ListValue* args); void HandleCloseSyncPromo(const base::ListValue* args);
// Javascript callback handler to initialize the sync promo. // JavaScript callback handler to initialize the sync promo.
void HandleInitializeSyncPromo(const base::ListValue* args); void HandleInitializeSyncPromo(const base::ListValue* args);
// Javascript callback handler to switch the advanced sync settings. |args| is // JavaScript handler to record the duration for which the throbber was
// visible during an attempted sign-in flow.
void HandleRecordThrobberTime(const base::ListValue* args);
// JavaScript handler to record the number of times a user attempted to sign
// in to chrome while they were on the sync promo page.
void HandleRecordSignInAttempts(const base::ListValue* args);
// JavaScript callback handler to switch the advanced sync settings. |args| is
// the list of arguments passed from JS and should be an empty list. // the list of arguments passed from JS and should be an empty list.
void HandleShowAdvancedSettings(const base::ListValue* args); void HandleShowAdvancedSettings(const base::ListValue* args);
// Javascript callback handler to record user actions on the sync promo. // JavaScript callback handler to record user actions on the sync promo.
void HandleUserFlowAction(const base::ListValue* args); void HandleUserFlowAction(const base::ListValue* args);
// JavaScript callback handler for when a user clicks skip.
void HandleUserSkipped(const base::ListValue* args);
// Return the number of times the user with the current profile has seen the // Return the number of times the user with the current profile has seen the
// sync promo. // sync promo.
int GetViewCount() const; int GetViewCount() const;
......
...@@ -453,26 +453,6 @@ namespace extension_misc { ...@@ -453,26 +453,6 @@ namespace extension_misc {
UNLOAD_REASON_UNINSTALL, // Extension is being uninstalled. UNLOAD_REASON_UNINSTALL, // Extension is being uninstalled.
UNLOAD_REASON_TERMINATE, // Extension has terminated. UNLOAD_REASON_TERMINATE, // Extension has terminated.
}; };
} // extension_misc
// User actions on the sync promo (aka "Sign in to Chrome").
enum SyncPromoBuckets {
SYNC_PROMO_VIEWED,
SYNC_PROMO_LEARN_MORE_CLICKED,
SYNC_PROMO_ACCOUNT_HELP_CLICKED,
SYNC_PROMO_CREATE_ACCOUNT_CLICKED,
SYNC_PROMO_SKIP_CLICKED,
SYNC_PROMO_SIGN_IN_ATTEMPTED,
SYNC_PROMO_SIGNED_IN_SUCCESSFULLY,
SYNC_PROMO_ADVANCED_CLICKED,
SYNC_PROMO_ENCRYPTION_HELP_CLICKED,
SYNC_PROMO_CANCELLED_AFTER_SIGN_IN,
SYNC_PROMO_CONFIRMED_AFTER_SIGN_IN,
SYNC_PROMO_CLOSED_TAB,
SYNC_PROMO_CLOSED_WINDOW,
SYNC_PROMO_BUCKET_BOUNDARY,
SYNC_PROMO_FIRST_VALID_JS_ACTION = SYNC_PROMO_LEARN_MORE_CLICKED,
SYNC_PROMO_LAST_VALID_JS_ACTION = SYNC_PROMO_CONFIRMED_AFTER_SIGN_IN,
};
} // extension_misc
#endif // CHROME_COMMON_EXTENSIONS_EXTENSION_CONSTANTS_H_ #endif // CHROME_COMMON_EXTENSIONS_EXTENSION_CONSTANTS_H_
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