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/screens/error_screen_actor.h"
22 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
23 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
24 #include "chrome/browser/chromeos/login/ui/oobe_display.h"
25 #include "chrome/browser/chromeos/login/ui/webui_login_view.h"
26 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
27 #include "chrome/browser/chromeos/settings/cros_settings.h"
28 #include "chrome/browser/lifetime/application_lifetime.h"
29 #include "chrome/browser/profiles/profile.h"
30 #include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
31 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.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 virtual ~AppWindowWatcher() {
80 window_registry_->RemoveObserver(this);
84 // extensions::AppWindowRegistry::Observer overrides:
85 virtual void OnAppWindowAdded(extensions::AppWindow* app_window) override {
86 if (app_window->extension_id() == app_id_) {
87 window_registry_->RemoveObserver(this);
88 NotifyAppWindowCreated();
92 void NotifyAppWindowCreated() {
93 controller_->OnAppWindowCreated();
96 AppLaunchController* controller_;
98 extensions::AppWindowRegistry* window_registry_;
99 base::WeakPtrFactory<AppWindowWatcher> weak_factory_;
101 DISALLOW_COPY_AND_ASSIGN(AppWindowWatcher);
104 ////////////////////////////////////////////////////////////////////////////////
105 // AppLaunchController
107 AppLaunchController::AppLaunchController(const std::string& app_id,
108 bool diagnostic_mode,
109 LoginDisplayHost* host,
110 OobeDisplay* oobe_display)
113 diagnostic_mode_(diagnostic_mode),
115 oobe_display_(oobe_display),
116 app_launch_splash_screen_actor_(
117 oobe_display_->GetAppLaunchSplashScreenActor()),
118 webui_visible_(false),
119 launcher_ready_(false),
120 waiting_for_network_(false),
121 network_wait_timedout_(false),
122 showing_network_dialog_(false),
123 network_config_requested_(false),
124 launch_splash_start_time_(0) {
127 AppLaunchController::~AppLaunchController() {
128 app_launch_splash_screen_actor_->SetDelegate(NULL);
131 void AppLaunchController::StartAppLaunch() {
132 DVLOG(1) << "Starting kiosk mode...";
134 webui_visible_ = host_->GetWebUILoginView()->webui_visible();
135 if (!webui_visible_) {
136 registrar_.Add(this, chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
137 content::NotificationService::AllSources());
139 launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
141 // TODO(tengs): Add a loading profile app launch state.
142 app_launch_splash_screen_actor_->SetDelegate(this);
143 app_launch_splash_screen_actor_->Show(app_id_);
145 KioskAppManager::App app;
146 CHECK(KioskAppManager::Get());
147 CHECK(KioskAppManager::Get()->GetApp(app_id_, &app));
148 kiosk_profile_loader_.reset(
149 new KioskProfileLoader(app.user_id, false, this));
150 kiosk_profile_loader_->Start();
154 void AppLaunchController::SkipSplashWaitForTesting() {
155 skip_splash_wait_ = true;
159 void AppLaunchController::SetNetworkWaitForTesting(int wait_time_secs) {
160 network_wait_time_ = wait_time_secs;
164 void AppLaunchController::SetNetworkTimeoutCallbackForTesting(
165 base::Closure* callback) {
166 network_timeout_callback_ = callback;
170 void AppLaunchController::SetCanConfigureNetworkCallbackForTesting(
171 ReturnBoolCallback* can_configure_network_callback) {
172 can_configure_network_callback_ = can_configure_network_callback;
176 void AppLaunchController::SetNeedOwnerAuthToConfigureNetworkCallbackForTesting(
177 ReturnBoolCallback* need_owner_auth_callback) {
178 need_owner_auth_to_configure_network_callback_ = need_owner_auth_callback;
181 void AppLaunchController::OnConfigureNetwork() {
183 showing_network_dialog_ = true;
184 if (CanConfigureNetwork() && NeedOwnerAuthToConfigureNetwork()) {
185 signin_screen_.reset(new AppLaunchSigninScreen(
186 static_cast<OobeUI*>(oobe_display_), this));
187 signin_screen_->Show();
189 // If kiosk mode was configured through enterprise policy, we may
190 // not have an owner user.
191 // TODO(tengs): We need to figure out the appropriate security meausres
197 void AppLaunchController::OnOwnerSigninSuccess() {
198 app_launch_splash_screen_actor_->ShowNetworkConfigureUI();
199 signin_screen_.reset();
202 void AppLaunchController::Observe(
204 const content::NotificationSource& source,
205 const content::NotificationDetails& details) {
206 DCHECK_EQ(chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, type);
207 DCHECK(!webui_visible_);
208 webui_visible_ = true;
209 launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
214 void AppLaunchController::OnCancelAppLaunch() {
215 if (KioskAppManager::Get()->GetDisableBailoutShortcut())
218 OnLaunchFailed(KioskAppLaunchError::USER_CANCEL);
221 void AppLaunchController::OnNetworkConfigRequested(bool requested) {
222 network_config_requested_ = requested;
224 MaybeShowNetworkConfigureUI();
226 startup_app_launcher_->RestartLauncher();
229 void AppLaunchController::OnNetworkStateChanged(bool online) {
230 if (!waiting_for_network_)
233 if (online && !network_config_requested_)
234 startup_app_launcher_->ContinueWithNetworkReady();
235 else if (network_wait_timedout_)
236 MaybeShowNetworkConfigureUI();
239 void AppLaunchController::OnProfileLoaded(Profile* profile) {
240 DVLOG(1) << "Profile loaded... Starting app launch.";
243 // This is needed to trigger input method extensions being loaded.
244 profile_->InitChromeOSPreferences();
246 kiosk_profile_loader_.reset();
247 startup_app_launcher_.reset(
248 new StartupAppLauncher(profile_, app_id_, diagnostic_mode_, this));
249 startup_app_launcher_->Initialize();
252 void AppLaunchController::OnProfileLoadFailed(
253 KioskAppLaunchError::Error error) {
254 OnLaunchFailed(error);
257 void AppLaunchController::CleanUp() {
258 kiosk_profile_loader_.reset();
259 startup_app_launcher_.reset();
260 splash_wait_timer_.Stop();
266 void AppLaunchController::OnNetworkWaitTimedout() {
267 DCHECK(waiting_for_network_);
268 LOG(WARNING) << "OnNetworkWaitTimedout... connection = "
269 << net::NetworkChangeNotifier::GetConnectionType();
270 network_wait_timedout_ = true;
272 MaybeShowNetworkConfigureUI();
274 if (network_timeout_callback_)
275 network_timeout_callback_->Run();
278 void AppLaunchController::OnAppWindowCreated() {
279 DVLOG(1) << "App window created, closing splash screen.";
283 bool AppLaunchController::CanConfigureNetwork() {
284 if (can_configure_network_callback_)
285 return can_configure_network_callback_->Run();
287 policy::BrowserPolicyConnectorChromeOS* connector =
288 g_browser_process->platform_part()->browser_policy_connector_chromeos();
289 if (connector->IsEnterpriseManaged()) {
291 if (CrosSettings::Get()->GetBoolean(
292 kAccountsPrefDeviceLocalAccountPromptForNetworkWhenOffline,
294 return should_prompt;
297 // Default to true to allow network configuration if the policy is missing.
301 return !user_manager::UserManager::Get()->GetOwnerEmail().empty();
304 bool AppLaunchController::NeedOwnerAuthToConfigureNetwork() {
305 if (need_owner_auth_to_configure_network_callback_)
306 return need_owner_auth_to_configure_network_callback_->Run();
308 policy::BrowserPolicyConnectorChromeOS* connector =
309 g_browser_process->platform_part()->browser_policy_connector_chromeos();
310 return !connector->IsEnterpriseManaged();
313 void AppLaunchController::MaybeShowNetworkConfigureUI() {
314 if (CanConfigureNetwork()) {
315 if (NeedOwnerAuthToConfigureNetwork()) {
316 if (network_config_requested_)
317 OnConfigureNetwork();
319 app_launch_splash_screen_actor_->ToggleNetworkConfig(true);
321 showing_network_dialog_ = true;
322 app_launch_splash_screen_actor_->ShowNetworkConfigureUI();
325 app_launch_splash_screen_actor_->UpdateAppLaunchState(
326 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_NETWORK_WAIT_TIMEOUT);
330 void AppLaunchController::InitializeNetwork() {
331 // Show the network configuration dialog if network is not initialized
332 // after a brief wait time.
333 waiting_for_network_ = true;
334 network_wait_timer_.Start(
336 base::TimeDelta::FromSeconds(network_wait_time_),
337 this, &AppLaunchController::OnNetworkWaitTimedout);
339 app_launch_splash_screen_actor_->UpdateAppLaunchState(
340 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_PREPARING_NETWORK);
343 bool AppLaunchController::IsNetworkReady() {
344 return app_launch_splash_screen_actor_->IsNetworkReady();
347 void AppLaunchController::OnLoadingOAuthFile() {
348 app_launch_splash_screen_actor_->UpdateAppLaunchState(
349 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_AUTH_FILE);
352 void AppLaunchController::OnInitializingTokenService() {
353 app_launch_splash_screen_actor_->UpdateAppLaunchState(
354 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE);
357 void AppLaunchController::OnInstallingApp() {
358 app_launch_splash_screen_actor_->UpdateAppLaunchState(
359 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_INSTALLING_APPLICATION);
361 waiting_for_network_ = false;
362 network_wait_timer_.Stop();
363 app_launch_splash_screen_actor_->ToggleNetworkConfig(false);
365 // We have connectivity at this point, so we can skip the network
366 // configuration dialog if it is being shown.
367 if (showing_network_dialog_) {
368 app_launch_splash_screen_actor_->Show(app_id_);
369 showing_network_dialog_ = false;
370 launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
374 void AppLaunchController::OnReadyToLaunch() {
375 launcher_ready_ = true;
377 if (network_config_requested_)
383 if (splash_wait_timer_.IsRunning())
386 const int64 time_taken_ms = (base::TimeTicks::Now() -
387 base::TimeTicks::FromInternalValue(launch_splash_start_time_)).
390 // Enforce that we show app install splash screen for some minimum amount
392 if (!skip_splash_wait_ && time_taken_ms < kAppInstallSplashScreenMinTimeMS) {
393 splash_wait_timer_.Start(
395 base::TimeDelta::FromMilliseconds(
396 kAppInstallSplashScreenMinTimeMS - time_taken_ms),
398 &AppLaunchController::OnReadyToLaunch);
402 startup_app_launcher_->LaunchApp();
405 void AppLaunchController::OnLaunchSucceeded() {
406 DVLOG(1) << "Kiosk launch succeeded, wait for app window.";
407 app_launch_splash_screen_actor_->UpdateAppLaunchState(
408 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_WAITING_APP_WINDOW);
410 DCHECK(!app_window_watcher_);
411 app_window_watcher_.reset(new AppWindowWatcher(this, app_id_));
414 void AppLaunchController::OnLaunchFailed(KioskAppLaunchError::Error error) {
415 LOG(ERROR) << "Kiosk launch failed. Will now shut down."
416 << ", error=" << error;
417 DCHECK_NE(KioskAppLaunchError::NONE, error);
419 // Saves the error and ends the session to go back to login screen.
420 KioskAppLaunchError::Save(error);
421 chrome::AttemptUserExit();
425 bool AppLaunchController::IsShowingNetworkConfigScreen() {
426 return network_config_requested_;
429 } // namespace chromeos