blob: 1e836188fec2284bb080afec76e036d8ddfd53d1 [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/sync_promo_handler.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/metrics/histogram.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/sync_setup_flow.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/webui/sync_promo_ui.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/notification_details.h"
#include "content/common/notification_service.h"
SyncPromoHandler::SyncPromoHandler(ProfileManager* profile_manager)
: SyncSetupHandler(profile_manager),
window_already_closed_(false) {
}
SyncPromoHandler::~SyncPromoHandler() {
}
// static
void SyncPromoHandler::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterIntegerPref(prefs::kSyncPromoViewCount, 0,
PrefService::UNSYNCABLE_PREF);
}
WebUIMessageHandler* SyncPromoHandler::Attach(WebUI* web_ui) {
DCHECK(web_ui);
// Keep a reference to the preferences service for convenience and it's
// probably a little faster that getting it via Profile::FromWebUI() every
// time we need to interact with preferences.
prefs_ = Profile::FromWebUI(web_ui)->GetPrefs();
DCHECK(prefs_);
// Ignore events from view-source:chrome://syncpromo.
if (!web_ui->tab_contents()->controller().GetActiveEntry()->
IsViewSourceMode()) {
// Listen to see if the tab we're in gets closed.
registrar_.Add(this, content::NOTIFICATION_TAB_CLOSING,
Source<NavigationController>(&web_ui->tab_contents()->controller()));
// Listen to see if the window we're in gets closed.
registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSING,
NotificationService::AllSources());
}
return SyncSetupHandler::Attach(web_ui);
}
void SyncPromoHandler::RegisterMessages() {
web_ui_->RegisterMessageCallback("SyncPromo:Close",
base::Bind(&SyncPromoHandler::HandleCloseSyncPromo,
base::Unretained(this)));
web_ui_->RegisterMessageCallback("SyncPromo:Initialize",
base::Bind(&SyncPromoHandler::HandleInitializeSyncPromo,
base::Unretained(this)));
web_ui_->RegisterMessageCallback("SyncPromo:UserFlowAction",
base::Bind(&SyncPromoHandler::HandleUserFlowAction,
base::Unretained(this)));
web_ui_->RegisterMessageCallback("SyncPromo:ShowAdvancedSettings",
base::Bind(&SyncPromoHandler::HandleShowAdvancedSettings,
base::Unretained(this)));
SyncSetupHandler::RegisterMessages();
}
void SyncPromoHandler::ShowConfigure(const base::DictionaryValue& args) {
bool usePassphrase = false;
args.GetBoolean("usePassphrase", &usePassphrase);
if (usePassphrase) {
// If a passphrase is required then we must show the configure pane.
SyncSetupHandler::ShowConfigure(args);
} else {
// If no passphrase is required then skip the configure pane and sync
// everything by default. This makes the first run experience simpler.
// Note, there's an advanced link in the sync promo that takes users
// to Settings where the configure pane is not skipped.
SyncConfiguration configuration;
configuration.sync_everything = true;
DCHECK(flow());
flow()->OnUserConfigured(configuration);
}
}
void SyncPromoHandler::Observe(int type,
const NotificationSource& source,
const NotificationDetails& details) {
switch (type) {
case content::NOTIFICATION_TAB_CLOSING: {
if (!window_already_closed_)
RecordUserFlowAction(extension_misc::SYNC_PROMO_CLOSED_TAB);
break;
}
case chrome::NOTIFICATION_BROWSER_CLOSING: {
// Make sure we're in the tab strip of the closing window.
Browser* browser = Source<Browser>(source).ptr();
if (browser->tabstrip_model()->GetWrapperIndex(
web_ui_->tab_contents()) != TabStripModel::kNoTab) {
RecordUserFlowAction(extension_misc::SYNC_PROMO_CLOSED_WINDOW);
window_already_closed_ = true;
}
break;
}
default: {
NOTREACHED();
}
}
}
void SyncPromoHandler::ShowSetupUI() {
ProfileSyncService* service =
Profile::FromWebUI(web_ui_)->GetProfileSyncService();
service->get_wizard().Step(SyncSetupWizard::GetLoginState());
}
void SyncPromoHandler::HandleCloseSyncPromo(const base::ListValue* args) {
CloseSyncSetup();
// If there's no previous page on this tab then it means that the promo was
// displayed at startup. In this case we want to close the browser tab that
// the promo is in.
if (!web_ui_->tab_contents()->controller().CanGoBack()) {
Browser* browser =
BrowserList::FindBrowserWithTabContents(web_ui_->tab_contents());
browser->CloseTabContents(web_ui_->tab_contents());
} else {
web_ui_->tab_contents()->OpenURL(GURL(chrome::kChromeUINewTabURL),
GURL(), CURRENT_TAB,
content::PAGE_TRANSITION_LINK);
}
}
void SyncPromoHandler::HandleInitializeSyncPromo(const base::ListValue* args) {
OpenSyncSetup();
// We don't need to compute anything for this, just do this every time.
RecordUserFlowAction(extension_misc::SYNC_PROMO_VIEWED);
// 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).
IncrementViewCountBy(1);
// Record +1 for every view. This is the only thing we record that's not part
// of the user flow histogram.
UMA_HISTOGRAM_COUNTS("SyncPromo.NumTimesViewed", GetViewCount());
}
void SyncPromoHandler::HandleShowAdvancedSettings(
const base::ListValue* args) {
CloseSyncSetup();
std::string url(chrome::kChromeUISettingsURL);
url += chrome::kSyncSetupSubPage;
web_ui_->tab_contents()->OpenURL(GURL(url), GURL(), CURRENT_TAB,
content::PAGE_TRANSITION_LINK);
}
void SyncPromoHandler::HandleUserFlowAction(const base::ListValue* args) {
double action_double;
CHECK(args->GetDouble(0, &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) {
RecordUserFlowAction(action);
} else {
NOTREACHED() << "Attempt to record invalid user flow action on sync promo.";
}
if (action == extension_misc::SYNC_PROMO_SKIP_CLICKED)
SyncPromoUI::SetUserSkippedSyncPromo(Profile::FromWebUI(web_ui_));
}
int SyncPromoHandler::GetViewCount() const {
// The locally persistent number of times the user has seen the sync promo.
return prefs_->GetInteger(prefs::kSyncPromoViewCount);
}
int SyncPromoHandler::IncrementViewCountBy(unsigned int amount) {
// Let the user increment by 0 if they really want. It might be useful for a
// weird way of sending preference change notifications...
int adjusted = GetViewCount() + amount;
prefs_->SetInteger(prefs::kSyncPromoViewCount, adjusted);
return adjusted;
}
void SyncPromoHandler::RecordUserFlowAction(int action) {
// Send an enumeration to our single user flow histogram.
UMA_HISTOGRAM_ENUMERATION("SyncPromo.UserFlow", action,
extension_misc::SYNC_PROMO_BUCKET_BOUNDARY);
}