startup_app_launcher.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/time.h"
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/values.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/app_mode/app_session_lifetime.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/login/user_manager.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/ui/app_launch_view.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_system.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/webstore_startup_installer.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/lifetime/application_lifetime.h"
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/signin/token_service.h"
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/signin/token_service_factory.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/extensions/application_launch.h"
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/chrome_paths.h"
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/chrome_switches.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/extension.h"
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/extensions/manifest_handlers/kiosk_enabled_info.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "google_apis/gaia/gaia_auth_consumer.h"
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "google_apis/gaia/gaia_constants.h"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using extensions::Extension;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using extensions::WebstoreStartupInstaller;
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chromeos {
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kOAuthRefreshToken[] = "refresh_token";
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kOAuthClientId[] = "client_id";
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kOAuthClientSecret[] = "client_secret";
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const base::FilePath::CharType kOAuthFileName[] =
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    FILE_PATH_LITERAL("kiosk_auth");
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Application install splash screen minimum show time in milliseconds.
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kAppInstallSplashScreenMinTimeMS = 3000;
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsAppInstalled(Profile* profile, const std::string& app_id) {
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return extensions::ExtensionSystem::Get(profile)->extension_service()->
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetInstalledExtension(app_id);
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)StartupAppLauncher::StartupAppLauncher(Profile* profile,
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       const std::string& app_id)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : profile_(profile),
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      app_id_(app_id),
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      launch_splash_start_time_(0) {
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(profile_);
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(Extension::IdIsValid(app_id_));
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ash::Shell::HasInstance());
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ash::Shell::GetInstance()->AddPreTargetHandler(this);
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)StartupAppLauncher::~StartupAppLauncher() {
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ash::Shell::HasInstance());
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ash::Shell::GetInstance()->RemovePreTargetHandler(this);
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::Start() {
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "Starting... connection = "
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           <<  net::NetworkChangeNotifier::GetConnectionType();
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chromeos::ShowAppLaunchSplashScreen(app_id_);
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  StartLoadingOAuthFile();
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void StartupAppLauncher::StartLoadingOAuthFile() {
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  KioskOAuthParams* auth_params = new KioskOAuthParams();
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  BrowserThread::PostBlockingPoolTaskAndReply(
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FROM_HERE,
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&StartupAppLauncher::LoadOAuthFileOnBlockingPool,
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 auth_params),
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&StartupAppLauncher::OnOAuthFileLoaded,
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 AsWeakPtr(),
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 base::Owned(auth_params)));
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static.
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void StartupAppLauncher::LoadOAuthFileOnBlockingPool(
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    KioskOAuthParams* auth_params) {
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int error_code = JSONFileValueSerializer::JSON_NO_ERROR;
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string error_msg;
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath user_data_dir;
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath auth_file = user_data_dir.Append(kOAuthFileName);
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<JSONFileValueSerializer> serializer(
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      new JSONFileValueSerializer(user_data_dir.Append(kOAuthFileName)));
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<base::Value> value(
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      serializer->Deserialize(&error_code, &error_msg));
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::DictionaryValue* dict = NULL;
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (error_code != JSONFileValueSerializer::JSON_NO_ERROR ||
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      !value.get() || !value->GetAsDictionary(&dict)) {
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LOG(WARNING) << "Can't find auth file at " << auth_file.value();
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict->GetString(kOAuthRefreshToken, &auth_params->refresh_token);
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict->GetString(kOAuthClientId, &auth_params->client_id);
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  dict->GetString(kOAuthClientSecret, &auth_params->client_secret);
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void StartupAppLauncher::OnOAuthFileLoaded(KioskOAuthParams* auth_params) {
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  auth_params_ = *auth_params;
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Override chrome client_id and secret that will be used for identity
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // API token minting.
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!auth_params_.client_id.empty() && !auth_params_.client_secret.empty()) {
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UserManager::Get()->SetAppModeChromeClientOAuthInfo(
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            auth_params_.client_id,
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            auth_params_.client_secret);
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If we are restarting chrome (i.e. on crash), we need to initialize
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // TokenService as well.
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  InitializeTokenService();
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void StartupAppLauncher::InitializeNetwork() {
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  chromeos::UpdateAppLaunchSplashScreenState(
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      chromeos::APP_LAUNCH_STATE_PREPARING_NETWORK);
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Set a maximum allowed wait time for network.
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int kMaxNetworkWaitSeconds = 5 * 60;
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  network_wait_timer_.Start(
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::TimeDelta::FromSeconds(kMaxNetworkWaitSeconds),
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this, &StartupAppLauncher::OnNetworkWaitTimedout);
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnNetworkChanged(net::NetworkChangeNotifier::GetConnectionType());
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void StartupAppLauncher::InitializeTokenService() {
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  chromeos::UpdateAppLaunchSplashScreenState(
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      chromeos::APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE);
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  TokenService* token_service =
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      TokenServiceFactory::GetForProfile(profile_);
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (token_service->HasOAuthLoginToken()) {
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    InitializeNetwork();
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  registrar_.Add(this,
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 chrome::NOTIFICATION_TOKEN_LOADING_FINISHED,
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 content::Source<TokenService>(token_service));
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  registrar_.Add(this,
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 chrome::NOTIFICATION_TOKEN_AVAILABLE,
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 content::Source<TokenService>(token_service));
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  token_service->Initialize(GaiaConstants::kChromeSource, profile_);
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Pass oauth2 refresh token from the auth file.
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // TODO(zelidrag): We should probably remove this option after M27.
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!auth_params_.refresh_token.empty()) {
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    token_service->UpdateCredentialsWithOAuth2(
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        GaiaAuthConsumer::ClientOAuthResult(
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            auth_params_.refresh_token,
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            std::string(),  // access_token
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            0));            // new_expires_in_secs
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Load whatever tokens we have stored there last time around.
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    token_service->LoadTokensFromDB();
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void StartupAppLauncher::Observe(
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int type,
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const content::NotificationSource& source,
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const content::NotificationDetails& details) {
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  switch (type) {
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case chrome::NOTIFICATION_TOKEN_LOADING_FINISHED: {
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      registrar_.RemoveAll();
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      InitializeNetwork();
186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case chrome::NOTIFICATION_TOKEN_AVAILABLE: {
189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      TokenService::TokenAvailableDetails* token_details =
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          content::Details<TokenService::TokenAvailableDetails>(
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              details).ptr();
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (token_details->service() ==
193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              GaiaConstants::kGaiaOAuth2LoginRefreshToken) {
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        registrar_.RemoveAll();
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        InitializeNetwork();
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    default:
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      NOTREACHED();
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::Cleanup() {
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chromeos::CloseAppLaunchSplashScreen();
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete this;
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::OnLaunchSuccess() {
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int64 time_taken_ms = (base::TimeTicks::Now() -
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::TimeTicks::FromInternalValue(launch_splash_start_time_)).
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      InMilliseconds();
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Enforce that we show app install splash screen for some minimum amount
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // of time.
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (time_taken_ms < kAppInstallSplashScreenMinTimeMS) {
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostDelayedTask(
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::UI,
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&StartupAppLauncher::OnLaunchSuccess, AsWeakPtr()),
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::TimeDelta::FromMilliseconds(
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            kAppInstallSplashScreenMinTimeMS - time_taken_ms));
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Cleanup();
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::OnLaunchFailure(KioskAppLaunchError::Error error) {
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_NE(KioskAppLaunchError::NONE, error);
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Saves the error and ends the session to go back to login screen.
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  KioskAppLaunchError::Save(error);
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chrome::AttemptUserExit();
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Cleanup();
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::Launch() {
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const Extension* extension = extensions::ExtensionSystem::Get(profile_)->
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension_service()->GetInstalledExtension(app_id_);
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(extension);
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!extensions::KioskEnabledInfo::IsKioskEnabled(extension)) {
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    OnLaunchFailure(KioskAppLaunchError::NOT_KIOSK_ENABLED);
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Always open the app in a window.
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chrome::OpenApplication(chrome::AppLaunchParams(profile_,
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  extension,
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  extension_misc::LAUNCH_WINDOW,
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  NEW_WINDOW));
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  InitAppSession(profile_, app_id_);
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  content::NotificationService::current()->Notify(
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      chrome::NOTIFICATION_KIOSK_APP_LAUNCHED,
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      content::NotificationService::AllSources(),
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      content::NotificationService::NoDetails());
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnLaunchSuccess();
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::BeginInstall() {
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "BeginInstall... connection = "
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           <<  net::NetworkChangeNotifier::GetConnectionType();
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chromeos::UpdateAppLaunchSplashScreenState(
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      chromeos::APP_LAUNCH_STATE_INSTALLING_APPLICATION);
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (IsAppInstalled(profile_, app_id_)) {
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Launch();
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  installer_ = new WebstoreStartupInstaller(
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      app_id_,
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      profile_,
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      false,
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&StartupAppLauncher::InstallCallback, AsWeakPtr()));
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  installer_->BeginInstall();
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::InstallCallback(bool success,
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                         const std::string& error) {
288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  installer_ = NULL;
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (success) {
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Schedules Launch() to be called after the callback returns.
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // So that the app finishes its installation.
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::UI,
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&StartupAppLauncher::Launch, AsWeakPtr()));
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LOG(ERROR) << "Failed to install app with error: " << error;
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL);
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::OnNetworkWaitTimedout() {
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LOG(WARNING) << "OnNetworkWaitTimedout... connection = "
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               <<  net::NetworkChangeNotifier::GetConnectionType();
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Timeout in waiting for online. Try the install anyway.
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BeginInstall();
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::OnNetworkChanged(
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::NetworkChangeNotifier::ConnectionType type) {
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "OnNetworkChanged... connection = "
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           <<  net::NetworkChangeNotifier::GetConnectionType();
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!net::NetworkChangeNotifier::IsOffline()) {
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DVLOG(1) << "Network up and running!";
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    network_wait_timer_.Stop();
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BeginInstall();
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DVLOG(1) << "Network not running yet!";
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void StartupAppLauncher::OnKeyEvent(ui::KeyEvent* event) {
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (event->type() != ui::ET_KEY_PRESSED)
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (KioskAppManager::Get()->GetDisableBailoutShortcut())
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (event->key_code() != ui::VKEY_S ||
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !(event->flags() & ui::EF_CONTROL_DOWN) ||
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !(event->flags() & ui::EF_ALT_DOWN)) {
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnLaunchFailure(KioskAppLaunchError::USER_CANCEL);
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}   // namespace chromeos
343