first_run_controller.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 20namespace { 21 22size_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. 26chromeos::FirstRunController* g_instance; 27 28void RecordCompletion(chromeos::first_run::TutorialCompletion type) { 29 UMA_HISTOGRAM_ENUMERATION("CrosFirstRun.TutorialCompletion", 30 type, 31 chromeos::first_run::kTutorialCompletionSize); 32} 33 34} // namespace 35 36namespace chromeos { 37 38FirstRunController::~FirstRunController() {} 39 40// static 41void 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 51void 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 61FirstRunController* FirstRunController::GetInstanceForTest() { 62 return g_instance; 63} 64 65FirstRunController::FirstRunController() 66 : actor_(NULL), 67 current_step_index_(NONE_STEP_INDEX), 68 user_profile_(NULL) { 69} 70 71void 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 92void 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 111void FirstRunController::OnActorInitialized() { 112 RegisterSteps(); 113 ShowNextStep(); 114} 115 116void FirstRunController::OnNextButtonClicked(const std::string& step_name) { 117 DCHECK(GetCurrentStep() && GetCurrentStep()->name() == step_name); 118 GetCurrentStep()->OnBeforeHide(); 119 actor_->HideCurrentStep(); 120} 121 122void 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 131void 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 138void FirstRunController::OnStepShown(const std::string& step_name) { 139 DCHECK(GetCurrentStep() && GetCurrentStep()->name() == step_name); 140} 141 142void FirstRunController::OnActorFinalized() { 143 if (!on_actor_finalized_.is_null()) 144 on_actor_finalized_.Run(); 145 Stop(); 146} 147 148void 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 155void FirstRunController::OnCancelled() { 156 RecordCompletion(first_run::kTutorialNotFinished); 157 Stop(); 158} 159 160void 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 169void FirstRunController::ShowNextStep() { 170 AdvanceStep(); 171 if (!GetCurrentStep()) { 172 actor_->Finalize(); 173 RecordCompletion(first_run::kTutorialCompletedWithGotIt); 174 return; 175 } 176 GetCurrentStep()->Show(); 177} 178 179void 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 188first_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