screensaver_controller.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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/screensaver/screensaver_controller.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/logging.h"
13#include "chrome/browser/extensions/extension_service.h"
14#include "chrome/browser/extensions/extension_system.h"
15#include "chrome/browser/profiles/profile_manager.h"
16#include "chrome/common/chrome_notification_types.h"
17#include "chrome/common/extensions/extension.h"
18#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
19#include "chromeos/dbus/dbus_thread_manager.h"
20#include "chromeos/dbus/power_manager_client.h"
21#include "content/public/browser/notification_service.h"
22
23namespace {
24
25const int kScreensaverTimeoutMinutes = 2;
26
27ExtensionService* GetDefaultExtensionService() {
28  Profile* default_profile = ProfileManager::GetDefaultProfile();
29  DCHECK(default_profile);
30  ExtensionService* service =
31      extensions::ExtensionSystem::Get(default_profile)->extension_service();
32  DCHECK(service);
33
34  return service;
35}
36
37// Find the screensaver extension for the given service, excluding
38// the one with exclude_id.
39std::string FindScreensaverExtension(ExtensionService* service,
40                                     const std::string& exclude_id) {
41  const ExtensionSet* extensions = service->extensions();
42  if (!extensions)
43    return std::string();
44
45  for (ExtensionSet::const_iterator it = extensions->begin();
46      it != extensions->end();
47      ++it) {
48    const extensions::Extension* extension = *it;
49    if (extension &&
50        extension->id() != exclude_id &&
51        extension->HasAPIPermission(extensions::APIPermission::kScreensaver)) {
52      return extension->id();
53    }
54  }
55
56  return std::string();
57}
58
59void UninstallPreviousScreensavers(const extensions::Extension* current) {
60  Profile* default_profile = ProfileManager::GetDefaultProfile();
61  DCHECK(default_profile);
62  ExtensionService* service =
63      extensions::ExtensionSystem::Get(default_profile)->extension_service();
64  DCHECK(service);
65
66  std::string screensaver_id;
67  while ((screensaver_id = FindScreensaverExtension(service, current->id()))
68         != "") {
69    string16 error;
70    if (!service->UninstallExtension(screensaver_id, false, &error))
71      LOG(ERROR)
72          << "Couldn't uninstall previous screensaver extension with id: "
73          << screensaver_id << " \nError: " << error;
74  }
75}
76
77}  // namespace
78
79namespace chromeos {
80
81ScreensaverController::ScreensaverController()
82    : threshold_(base::TimeDelta::FromMinutes(kScreensaverTimeoutMinutes)),
83      weak_ptr_factory_(this) {
84  // Register for extension changes.
85  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
86                 content::NotificationService::AllSources());
87  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
88                 content::NotificationService::AllSources());
89
90  std::string screensaver_extension_id =
91      FindScreensaverExtension(GetDefaultExtensionService(), std::string());
92  if (!screensaver_extension_id.empty())
93    SetupScreensaver(screensaver_extension_id);
94}
95
96ScreensaverController::~ScreensaverController() {
97  TeardownScreensaver();
98}
99
100void ScreensaverController::Observe(
101    int type,
102    const content::NotificationSource& source,
103    const content::NotificationDetails& details) {
104  switch (type) {
105    case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
106      const extensions::Extension* extension =
107          content::Details<const extensions::InstalledExtensionInfo>(details)->
108              extension;
109      // Uninstall any previously installed screensaver extensions if a new
110      // screensaver extension is installed.
111      if (extension->HasAPIPermission(extensions::APIPermission::kScreensaver))
112        UninstallPreviousScreensavers(extension);
113      break;
114    }
115    case chrome::NOTIFICATION_EXTENSION_LOADED: {
116      const extensions::Extension* extension =
117          content::Details<const extensions::Extension>(details).ptr();
118      if (extension->HasAPIPermission(extensions::APIPermission::kScreensaver))
119        SetupScreensaver(extension->id());
120      break;
121    }
122    case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
123      const extensions::Extension* extension =
124          content::Details<extensions::UnloadedExtensionInfo>(
125              details)->extension;
126      if (extension->id() == screensaver_extension_id_)
127        TeardownScreensaver();
128      break;
129    }
130  }
131}
132
133void ScreensaverController::IdleNotify(int64 threshold) {
134  ExtensionService* service = GetDefaultExtensionService();
135  const extensions::Extension* screensaver_extension =
136      service->GetExtensionById(screensaver_extension_id_,
137                                ExtensionService::INCLUDE_ENABLED);
138  ash::ShowScreensaver(
139      extensions::AppLaunchInfo::GetFullLaunchURL(screensaver_extension));
140
141  if (!ash::Shell::GetInstance()->user_activity_detector()->HasObserver(this))
142    ash::Shell::GetInstance()->user_activity_detector()->AddObserver(this);
143}
144
145void ScreensaverController::OnUserActivity() {
146  // We don't want to handle further user notifications; we'll either login
147  // the user and close out or or at least close the screensaver.
148  if (ash::Shell::GetInstance()->user_activity_detector()->HasObserver(this))
149    ash::Shell::GetInstance()->user_activity_detector()->RemoveObserver(this);
150  ash::CloseScreensaver();
151
152  RequestNextIdleNotification();
153}
154
155void ScreensaverController::SetupScreensaver(
156    const std::string& screensaver_extension_id) {
157  screensaver_extension_id_ = screensaver_extension_id;
158
159  PowerManagerClient* power_manager =
160      DBusThreadManager::Get()->GetPowerManagerClient();
161  if (!power_manager->HasObserver(this))
162    power_manager->AddObserver(this);
163
164  RequestNextIdleNotification();
165}
166
167void ScreensaverController::TeardownScreensaver() {
168  PowerManagerClient* power_manager =
169      DBusThreadManager::Get()->GetPowerManagerClient();
170  if (power_manager && power_manager->HasObserver(this))
171    power_manager->RemoveObserver(this);
172
173  if (ash::Shell::GetInstance() &&
174      ash::Shell::GetInstance()->user_activity_detector()->HasObserver(this)) {
175    ash::Shell::GetInstance()->user_activity_detector()->RemoveObserver(this);
176  }
177
178  ash::CloseScreensaver();
179  screensaver_extension_id_ = "";
180}
181
182void ScreensaverController::RequestNextIdleNotification() {
183  DBusThreadManager::Get()->GetPowerManagerClient()->
184      RequestIdleNotification(threshold_.InMilliseconds());
185}
186
187}  // namespace chromeos
188