Upstream version 5.34.104.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/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"
35
36 namespace chromeos {
37
38 namespace {
39
40 // Application install splash screen minimum show time in milliseconds.
41 const int kAppInstallSplashScreenMinTimeMS = 3000;
42
43 }  // namespace
44
45 // static
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;
53
54 ////////////////////////////////////////////////////////////////////////////////
55 // AppLaunchController::AppWindowWatcher
56
57 class AppLaunchController::AppWindowWatcher
58     : public apps::AppWindowRegistry::Observer {
59  public:
60   explicit AppWindowWatcher(AppLaunchController* controller,
61                             const std::string& app_id)
62       : controller_(controller),
63         app_id_(app_id),
64         window_registry_(apps::AppWindowRegistry::Get(controller->profile_)),
65         weak_factory_(this) {
66     if (!window_registry_->GetAppWindowsForApp(app_id).empty()) {
67       base::MessageLoop::current()->PostTask(
68           FROM_HERE,
69           base::Bind(&AppWindowWatcher::NotifyAppWindowCreated,
70                      weak_factory_.GetWeakPtr()));
71       return;
72     } else {
73       window_registry_->AddObserver(this);
74     }
75   }
76   virtual ~AppWindowWatcher() {
77     window_registry_->RemoveObserver(this);
78   }
79
80  private:
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();
86     }
87   }
88   virtual void OnAppWindowIconChanged(apps::AppWindow* app_window) OVERRIDE {}
89   virtual void OnAppWindowRemoved(apps::AppWindow* app_window) OVERRIDE {}
90
91   void NotifyAppWindowCreated() {
92     controller_->OnAppWindowCreated();
93   }
94
95   AppLaunchController* controller_;
96   std::string app_id_;
97   apps::AppWindowRegistry* window_registry_;
98   base::WeakPtrFactory<AppWindowWatcher> weak_factory_;
99
100   DISALLOW_COPY_AND_ASSIGN(AppWindowWatcher);
101 };
102
103 ////////////////////////////////////////////////////////////////////////////////
104 // AppLaunchController
105
106 AppLaunchController::AppLaunchController(const std::string& app_id,
107                                          bool diagnostic_mode,
108                                          LoginDisplayHost* host,
109                                          OobeDisplay* oobe_display)
110     : profile_(NULL),
111       app_id_(app_id),
112       diagnostic_mode_(diagnostic_mode),
113       host_(host),
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) {
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         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::OnNetworkStateChanged(bool online) {
220   if (!waiting_for_network_)
221     return;
222
223   if (online)
224     startup_app_launcher_->ContinueWithNetworkReady();
225   else if (network_wait_timedout_)
226     MaybeShowNetworkConfigureUI();
227 }
228
229 void AppLaunchController::OnProfileLoaded(Profile* profile) {
230   DVLOG(1) << "Profile loaded... Starting app launch.";
231   profile_ = profile;
232
233   kiosk_profile_loader_.reset();
234   startup_app_launcher_.reset(
235       new StartupAppLauncher(profile_, app_id_, diagnostic_mode_, this));
236   startup_app_launcher_->Initialize();
237 }
238
239 void AppLaunchController::OnProfileLoadFailed(
240     KioskAppLaunchError::Error error) {
241   OnLaunchFailed(error);
242 }
243
244 void AppLaunchController::CleanUp() {
245   kiosk_profile_loader_.reset();
246   startup_app_launcher_.reset();
247   splash_wait_timer_.Stop();
248
249   if (host_)
250     host_->Finalize();
251 }
252
253 void AppLaunchController::OnNetworkWaitTimedout() {
254   DCHECK(waiting_for_network_);
255   LOG(WARNING) << "OnNetworkWaitTimedout... connection = "
256                <<  net::NetworkChangeNotifier::GetConnectionType();
257   network_wait_timedout_ = true;
258
259   MaybeShowNetworkConfigureUI();
260
261   if (network_timeout_callback_)
262     network_timeout_callback_->Run();
263 }
264
265 void AppLaunchController::OnAppWindowCreated() {
266   DVLOG(1) << "App window created, closing splash screen.";
267   CleanUp();
268 }
269
270 bool AppLaunchController::CanConfigureNetwork() {
271   if (can_configure_network_callback_)
272     return can_configure_network_callback_->Run();
273
274   policy::BrowserPolicyConnectorChromeOS* connector =
275       g_browser_process->platform_part()->browser_policy_connector_chromeos();
276   if (connector->IsEnterpriseManaged()) {
277     bool should_prompt;
278     if (CrosSettings::Get()->GetBoolean(
279             kAccountsPrefDeviceLocalAccountPromptForNetworkWhenOffline,
280             &should_prompt)) {
281       return should_prompt;
282     }
283
284     // Default to true to allow network configuration if the policy is missing.
285     return true;
286   }
287
288   return !UserManager::Get()->GetOwnerEmail().empty();
289 }
290
291 bool AppLaunchController::NeedOwnerAuthToConfigureNetwork() {
292   if (need_owner_auth_to_configure_network_callback_)
293     return need_owner_auth_to_configure_network_callback_->Run();
294
295   policy::BrowserPolicyConnectorChromeOS* connector =
296       g_browser_process->platform_part()->browser_policy_connector_chromeos();
297   return !connector->IsEnterpriseManaged();
298 }
299
300 void AppLaunchController::MaybeShowNetworkConfigureUI() {
301   if (CanConfigureNetwork()) {
302     if (NeedOwnerAuthToConfigureNetwork()) {
303       app_launch_splash_screen_actor_->ToggleNetworkConfig(true);
304     } else {
305       showing_network_dialog_ = true;
306       app_launch_splash_screen_actor_->ShowNetworkConfigureUI();
307     }
308   } else {
309     app_launch_splash_screen_actor_->UpdateAppLaunchState(
310         AppLaunchSplashScreenActor::APP_LAUNCH_STATE_NETWORK_WAIT_TIMEOUT);
311   }
312 }
313
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(
319       FROM_HERE,
320       base::TimeDelta::FromSeconds(network_wait_time_),
321       this, &AppLaunchController::OnNetworkWaitTimedout);
322
323   app_launch_splash_screen_actor_->UpdateAppLaunchState(
324       AppLaunchSplashScreenActor::APP_LAUNCH_STATE_PREPARING_NETWORK);
325 }
326
327 bool AppLaunchController::IsNetworkReady() {
328   return app_launch_splash_screen_actor_->IsNetworkReady();
329 }
330
331 void AppLaunchController::OnLoadingOAuthFile() {
332   app_launch_splash_screen_actor_->UpdateAppLaunchState(
333       AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_AUTH_FILE);
334 }
335
336 void AppLaunchController::OnInitializingTokenService() {
337   app_launch_splash_screen_actor_->UpdateAppLaunchState(
338       AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE);
339 }
340
341 void AppLaunchController::OnInstallingApp() {
342   app_launch_splash_screen_actor_->UpdateAppLaunchState(
343       AppLaunchSplashScreenActor::APP_LAUNCH_STATE_INSTALLING_APPLICATION);
344
345   waiting_for_network_ = false;
346   network_wait_timer_.Stop();
347   app_launch_splash_screen_actor_->ToggleNetworkConfig(false);
348
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();
355   }
356 }
357
358 void AppLaunchController::OnReadyToLaunch() {
359   launcher_ready_ = true;
360   if (!webui_visible_)
361     return;
362
363   if (splash_wait_timer_.IsRunning())
364     return;
365
366   const int64 time_taken_ms = (base::TimeTicks::Now() -
367       base::TimeTicks::FromInternalValue(launch_splash_start_time_)).
368       InMilliseconds();
369
370   // Enforce that we show app install splash screen for some minimum amount
371   // of time.
372   if (!skip_splash_wait_ && time_taken_ms < kAppInstallSplashScreenMinTimeMS) {
373     splash_wait_timer_.Start(
374         FROM_HERE,
375         base::TimeDelta::FromMilliseconds(
376             kAppInstallSplashScreenMinTimeMS - time_taken_ms),
377         this,
378         &AppLaunchController::OnReadyToLaunch);
379     return;
380   }
381
382   startup_app_launcher_->LaunchApp();
383 }
384
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);
389
390   DCHECK(!app_window_watcher_);
391   app_window_watcher_.reset(new AppWindowWatcher(this, app_id_));
392 }
393
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);
398
399   // Saves the error and ends the session to go back to login screen.
400   KioskAppLaunchError::Save(error);
401   chrome::AttemptUserExit();
402   CleanUp();
403 }
404
405 }   // namespace chromeos