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
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/login/app_launch_controller.h"
8 #include "base/callback.h"
9 #include "base/files/file_path.h"
10 #include "base/json/json_file_value_serializer.h"
11 #include "base/logging.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/time/time.h"
15 #include "base/values.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/chrome_notification_types.h"
18 #include "chrome/browser/chromeos/app_mode/app_session_lifetime.h"
19 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
20 #include "chrome/browser/chromeos/app_mode/startup_app_launcher.h"
21 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
22 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
23 #include "chrome/browser/chromeos/login/ui/oobe_display.h"
24 #include "chrome/browser/chromeos/login/ui/webui_login_view.h"
25 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
26 #include "chrome/browser/chromeos/settings/cros_settings.h"
27 #include "chrome/browser/lifetime/application_lifetime.h"
28 #include "chrome/browser/profiles/profile.h"
29 #include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
30 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
31 #include "chromeos/settings/cros_settings_names.h"
32 #include "components/user_manager/user_manager.h"
33 #include "content/public/browser/notification_service.h"
34 #include "extensions/browser/app_window/app_window.h"
35 #include "extensions/browser/app_window/app_window_registry.h"
36 #include "net/base/network_change_notifier.h"
42 // Application install splash screen minimum show time in milliseconds.
43 const int kAppInstallSplashScreenMinTimeMS
= 3000;
48 bool AppLaunchController::skip_splash_wait_
= false;
49 int AppLaunchController::network_wait_time_
= 10;
50 base::Closure
* AppLaunchController::network_timeout_callback_
= NULL
;
51 AppLaunchController::ReturnBoolCallback
*
52 AppLaunchController::can_configure_network_callback_
= NULL
;
53 AppLaunchController::ReturnBoolCallback
*
54 AppLaunchController::need_owner_auth_to_configure_network_callback_
= NULL
;
56 ////////////////////////////////////////////////////////////////////////////////
57 // AppLaunchController::AppWindowWatcher
59 class AppLaunchController::AppWindowWatcher
60 : public extensions::AppWindowRegistry::Observer
{
62 explicit AppWindowWatcher(AppLaunchController
* controller
,
63 const std::string
& app_id
)
64 : controller_(controller
),
67 extensions::AppWindowRegistry::Get(controller
->profile_
)),
69 if (!window_registry_
->GetAppWindowsForApp(app_id
).empty()) {
70 base::MessageLoop::current()->PostTask(
72 base::Bind(&AppWindowWatcher::NotifyAppWindowCreated
,
73 weak_factory_
.GetWeakPtr()));
76 window_registry_
->AddObserver(this);
79 ~AppWindowWatcher() override
{ window_registry_
->RemoveObserver(this); }
82 // extensions::AppWindowRegistry::Observer overrides:
83 void OnAppWindowAdded(extensions::AppWindow
* app_window
) override
{
84 if (app_window
->extension_id() == app_id_
) {
85 window_registry_
->RemoveObserver(this);
86 NotifyAppWindowCreated();
90 void NotifyAppWindowCreated() {
91 controller_
->OnAppWindowCreated();
94 AppLaunchController
* controller_
;
96 extensions::AppWindowRegistry
* window_registry_
;
97 base::WeakPtrFactory
<AppWindowWatcher
> weak_factory_
;
99 DISALLOW_COPY_AND_ASSIGN(AppWindowWatcher
);
102 ////////////////////////////////////////////////////////////////////////////////
103 // AppLaunchController
105 AppLaunchController::AppLaunchController(const std::string
& app_id
,
106 bool diagnostic_mode
,
107 LoginDisplayHost
* host
,
108 OobeDisplay
* oobe_display
)
111 diagnostic_mode_(diagnostic_mode
),
113 oobe_display_(oobe_display
),
114 app_launch_splash_screen_actor_(
115 oobe_display_
->GetAppLaunchSplashScreenActor()),
116 webui_visible_(false),
117 launcher_ready_(false),
118 waiting_for_network_(false),
119 network_wait_timedout_(false),
120 showing_network_dialog_(false),
121 network_config_requested_(false),
122 launch_splash_start_time_(0) {
125 AppLaunchController::~AppLaunchController() {
126 app_launch_splash_screen_actor_
->SetDelegate(NULL
);
129 void AppLaunchController::StartAppLaunch(bool is_auto_launch
) {
130 DVLOG(1) << "Starting kiosk mode...";
132 webui_visible_
= host_
->GetWebUILoginView()->webui_visible();
133 if (!webui_visible_
) {
134 registrar_
.Add(this, chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE
,
135 content::NotificationService::AllSources());
137 launch_splash_start_time_
= base::TimeTicks::Now().ToInternalValue();
139 // TODO(tengs): Add a loading profile app launch state.
140 app_launch_splash_screen_actor_
->SetDelegate(this);
141 app_launch_splash_screen_actor_
->Show(app_id_
);
143 KioskAppManager::App app
;
144 CHECK(KioskAppManager::Get());
145 CHECK(KioskAppManager::Get()->GetApp(app_id_
, &app
));
147 if (is_auto_launch
) {
149 if (!CrosSettings::Get()->GetInteger(
150 kAccountsPrefDeviceLocalAccountAutoLoginDelay
, &delay
)) {
153 DCHECK_EQ(0, delay
) << "Kiosks do not support non-zero auto-login delays";
155 // If we are launching a kiosk app with zero delay, mark it appropriately.
157 KioskAppManager::Get()->SetAppWasAutoLaunchedWithZeroDelay(app_id_
);
160 kiosk_profile_loader_
.reset(
161 new KioskProfileLoader(app
.user_id
, false, this));
162 kiosk_profile_loader_
->Start();
166 void AppLaunchController::SkipSplashWaitForTesting() {
167 skip_splash_wait_
= true;
171 void AppLaunchController::SetNetworkWaitForTesting(int wait_time_secs
) {
172 network_wait_time_
= wait_time_secs
;
176 void AppLaunchController::SetNetworkTimeoutCallbackForTesting(
177 base::Closure
* callback
) {
178 network_timeout_callback_
= callback
;
182 void AppLaunchController::SetCanConfigureNetworkCallbackForTesting(
183 ReturnBoolCallback
* can_configure_network_callback
) {
184 can_configure_network_callback_
= can_configure_network_callback
;
188 void AppLaunchController::SetNeedOwnerAuthToConfigureNetworkCallbackForTesting(
189 ReturnBoolCallback
* need_owner_auth_callback
) {
190 need_owner_auth_to_configure_network_callback_
= need_owner_auth_callback
;
193 void AppLaunchController::OnConfigureNetwork() {
195 showing_network_dialog_
= true;
196 if (CanConfigureNetwork() && NeedOwnerAuthToConfigureNetwork()) {
197 signin_screen_
.reset(new AppLaunchSigninScreen(
198 static_cast<OobeUI
*>(oobe_display_
), this));
199 signin_screen_
->Show();
201 // If kiosk mode was configured through enterprise policy, we may
202 // not have an owner user.
203 // TODO(tengs): We need to figure out the appropriate security meausres
209 void AppLaunchController::OnOwnerSigninSuccess() {
210 app_launch_splash_screen_actor_
->ShowNetworkConfigureUI();
211 signin_screen_
.reset();
214 void AppLaunchController::Observe(
216 const content::NotificationSource
& source
,
217 const content::NotificationDetails
& details
) {
218 DCHECK_EQ(chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE
, type
);
219 DCHECK(!webui_visible_
);
220 webui_visible_
= true;
221 launch_splash_start_time_
= base::TimeTicks::Now().ToInternalValue();
226 void AppLaunchController::OnCancelAppLaunch() {
227 if (KioskAppManager::Get()->GetDisableBailoutShortcut())
230 OnLaunchFailed(KioskAppLaunchError::USER_CANCEL
);
233 void AppLaunchController::OnNetworkConfigRequested(bool requested
) {
234 network_config_requested_
= requested
;
236 MaybeShowNetworkConfigureUI();
238 startup_app_launcher_
->RestartLauncher();
241 void AppLaunchController::OnNetworkStateChanged(bool online
) {
242 if (!waiting_for_network_
)
245 if (online
&& !network_config_requested_
)
246 startup_app_launcher_
->ContinueWithNetworkReady();
247 else if (network_wait_timedout_
)
248 MaybeShowNetworkConfigureUI();
251 void AppLaunchController::OnProfileLoaded(Profile
* profile
) {
252 DVLOG(1) << "Profile loaded... Starting app launch.";
255 // This is needed to trigger input method extensions being loaded.
256 profile_
->InitChromeOSPreferences();
258 kiosk_profile_loader_
.reset();
259 startup_app_launcher_
.reset(
260 new StartupAppLauncher(profile_
, app_id_
, diagnostic_mode_
, this));
261 startup_app_launcher_
->Initialize();
264 void AppLaunchController::OnProfileLoadFailed(
265 KioskAppLaunchError::Error error
) {
266 OnLaunchFailed(error
);
269 void AppLaunchController::CleanUp() {
270 kiosk_profile_loader_
.reset();
271 startup_app_launcher_
.reset();
272 splash_wait_timer_
.Stop();
278 void AppLaunchController::OnNetworkWaitTimedout() {
279 DCHECK(waiting_for_network_
);
280 LOG(WARNING
) << "OnNetworkWaitTimedout... connection = "
281 << net::NetworkChangeNotifier::GetConnectionType();
282 network_wait_timedout_
= true;
284 MaybeShowNetworkConfigureUI();
286 if (network_timeout_callback_
)
287 network_timeout_callback_
->Run();
290 void AppLaunchController::OnAppWindowCreated() {
291 DVLOG(1) << "App window created, closing splash screen.";
295 bool AppLaunchController::CanConfigureNetwork() {
296 if (can_configure_network_callback_
)
297 return can_configure_network_callback_
->Run();
299 policy::BrowserPolicyConnectorChromeOS
* connector
=
300 g_browser_process
->platform_part()->browser_policy_connector_chromeos();
301 if (connector
->IsEnterpriseManaged()) {
303 if (CrosSettings::Get()->GetBoolean(
304 kAccountsPrefDeviceLocalAccountPromptForNetworkWhenOffline
,
306 return should_prompt
;
309 // Default to true to allow network configuration if the policy is missing.
313 return !user_manager::UserManager::Get()->GetOwnerEmail().empty();
316 bool AppLaunchController::NeedOwnerAuthToConfigureNetwork() {
317 if (need_owner_auth_to_configure_network_callback_
)
318 return need_owner_auth_to_configure_network_callback_
->Run();
320 policy::BrowserPolicyConnectorChromeOS
* connector
=
321 g_browser_process
->platform_part()->browser_policy_connector_chromeos();
322 return !connector
->IsEnterpriseManaged();
325 void AppLaunchController::MaybeShowNetworkConfigureUI() {
326 if (CanConfigureNetwork()) {
327 if (NeedOwnerAuthToConfigureNetwork()) {
328 if (network_config_requested_
)
329 OnConfigureNetwork();
331 app_launch_splash_screen_actor_
->ToggleNetworkConfig(true);
333 showing_network_dialog_
= true;
334 app_launch_splash_screen_actor_
->ShowNetworkConfigureUI();
337 app_launch_splash_screen_actor_
->UpdateAppLaunchState(
338 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_NETWORK_WAIT_TIMEOUT
);
342 void AppLaunchController::InitializeNetwork() {
343 // Show the network configuration dialog if network is not initialized
344 // after a brief wait time.
345 waiting_for_network_
= true;
346 network_wait_timer_
.Start(
348 base::TimeDelta::FromSeconds(network_wait_time_
),
349 this, &AppLaunchController::OnNetworkWaitTimedout
);
351 app_launch_splash_screen_actor_
->UpdateAppLaunchState(
352 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_PREPARING_NETWORK
);
355 bool AppLaunchController::IsNetworkReady() {
356 return app_launch_splash_screen_actor_
->IsNetworkReady();
359 void AppLaunchController::OnLoadingOAuthFile() {
360 app_launch_splash_screen_actor_
->UpdateAppLaunchState(
361 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_AUTH_FILE
);
364 void AppLaunchController::OnInitializingTokenService() {
365 app_launch_splash_screen_actor_
->UpdateAppLaunchState(
366 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE
);
369 void AppLaunchController::OnInstallingApp() {
370 app_launch_splash_screen_actor_
->UpdateAppLaunchState(
371 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_INSTALLING_APPLICATION
);
373 waiting_for_network_
= false;
374 network_wait_timer_
.Stop();
375 app_launch_splash_screen_actor_
->ToggleNetworkConfig(false);
377 // We have connectivity at this point, so we can skip the network
378 // configuration dialog if it is being shown.
379 if (showing_network_dialog_
) {
380 app_launch_splash_screen_actor_
->Show(app_id_
);
381 showing_network_dialog_
= false;
382 launch_splash_start_time_
= base::TimeTicks::Now().ToInternalValue();
386 void AppLaunchController::OnReadyToLaunch() {
387 launcher_ready_
= true;
389 if (network_config_requested_
)
395 if (splash_wait_timer_
.IsRunning())
398 const int64 time_taken_ms
= (base::TimeTicks::Now() -
399 base::TimeTicks::FromInternalValue(launch_splash_start_time_
)).
402 // Enforce that we show app install splash screen for some minimum amount
404 if (!skip_splash_wait_
&& time_taken_ms
< kAppInstallSplashScreenMinTimeMS
) {
405 splash_wait_timer_
.Start(
407 base::TimeDelta::FromMilliseconds(
408 kAppInstallSplashScreenMinTimeMS
- time_taken_ms
),
410 &AppLaunchController::OnReadyToLaunch
);
414 startup_app_launcher_
->LaunchApp();
417 void AppLaunchController::OnLaunchSucceeded() {
418 DVLOG(1) << "Kiosk launch succeeded, wait for app window.";
419 app_launch_splash_screen_actor_
->UpdateAppLaunchState(
420 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_WAITING_APP_WINDOW
);
422 DCHECK(!app_window_watcher_
);
423 app_window_watcher_
.reset(new AppWindowWatcher(this, app_id_
));
426 void AppLaunchController::OnLaunchFailed(KioskAppLaunchError::Error error
) {
427 LOG(ERROR
) << "Kiosk launch failed. Will now shut down."
428 << ", error=" << error
;
429 DCHECK_NE(KioskAppLaunchError::NONE
, error
);
431 // Saves the error and ends the session to go back to login screen.
432 KioskAppLaunchError::Save(error
);
433 chrome::AttemptUserExit();
437 bool AppLaunchController::IsShowingNetworkConfigScreen() {
438 return network_config_requested_
;
441 } // namespace chromeos