Home | History | Annotate | Download | only in first_run
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/first_run/first_run_controller.h"
      6 
      7 #include "ash/shell.h"
      8 #include "base/logging.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/metrics/histogram.h"
     11 #include "chrome/browser/chromeos/first_run/first_run_view.h"
     12 #include "chrome/browser/chromeos/first_run/metrics.h"
     13 #include "chrome/browser/chromeos/first_run/steps/app_list_step.h"
     14 #include "chrome/browser/chromeos/first_run/steps/help_step.h"
     15 #include "chrome/browser/chromeos/first_run/steps/tray_step.h"
     16 #include "chrome/browser/chromeos/login/user_manager.h"
     17 #include "chrome/browser/ui/chrome_pages.h"
     18 #include "ui/views/widget/widget.h"
     19 
     20 namespace {
     21 
     22 size_t NONE_STEP_INDEX = std::numeric_limits<size_t>::max();
     23 
     24 // Instance of currently running controller, or NULL if controller is not
     25 // running now.
     26 chromeos::FirstRunController* g_instance;
     27 
     28 void RecordCompletion(chromeos::first_run::TutorialCompletion type) {
     29   UMA_HISTOGRAM_ENUMERATION("CrosFirstRun.TutorialCompletion",
     30                             type,
     31                             chromeos::first_run::kTutorialCompletionSize);
     32 }
     33 
     34 }  // namespace
     35 
     36 namespace chromeos {
     37 
     38 FirstRunController::~FirstRunController() {}
     39 
     40 // static
     41 void FirstRunController::Start() {
     42   if (g_instance) {
     43     LOG(WARNING) << "First-run tutorial is running already.";
     44     return;
     45   }
     46   g_instance = new FirstRunController();
     47   g_instance->Init();
     48 }
     49 
     50 // static
     51 void FirstRunController::Stop() {
     52   if (!g_instance) {
     53     LOG(WARNING) << "First-run tutorial is not running.";
     54     return;
     55   }
     56   g_instance->Finalize();
     57   base::MessageLoop::current()->DeleteSoon(FROM_HERE, g_instance);
     58   g_instance = NULL;
     59 }
     60 
     61 FirstRunController* FirstRunController::GetInstanceForTest() {
     62   return g_instance;
     63 }
     64 
     65 FirstRunController::FirstRunController()
     66     : actor_(NULL),
     67       current_step_index_(NONE_STEP_INDEX),
     68       user_profile_(NULL) {
     69 }
     70 
     71 void FirstRunController::Init() {
     72   start_time_ = base::Time::Now();
     73   UserManager* user_manager = UserManager::Get();
     74   user_profile_ = user_manager->GetProfileByUser(user_manager->GetActiveUser());
     75 
     76   shell_helper_.reset(ash::Shell::GetInstance()->CreateFirstRunHelper());
     77   shell_helper_->AddObserver(this);
     78 
     79   FirstRunView* view = new FirstRunView();
     80   view->Init(user_profile_);
     81   shell_helper_->GetOverlayWidget()->SetContentsView(view);
     82   actor_ = view->GetActor();
     83   actor_->set_delegate(this);
     84   shell_helper_->GetOverlayWidget()->Show();
     85   view->RequestFocus();
     86   web_contents_for_tests_ = view->GetWebContents();
     87 
     88   if (actor_->IsInitialized())
     89     OnActorInitialized();
     90 }
     91 
     92 void FirstRunController::Finalize() {
     93   int furthest_step = current_step_index_ == NONE_STEP_INDEX
     94                           ? steps_.size() - 1
     95                           : current_step_index_;
     96   UMA_HISTOGRAM_ENUMERATION("CrosFirstRun.FurthestStep",
     97                             furthest_step,
     98                             steps_.size());
     99   UMA_HISTOGRAM_MEDIUM_TIMES("CrosFirstRun.TimeSpent",
    100                              base::Time::Now() - start_time_);
    101   if (GetCurrentStep())
    102     GetCurrentStep()->OnBeforeHide();
    103   steps_.clear();
    104   if (actor_)
    105     actor_->set_delegate(NULL);
    106   actor_ = NULL;
    107   shell_helper_->RemoveObserver(this);
    108   shell_helper_.reset();
    109 }
    110 
    111 void FirstRunController::OnActorInitialized() {
    112   RegisterSteps();
    113   ShowNextStep();
    114 }
    115 
    116 void FirstRunController::OnNextButtonClicked(const std::string& step_name) {
    117   DCHECK(GetCurrentStep() && GetCurrentStep()->name() == step_name);
    118   GetCurrentStep()->OnBeforeHide();
    119   actor_->HideCurrentStep();
    120 }
    121 
    122 void FirstRunController::OnHelpButtonClicked() {
    123   RecordCompletion(first_run::kTutorialCompletedWithKeepExploring);
    124   on_actor_finalized_ = base::Bind(chrome::ShowHelpForProfile,
    125                                    user_profile_,
    126                                    chrome::HOST_DESKTOP_TYPE_ASH,
    127                                    chrome::HELP_SOURCE_MENU);
    128   actor_->Finalize();
    129 }
    130 
    131 void FirstRunController::OnStepHidden(const std::string& step_name) {
    132   DCHECK(GetCurrentStep() && GetCurrentStep()->name() == step_name);
    133   GetCurrentStep()->OnAfterHide();
    134   if (!actor_->IsFinalizing())
    135     ShowNextStep();
    136 }
    137 
    138 void FirstRunController::OnStepShown(const std::string& step_name) {
    139   DCHECK(GetCurrentStep() && GetCurrentStep()->name() == step_name);
    140 }
    141 
    142 void FirstRunController::OnActorFinalized() {
    143   if (!on_actor_finalized_.is_null())
    144     on_actor_finalized_.Run();
    145   Stop();
    146 }
    147 
    148 void FirstRunController::OnActorDestroyed() {
    149   // Normally this shouldn't happen because we are implicitly controlling
    150   // actor's lifetime.
    151   NOTREACHED() <<
    152     "FirstRunActor destroyed before FirstRunController::Finalize.";
    153 }
    154 
    155 void FirstRunController::OnCancelled() {
    156   RecordCompletion(first_run::kTutorialNotFinished);
    157   Stop();
    158 }
    159 
    160 void FirstRunController::RegisterSteps() {
    161   steps_.push_back(make_linked_ptr(
    162       new first_run::AppListStep(shell_helper_.get(), actor_)));
    163   steps_.push_back(make_linked_ptr(
    164       new first_run::TrayStep(shell_helper_.get(), actor_)));
    165   steps_.push_back(make_linked_ptr(
    166       new first_run::HelpStep(shell_helper_.get(), actor_)));
    167 }
    168 
    169 void FirstRunController::ShowNextStep() {
    170   AdvanceStep();
    171   if (!GetCurrentStep()) {
    172     actor_->Finalize();
    173     RecordCompletion(first_run::kTutorialCompletedWithGotIt);
    174     return;
    175   }
    176   GetCurrentStep()->Show();
    177 }
    178 
    179 void FirstRunController::AdvanceStep() {
    180   if (current_step_index_ == NONE_STEP_INDEX)
    181     current_step_index_ = 0;
    182   else
    183     ++current_step_index_;
    184   if (current_step_index_ >= steps_.size())
    185     current_step_index_ = NONE_STEP_INDEX;
    186 }
    187 
    188 first_run::Step* FirstRunController::GetCurrentStep() const {
    189   return current_step_index_ != NONE_STEP_INDEX ?
    190       steps_[current_step_index_].get() : NULL;
    191 }
    192 
    193 }  // namespace chromeos
    194 
    195