blob: 1daa428bab826254ed525cc130b127e838aef76b [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_screensaver.h"
#include "ash/screensaver/screensaver_view.h"
#include "ash/shell.h"
#include "ash/wm/user_activity_detector.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
#include "chrome/browser/chromeos/login/existing_user_controller.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/sandboxed_unpacker.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_file_util.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
using extensions::Extension;
using extensions::SandboxedUnpacker;
namespace chromeos {
typedef base::Callback<void(
scoped_refptr<Extension>,
const FilePath&)> UnpackCallback;
class ScreensaverUnpackerClient
: public extensions::SandboxedUnpackerClient {
public:
explicit ScreensaverUnpackerClient(const UnpackCallback& unpacker_callback)
: unpack_callback_(unpacker_callback) {}
void OnUnpackSuccess(const FilePath& temp_dir,
const FilePath& extension_root,
const base::DictionaryValue* original_manifest,
const Extension* extension) OVERRIDE;
void OnUnpackFailure(const string16& error) OVERRIDE;
protected:
virtual ~ScreensaverUnpackerClient() {}
private:
void LoadScreensaverExtension(
const FilePath& extension_base_path,
const FilePath& screensaver_extension_path);
UnpackCallback unpack_callback_;
DISALLOW_COPY_AND_ASSIGN(ScreensaverUnpackerClient);
};
void ScreensaverUnpackerClient::OnUnpackSuccess(
const FilePath& temp_dir,
const FilePath& extension_root,
const base::DictionaryValue* original_manifest,
const Extension* extension) {
content::BrowserThread::PostTask(
content::BrowserThread::FILE,
FROM_HERE,
base::Bind(&ScreensaverUnpackerClient::LoadScreensaverExtension,
this,
temp_dir,
extension_root));
}
void ScreensaverUnpackerClient::OnUnpackFailure(const string16& error) {
LOG(ERROR) << "Couldn't unpack screensaver extension. Error: " << error;
}
void ScreensaverUnpackerClient::LoadScreensaverExtension(
const FilePath& extension_base_path,
const FilePath& screensaver_extension_path) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
std::string error;
scoped_refptr<Extension> screensaver_extension =
extension_file_util::LoadExtension(screensaver_extension_path,
Extension::COMPONENT,
Extension::NO_FLAGS,
&error);
if (!screensaver_extension) {
LOG(ERROR) << "Could not load screensaver extension from: "
<< screensaver_extension_path.value() << " due to: " << error;
return;
}
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
base::Bind(
unpack_callback_,
screensaver_extension,
extension_base_path));
}
KioskModeScreensaver::KioskModeScreensaver()
: weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
chromeos::KioskModeSettings* kiosk_mode_settings =
chromeos::KioskModeSettings::Get();
if (kiosk_mode_settings->is_initialized()) {
GetScreensaverCrxPath();
} else {
kiosk_mode_settings->Initialize(base::Bind(
&KioskModeScreensaver::GetScreensaverCrxPath,
weak_ptr_factory_.GetWeakPtr()));
}
}
KioskModeScreensaver::~KioskModeScreensaver() {
// If the extension was unpacked.
if (!extension_base_path_.empty()) {
// Delete it.
content::BrowserThread::PostTask(
content::BrowserThread::FILE,
FROM_HERE,
base::Bind(
&extension_file_util::DeleteFile, extension_base_path_, true));
}
// In case we're shutting down without ever triggering the active
// notification and/or logging in.
if (ash::Shell::GetInstance() &&
ash::Shell::GetInstance()->user_activity_detector())
ash::Shell::GetInstance()->user_activity_detector()->RemoveObserver(this);
registrar_.RemoveAll();
}
void KioskModeScreensaver::GetScreensaverCrxPath() {
chromeos::KioskModeSettings::Get()->GetScreensaverPath(
base::Bind(&KioskModeScreensaver::ScreensaverPathCallback,
weak_ptr_factory_.GetWeakPtr()));
}
void KioskModeScreensaver::ScreensaverPathCallback(
const FilePath& screensaver_crx) {
if (screensaver_crx.empty())
return;
scoped_refptr<SandboxedUnpacker> screensaver_unpacker(
new SandboxedUnpacker(
screensaver_crx,
true,
Extension::COMPONENT,
Extension::NO_FLAGS,
new ScreensaverUnpackerClient(base::Bind(
&KioskModeScreensaver::SetupScreensaver,
weak_ptr_factory_.GetWeakPtr()))));
// Fire off the unpacker on the file thread; don't need it to return.
content::BrowserThread::PostTask(
content::BrowserThread::FILE,
FROM_HERE,
base::Bind(
&SandboxedUnpacker::Start, screensaver_unpacker.get()));
}
void KioskModeScreensaver::SetupScreensaver(
scoped_refptr<Extension> extension,
const FilePath& extension_base_path) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
extension_base_path_ = extension_base_path;
// If the user is already logged in, don't need to display the screensaver.
if (chromeos::UserManager::Get()->IsUserLoggedIn())
return;
// Add our observers for login and user active.
registrar_.Add(this, chrome::NOTIFICATION_SESSION_STARTED,
content::NotificationService::AllSources());
ash::Shell::GetInstance()->user_activity_detector()->AddObserver(this);
Profile* default_profile = ProfileManager::GetDefaultProfile();
// Add the extension to the extension service and display the screensaver.
if (default_profile) {
default_profile->GetExtensionService()->AddExtension(extension);
ash::ShowScreensaver(extension->GetFullLaunchURL());
} else {
LOG(ERROR) << "Couldn't get default profile. Unable to load screensaver!";
ShutdownKioskModeScreensaver();
}
}
// NotificationObserver overrides:
void KioskModeScreensaver::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK_EQ(type, chrome::NOTIFICATION_SESSION_STARTED);
registrar_.RemoveAll();
ash::CloseScreensaver();
ShutdownKioskModeScreensaver();
}
void KioskModeScreensaver::OnUserActivity() {
// We don't want to handle further user notifications; we'll either login
// the user and close out or or at least close the screensaver.
ash::Shell::GetInstance()->user_activity_detector()->RemoveObserver(this);
// User is active, log us in.
ExistingUserController* controller =
ExistingUserController::current_controller();
if (controller) {
// Logging in will shut us down and remove the screen saver.
controller->LoginAsDemoUser();
} else {
// Remove the screensaver so the user can at least use the underlying
// login screen to be able to log in.
ash::CloseScreensaver();
ShutdownKioskModeScreensaver();
}
}
static KioskModeScreensaver* g_kiosk_mode_screensaver = NULL;
void InitializeKioskModeScreensaver() {
if (g_kiosk_mode_screensaver) {
LOG(WARNING) << "Screensaver was already initialized";
return;
}
g_kiosk_mode_screensaver = new KioskModeScreensaver();
}
void ShutdownKioskModeScreensaver() {
delete g_kiosk_mode_screensaver;
g_kiosk_mode_screensaver = NULL;
}
} // namespace chromeos