<commit_before>// 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/sync_promo_handler.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/metrics/histogram.h"
#include "base/time.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/sync_promo_trial.h"
#include "chrome/browser/ui/webui/sync_promo/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/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;
}

static void RecordExperimentOutcomesOnSignIn() {
  if (sync_promo_trial::IsExperimentActive())
    sync_promo_trial::RecordUserSignedIn();
  if (sync_promo_trial::IsPartOfBrandTrialToEnable())
    sync_promo_trial::RecordUserSignedInWithTrialBrand();
}

}  // namespace

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);
  prefs->RegisterBooleanPref(prefs::kSyncPromoShowNTPBubble, false,
      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,
        content::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,
        content::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:RecordSignInAttempts",
      base::Bind(&SyncPromoHandler::HandleRecordSignInAttempts,
                 base::Unretained(this)));
  web_ui_->RegisterMessageCallback("SyncPromo:RecordThrobberTime",
      base::Bind(&SyncPromoHandler::HandleRecordThrobberTime,
                 base::Unretained(this)));
  web_ui_->RegisterMessageCallback("SyncPromo:ShowAdvancedSettings",
      base::Bind(&SyncPromoHandler::HandleShowAdvancedSettings,
                 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();
}

void SyncPromoHandler::ShowGaiaSuccessAndClose() {
  RecordExperimentOutcomesOnSignIn();
  SyncSetupHandler::ShowGaiaSuccessAndClose();
}

void SyncPromoHandler::ShowGaiaSuccessAndSettingUp() {
  RecordExperimentOutcomesOnSignIn();
  SyncSetupHandler::ShowGaiaSuccessAndSettingUp();
}

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 content::NotificationSource& source,
                               const content::NotificationDetails& details) {
  switch (type) {
    case content::NOTIFICATION_TAB_CLOSING: {
      if (!window_already_closed_)
        RecordUserFlowAction(SYNC_PROMO_CLOSED_TAB);
      break;
    }
    case chrome::NOTIFICATION_BROWSER_CLOSING: {
      // Make sure we're in the tab strip of the closing window.
      Browser* browser = content::Source<Browser>(source).ptr();
      if (browser->tabstrip_model()->GetWrapperIndex(
              web_ui_->tab_contents()) != TabStripModel::kNoTab) {
        RecordUserFlowAction(SYNC_PROMO_CLOSED_WINDOW);
        window_already_closed_ = true;
      }
      break;
    }
    default: {
      NOTREACHED();
    }
  }
}

void SyncPromoHandler::StepWizardForShowSetupUI() {
  ProfileSyncService* service =
      Profile::FromWebUI(web_ui_)->GetProfileSyncService();
  service->get_wizard().Step(SyncSetupWizard::GetLoginState());
}

void SyncPromoHandler::ShowSetupUI() {
  // We don't need to do anything here; The UI for the sync promo is already
  // displayed.
}

void SyncPromoHandler::HandleCloseSyncPromo(const base::ListValue* args) {
  CloseSyncSetup();

  // If the user has signed in then set the pref to show them NTP bubble
  // confirming that they're signed in.
  std::string username = prefs_->GetString(prefs::kGoogleServicesUsername);
  if (!username.empty())<commit_msg>[Sync Promo] Set initial focus to email address when viewing chrome://syncpromo.<commit_after>// 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/sync_promo_handler.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/metrics/histogram.h"
#include "base/time.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/sync_promo_trial.h"
#include "chrome/browser/ui/webui/sync_promo/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/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;
}

static void RecordExperimentOutcomesOnSignIn() {
  if (sync_promo_trial::IsExperimentActive())
    sync_promo_trial::RecordUserSignedIn();
  if (sync_promo_trial::IsPartOfBrandTrialToEnable())
    sync_promo_trial::RecordUserSignedInWithTrialBrand();
}

}  // namespace

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);
  prefs->RegisterBooleanPref(prefs::kSyncPromoShowNTPBubble, false,
      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,
        content::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,
        content::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:RecordSignInAttempts",
      base::Bind(&SyncPromoHandler::HandleRecordSignInAttempts,
                 base::Unretained(this)));
  web_ui_->RegisterMessageCallback("SyncPromo:RecordThrobberTime",
      base::Bind(&SyncPromoHandler::HandleRecordThrobberTime,
                 base::Unretained(this)));
  web_ui_->RegisterMessageCallback("SyncPromo:ShowAdvancedSettings",
      base::Bind(&SyncPromoHandler::HandleShowAdvancedSettings,
                 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();
}

void SyncPromoHandler::ShowGaiaSuccessAndClose() {
  RecordExperimentOutcomesOnSignIn();
  SyncSetupHandler::ShowGaiaSuccessAndClose();
}

void SyncPromoHandler::ShowGaiaSuccessAndSettingUp() {
  RecordExperimentOutcomesOnSignIn();
  SyncSetupHandler::ShowGaiaSuccessAndSettingUp();
}

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 content::NotificationSource& source,
                               const content::NotificationDetails& details) {
  switch (type) {
    case content::NOTIFICATION_TAB_CLOSING: {
      if (!window_already_closed_)
        RecordUserFlowAction(SYNC_PROMO_CLOSED_TAB);
      break;
    }
    case chrome::NOTIFICATION_BROWSER_CLOSING: {
      // Make sure we're in the tab strip of the closing window.
      Browser* browser = content::Source<Browser>(source).ptr();
      if (browser->tabstrip_model()->GetWrapperIndex(
              web_ui_->tab_contents()) != TabStripModel::kNoTab) {
        RecordUserFlowAction(SYNC_PROMO_CLOSED_WINDOW);
        window_already_closed_ = true;
      }
      break;
    }
    default: {
      NOTREACHED();
    }
  }
}

void SyncPromoHandler::StepWizardForShowSetupUI() {
}

void SyncPromoHandler::ShowSetupUI() {
  // SyncSetupWizard::Step should be called in StepWizardForShowSetupUI above,
  // but it causes the sync promo page to not set focus properly to the login
  // email address. This happens because focus is lost between the call to
  // StepWizardForShowSetupUI and ShowSetupUI.
  // TODO(binji): Move this function back and fix the focus the right way.
  ProfileSyncService* service =
      Profile::FromWebUI(web_ui_)->GetProfileSyncService();
  service->get_wizard().Step(SyncSetupWizard::GetLoginState());
}

void SyncPromoHandler::HandleCloseSyncPromo(const base::ListValue* args) {
  CloseSyncSetup();

  // If the user has signed in then set the pref to show them NTP bubble
  // confirming that they're signed in.
  std::string username = prefs_->GetString(prefs::kGoogleServicesUsername);
  if (!username.empty())
{'fraction_non_alphanumeric': 0.1036999748301032, 'fraction_numerical': 0.0006292474200855776, 'mean_word_length': 4.800364963503649, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6268518', 'n_tokens_mistral': 5089, 'n_tokens_neox': 5015, 'n_words': 934}