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/logging.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/time/time.h"
17 #include "base/values.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/chrome_notification_types.h"
20 #include "chrome/browser/chromeos/app_mode/app_session_lifetime.h"
21 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
22 #include "chrome/browser/chromeos/app_mode/startup_app_launcher.h"
23 #include "chrome/browser/chromeos/login/login_display_host.h"
24 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
25 #include "chrome/browser/chromeos/login/oobe_display.h"
26 #include "chrome/browser/chromeos/login/screens/error_screen_actor.h"
27 #include "chrome/browser/chromeos/login/webui_login_view.h"
28 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
29 #include "chrome/browser/chromeos/settings/cros_settings.h"
30 #include "chrome/browser/lifetime/application_lifetime.h"
31 #include "chrome/browser/profiles/profile.h"
32 #include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
33 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
34 #include "content/public/browser/notification_service.h"
35 #include "net/base/network_change_notifier.h"
41 // Application install splash screen minimum show time in milliseconds.
42 const int kAppInstallSplashScreenMinTimeMS = 3000;
47 bool AppLaunchController::skip_splash_wait_ = false;
48 int AppLaunchController::network_wait_time_ = 10;
49 base::Closure* AppLaunchController::network_timeout_callback_ = NULL;
50 AppLaunchController::ReturnBoolCallback*
51 AppLaunchController::can_configure_network_callback_ = NULL;
52 AppLaunchController::ReturnBoolCallback*
53 AppLaunchController::need_owner_auth_to_configure_network_callback_ = NULL;
55 ////////////////////////////////////////////////////////////////////////////////
56 // AppLaunchController::AppWindowWatcher
58 class AppLaunchController::AppWindowWatcher
59 : public apps::AppWindowRegistry::Observer {
61 explicit AppWindowWatcher(AppLaunchController* controller,
62 const std::string& app_id)
63 : controller_(controller),
65 window_registry_(apps::AppWindowRegistry::Get(controller->profile_)),
67 if (!window_registry_->GetAppWindowsForApp(app_id).empty()) {
68 base::MessageLoop::current()->PostTask(
70 base::Bind(&AppWindowWatcher::NotifyAppWindowCreated,
71 weak_factory_.GetWeakPtr()));
74 window_registry_->AddObserver(this);
77 virtual ~AppWindowWatcher() {
78 window_registry_->RemoveObserver(this);
82 // apps::AppWindowRegistry::Observer overrides:
83 virtual void OnAppWindowAdded(apps::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 apps::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() {
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));
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::OnNetworkConfigRequested(bool requested) {
220 network_config_requested_ = requested;
222 MaybeShowNetworkConfigureUI();
224 startup_app_launcher_->RestartLauncher();
227 void AppLaunchController::OnNetworkStateChanged(bool online) {
228 if (!waiting_for_network_)
231 if (online && !network_config_requested_)
232 startup_app_launcher_->ContinueWithNetworkReady();
233 else if (network_wait_timedout_)
234 MaybeShowNetworkConfigureUI();
237 void AppLaunchController::OnProfileLoaded(Profile* profile) {
238 DVLOG(1) << "Profile loaded... Starting app launch.";
241 // This is needed to trigger input method extensions being loaded.
242 profile_->InitChromeOSPreferences();
244 kiosk_profile_loader_.reset();
245 startup_app_launcher_.reset(
246 new StartupAppLauncher(profile_, app_id_, diagnostic_mode_, this));
247 startup_app_launcher_->Initialize();
250 void AppLaunchController::OnProfileLoadFailed(
251 KioskAppLaunchError::Error error) {
252 OnLaunchFailed(error);
255 void AppLaunchController::CleanUp() {
256 kiosk_profile_loader_.reset();
257 startup_app_launcher_.reset();
258 splash_wait_timer_.Stop();
264 void AppLaunchController::OnNetworkWaitTimedout() {
265 DCHECK(waiting_for_network_);
266 LOG(WARNING) << "OnNetworkWaitTimedout... connection = "
267 << net::NetworkChangeNotifier::GetConnectionType();
268 network_wait_timedout_ = true;
270 MaybeShowNetworkConfigureUI();
272 if (network_timeout_callback_)
273 network_timeout_callback_->Run();
276 void AppLaunchController::OnAppWindowCreated() {
277 DVLOG(1) << "App window created, closing splash screen.";
281 bool AppLaunchController::CanConfigureNetwork() {
282 if (can_configure_network_callback_)
283 return can_configure_network_callback_->Run();
285 policy::BrowserPolicyConnectorChromeOS* connector =
286 g_browser_process->platform_part()->browser_policy_connector_chromeos();
287 if (connector->IsEnterpriseManaged()) {
289 if (CrosSettings::Get()->GetBoolean(
290 kAccountsPrefDeviceLocalAccountPromptForNetworkWhenOffline,
292 return should_prompt;
295 // Default to true to allow network configuration if the policy is missing.
299 return !UserManager::Get()->GetOwnerEmail().empty();
302 bool AppLaunchController::NeedOwnerAuthToConfigureNetwork() {
303 if (need_owner_auth_to_configure_network_callback_)
304 return need_owner_auth_to_configure_network_callback_->Run();
306 policy::BrowserPolicyConnectorChromeOS* connector =
307 g_browser_process->platform_part()->browser_policy_connector_chromeos();
308 return !connector->IsEnterpriseManaged();
311 void AppLaunchController::MaybeShowNetworkConfigureUI() {
312 if (CanConfigureNetwork()) {
313 if (NeedOwnerAuthToConfigureNetwork()) {
314 if (network_config_requested_)
315 OnConfigureNetwork();
317 app_launch_splash_screen_actor_->ToggleNetworkConfig(true);
319 showing_network_dialog_ = true;
320 app_launch_splash_screen_actor_->ShowNetworkConfigureUI();
323 app_launch_splash_screen_actor_->UpdateAppLaunchState(
324 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_NETWORK_WAIT_TIMEOUT);
328 void AppLaunchController::InitializeNetwork() {
329 // Show the network configuration dialog if network is not initialized
330 // after a brief wait time.
331 waiting_for_network_ = true;
332 network_wait_timer_.Start(
334 base::TimeDelta::FromSeconds(network_wait_time_),
335 this, &AppLaunchController::OnNetworkWaitTimedout);
337 app_launch_splash_screen_actor_->UpdateAppLaunchState(
338 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_PREPARING_NETWORK);
341 bool AppLaunchController::IsNetworkReady() {
342 return app_launch_splash_screen_actor_->IsNetworkReady();
345 void AppLaunchController::OnLoadingOAuthFile() {
346 app_launch_splash_screen_actor_->UpdateAppLaunchState(
347 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_AUTH_FILE);
350 void AppLaunchController::OnInitializingTokenService() {
351 app_launch_splash_screen_actor_->UpdateAppLaunchState(
352 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE);
355 void AppLaunchController::OnInstallingApp() {
356 app_launch_splash_screen_actor_->UpdateAppLaunchState(
357 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_INSTALLING_APPLICATION);
359 waiting_for_network_ = false;
360 network_wait_timer_.Stop();
361 app_launch_splash_screen_actor_->ToggleNetworkConfig(false);
363 // We have connectivity at this point, so we can skip the network
364 // configuration dialog if it is being shown.
365 if (showing_network_dialog_) {
366 app_launch_splash_screen_actor_->Show(app_id_);
367 showing_network_dialog_ = false;
368 launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
372 void AppLaunchController::OnReadyToLaunch() {
373 launcher_ready_ = true;
375 if (network_config_requested_)
381 if (splash_wait_timer_.IsRunning())
384 const int64 time_taken_ms = (base::TimeTicks::Now() -
385 base::TimeTicks::FromInternalValue(launch_splash_start_time_)).
388 // Enforce that we show app install splash screen for some minimum amount
390 if (!skip_splash_wait_ && time_taken_ms < kAppInstallSplashScreenMinTimeMS) {
391 splash_wait_timer_.Start(
393 base::TimeDelta::FromMilliseconds(
394 kAppInstallSplashScreenMinTimeMS - time_taken_ms),
396 &AppLaunchController::OnReadyToLaunch);
400 startup_app_launcher_->LaunchApp();
403 void AppLaunchController::OnLaunchSucceeded() {
404 DVLOG(1) << "Kiosk launch succeeded, wait for app window.";
405 app_launch_splash_screen_actor_->UpdateAppLaunchState(
406 AppLaunchSplashScreenActor::APP_LAUNCH_STATE_WAITING_APP_WINDOW);
408 DCHECK(!app_window_watcher_);
409 app_window_watcher_.reset(new AppWindowWatcher(this, app_id_));
412 void AppLaunchController::OnLaunchFailed(KioskAppLaunchError::Error error) {
413 LOG(ERROR) << "Kiosk launch failed. Will now shut down."
414 << ", error=" << error;
415 DCHECK_NE(KioskAppLaunchError::NONE, error);
417 // Saves the error and ends the session to go back to login screen.
418 KioskAppLaunchError::Save(error);
419 chrome::AttemptUserExit();
423 bool AppLaunchController::IsShowingNetworkConfigScreen() {
424 return network_config_requested_;
427 } // namespace chromeos