158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// found in the LICENSE file. 458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/chromeos/first_run/first_run_controller.h" 658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ash/shell.h" 858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/logging.h" 958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/message_loop/message_loop.h" 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/histogram.h" 1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/chromeos/first_run/first_run_view.h" 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/chromeos/first_run/metrics.h" 13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/chromeos/first_run/steps/app_list_step.h" 14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/chromeos/first_run/steps/help_step.h" 15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/chromeos/first_run/steps/tray_step.h" 16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/chromeos/profiles/profile_helper.h" 17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/chrome_pages.h" 186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "components/user_manager/user_manager.h" 1958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "ui/views/widget/widget.h" 2058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 2158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace { 2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)size_t NONE_STEP_INDEX = std::numeric_limits<size_t>::max(); 2458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Instance of currently running controller, or NULL if controller is not 26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// running now. 27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)chromeos::FirstRunController* g_instance; 2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void RecordCompletion(chromeos::first_run::TutorialCompletion type) { 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("CrosFirstRun.TutorialCompletion", 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) type, 32effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch chromeos::first_run::TUTORIAL_COMPLETION_SIZE); 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} // namespace 3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace chromeos { 3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)FirstRunController::~FirstRunController() {} 4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// static 42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void FirstRunController::Start() { 431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if !defined(USE_ATHENA) 441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // crbug.com/413914 45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (g_instance) { 46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) LOG(WARNING) << "First-run tutorial is running already."; 47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) g_instance = new FirstRunController(); 50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) g_instance->Init(); 511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif 5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// static 55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void FirstRunController::Stop() { 561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if !defined(USE_ATHENA) 57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!g_instance) { 58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) LOG(WARNING) << "First-run tutorial is not running."; 5958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) g_instance->Finalize(); 62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::MessageLoop::current()->DeleteSoon(FROM_HERE, g_instance); 63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) g_instance = NULL; 641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif 65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)FirstRunController* FirstRunController::GetInstanceForTest() { 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return g_instance; 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)FirstRunController::FirstRunController() 72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : actor_(NULL), 73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) current_step_index_(NONE_STEP_INDEX), 74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) user_profile_(NULL) { 75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void FirstRunController::Init() { 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) start_time_ = base::Time::Now(); 796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) user_manager::UserManager* user_manager = user_manager::UserManager::Get(); 806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) user_profile_ = ProfileHelper::Get()->GetProfileByUserUnsafe( 816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) user_manager->GetActiveUser()); 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) shell_helper_.reset(ash::Shell::GetInstance()->CreateFirstRunHelper()); 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) shell_helper_->AddObserver(this); 85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) FirstRunView* view = new FirstRunView(); 87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) view->Init(user_profile_); 88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) shell_helper_->GetOverlayWidget()->SetContentsView(view); 8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) actor_ = view->GetActor(); 9058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) actor_->set_delegate(this); 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) shell_helper_->GetOverlayWidget()->Show(); 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) view->RequestFocus(); 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) web_contents_for_tests_ = view->GetWebContents(); 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (actor_->IsInitialized()) 9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) OnActorInitialized(); 9758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void FirstRunController::Finalize() { 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int furthest_step = current_step_index_ == NONE_STEP_INDEX 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ? steps_.size() - 1 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : current_step_index_; 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("CrosFirstRun.FurthestStep", 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) furthest_step, 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) steps_.size()); 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UMA_HISTOGRAM_MEDIUM_TIMES("CrosFirstRun.TimeSpent", 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Time::Now() - start_time_); 108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (GetCurrentStep()) 109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) GetCurrentStep()->OnBeforeHide(); 110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) steps_.clear(); 11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (actor_) 11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) actor_->set_delegate(NULL); 11358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) actor_ = NULL; 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) shell_helper_->RemoveObserver(this); 115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) shell_helper_.reset(); 11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 11758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 11858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void FirstRunController::OnActorInitialized() { 119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) RegisterSteps(); 120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ShowNextStep(); 12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void FirstRunController::OnNextButtonClicked(const std::string& step_name) { 124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(GetCurrentStep() && GetCurrentStep()->name() == step_name); 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GetCurrentStep()->OnBeforeHide(); 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) actor_->HideCurrentStep(); 127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void FirstRunController::OnHelpButtonClicked() { 130effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch RecordCompletion(first_run::TUTORIAL_COMPLETED_WITH_KEEP_EXPLORING); 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) on_actor_finalized_ = base::Bind(chrome::ShowHelpForProfile, 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) user_profile_, 1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) chrome::HOST_DESKTOP_TYPE_ASH, 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) chrome::HELP_SOURCE_MENU); 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) actor_->Finalize(); 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FirstRunController::OnStepHidden(const std::string& step_name) { 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(GetCurrentStep() && GetCurrentStep()->name() == step_name); 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GetCurrentStep()->OnAfterHide(); 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!actor_->IsFinalizing()) 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ShowNextStep(); 143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FirstRunController::OnStepShown(const std::string& step_name) { 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(GetCurrentStep() && GetCurrentStep()->name() == step_name); 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FirstRunController::OnActorFinalized() { 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!on_actor_finalized_.is_null()) 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) on_actor_finalized_.Run(); 15258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) Stop(); 15358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 15458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 15558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void FirstRunController::OnActorDestroyed() { 156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Normally this shouldn't happen because we are implicitly controlling 157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // actor's lifetime. 158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) NOTREACHED() << 159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) "FirstRunActor destroyed before FirstRunController::Finalize."; 160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FirstRunController::OnCancelled() { 163effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch RecordCompletion(first_run::TUTORIAL_NOT_FINISHED); 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Stop(); 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void FirstRunController::RegisterSteps() { 168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) steps_.push_back(make_linked_ptr( 169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) new first_run::AppListStep(shell_helper_.get(), actor_))); 170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) steps_.push_back(make_linked_ptr( 171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) new first_run::TrayStep(shell_helper_.get(), actor_))); 172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) steps_.push_back(make_linked_ptr( 173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) new first_run::HelpStep(shell_helper_.get(), actor_))); 174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void FirstRunController::ShowNextStep() { 177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AdvanceStep(); 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!GetCurrentStep()) { 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) actor_->Finalize(); 180effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch RecordCompletion(first_run::TUTORIAL_COMPLETED_WITH_GOT_IT); 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GetCurrentStep()->Show(); 184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void FirstRunController::AdvanceStep() { 187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (current_step_index_ == NONE_STEP_INDEX) 188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) current_step_index_ = 0; 189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) else 190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ++current_step_index_; 191f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (current_step_index_ >= steps_.size()) 192f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) current_step_index_ = NONE_STEP_INDEX; 193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 195f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)first_run::Step* FirstRunController::GetCurrentStep() const { 196f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return current_step_index_ != NONE_STEP_INDEX ? 197f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) steps_[current_step_index_].get() : NULL; 19858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 19958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 20058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} // namespace chromeos 20158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 202