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