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