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