Upstream version 7.36.149.0
[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/app_window.h"
8 #include "apps/app_window_registry.h"
9 #include "base/bind.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"
36
37 namespace chromeos {
38
39 namespace {
40
41 // Application install splash screen minimum show time in milliseconds.
42 const int kAppInstallSplashScreenMinTimeMS = 3000;
43
44 }  // namespace
45
46 // static
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;
54
55 ////////////////////////////////////////////////////////////////////////////////
56 // AppLaunchController::AppWindowWatcher
57
58 class AppLaunchController::AppWindowWatcher
59     : public apps::AppWindowRegistry::Observer {
60  public:
61   explicit AppWindowWatcher(AppLaunchController* controller,
62                             const std::string& app_id)
63       : controller_(controller),
64         app_id_(app_id),
65         window_registry_(apps::AppWindowRegistry::Get(controller->profile_)),
66         weak_factory_(this) {
67     if (!window_registry_->GetAppWindowsForApp(app_id).empty()) {
68       base::MessageLoop::current()->PostTask(
69           FROM_HERE,
70           base::Bind(&AppWindowWatcher::NotifyAppWindowCreated,
71                      weak_factory_.GetWeakPtr()));
72       return;
73     } else {
74       window_registry_->AddObserver(this);
75     }
76   }
77   virtual ~AppWindowWatcher() {
78     window_registry_->RemoveObserver(this);
79   }
80
81  private:
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();
87     }
88   }
89
90   void NotifyAppWindowCreated() {
91     controller_->OnAppWindowCreated();
92   }
93
94   AppLaunchController* controller_;
95   std::string app_id_;
96   apps::AppWindowRegistry* window_registry_;
97   base::WeakPtrFactory<AppWindowWatcher> weak_factory_;
98
99   DISALLOW_COPY_AND_ASSIGN(AppWindowWatcher);
100 };
101
102 ////////////////////////////////////////////////////////////////////////////////
103 // AppLaunchController
104
105 AppLaunchController::AppLaunchController(const std::string& app_id,
106                                          bool diagnostic_mode,
107                                          LoginDisplayHost* host,
108                                          OobeDisplay* oobe_display)
109     : profile_(NULL),
110       app_id_(app_id),
111       diagnostic_mode_(diagnostic_mode),
112       host_(host),
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) {
123 }
124
125 AppLaunchController::~AppLaunchController() {
126   app_launch_splash_screen_actor_->SetDelegate(NULL);
127 }
128
129 void AppLaunchController::StartAppLaunch() {
130   DVLOG(1) << "Starting kiosk mode...";
131
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());
136   }
137   launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
138
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_);
142
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();
149 }
150
151 // static
152 void AppLaunchController::SkipSplashWaitForTesting() {
153   skip_splash_wait_ = true;
154 }
155
156 // static
157 void AppLaunchController::SetNetworkWaitForTesting(int wait_time_secs) {
158   network_wait_time_ = wait_time_secs;
159 }
160
161 // static
162 void AppLaunchController::SetNetworkTimeoutCallbackForTesting(
163     base::Closure* callback) {
164   network_timeout_callback_ = callback;
165 }
166
167 // static
168 void AppLaunchController::SetCanConfigureNetworkCallbackForTesting(
169     ReturnBoolCallback* can_configure_network_callback) {
170   can_configure_network_callback_ = can_configure_network_callback;
171 }
172
173 // static
174 void AppLaunchController::SetNeedOwnerAuthToConfigureNetworkCallbackForTesting(
175     ReturnBoolCallback* need_owner_auth_callback) {
176   need_owner_auth_to_configure_network_callback_ = need_owner_auth_callback;
177 }
178
179 void AppLaunchController::OnConfigureNetwork() {
180   DCHECK(profile_);
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();
186   } else {
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
190     // for this case.
191     NOTREACHED();
192   }
193 }
194
195 void AppLaunchController::OnOwnerSigninSuccess() {
196   app_launch_splash_screen_actor_->ShowNetworkConfigureUI();
197   signin_screen_.reset();
198 }
199
200 void AppLaunchController::Observe(
201     int type,
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();
208   if (launcher_ready_)
209     OnReadyToLaunch();
210 }
211
212 void AppLaunchController::OnCancelAppLaunch() {
213   if (KioskAppManager::Get()->GetDisableBailoutShortcut())
214     return;
215
216   OnLaunchFailed(KioskAppLaunchError::USER_CANCEL);
217 }
218
219 void AppLaunchController::OnNetworkConfigRequested(bool requested) {
220   network_config_requested_ = requested;
221   if (requested)
222     MaybeShowNetworkConfigureUI();
223   else
224     startup_app_launcher_->RestartLauncher();
225 }
226
227 void AppLaunchController::OnNetworkStateChanged(bool online) {
228   if (!waiting_for_network_)
229     return;
230
231   if (online && !network_config_requested_)
232     startup_app_launcher_->ContinueWithNetworkReady();
233   else if (network_wait_timedout_)
234     MaybeShowNetworkConfigureUI();
235 }
236
237 void AppLaunchController::OnProfileLoaded(Profile* profile) {
238   DVLOG(1) << "Profile loaded... Starting app launch.";
239   profile_ = profile;
240
241   // This is needed to trigger input method extensions being loaded.
242   profile_->InitChromeOSPreferences();
243
244   kiosk_profile_loader_.reset();
245   startup_app_launcher_.reset(
246       new StartupAppLauncher(profile_, app_id_, diagnostic_mode_, this));
247   startup_app_launcher_->Initialize();
248 }
249
250 void AppLaunchController::OnProfileLoadFailed(
251     KioskAppLaunchError::Error error) {
252   OnLaunchFailed(error);
253 }
254
255 void AppLaunchController::CleanUp() {
256   kiosk_profile_loader_.reset();
257   startup_app_launcher_.reset();
258   splash_wait_timer_.Stop();
259
260   if (host_)
261     host_->Finalize();
262 }
263
264 void AppLaunchController::OnNetworkWaitTimedout() {
265   DCHECK(waiting_for_network_);
266   LOG(WARNING) << "OnNetworkWaitTimedout... connection = "
267                <<  net::NetworkChangeNotifier::GetConnectionType();
268   network_wait_timedout_ = true;
269
270   MaybeShowNetworkConfigureUI();
271
272   if (network_timeout_callback_)
273     network_timeout_callback_->Run();
274 }
275
276 void AppLaunchController::OnAppWindowCreated() {
277   DVLOG(1) << "App window created, closing splash screen.";
278   CleanUp();
279 }
280
281 bool AppLaunchController::CanConfigureNetwork() {
282   if (can_configure_network_callback_)
283     return can_configure_network_callback_->Run();
284
285   policy::BrowserPolicyConnectorChromeOS* connector =
286       g_browser_process->platform_part()->browser_policy_connector_chromeos();
287   if (connector->IsEnterpriseManaged()) {
288     bool should_prompt;
289     if (CrosSettings::Get()->GetBoolean(
290             kAccountsPrefDeviceLocalAccountPromptForNetworkWhenOffline,
291             &should_prompt)) {
292       return should_prompt;
293     }
294
295     // Default to true to allow network configuration if the policy is missing.
296     return true;
297   }
298
299   return !UserManager::Get()->GetOwnerEmail().empty();
300 }
301
302 bool AppLaunchController::NeedOwnerAuthToConfigureNetwork() {
303   if (need_owner_auth_to_configure_network_callback_)
304     return need_owner_auth_to_configure_network_callback_->Run();
305
306   policy::BrowserPolicyConnectorChromeOS* connector =
307       g_browser_process->platform_part()->browser_policy_connector_chromeos();
308   return !connector->IsEnterpriseManaged();
309 }
310
311 void AppLaunchController::MaybeShowNetworkConfigureUI() {
312   if (CanConfigureNetwork()) {
313     if (NeedOwnerAuthToConfigureNetwork()) {
314       if (network_config_requested_)
315         OnConfigureNetwork();
316       else
317         app_launch_splash_screen_actor_->ToggleNetworkConfig(true);
318     } else {
319       showing_network_dialog_ = true;
320       app_launch_splash_screen_actor_->ShowNetworkConfigureUI();
321     }
322   } else {
323     app_launch_splash_screen_actor_->UpdateAppLaunchState(
324         AppLaunchSplashScreenActor::APP_LAUNCH_STATE_NETWORK_WAIT_TIMEOUT);
325   }
326 }
327
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(
333       FROM_HERE,
334       base::TimeDelta::FromSeconds(network_wait_time_),
335       this, &AppLaunchController::OnNetworkWaitTimedout);
336
337   app_launch_splash_screen_actor_->UpdateAppLaunchState(
338       AppLaunchSplashScreenActor::APP_LAUNCH_STATE_PREPARING_NETWORK);
339 }
340
341 bool AppLaunchController::IsNetworkReady() {
342   return app_launch_splash_screen_actor_->IsNetworkReady();
343 }
344
345 void AppLaunchController::OnLoadingOAuthFile() {
346   app_launch_splash_screen_actor_->UpdateAppLaunchState(
347       AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_AUTH_FILE);
348 }
349
350 void AppLaunchController::OnInitializingTokenService() {
351   app_launch_splash_screen_actor_->UpdateAppLaunchState(
352       AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE);
353 }
354
355 void AppLaunchController::OnInstallingApp() {
356   app_launch_splash_screen_actor_->UpdateAppLaunchState(
357       AppLaunchSplashScreenActor::APP_LAUNCH_STATE_INSTALLING_APPLICATION);
358
359   waiting_for_network_ = false;
360   network_wait_timer_.Stop();
361   app_launch_splash_screen_actor_->ToggleNetworkConfig(false);
362
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();
369   }
370 }
371
372 void AppLaunchController::OnReadyToLaunch() {
373   launcher_ready_ = true;
374
375   if (network_config_requested_)
376     return;
377
378   if (!webui_visible_)
379     return;
380
381   if (splash_wait_timer_.IsRunning())
382     return;
383
384   const int64 time_taken_ms = (base::TimeTicks::Now() -
385       base::TimeTicks::FromInternalValue(launch_splash_start_time_)).
386       InMilliseconds();
387
388   // Enforce that we show app install splash screen for some minimum amount
389   // of time.
390   if (!skip_splash_wait_ && time_taken_ms < kAppInstallSplashScreenMinTimeMS) {
391     splash_wait_timer_.Start(
392         FROM_HERE,
393         base::TimeDelta::FromMilliseconds(
394             kAppInstallSplashScreenMinTimeMS - time_taken_ms),
395         this,
396         &AppLaunchController::OnReadyToLaunch);
397     return;
398   }
399
400   startup_app_launcher_->LaunchApp();
401 }
402
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);
407
408   DCHECK(!app_window_watcher_);
409   app_window_watcher_.reset(new AppWindowWatcher(this, app_id_));
410 }
411
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);
416
417   // Saves the error and ends the session to go back to login screen.
418   KioskAppLaunchError::Save(error);
419   chrome::AttemptUserExit();
420   CleanUp();
421 }
422
423 bool AppLaunchController::IsShowingNetworkConfigScreen() {
424   return network_config_requested_;
425 }
426
427 }   // namespace chromeos