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 21 namespace { 22 23 size_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. 27 chromeos::FirstRunController* g_instance; 28 29 void 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 37 namespace chromeos { 38 39 FirstRunController::~FirstRunController() {} 40 41 // static 42 void 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 55 void 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 67 FirstRunController* FirstRunController::GetInstanceForTest() { 68 return g_instance; 69 } 70 71 FirstRunController::FirstRunController() 72 : actor_(NULL), 73 current_step_index_(NONE_STEP_INDEX), 74 user_profile_(NULL) { 75 } 76 77 void 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 99 void 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 118 void FirstRunController::OnActorInitialized() { 119 RegisterSteps(); 120 ShowNextStep(); 121 } 122 123 void FirstRunController::OnNextButtonClicked(const std::string& step_name) { 124 DCHECK(GetCurrentStep() && GetCurrentStep()->name() == step_name); 125 GetCurrentStep()->OnBeforeHide(); 126 actor_->HideCurrentStep(); 127 } 128 129 void 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 138 void 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 145 void FirstRunController::OnStepShown(const std::string& step_name) { 146 DCHECK(GetCurrentStep() && GetCurrentStep()->name() == step_name); 147 } 148 149 void FirstRunController::OnActorFinalized() { 150 if (!on_actor_finalized_.is_null()) 151 on_actor_finalized_.Run(); 152 Stop(); 153 } 154 155 void 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 162 void FirstRunController::OnCancelled() { 163 RecordCompletion(first_run::TUTORIAL_NOT_FINISHED); 164 Stop(); 165 } 166 167 void 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 176 void 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 186 void 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 195 first_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