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