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 |