startup_app_launcher.cc revision a36e5920737c6adbddd3e43b760e5de8431db6e0
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/app_mode/startup_app_launcher.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/shell.h"
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/command_line.h"
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/files/file_path.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/json/json_file_value_serializer.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/path_service.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/values.h"
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/app_mode/app_session_lifetime.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/login/user_manager.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/ui/app_launch_view.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_system.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/webstore_startup_installer.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/lifetime/application_lifetime.h"
23a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "chrome/browser/signin/profile_oauth2_token_service.h"
24a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/signin/token_service.h"
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/signin/token_service_factory.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/extensions/application_launch.h"
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/chrome_paths.h"
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/chrome_switches.h"
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/extension.h"
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/extensions/manifest_handlers/kiosk_enabled_info.h"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/public/browser/notification_service.h"
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "google_apis/gaia/gaia_auth_consumer.h"
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "google_apis/gaia/gaia_constants.h"
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using extensions::Extension;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using extensions::WebstoreStartupInstaller;
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chromeos {
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kOAuthRefreshToken[] = "refresh_token";
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kOAuthClientId[] = "client_id";
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kOAuthClientSecret[] = "client_secret";
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const base::FilePath::CharType kOAuthFileName[] =
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    FILE_PATH_LITERAL("kiosk_auth");
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Application install splash screen minimum show time in milliseconds.
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kAppInstallSplashScreenMinTimeMS = 3000;
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsAppInstalled(Profile* profile, const std::string& app_id) {
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return extensions::ExtensionSystem::Get(profile)->extension_service()->
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetInstalledExtension(app_id);
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)StartupAppLauncher::StartupAppLauncher(Profile* profile,
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       const std::string& app_id)
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : profile_(profile),
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      app_id_(app_id),
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      launch_splash_start_time_(0) {
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(profile_);
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(Extension::IdIsValid(app_id_));
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ash::Shell::HasInstance());
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ash::Shell::GetInstance()->AddPreTargetHandler(this);
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)StartupAppLauncher::~StartupAppLauncher() {
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ash::Shell::HasInstance());
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ash::Shell::GetInstance()->RemovePreTargetHandler(this);
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::Start() {
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "Starting... connection = "
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           <<  net::NetworkChangeNotifier::GetConnectionType();
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chromeos::ShowAppLaunchSplashScreen(app_id_);
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  StartLoadingOAuthFile();
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void StartupAppLauncher::StartLoadingOAuthFile() {
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  KioskOAuthParams* auth_params = new KioskOAuthParams();
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  BrowserThread::PostBlockingPoolTaskAndReply(
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&StartupAppLauncher::LoadOAuthFileOnBlockingPool,
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 auth_params),
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&StartupAppLauncher::OnOAuthFileLoaded,
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 AsWeakPtr(),
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 base::Owned(auth_params)));
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static.
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void StartupAppLauncher::LoadOAuthFileOnBlockingPool(
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    KioskOAuthParams* auth_params) {
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int error_code = JSONFileValueSerializer::JSON_NO_ERROR;
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string error_msg;
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath user_data_dir;
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath auth_file = user_data_dir.Append(kOAuthFileName);
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<JSONFileValueSerializer> serializer(
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      new JSONFileValueSerializer(user_data_dir.Append(kOAuthFileName)));
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<base::Value> value(
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      serializer->Deserialize(&error_code, &error_msg));
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* dict = NULL;
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (error_code != JSONFileValueSerializer::JSON_NO_ERROR ||
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      !value.get() || !value->GetAsDictionary(&dict)) {
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(WARNING) << "Can't find auth file at " << auth_file.value();
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict->GetString(kOAuthRefreshToken, &auth_params->refresh_token);
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict->GetString(kOAuthClientId, &auth_params->client_id);
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict->GetString(kOAuthClientSecret, &auth_params->client_secret);
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void StartupAppLauncher::OnOAuthFileLoaded(KioskOAuthParams* auth_params) {
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  auth_params_ = *auth_params;
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Override chrome client_id and secret that will be used for identity
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // API token minting.
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!auth_params_.client_id.empty() && !auth_params_.client_secret.empty()) {
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UserManager::Get()->SetAppModeChromeClientOAuthInfo(
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            auth_params_.client_id,
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            auth_params_.client_secret);
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If we are restarting chrome (i.e. on crash), we need to initialize
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // TokenService as well.
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  InitializeTokenService();
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void StartupAppLauncher::InitializeNetwork() {
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  chromeos::UpdateAppLaunchSplashScreenState(
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      chromeos::APP_LAUNCH_STATE_PREPARING_NETWORK);
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Set a maximum allowed wait time for network.
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int kMaxNetworkWaitSeconds = 5 * 60;
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  network_wait_timer_.Start(
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::TimeDelta::FromSeconds(kMaxNetworkWaitSeconds),
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this, &StartupAppLauncher::OnNetworkWaitTimedout);
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnNetworkChanged(net::NetworkChangeNotifier::GetConnectionType());
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void StartupAppLauncher::InitializeTokenService() {
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  chromeos::UpdateAppLaunchSplashScreenState(
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      chromeos::APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE);
153a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  ProfileOAuth2TokenService* profile_token_service =
154a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
155a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (profile_token_service->RefreshTokenIsAvailable()) {
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    InitializeNetwork();
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
160a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // At the end of this method, the execution will be put on hold until
161a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // ProfileOAuth2TokenService triggers either OnRefreshTokenAvailable or
162a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // OnRefreshTokensLoaded. Given that we want to handle exactly one event,
163a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // whichever comes first, both handlers call RemoveObserver on PO2TS. Handling
164a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // any of the two events is the only way to resume the execution and enable
165a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Cleanup method to be called, self-invoking a destructor. In destructor
166a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // StartupAppLauncher is no longer an observer of PO2TS and there is no need
167a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // to call RemoveObserver again.
168a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  profile_token_service->AddObserver(this);
169a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
170a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  token_service->Initialize(GaiaConstants::kChromeSource, profile_);
172a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Pass oauth2 refresh token from the auth file.
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // TODO(zelidrag): We should probably remove this option after M27.
175a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // TODO(fgorski): This can go when we have persistence implemented on PO2TS.
176a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Unless the code is no longer needed.
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!auth_params_.refresh_token.empty()) {
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    token_service->UpdateCredentialsWithOAuth2(
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        GaiaAuthConsumer::ClientOAuthResult(
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            auth_params_.refresh_token,
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            std::string(),  // access_token
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            0));            // new_expires_in_secs
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Load whatever tokens we have stored there last time around.
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    token_service->LoadTokensFromDB();
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
189a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void StartupAppLauncher::OnRefreshTokenAvailable(
190a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const std::string& account_id) {
191a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)
192a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      ->RemoveObserver(this);
193a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  InitializeNetwork();
194a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
195a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
196a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void StartupAppLauncher::OnRefreshTokensLoaded() {
197a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)
198a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      ->RemoveObserver(this);
199a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  InitializeNetwork();
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::Cleanup() {
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chromeos::CloseAppLaunchSplashScreen();
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete this;
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::OnLaunchSuccess() {
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int64 time_taken_ms = (base::TimeTicks::Now() -
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::TimeTicks::FromInternalValue(launch_splash_start_time_)).
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      InMilliseconds();
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Enforce that we show app install splash screen for some minimum amount
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // of time.
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (time_taken_ms < kAppInstallSplashScreenMinTimeMS) {
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostDelayedTask(
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::UI,
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&StartupAppLauncher::OnLaunchSuccess, AsWeakPtr()),
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::TimeDelta::FromMilliseconds(
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            kAppInstallSplashScreenMinTimeMS - time_taken_ms));
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Cleanup();
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::OnLaunchFailure(KioskAppLaunchError::Error error) {
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_NE(KioskAppLaunchError::NONE, error);
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Saves the error and ends the session to go back to login screen.
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  KioskAppLaunchError::Save(error);
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chrome::AttemptUserExit();
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Cleanup();
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::Launch() {
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const Extension* extension = extensions::ExtensionSystem::Get(profile_)->
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension_service()->GetInstalledExtension(app_id_);
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(extension);
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!extensions::KioskEnabledInfo::IsKioskEnabled(extension)) {
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    OnLaunchFailure(KioskAppLaunchError::NOT_KIOSK_ENABLED);
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Always open the app in a window.
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chrome::OpenApplication(chrome::AppLaunchParams(profile_,
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  extension,
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  extension_misc::LAUNCH_WINDOW,
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  NEW_WINDOW));
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  InitAppSession(profile_, app_id_);
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  content::NotificationService::current()->Notify(
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      chrome::NOTIFICATION_KIOSK_APP_LAUNCHED,
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      content::NotificationService::AllSources(),
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      content::NotificationService::NoDetails());
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnLaunchSuccess();
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::BeginInstall() {
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "BeginInstall... connection = "
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           <<  net::NetworkChangeNotifier::GetConnectionType();
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chromeos::UpdateAppLaunchSplashScreenState(
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      chromeos::APP_LAUNCH_STATE_INSTALLING_APPLICATION);
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (IsAppInstalled(profile_, app_id_)) {
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Launch();
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  installer_ = new WebstoreStartupInstaller(
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      app_id_,
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      profile_,
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      false,
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&StartupAppLauncher::InstallCallback, AsWeakPtr()));
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  installer_->BeginInstall();
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::InstallCallback(bool success,
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         const std::string& error) {
285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  installer_ = NULL;
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (success) {
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Schedules Launch() to be called after the callback returns.
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // So that the app finishes its installation.
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::UI,
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&StartupAppLauncher::Launch, AsWeakPtr()));
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LOG(ERROR) << "Failed to install app with error: " << error;
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL);
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::OnNetworkWaitTimedout() {
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LOG(WARNING) << "OnNetworkWaitTimedout... connection = "
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               <<  net::NetworkChangeNotifier::GetConnectionType();
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Timeout in waiting for online. Try the install anyway.
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BeginInstall();
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::OnNetworkChanged(
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::NetworkChangeNotifier::ConnectionType type) {
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "OnNetworkChanged... connection = "
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           <<  net::NetworkChangeNotifier::GetConnectionType();
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!net::NetworkChangeNotifier::IsOffline()) {
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DVLOG(1) << "Network up and running!";
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    network_wait_timer_.Stop();
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BeginInstall();
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DVLOG(1) << "Network not running yet!";
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::OnKeyEvent(ui::KeyEvent* event) {
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (event->type() != ui::ET_KEY_PRESSED)
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (KioskAppManager::Get()->GetDisableBailoutShortcut())
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (event->key_code() != ui::VKEY_S ||
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !(event->flags() & ui::EF_CONTROL_DOWN) ||
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !(event->flags() & ui::EF_ALT_DOWN)) {
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnLaunchFailure(KioskAppLaunchError::USER_CANCEL);
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}   // namespace chromeos
340