| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/app_mode/startup_app_launcher.h" | 5 #include "chrome/browser/chromeos/app_mode/startup_app_launcher.h" |
| 6 | 6 |
| 7 #include "ash/shell.h" | |
| 8 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 9 #include "base/files/file_path.h" | 8 #include "base/files/file_path.h" |
| 10 #include "base/json/json_file_value_serializer.h" | 9 #include "base/json/json_file_value_serializer.h" |
| 11 #include "base/path_service.h" | 10 #include "base/path_service.h" |
| 12 #include "base/time/time.h" | 11 #include "base/time/time.h" |
| 13 #include "base/values.h" | 12 #include "base/values.h" |
| 14 #include "chrome/browser/chrome_notification_types.h" | 13 #include "chrome/browser/chrome_notification_types.h" |
| 15 #include "chrome/browser/chromeos/app_mode/app_session_lifetime.h" | 14 #include "chrome/browser/chromeos/app_mode/app_session_lifetime.h" |
| 16 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" | 15 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" |
| 17 #include "chrome/browser/chromeos/login/user_manager.h" | 16 #include "chrome/browser/chromeos/login/user_manager.h" |
| 18 #include "chrome/browser/chromeos/ui/app_launch_view.h" | |
| 19 #include "chrome/browser/extensions/extension_service.h" | 17 #include "chrome/browser/extensions/extension_service.h" |
| 20 #include "chrome/browser/extensions/extension_system.h" | 18 #include "chrome/browser/extensions/extension_system.h" |
| 21 #include "chrome/browser/extensions/webstore_startup_installer.h" | 19 #include "chrome/browser/extensions/webstore_startup_installer.h" |
| 22 #include "chrome/browser/lifetime/application_lifetime.h" | 20 #include "chrome/browser/lifetime/application_lifetime.h" |
| 23 #include "chrome/browser/signin/profile_oauth2_token_service.h" | 21 #include "chrome/browser/signin/profile_oauth2_token_service.h" |
| 24 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" | 22 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" |
| 25 #include "chrome/browser/signin/token_service.h" | 23 #include "chrome/browser/signin/token_service.h" |
| 26 #include "chrome/browser/signin/token_service_factory.h" | 24 #include "chrome/browser/signin/token_service_factory.h" |
| 27 #include "chrome/browser/ui/extensions/application_launch.h" | 25 #include "chrome/browser/ui/extensions/application_launch.h" |
| 28 #include "chrome/common/chrome_paths.h" | 26 #include "chrome/common/chrome_paths.h" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 42 | 40 |
| 43 namespace { | 41 namespace { |
| 44 | 42 |
| 45 const char kOAuthRefreshToken[] = "refresh_token"; | 43 const char kOAuthRefreshToken[] = "refresh_token"; |
| 46 const char kOAuthClientId[] = "client_id"; | 44 const char kOAuthClientId[] = "client_id"; |
| 47 const char kOAuthClientSecret[] = "client_secret"; | 45 const char kOAuthClientSecret[] = "client_secret"; |
| 48 | 46 |
| 49 const base::FilePath::CharType kOAuthFileName[] = | 47 const base::FilePath::CharType kOAuthFileName[] = |
| 50 FILE_PATH_LITERAL("kiosk_auth"); | 48 FILE_PATH_LITERAL("kiosk_auth"); |
| 51 | 49 |
| 52 // Application install splash screen minimum show time in milliseconds. | |
| 53 const int kAppInstallSplashScreenMinTimeMS = 3000; | |
| 54 | |
| 55 bool IsAppInstalled(Profile* profile, const std::string& app_id) { | 50 bool IsAppInstalled(Profile* profile, const std::string& app_id) { |
| 56 return extensions::ExtensionSystem::Get(profile)->extension_service()-> | 51 return extensions::ExtensionSystem::Get(profile)->extension_service()-> |
| 57 GetInstalledExtension(app_id); | 52 GetInstalledExtension(app_id); |
| 58 } | 53 } |
| 59 | 54 |
| 60 } // namespace | 55 } // namespace |
| 61 | 56 |
| 57 |
| 62 StartupAppLauncher::StartupAppLauncher(Profile* profile, | 58 StartupAppLauncher::StartupAppLauncher(Profile* profile, |
| 63 const std::string& app_id) | 59 const std::string& app_id) |
| 64 : profile_(profile), | 60 : profile_(profile), |
| 65 app_id_(app_id), | 61 app_id_(app_id) { |
| 66 launch_splash_start_time_(0) { | |
| 67 DCHECK(profile_); | 62 DCHECK(profile_); |
| 68 DCHECK(Extension::IdIsValid(app_id_)); | 63 DCHECK(Extension::IdIsValid(app_id_)); |
| 69 DCHECK(ash::Shell::HasInstance()); | |
| 70 ash::Shell::GetInstance()->AddPreTargetHandler(this); | |
| 71 } | 64 } |
| 72 | 65 |
| 73 StartupAppLauncher::~StartupAppLauncher() { | 66 StartupAppLauncher::~StartupAppLauncher() { |
| 74 DCHECK(ash::Shell::HasInstance()); | |
| 75 ash::Shell::GetInstance()->RemovePreTargetHandler(this); | |
| 76 } | 67 } |
| 77 | 68 |
| 78 void StartupAppLauncher::Start() { | 69 void StartupAppLauncher::Start() { |
| 79 launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue(); | |
| 80 DVLOG(1) << "Starting... connection = " | 70 DVLOG(1) << "Starting... connection = " |
| 81 << net::NetworkChangeNotifier::GetConnectionType(); | 71 << net::NetworkChangeNotifier::GetConnectionType(); |
| 82 chromeos::ShowAppLaunchSplashScreen(app_id_); | |
| 83 StartLoadingOAuthFile(); | 72 StartLoadingOAuthFile(); |
| 84 } | 73 } |
| 85 | 74 |
| 75 void StartupAppLauncher::AddObserver(Observer* observer) { |
| 76 observer_list_.AddObserver(observer); |
| 77 } |
| 78 |
| 79 void StartupAppLauncher::RemoveObserver(Observer* observer) { |
| 80 observer_list_.RemoveObserver(observer); |
| 81 } |
| 82 |
| 86 void StartupAppLauncher::StartLoadingOAuthFile() { | 83 void StartupAppLauncher::StartLoadingOAuthFile() { |
| 84 FOR_EACH_OBSERVER(Observer, observer_list_, OnLoadingOAuthFile()); |
| 85 |
| 87 KioskOAuthParams* auth_params = new KioskOAuthParams(); | 86 KioskOAuthParams* auth_params = new KioskOAuthParams(); |
| 88 BrowserThread::PostBlockingPoolTaskAndReply( | 87 BrowserThread::PostBlockingPoolTaskAndReply( |
| 89 FROM_HERE, | 88 FROM_HERE, |
| 90 base::Bind(&StartupAppLauncher::LoadOAuthFileOnBlockingPool, | 89 base::Bind(&StartupAppLauncher::LoadOAuthFileOnBlockingPool, |
| 91 auth_params), | 90 auth_params), |
| 92 base::Bind(&StartupAppLauncher::OnOAuthFileLoaded, | 91 base::Bind(&StartupAppLauncher::OnOAuthFileLoaded, |
| 93 AsWeakPtr(), | 92 AsWeakPtr(), |
| 94 base::Owned(auth_params))); | 93 base::Owned(auth_params))); |
| 95 } | 94 } |
| 96 | 95 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 127 auth_params_.client_id, | 126 auth_params_.client_id, |
| 128 auth_params_.client_secret); | 127 auth_params_.client_secret); |
| 129 } | 128 } |
| 130 | 129 |
| 131 // If we are restarting chrome (i.e. on crash), we need to initialize | 130 // If we are restarting chrome (i.e. on crash), we need to initialize |
| 132 // TokenService as well. | 131 // TokenService as well. |
| 133 InitializeTokenService(); | 132 InitializeTokenService(); |
| 134 } | 133 } |
| 135 | 134 |
| 136 void StartupAppLauncher::InitializeNetwork() { | 135 void StartupAppLauncher::InitializeNetwork() { |
| 137 chromeos::UpdateAppLaunchSplashScreenState( | 136 FOR_EACH_OBSERVER(Observer, observer_list_, OnInitializingNetwork()); |
| 138 chromeos::APP_LAUNCH_STATE_PREPARING_NETWORK); | 137 |
| 139 // Set a maximum allowed wait time for network. | 138 // Set a maximum allowed wait time for network. |
| 140 const int kMaxNetworkWaitSeconds = 5 * 60; | 139 const int kMaxNetworkWaitSeconds = 5 * 60; |
| 141 network_wait_timer_.Start( | 140 network_wait_timer_.Start( |
| 142 FROM_HERE, | 141 FROM_HERE, |
| 143 base::TimeDelta::FromSeconds(kMaxNetworkWaitSeconds), | 142 base::TimeDelta::FromSeconds(kMaxNetworkWaitSeconds), |
| 144 this, &StartupAppLauncher::OnNetworkWaitTimedout); | 143 this, &StartupAppLauncher::OnNetworkWaitTimedout); |
| 145 | 144 |
| 146 net::NetworkChangeNotifier::AddNetworkChangeObserver(this); | 145 net::NetworkChangeNotifier::AddNetworkChangeObserver(this); |
| 147 OnNetworkChanged(net::NetworkChangeNotifier::GetConnectionType()); | 146 OnNetworkChanged(net::NetworkChangeNotifier::GetConnectionType()); |
| 148 } | 147 } |
| 149 | 148 |
| 150 void StartupAppLauncher::InitializeTokenService() { | 149 void StartupAppLauncher::InitializeTokenService() { |
| 151 chromeos::UpdateAppLaunchSplashScreenState( | 150 FOR_EACH_OBSERVER(Observer, observer_list_, OnInitializingTokenService()); |
| 152 chromeos::APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE); | 151 |
| 153 ProfileOAuth2TokenService* profile_token_service = | 152 ProfileOAuth2TokenService* profile_token_service = |
| 154 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_); | 153 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_); |
| 155 if (profile_token_service->RefreshTokenIsAvailable()) { | 154 if (profile_token_service->RefreshTokenIsAvailable()) { |
| 156 InitializeNetwork(); | 155 InitializeNetwork(); |
| 157 return; | 156 return; |
| 158 } | 157 } |
| 159 | 158 |
| 160 // At the end of this method, the execution will be put on hold until | 159 // At the end of this method, the execution will be put on hold until |
| 161 // ProfileOAuth2TokenService triggers either OnRefreshTokenAvailable or | 160 // ProfileOAuth2TokenService triggers either OnRefreshTokenAvailable or |
| 162 // OnRefreshTokensLoaded. Given that we want to handle exactly one event, | 161 // OnRefreshTokensLoaded. Given that we want to handle exactly one event, |
| (...skipping 29 matching lines...) Expand all Loading... |
| 192 ->RemoveObserver(this); | 191 ->RemoveObserver(this); |
| 193 InitializeNetwork(); | 192 InitializeNetwork(); |
| 194 } | 193 } |
| 195 | 194 |
| 196 void StartupAppLauncher::OnRefreshTokensLoaded() { | 195 void StartupAppLauncher::OnRefreshTokensLoaded() { |
| 197 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_) | 196 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_) |
| 198 ->RemoveObserver(this); | 197 ->RemoveObserver(this); |
| 199 InitializeNetwork(); | 198 InitializeNetwork(); |
| 200 } | 199 } |
| 201 | 200 |
| 202 void StartupAppLauncher::Cleanup() { | |
| 203 chromeos::CloseAppLaunchSplashScreen(); | |
| 204 | |
| 205 delete this; | |
| 206 } | |
| 207 | |
| 208 void StartupAppLauncher::OnLaunchSuccess() { | 201 void StartupAppLauncher::OnLaunchSuccess() { |
| 209 const int64 time_taken_ms = (base::TimeTicks::Now() - | 202 FOR_EACH_OBSERVER(Observer, observer_list_, OnLaunchSucceeded()); |
| 210 base::TimeTicks::FromInternalValue(launch_splash_start_time_)). | |
| 211 InMilliseconds(); | |
| 212 | |
| 213 // Enforce that we show app install splash screen for some minimum amount | |
| 214 // of time. | |
| 215 if (time_taken_ms < kAppInstallSplashScreenMinTimeMS) { | |
| 216 BrowserThread::PostDelayedTask( | |
| 217 BrowserThread::UI, | |
| 218 FROM_HERE, | |
| 219 base::Bind(&StartupAppLauncher::OnLaunchSuccess, AsWeakPtr()), | |
| 220 base::TimeDelta::FromMilliseconds( | |
| 221 kAppInstallSplashScreenMinTimeMS - time_taken_ms)); | |
| 222 return; | |
| 223 } | |
| 224 | |
| 225 Cleanup(); | |
| 226 } | 203 } |
| 227 | 204 |
| 228 void StartupAppLauncher::OnLaunchFailure(KioskAppLaunchError::Error error) { | 205 void StartupAppLauncher::OnLaunchFailure(KioskAppLaunchError::Error error) { |
| 206 LOG(ERROR) << "App launch failed"; |
| 229 DCHECK_NE(KioskAppLaunchError::NONE, error); | 207 DCHECK_NE(KioskAppLaunchError::NONE, error); |
| 230 | 208 |
| 231 // Saves the error and ends the session to go back to login screen. | 209 FOR_EACH_OBSERVER(Observer, observer_list_, OnLaunchFailed(error)); |
| 232 KioskAppLaunchError::Save(error); | |
| 233 chrome::AttemptUserExit(); | |
| 234 | |
| 235 Cleanup(); | |
| 236 } | 210 } |
| 237 | 211 |
| 238 void StartupAppLauncher::Launch() { | 212 void StartupAppLauncher::Launch() { |
| 239 const Extension* extension = extensions::ExtensionSystem::Get(profile_)-> | 213 const Extension* extension = extensions::ExtensionSystem::Get(profile_)-> |
| 240 extension_service()->GetInstalledExtension(app_id_); | 214 extension_service()->GetInstalledExtension(app_id_); |
| 241 CHECK(extension); | 215 CHECK(extension); |
| 242 | 216 |
| 243 if (!extensions::KioskEnabledInfo::IsKioskEnabled(extension)) { | 217 if (!extensions::KioskEnabledInfo::IsKioskEnabled(extension)) { |
| 244 OnLaunchFailure(KioskAppLaunchError::NOT_KIOSK_ENABLED); | 218 OnLaunchFailure(KioskAppLaunchError::NOT_KIOSK_ENABLED); |
| 245 return; | 219 return; |
| 246 } | 220 } |
| 247 | 221 |
| 248 // Always open the app in a window. | 222 // Always open the app in a window. |
| 249 chrome::OpenApplication(chrome::AppLaunchParams(profile_, | 223 chrome::OpenApplication(chrome::AppLaunchParams(profile_, |
| 250 extension, | 224 extension, |
| 251 extension_misc::LAUNCH_WINDOW, | 225 extension_misc::LAUNCH_WINDOW, |
| 252 NEW_WINDOW)); | 226 NEW_WINDOW)); |
| 253 InitAppSession(profile_, app_id_); | 227 InitAppSession(profile_, app_id_); |
| 254 | 228 |
| 255 content::NotificationService::current()->Notify( | 229 content::NotificationService::current()->Notify( |
| 256 chrome::NOTIFICATION_KIOSK_APP_LAUNCHED, | 230 chrome::NOTIFICATION_KIOSK_APP_LAUNCHED, |
| 257 content::NotificationService::AllSources(), | 231 content::NotificationService::AllSources(), |
| 258 content::NotificationService::NoDetails()); | 232 content::NotificationService::NoDetails()); |
| 259 | 233 |
| 260 OnLaunchSuccess(); | 234 OnLaunchSuccess(); |
| 261 } | 235 } |
| 262 | 236 |
| 263 void StartupAppLauncher::BeginInstall() { | 237 void StartupAppLauncher::BeginInstall() { |
| 238 FOR_EACH_OBSERVER(Observer, observer_list_, OnInstallingApp()); |
| 239 |
| 264 DVLOG(1) << "BeginInstall... connection = " | 240 DVLOG(1) << "BeginInstall... connection = " |
| 265 << net::NetworkChangeNotifier::GetConnectionType(); | 241 << net::NetworkChangeNotifier::GetConnectionType(); |
| 266 | 242 |
| 267 chromeos::UpdateAppLaunchSplashScreenState( | |
| 268 chromeos::APP_LAUNCH_STATE_INSTALLING_APPLICATION); | |
| 269 | |
| 270 if (IsAppInstalled(profile_, app_id_)) { | 243 if (IsAppInstalled(profile_, app_id_)) { |
| 271 Launch(); | 244 Launch(); |
| 272 return; | 245 return; |
| 273 } | 246 } |
| 274 | 247 |
| 275 installer_ = new WebstoreStartupInstaller( | 248 installer_ = new WebstoreStartupInstaller( |
| 276 app_id_, | 249 app_id_, |
| 277 profile_, | 250 profile_, |
| 278 false, | 251 false, |
| 279 base::Bind(&StartupAppLauncher::InstallCallback, AsWeakPtr())); | 252 base::Bind(&StartupAppLauncher::InstallCallback, AsWeakPtr())); |
| 280 installer_->BeginInstall(); | 253 installer_->BeginInstall(); |
| 281 } | 254 } |
| 282 | 255 |
| 283 void StartupAppLauncher::InstallCallback(bool success, | 256 void StartupAppLauncher::InstallCallback(bool success, |
| 284 const std::string& error) { | 257 const std::string& error) { |
| 285 installer_ = NULL; | 258 installer_ = NULL; |
| 286 if (success) { | 259 if (success) { |
| 287 // Schedules Launch() to be called after the callback returns. | 260 // Schedules Launch() to be called after the callback returns. |
| 288 // So that the app finishes its installation. | 261 // So that the app finishes its installation. |
| 289 BrowserThread::PostTask( | 262 BrowserThread::PostTask( |
| 290 BrowserThread::UI, | 263 BrowserThread::UI, |
| 291 FROM_HERE, | 264 FROM_HERE, |
| 292 base::Bind(&StartupAppLauncher::Launch, AsWeakPtr())); | 265 base::Bind(&StartupAppLauncher::Launch, AsWeakPtr())); |
| 293 return; | 266 return; |
| 294 } | 267 } |
| 295 | 268 |
| 296 LOG(ERROR) << "Failed to install app with error: " << error; | 269 // TODO: revert this. |
| 270 LOG(ERROR) << "Failed to install app with error: " << error << "."; |
| 271 LOG(ERROR) << " " << app_id_; |
| 297 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL); | 272 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL); |
| 298 } | 273 } |
| 299 | 274 |
| 300 void StartupAppLauncher::OnNetworkWaitTimedout() { | 275 void StartupAppLauncher::OnNetworkWaitTimedout() { |
| 301 LOG(WARNING) << "OnNetworkWaitTimedout... connection = " | 276 LOG(WARNING) << "OnNetworkWaitTimedout... connection = " |
| 302 << net::NetworkChangeNotifier::GetConnectionType(); | 277 << net::NetworkChangeNotifier::GetConnectionType(); |
| 278 |
| 279 FOR_EACH_OBSERVER(Observer, observer_list_, OnNetworkWaitTimedout()); |
| 280 |
| 303 // Timeout in waiting for online. Try the install anyway. | 281 // Timeout in waiting for online. Try the install anyway. |
| 304 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); | 282 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); |
| 305 BeginInstall(); | 283 BeginInstall(); |
| 306 } | 284 } |
| 307 | 285 |
| 308 void StartupAppLauncher::OnNetworkChanged( | 286 void StartupAppLauncher::OnNetworkChanged( |
| 309 net::NetworkChangeNotifier::ConnectionType type) { | 287 net::NetworkChangeNotifier::ConnectionType type) { |
| 310 DVLOG(1) << "OnNetworkChanged... connection = " | 288 DVLOG(1) << "OnNetworkChanged... connection = " |
| 311 << net::NetworkChangeNotifier::GetConnectionType(); | 289 << net::NetworkChangeNotifier::GetConnectionType(); |
| 312 if (!net::NetworkChangeNotifier::IsOffline()) { | 290 if (!net::NetworkChangeNotifier::IsOffline()) { |
| 313 DVLOG(1) << "Network up and running!"; | 291 DVLOG(1) << "Network up and running!"; |
| 314 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); | 292 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); |
| 315 network_wait_timer_.Stop(); | 293 network_wait_timer_.Stop(); |
| 316 | 294 |
| 317 BeginInstall(); | 295 BeginInstall(); |
| 318 } else { | 296 } else { |
| 319 DVLOG(1) << "Network not running yet!"; | 297 DVLOG(1) << "Network not running yet!"; |
| 320 } | 298 } |
| 321 } | 299 } |
| 322 | 300 |
| 323 void StartupAppLauncher::OnKeyEvent(ui::KeyEvent* event) { | |
| 324 if (event->type() != ui::ET_KEY_PRESSED) | |
| 325 return; | |
| 326 | |
| 327 if (KioskAppManager::Get()->GetDisableBailoutShortcut()) | |
| 328 return; | |
| 329 | |
| 330 if (event->key_code() != ui::VKEY_S || | |
| 331 !(event->flags() & ui::EF_CONTROL_DOWN) || | |
| 332 !(event->flags() & ui::EF_ALT_DOWN)) { | |
| 333 return; | |
| 334 } | |
| 335 | |
| 336 OnLaunchFailure(KioskAppLaunchError::USER_CANCEL); | |
| 337 } | |
| 338 | |
| 339 } // namespace chromeos | 301 } // namespace chromeos |
| OLD | NEW |