• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/users/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 
RecordCompletion(chromeos::first_run::TutorialCompletion type)28 void RecordCompletion(chromeos::first_run::TutorialCompletion type) {
29   UMA_HISTOGRAM_ENUMERATION("CrosFirstRun.TutorialCompletion",
30                             type,
31                             chromeos::first_run::TUTORIAL_COMPLETION_SIZE);
32 }
33 
34 }  // namespace
35 
36 namespace chromeos {
37 
~FirstRunController()38 FirstRunController::~FirstRunController() {}
39 
40 // static
Start()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
Stop()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 
GetInstanceForTest()61 FirstRunController* FirstRunController::GetInstanceForTest() {
62   return g_instance;
63 }
64 
FirstRunController()65 FirstRunController::FirstRunController()
66     : actor_(NULL),
67       current_step_index_(NONE_STEP_INDEX),
68       user_profile_(NULL) {
69 }
70 
Init()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 
Finalize()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 
OnActorInitialized()111 void FirstRunController::OnActorInitialized() {
112   RegisterSteps();
113   ShowNextStep();
114 }
115 
OnNextButtonClicked(const std::string & step_name)116 void FirstRunController::OnNextButtonClicked(const std::string& step_name) {
117   DCHECK(GetCurrentStep() && GetCurrentStep()->name() == step_name);
118   GetCurrentStep()->OnBeforeHide();
119   actor_->HideCurrentStep();
120 }
121 
OnHelpButtonClicked()122 void FirstRunController::OnHelpButtonClicked() {
123   RecordCompletion(first_run::TUTORIAL_COMPLETED_WITH_KEEP_EXPLORING);
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 
OnStepHidden(const std::string & step_name)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 
OnStepShown(const std::string & step_name)138 void FirstRunController::OnStepShown(const std::string& step_name) {
139   DCHECK(GetCurrentStep() && GetCurrentStep()->name() == step_name);
140 }
141 
OnActorFinalized()142 void FirstRunController::OnActorFinalized() {
143   if (!on_actor_finalized_.is_null())
144     on_actor_finalized_.Run();
145   Stop();
146 }
147 
OnActorDestroyed()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 
OnCancelled()155 void FirstRunController::OnCancelled() {
156   RecordCompletion(first_run::TUTORIAL_NOT_FINISHED);
157   Stop();
158 }
159 
RegisterSteps()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 
ShowNextStep()169 void FirstRunController::ShowNextStep() {
170   AdvanceStep();
171   if (!GetCurrentStep()) {
172     actor_->Finalize();
173     RecordCompletion(first_run::TUTORIAL_COMPLETED_WITH_GOT_IT);
174     return;
175   }
176   GetCurrentStep()->Show();
177 }
178 
AdvanceStep()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 
GetCurrentStep() const188 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