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