e95078d51041f66a4399b8a31f43da9a231b1f47
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / login / app_launch_controller.cc
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.
4
5 #include "chrome/browser/chromeos/login/app_launch_controller.h"
6
7 #include "apps/shell_window_registry.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/time/time.h"
12 #include "base/values.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/chromeos/app_mode/app_session_lifetime.h"
16 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
17 #include "chrome/browser/chromeos/app_mode/startup_app_launcher.h"
18 #include "chrome/browser/chromeos/login/login_display_host.h"
19 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
20 #include "chrome/browser/chromeos/login/oobe_display.h"
21 #include "chrome/browser/chromeos/login/screens/error_screen_actor.h"
22 #include "chrome/browser/chromeos/login/webui_login_view.h"
23 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
24 #include "chrome/browser/chromeos/settings/cros_settings.h"
25 #include "chrome/browser/lifetime/application_lifetime.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
28 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
29 #include "content/public/browser/notification_service.h"
30 #include "net/base/network_change_notifier.h"
31
32 namespace chromeos {
33
34 namespace {
35
36 // Application install splash screen minimum show time in milliseconds.
37 const int kAppInstallSplashScreenMinTimeMS = 3000;
38
39 }  // namespace
40
41 // static
42 bool AppLaunchController::skip_splash_wait_ = false;
43 int AppLaunchController::network_wait_time_ = 10;
44 base::Closure* AppLaunchController::network_timeout_callback_ = NULL;
45 AppLaunchController::ReturnBoolCallback*
46     AppLaunchController::can_configure_network_callback_ = NULL;
47 AppLaunchController::ReturnBoolCallback*
48     AppLaunchController::need_owner_auth_to_configure_network_callback_ = NULL;
49
50 ////////////////////////////////////////////////////////////////////////////////
51 // AppLaunchController::AppWindowWatcher
52
53 class AppLaunchController::AppWindowWatcher
54     : public apps::ShellWindowRegistry::Observer {
55  public:
56   explicit AppWindowWatcher(AppLaunchController* controller)
57     : controller_(controller),
58       window_registry_(apps::ShellWindowRegistry::Get(controller->profile_)) {
59     window_registry_->AddObserver(this);
60   }
61   virtual ~AppWindowWatcher() {
62     window_registry_->RemoveObserver(this);
63   }
64
65  private:
66   // apps::ShellWindowRegistry::Observer overrides:
67   virtual void OnShellWindowAdded(apps::ShellWindow* shell_window) OVERRIDE {
68     if (controller_) {
69       controller_->OnAppWindowCreated();
70       controller_= NULL;
71     }
72   }
73   virtual void OnShellWindowIconChanged(
74       apps::ShellWindow* shell_window) OVERRIDE {}
75   virtual void OnShellWindowRemoved(apps::ShellWindow* shell_window) OVERRIDE {}
76
77   AppLaunchController* controller_;
78   apps::ShellWindowRegistry* window_registry_;
79
80   DISALLOW_COPY_AND_ASSIGN(AppWindowWatcher);
81 };
82
83 ////////////////////////////////////////////////////////////////////////////////
84 // AppLaunchController
85
86 AppLaunchController::AppLaunchController(const std::string& app_id,
87                                          LoginDisplayHost* host,
88                                          OobeDisplay* oobe_display)
89     : profile_(NULL),
90       app_id_(app_id),
91       host_(host),
92       oobe_display_(oobe_display),
93       app_launch_splash_screen_actor_(
94           oobe_display_->GetAppLaunchSplashScreenActor()),
95       webui_visible_(false),
96       launcher_ready_(false),
97       waiting_for_network_(false),
98       network_wait_timedout_(false),
99       showing_network_dialog_(false),
100       launch_splash_start_time_(0) {
101 }
102
103 AppLaunchController::~AppLaunchController() {
104   app_launch_splash_screen_actor_->SetDelegate(NULL);
105 }
106
107 void AppLaunchController::StartAppLaunch() {
108   DVLOG(1) << "Starting kiosk mode...";
109
110   webui_visible_ = host_->GetWebUILoginView()->webui_visible();
111   if (!webui_visible_) {
112     registrar_.Add(this, chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
113                    content::NotificationService::AllSources());
114   }
115   launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
116
117   // TODO(tengs): Add a loading profile app launch state.
118   app_launch_splash_screen_actor_->SetDelegate(this);
119   app_launch_splash_screen_actor_->Show(app_id_);
120
121   kiosk_profile_loader_.reset(
122       new KioskProfileLoader(KioskAppManager::Get(), app_id_, this));
123   kiosk_profile_loader_->Start();
124 }
125
126 // static
127 void AppLaunchController::SkipSplashWaitForTesting() {
128   skip_splash_wait_ = true;
129 }
130
131 // static
132 void AppLaunchController::SetNetworkWaitForTesting(int wait_time_secs) {
133   network_wait_time_ = wait_time_secs;
134 }
135
136 // static
137 void AppLaunchController::SetNetworkTimeoutCallbackForTesting(
138     base::Closure* callback) {
139   network_timeout_callback_ = callback;
140 }
141
142 // static
143 void AppLaunchController::SetCanConfigureNetworkCallbackForTesting(
144     ReturnBoolCallback* can_configure_network_callback) {
145   can_configure_network_callback_ = can_configure_network_callback;
146 }
147
148 // static
149 void AppLaunchController::SetNeedOwnerAuthToConfigureNetworkCallbackForTesting(
150     ReturnBoolCallback* need_owner_auth_callback) {
151   need_owner_auth_to_configure_network_callback_ = need_owner_auth_callback;
152 }
153
154 void AppLaunchController::OnConfigureNetwork() {
155   DCHECK(profile_);
156   showing_network_dialog_ = true;
157   if (CanConfigureNetwork() && NeedOwnerAuthToConfigureNetwork()) {
158     signin_screen_.reset(new AppLaunchSigninScreen(
159        static_cast<OobeUI*>(oobe_display_), this));
160     signin_screen_->Show();
161   } else {
162     // If kiosk mode was configured through enterprise policy, we may
163     // not have an owner user.
164     // TODO(tengs): We need to figure out the appropriate security meausres
165     // for this case.
166     NOTREACHED();
167   }
168 }
169
170 void AppLaunchController::OnOwnerSigninSuccess() {
171   app_launch_splash_screen_actor_->ShowNetworkConfigureUI();
172   signin_screen_.reset();
173 }
174
175 void AppLaunchController::Observe(
176     int type,
177     const content::NotificationSource& source,
178     const content::NotificationDetails& details) {
179   DCHECK_EQ(chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, type);
180   DCHECK(!webui_visible_);
181   webui_visible_ = true;
182   launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
183   if (launcher_ready_)
184     OnReadyToLaunch();
185 }
186
187 void AppLaunchController::OnCancelAppLaunch() {
188   if (KioskAppManager::Get()->GetDisableBailoutShortcut())
189     return;
190
191   OnLaunchFailed(KioskAppLaunchError::USER_CANCEL);
192 }
193
194 void AppLaunchController::OnNetworkStateChanged(bool online) {
195   if (!waiting_for_network_)
196     return;
197
198   if (online)
199     startup_app_launcher_->ContinueWithNetworkReady();
200   else if (network_wait_timedout_)
201     MaybeShowNetworkConfigureUI();
202 }
203
204 void AppLaunchController::OnProfileLoaded(Profile* profile) {
205   DVLOG(1) << "Profile loaded... Starting app launch.";
206   profile_ = profile;
207
208   kiosk_profile_loader_.reset();
209   startup_app_launcher_.reset(new StartupAppLauncher(profile_, app_id_, this));
210   startup_app_launcher_->Initialize();
211 }
212
213 void AppLaunchController::OnProfileLoadFailed(
214     KioskAppLaunchError::Error error) {
215   OnLaunchFailed(error);
216 }
217
218 void AppLaunchController::CleanUp() {
219   kiosk_profile_loader_.reset();
220   startup_app_launcher_.reset();
221   splash_wait_timer_.Stop();
222
223   if (host_)
224     host_->Finalize();
225 }
226
227 void AppLaunchController::OnNetworkWaitTimedout() {
228   DCHECK(waiting_for_network_);
229   LOG(WARNING) << "OnNetworkWaitTimedout... connection = "
230                <<  net::NetworkChangeNotifier::GetConnectionType();
231   network_wait_timedout_ = true;
232
233   MaybeShowNetworkConfigureUI();
234
235   if (network_timeout_callback_)
236     network_timeout_callback_->Run();
237 }
238
239 void AppLaunchController::OnAppWindowCreated() {
240   DVLOG(1) << "App window created, closing splash screen.";
241   CleanUp();
242 }
243
244 bool AppLaunchController::CanConfigureNetwork() {
245   if (can_configure_network_callback_)
246     return can_configure_network_callback_->Run();
247
248   policy::BrowserPolicyConnectorChromeOS* connector =
249       g_browser_process->platform_part()->browser_policy_connector_chromeos();
250   if (connector->IsEnterpriseManaged()) {
251     bool should_prompt;
252     if (CrosSettings::Get()->GetBoolean(
253             kAccountsPrefDeviceLocalAccountPromptForNetworkWhenOffline,
254             &should_prompt)) {
255       return should_prompt;
256     }
257
258     // Default to true to allow network configuration if the policy is missing.
259     return true;
260   }
261
262   return !UserManager::Get()->GetOwnerEmail().empty();
263 }
264
265 bool AppLaunchController::NeedOwnerAuthToConfigureNetwork() {
266   if (need_owner_auth_to_configure_network_callback_)
267     return need_owner_auth_to_configure_network_callback_->Run();
268
269   policy::BrowserPolicyConnectorChromeOS* connector =
270       g_browser_process->platform_part()->browser_policy_connector_chromeos();
271   return !connector->IsEnterpriseManaged();
272 }
273
274 void AppLaunchController::MaybeShowNetworkConfigureUI() {
275   if (CanConfigureNetwork()) {
276     if (NeedOwnerAuthToConfigureNetwork()) {
277       app_launch_splash_screen_actor_->ToggleNetworkConfig(true);
278     } else {
279       showing_network_dialog_ = true;
280       app_launch_splash_screen_actor_->ShowNetworkConfigureUI();
281     }
282   } else {
283     app_launch_splash_screen_actor_->UpdateAppLaunchState(
284         AppLaunchSplashScreenActor::APP_LAUNCH_STATE_NETWORK_WAIT_TIMEOUT);
285   }
286 }
287
288 void AppLaunchController::InitializeNetwork() {
289   // Show the network configration dialog if network is not initialized
290   // after a brief wait time.
291   waiting_for_network_ = true;
292   network_wait_timer_.Start(
293       FROM_HERE,
294       base::TimeDelta::FromSeconds(network_wait_time_),
295       this, &AppLaunchController::OnNetworkWaitTimedout);
296
297   app_launch_splash_screen_actor_->UpdateAppLaunchState(
298       AppLaunchSplashScreenActor::APP_LAUNCH_STATE_PREPARING_NETWORK);
299 }
300
301 void AppLaunchController::OnLoadingOAuthFile() {
302   app_launch_splash_screen_actor_->UpdateAppLaunchState(
303       AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_AUTH_FILE);
304 }
305
306 void AppLaunchController::OnInitializingTokenService() {
307   app_launch_splash_screen_actor_->UpdateAppLaunchState(
308       AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE);
309 }
310
311 void AppLaunchController::OnInstallingApp() {
312   app_launch_splash_screen_actor_->UpdateAppLaunchState(
313       AppLaunchSplashScreenActor::APP_LAUNCH_STATE_INSTALLING_APPLICATION);
314
315   waiting_for_network_ = false;
316   network_wait_timer_.Stop();
317   app_launch_splash_screen_actor_->ToggleNetworkConfig(false);
318
319   // We have connectivity at this point, so we can skip the network
320   // configuration dialog if it is being shown.
321   if (showing_network_dialog_) {
322     app_launch_splash_screen_actor_->Show(app_id_);
323     showing_network_dialog_ = false;
324     launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
325   }
326 }
327
328 void AppLaunchController::OnReadyToLaunch() {
329   launcher_ready_ = true;
330   if (!webui_visible_)
331     return;
332
333   if (splash_wait_timer_.IsRunning())
334     return;
335
336   const int64 time_taken_ms = (base::TimeTicks::Now() -
337       base::TimeTicks::FromInternalValue(launch_splash_start_time_)).
338       InMilliseconds();
339
340   // Enforce that we show app install splash screen for some minimum amount
341   // of time.
342   if (!skip_splash_wait_ && time_taken_ms < kAppInstallSplashScreenMinTimeMS) {
343     splash_wait_timer_.Start(
344         FROM_HERE,
345         base::TimeDelta::FromMilliseconds(
346             kAppInstallSplashScreenMinTimeMS - time_taken_ms),
347         this,
348         &AppLaunchController::OnReadyToLaunch);
349     return;
350   }
351
352   startup_app_launcher_->LaunchApp();
353 }
354
355 void AppLaunchController::OnLaunchSucceeded() {
356   DVLOG(1) << "Kiosk launch succeeded, wait for app window.";
357   app_launch_splash_screen_actor_->UpdateAppLaunchState(
358       AppLaunchSplashScreenActor::APP_LAUNCH_STATE_WAITING_APP_WINDOW);
359
360   DCHECK(!app_window_watcher_);
361   app_window_watcher_.reset(new AppWindowWatcher(this));
362 }
363
364 void AppLaunchController::OnLaunchFailed(KioskAppLaunchError::Error error) {
365   LOG(ERROR) << "Kiosk launch failed. Will now shut down."
366              << ", error=" << error;
367   DCHECK_NE(KioskAppLaunchError::NONE, error);
368
369   // Saves the error and ends the session to go back to login screen.
370   KioskAppLaunchError::Save(error);
371   chrome::AttemptUserExit();
372   CleanUp();
373 }
374
375 }   // namespace chromeos