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"
7 #include "apps/app_window.h"
8 #include "apps/app_window_registry.h"
10 #include "base/callback.h"
11 #include "base/files/file_path.h"
12 #include "base/json/json_file_value_serializer.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/time/time.h"
16 #include "base/values.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/chrome_notification_types.h"
19 #include "chrome/browser/chromeos/app_mode/app_session_lifetime.h"
20 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
21 #include "chrome/browser/chromeos/app_mode/startup_app_launcher.h"
22 #include "chrome/browser/chromeos/login/login_display_host.h"
23 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
24 #include "chrome/browser/chromeos/login/oobe_display.h"
25 #include "chrome/browser/chromeos/login/screens/error_screen_actor.h"
26 #include "chrome/browser/chromeos/login/webui_login_view.h"
27 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
28 #include "chrome/browser/chromeos/settings/cros_settings.h"
29 #include "chrome/browser/lifetime/application_lifetime.h"
30 #include "chrome/browser/profiles/profile.h"
31 #include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
32 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
33 #include "content/public/browser/notification_service.h"
34 #include "net/base/network_change_notifier.h"
40 // Application install splash screen minimum show time in milliseconds.
41 const int kAppInstallSplashScreenMinTimeMS = 3000;
46 bool AppLaunchController::skip_splash_wait_ = false;
47 int AppLaunchController::network_wait_time_ = 10;
48 base::Closure* AppLaunchController::network_timeout_callback_ = NULL;
49 AppLaunchController::ReturnBoolCallback*
50 AppLaunchController::can_configure_network_callback_ = NULL;
51 AppLaunchController::ReturnBoolCallback*
52 AppLaunchController::need_owner_auth_to_configure_network_callback_ = NULL;
54 ////////////////////////////////////////////////////////////////////////////////
55 // AppLaunchController::AppWindowWatcher
57 class AppLaunchController::AppWindowWatcher
58 : public apps::AppWindowRegistry::Observer {
60 explicit AppWindowWatcher(AppLaunchController* controller,
61 const std::string& app_id)
62 : controller_(controller),
64 window_registry_(apps::AppWindowRegistry::Get(controller->profile_)),
66 if (!window_registry_->GetAppWindowsForApp(app_id).empty()) {
67 base::MessageLoop::current()->PostTask(
69 base::Bind(&AppWindowWatcher::NotifyAppWindowCreated,
70 weak_factory_.GetWeakPtr()));
73 window_registry_->AddObserver(this);
76 virtual ~AppWindowWatcher() {
77 window_registry_->RemoveObserver(this);
81 // apps::AppWindowRegistry::Observer overrides:
82 virtual void OnAppWindowAdded(apps::AppWindow* app_window) OVERRIDE {
83 if (app_window->extension_id() == app_id_) {
84 window_registry_->RemoveObserver(this);
85 NotifyAppWindowCreated();
88 virtual void OnAppWindowIconChanged(apps::AppWindow* app_window) OVERRIDE {}
89 virtual void OnAppWindowRemoved(apps::AppWindow* app_window) OVERRIDE {}
91 void NotifyAppWindowCreated() {
92 controller_->OnAppWindowCreated();
95 AppLaunchController* controller_;
97 apps::AppWindowRegistry* window_registry_;
98 base::WeakPtrFactory<AppWindowWatcher> weak_factory_;
100 DISALLOW_COPY_AND_ASSIGN(AppWindowWatcher);
103 ////////////////////////////////////////////////////////////////////////////////
104 // AppLaunchController
106 AppLaunchController::AppLaunchController(const std::string& app_id,
107 bool diagnostic_mode,
108 LoginDisplayHost* host,
109 OobeDisplay* oobe_display)
112 diagnostic_mode_(diagnostic_mode),
114 oobe_display_(oobe_display),
115 app_launch_splash_screen_actor_(
116 oobe_display_->GetAppLaunchSplashScreenActor()),
117 webui_visible_(false),
118 launcher_ready_(false),
119 waiting_for_network_(false),
120 network_wait_timedout_(false),
121 showing_network_dialog_(false),
122 launch_splash_start_time_(0) {
125 AppLaunchController::~AppLaunchController() {
126 app_launch_splash_screen_actor_->SetDelegate(NULL);
129 void AppLaunchController::StartAppLaunch() {
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 KioskAppManager::Get()->GetApp(app_id_, &app));
146 kiosk_profile_loader_.reset(
147 new KioskProfileLoader(app.user_id, false, this));
148 kiosk_profile_loader_->Start();
152 void AppLaunchController::SkipSplashWaitForTesting() {
153 skip_splash_wait_ = true;
157 void AppLaunchController::SetNetworkWaitForTesting(int wait_time_secs) {
158 network_wait_time_ = wait_time_secs;
162 void AppLaunchController::SetNetworkTimeoutCallbackForTesting(
163 base::Closure* callback) {
164 network_timeout_callback_ = callback;
168 void AppLaunchController::SetCanConfigureNetworkCallbackForTesting(
169 ReturnBoolCallback* can_configure_network_callback) {
170 can_configure_network_callback_ = can_configure_network_callback;
174 void AppLaunchController::SetNeedOwnerAuthToConfigureNetworkCallbackForTesting(
175 ReturnBoolCallback* need_owner_auth_callback) {
176 need_owner_auth_to_configure_network_callback_ = need_owner_auth_callback;
179 void AppLaunchController::OnConfigureNetwork() {
181 showing_network_dialog_ = true;
182 if (CanConfigureNetwork() && NeedOwnerAuthToConfigureNetwork()) {
183 signin_screen_.reset(new AppLaunchSigninScreen(
184 static_cast<OobeUI*>(oobe_display_), this));
185 signin_screen_->Show();
187 // If kiosk mode was configured through enterprise policy, we may
188 // not have an owner user.
189 // TODO(tengs): We need to figure out the appropriate security meausres
195 void AppLaunchController::OnOwnerSigninSuccess() {
196 app_launch_splash_screen_actor_->ShowNetworkConfigureUI();
197 signin_screen_.reset();
200 void AppLaunchController::Observe(
202 const content::NotificationSource& source,
203 const content::NotificationDetails& details) {
204 DCHECK_EQ(chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, type);
205 DCHECK(!webui_visible_);
206 webui_visible_ = true;
207 launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
212 void AppLaunchController::OnCancelAppLaunch() {
213 if (KioskAppManager::Get()->GetDisableBailoutShortcut())
216 OnLaunchFailed(KioskAppLaunchError::USER_CANCEL);
219 void AppLaunchController::OnNetworkStateChanged(bool online) {
220 if (!waiting_for_network_)
224 startup_app_launcher_->ContinueWithNetworkReady();
225 else if (network_wait_timedout_)
226 MaybeShowNetworkConfigureUI();
229 void AppLaunchController::OnProfileLoaded(Profile* profile) {
230 DVLOG(1) << "Profile loaded... Starting app launch.";
233 kiosk_profile_loader_.reset();
234 startup_app_launcher_.reset(
235 new StartupAppLauncher(profile_, app_id_, diagnostic_mode_, this));
236 startup_app_launcher_->Initialize();
239 void AppLaunchController::OnProfileLoadFailed(
240 KioskAppLaunchError::Error error) {
241 OnLaunchFailed(error);
244 void AppLaunchController::CleanUp() {
245 kiosk_profile_loader_.reset();
246 startup_app_launcher_.reset();
247 splash_wait_timer_.Stop();
253 void AppLaunchController::OnNetworkWaitTimedout() {
254 DCHECK(waiting_for_network_);
255 LOG(WARNING) << "OnNetworkWaitTimedout... connection = "
256 << net::NetworkChangeNotifier::GetConnectionType();
257 network_wait_timedout_ = true;
259 MaybeShowNetworkConfigureUI();
261 if (network_timeout_callback_)
262 network_timeout_callback_->Run();
265 void AppLaunchController::OnAppWindowCreated() {
266 DVLOG(1) << "App window created, closing splash screen.";
270 bool AppLaunchController::CanConfigureNetwork() {
271 if (can_configure_network_callback_)
272 return can_configure_network_callback_->Run();
274 policy::BrowserPolicyConnectorChromeOS* connector =
275 g_browser_process->platform_part()->browser_policy_connector_chromeos();
276 if (connector->IsEnterpriseManaged()) {
278 if (CrosSettings::Get()->GetBoolean(
279 kAccountsPrefDeviceLocalAccountPromptForNetworkWhenOffline,
281 return should_prompt;
284 // Default to true to allow network configuration if the policy is missing.
288 return !UserManager::Get()->GetOwnerEmail().empty();
291 bool AppLaunchController::NeedOwnerAuthToConfigureNetwork() {
292 if (need_owner_auth_to_configure_network_callback_)
293 return need_owner_auth_to_configure_network_callback_->Run();
295 policy::BrowserPolicyConnectorChromeOS* connector =
296 g_browser_process->platform_part()->browser_policy_connector_chromeos();
297 return !connector->IsEnterpriseManaged();
300 void AppLaunchController::MaybeShowNetworkConfigureUI() {
301 if (CanConfigureNetwork()) {
302 if (NeedOwnerAuthToConfigureNetwork()) {
303 app_launch_splash_screen_actor_->ToggleNetworkConfig(true);
305 showing_network_dialog_ = true;
306 app_launch_splash_screen_actor_->ShowNetworkConfigureUI();
309 app_launch_splash_screen_actor_->UpdateAppLaunchState(
310 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_NETWORK_WAIT_TIMEOUT);
314 void AppLaunchController::InitializeNetwork() {
315 // Show the network configration dialog if network is not initialized
316 // after a brief wait time.
317 waiting_for_network_ = true;
318 network_wait_timer_.Start(
320 base::TimeDelta::FromSeconds(network_wait_time_),
321 this, &AppLaunchController::OnNetworkWaitTimedout);
323 app_launch_splash_screen_actor_->UpdateAppLaunchState(
324 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_PREPARING_NETWORK);
327 bool AppLaunchController::IsNetworkReady() {
328 return app_launch_splash_screen_actor_->IsNetworkReady();
331 void AppLaunchController::OnLoadingOAuthFile() {
332 app_launch_splash_screen_actor_->UpdateAppLaunchState(
333 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_AUTH_FILE);
336 void AppLaunchController::OnInitializingTokenService() {
337 app_launch_splash_screen_actor_->UpdateAppLaunchState(
338 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE);
341 void AppLaunchController::OnInstallingApp() {
342 app_launch_splash_screen_actor_->UpdateAppLaunchState(
343 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_INSTALLING_APPLICATION);
345 waiting_for_network_ = false;
346 network_wait_timer_.Stop();
347 app_launch_splash_screen_actor_->ToggleNetworkConfig(false);
349 // We have connectivity at this point, so we can skip the network
350 // configuration dialog if it is being shown.
351 if (showing_network_dialog_) {
352 app_launch_splash_screen_actor_->Show(app_id_);
353 showing_network_dialog_ = false;
354 launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
358 void AppLaunchController::OnReadyToLaunch() {
359 launcher_ready_ = true;
363 if (splash_wait_timer_.IsRunning())
366 const int64 time_taken_ms = (base::TimeTicks::Now() -
367 base::TimeTicks::FromInternalValue(launch_splash_start_time_)).
370 // Enforce that we show app install splash screen for some minimum amount
372 if (!skip_splash_wait_ && time_taken_ms < kAppInstallSplashScreenMinTimeMS) {
373 splash_wait_timer_.Start(
375 base::TimeDelta::FromMilliseconds(
376 kAppInstallSplashScreenMinTimeMS - time_taken_ms),
378 &AppLaunchController::OnReadyToLaunch);
382 startup_app_launcher_->LaunchApp();
385 void AppLaunchController::OnLaunchSucceeded() {
386 DVLOG(1) << "Kiosk launch succeeded, wait for app window.";
387 app_launch_splash_screen_actor_->UpdateAppLaunchState(
388 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_WAITING_APP_WINDOW);
390 DCHECK(!app_window_watcher_);
391 app_window_watcher_.reset(new AppWindowWatcher(this, app_id_));
394 void AppLaunchController::OnLaunchFailed(KioskAppLaunchError::Error error) {
395 LOG(ERROR) << "Kiosk launch failed. Will now shut down."
396 << ", error=" << error;
397 DCHECK_NE(KioskAppLaunchError::NONE, error);
399 // Saves the error and ends the session to go back to login screen.
400 KioskAppLaunchError::Save(error);
401 chrome::AttemptUserExit();
405 } // namespace chromeos