Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / kiosk_mode / kiosk_mode_screensaver.cc
1 // Copyright (c) 2012 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/kiosk_mode/kiosk_mode_screensaver.h"
6
7 #include "ash/screensaver/screensaver_view.h"
8 #include "ash/shell.h"
9 #include "ash/wm/user_activity_detector.h"
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/lazy_instance.h"
13 #include "base/logging.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
17 #include "chrome/browser/chromeos/login/existing_user_controller.h"
18 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
19 #include "chrome/browser/chromeos/policy/app_pack_updater.h"
20 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
21 #include "chrome/browser/chromeos/profiles/profile_helper.h"
22 #include "chrome/browser/extensions/extension_service.h"
23 #include "chrome/browser/extensions/extension_system.h"
24 #include "chrome/browser/extensions/sandboxed_unpacker.h"
25 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
26 #include "chrome/common/extensions/extension_file_util.h"
27 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
28 #include "chromeos/login/login_state.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "content/public/browser/notification_service.h"
31 #include "extensions/common/extension.h"
32
33 using extensions::Extension;
34 using extensions::SandboxedUnpacker;
35
36 namespace chromeos {
37
38 namespace {
39
40 ExtensionService* GetDefaultExtensionService() {
41   Profile* default_profile = ProfileHelper::GetSigninProfile();
42   if (!default_profile)
43     return NULL;
44   return extensions::ExtensionSystem::Get(
45       default_profile)->extension_service();
46 }
47
48 typedef base::Callback<void(
49     scoped_refptr<Extension>,
50     const base::FilePath&)> UnpackCallback;
51
52 class ScreensaverUnpackerClient
53     : public extensions::SandboxedUnpackerClient {
54  public:
55   ScreensaverUnpackerClient(const base::FilePath& crx_path,
56                             const UnpackCallback& unpacker_callback)
57       : crx_path_(crx_path),
58         unpack_callback_(unpacker_callback) {}
59
60   virtual void OnUnpackSuccess(const base::FilePath& temp_dir,
61                                const base::FilePath& extension_root,
62                                const base::DictionaryValue* original_manifest,
63                                const Extension* extension,
64                                const SkBitmap& install_icon) OVERRIDE;
65   virtual void OnUnpackFailure(const base::string16& error) OVERRIDE;
66
67  protected:
68   virtual ~ScreensaverUnpackerClient() {}
69
70  private:
71   void LoadScreensaverExtension(
72       const base::FilePath& extension_base_path,
73       const base::FilePath& screensaver_extension_path);
74
75   void NotifyAppPackOfDamagedFile();
76
77   base::FilePath crx_path_;
78   UnpackCallback unpack_callback_;
79
80   DISALLOW_COPY_AND_ASSIGN(ScreensaverUnpackerClient);
81 };
82
83 void ScreensaverUnpackerClient::OnUnpackSuccess(
84     const base::FilePath& temp_dir,
85     const base::FilePath& extension_root,
86     const base::DictionaryValue* original_manifest,
87     const Extension* extension,
88     const SkBitmap& install_icon) {
89   content::BrowserThread::PostTask(
90       content::BrowserThread::FILE,
91       FROM_HERE,
92       base::Bind(&ScreensaverUnpackerClient::LoadScreensaverExtension,
93                  this,
94                  temp_dir,
95                  extension_root));
96 }
97
98 void ScreensaverUnpackerClient::OnUnpackFailure(const base::string16& error) {
99   LOG(ERROR) << "Couldn't unpack screensaver extension. Error: " << error;
100   NotifyAppPackOfDamagedFile();
101 }
102
103 void ScreensaverUnpackerClient::LoadScreensaverExtension(
104     const base::FilePath& extension_base_path,
105     const base::FilePath& screensaver_extension_path) {
106   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
107
108   ExtensionService* service = GetDefaultExtensionService();
109   // TODO(rkc): This is a HACK, please remove this method from extension
110   // service once this code is deprecated. See crbug.com/280363
111   if (service)
112     service->disable_garbage_collection();
113
114   std::string error;
115   scoped_refptr<Extension> screensaver_extension =
116       extension_file_util::LoadExtension(screensaver_extension_path,
117                                          extensions::Manifest::COMPONENT,
118                                          Extension::NO_FLAGS,
119                                          &error);
120   if (!screensaver_extension.get()) {
121     LOG(ERROR) << "Could not load screensaver extension from: "
122                << screensaver_extension_path.value() << " due to: " << error;
123     NotifyAppPackOfDamagedFile();
124     return;
125   }
126
127   content::BrowserThread::PostTask(
128       content::BrowserThread::UI,
129       FROM_HERE,
130       base::Bind(
131           unpack_callback_,
132           screensaver_extension,
133           extension_base_path));
134 }
135
136 void ScreensaverUnpackerClient::NotifyAppPackOfDamagedFile() {
137   if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
138     content::BrowserThread::PostTask(
139         content::BrowserThread::UI, FROM_HERE,
140         base::Bind(&ScreensaverUnpackerClient::NotifyAppPackOfDamagedFile,
141                    this));
142     return;
143   }
144
145   policy::BrowserPolicyConnectorChromeOS* connector =
146       g_browser_process->platform_part()->browser_policy_connector_chromeos();
147   policy::AppPackUpdater* updater = connector->GetAppPackUpdater();
148   if (updater)
149     updater->OnDamagedFileDetected(crx_path_);
150 }
151
152 }  // namespace
153
154 KioskModeScreensaver::KioskModeScreensaver()
155     : weak_ptr_factory_(this) {
156   chromeos::KioskModeSettings* kiosk_mode_settings =
157       chromeos::KioskModeSettings::Get();
158
159   if (kiosk_mode_settings->is_initialized()) {
160     GetScreensaverCrxPath();
161   } else {
162     kiosk_mode_settings->Initialize(base::Bind(
163         &KioskModeScreensaver::GetScreensaverCrxPath,
164         weak_ptr_factory_.GetWeakPtr()));
165   }
166 }
167
168 KioskModeScreensaver::~KioskModeScreensaver() {
169   // If we are shutting down the system might already be gone and we shouldn't
170   // do anything (see crbug.com/288216).
171   if (!g_browser_process || g_browser_process->IsShuttingDown())
172     return;
173
174   // If the extension was unpacked.
175   if (!extension_base_path_.empty()) {
176     ExtensionService* service = GetDefaultExtensionService();
177     // TODO(rkc): This is a HACK, please remove this method from extension
178     // service once this code is deprecated. See crbug.com/280363
179     if (service)
180       service->enable_garbage_collection();
181
182     // Delete it.
183     content::BrowserThread::PostTask(
184         content::BrowserThread::FILE,
185         FROM_HERE,
186         base::Bind(
187             &extension_file_util::DeleteFile, extension_base_path_, true));
188   }
189
190   // In case we're shutting down without ever triggering the active
191   // notification and/or logging in.
192   if (ash::Shell::GetInstance() &&
193       ash::Shell::GetInstance()->user_activity_detector() &&
194       ash::Shell::GetInstance()->user_activity_detector()->HasObserver(this))
195     ash::Shell::GetInstance()->user_activity_detector()->RemoveObserver(this);
196 }
197
198 void KioskModeScreensaver::GetScreensaverCrxPath() {
199   chromeos::KioskModeSettings::Get()->GetScreensaverPath(
200       base::Bind(&KioskModeScreensaver::ScreensaverPathCallback,
201                  weak_ptr_factory_.GetWeakPtr()));
202 }
203
204 void KioskModeScreensaver::ScreensaverPathCallback(
205     const base::FilePath& screensaver_crx) {
206   if (screensaver_crx.empty())
207     return;
208
209   ExtensionService* extension_service = GetDefaultExtensionService();
210   if (!extension_service)
211     return;
212   base::FilePath extensions_dir = extension_service->install_directory();
213   scoped_refptr<SandboxedUnpacker> screensaver_unpacker(
214       new SandboxedUnpacker(
215           screensaver_crx,
216           extensions::Manifest::COMPONENT,
217           Extension::NO_FLAGS,
218           extensions_dir,
219           content::BrowserThread::GetMessageLoopProxyForThread(
220               content::BrowserThread::FILE).get(),
221           new ScreensaverUnpackerClient(
222               screensaver_crx,
223               base::Bind(
224                   &KioskModeScreensaver::SetupScreensaver,
225                   weak_ptr_factory_.GetWeakPtr()))));
226
227   // Fire off the unpacker on the file thread; don't need it to return.
228   content::BrowserThread::PostTask(
229       content::BrowserThread::FILE,
230       FROM_HERE,
231       base::Bind(
232           &SandboxedUnpacker::Start, screensaver_unpacker.get()));
233 }
234
235 void KioskModeScreensaver::SetupScreensaver(
236     scoped_refptr<Extension> extension,
237     const base::FilePath& extension_base_path) {
238   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
239   extension_base_path_ = extension_base_path;
240
241   // If the user is already logged in, don't need to display the screensaver.
242   if (chromeos::LoginState::Get()->IsUserLoggedIn())
243     return;
244
245   ash::Shell::GetInstance()->user_activity_detector()->AddObserver(this);
246
247   ExtensionService* extension_service = GetDefaultExtensionService();
248   // Add the extension to the extension service and display the screensaver.
249   if (extension_service) {
250     extension_service->AddExtension(extension.get());
251     ash::ShowScreensaver(
252         extensions::AppLaunchInfo::GetFullLaunchURL(extension.get()));
253   } else {
254     LOG(ERROR) << "Couldn't get extension system. Unable to load screensaver!";
255     ShutdownKioskModeScreensaver();
256   }
257 }
258
259 void KioskModeScreensaver::OnUserActivity(const ui::Event* event) {
260   // We don't want to handle further user notifications; we'll either login
261   // the user and close out or or at least close the screensaver.
262   ash::Shell::GetInstance()->user_activity_detector()->RemoveObserver(this);
263
264   // Find the retail mode login page.
265   if (LoginDisplayHostImpl::default_host()) {
266     LoginDisplayHostImpl* webui_host =
267         static_cast<LoginDisplayHostImpl*>(
268             LoginDisplayHostImpl::default_host());
269     OobeUI* oobe_ui = webui_host->GetOobeUI();
270
271     // Show the login spinner.
272     if (oobe_ui)
273       oobe_ui->ShowRetailModeLoginSpinner();
274
275     // Close the screensaver, our login spinner is already showing.
276     ash::CloseScreensaver();
277
278     // Log us in.
279     ExistingUserController* controller =
280         ExistingUserController::current_controller();
281     if (controller && !chromeos::LoginState::Get()->IsUserLoggedIn())
282       controller->LoginAsRetailModeUser();
283   } else {
284     // No default host for the WebUiLoginDisplay means that we're already in the
285     // process of logging in - shut down screensaver and do nothing else.
286     ash::CloseScreensaver();
287   }
288
289   ShutdownKioskModeScreensaver();
290 }
291
292 static KioskModeScreensaver* g_kiosk_mode_screensaver = NULL;
293
294 void InitializeKioskModeScreensaver() {
295   if (g_kiosk_mode_screensaver) {
296     LOG(WARNING) << "Screensaver was already initialized";
297     return;
298   }
299
300   g_kiosk_mode_screensaver = new KioskModeScreensaver();
301 }
302
303 void ShutdownKioskModeScreensaver() {
304   delete g_kiosk_mode_screensaver;
305   g_kiosk_mode_screensaver = NULL;
306 }
307
308 }  // namespace chromeos