1 // Copyright 2013 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.
5 #include "chrome/browser/extensions/api/system_info/system_info_api.h"
10 #include "base/lazy_instance.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/memory/singleton.h"
13 #include "base/strings/string_util.h"
14 #include "base/values.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/extensions/api/system_storage/storage_info_provider.h"
17 #include "chrome/browser/extensions/event_router_forwarder.h"
18 #include "chrome/common/extensions/api/system_display.h"
19 #include "chrome/common/extensions/api/system_storage.h"
20 #include "components/storage_monitor/removable_storage_observer.h"
21 #include "components/storage_monitor/storage_info.h"
22 #include "components/storage_monitor/storage_monitor.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "ui/gfx/display_observer.h"
26 #if defined(OS_CHROMEOS)
27 #include "ash/shell.h"
28 #include "ui/gfx/screen.h"
31 namespace extensions {
33 using api::system_storage::StorageUnitInfo;
34 using content::BrowserThread;
35 using storage_monitor::StorageMonitor;
37 namespace system_display = api::system_display;
38 namespace system_storage = api::system_storage;
42 #if defined(OS_CHROMEOS)
43 bool IsDisplayChangedEvent(const std::string& event_name) {
44 return event_name == system_display::OnDisplayChanged::kEventName;
48 bool IsSystemStorageEvent(const std::string& event_name) {
49 return (event_name == system_storage::OnAttached::kEventName ||
50 event_name == system_storage::OnDetached::kEventName);
53 // Event router for systemInfo API. It is a singleton instance shared by
55 class SystemInfoEventRouter : public gfx::DisplayObserver,
56 public storage_monitor::RemovableStorageObserver {
58 static SystemInfoEventRouter* GetInstance();
60 SystemInfoEventRouter();
61 virtual ~SystemInfoEventRouter();
63 // Add/remove event listener for the |event_name| event.
64 void AddEventListener(const std::string& event_name);
65 void RemoveEventListener(const std::string& event_name);
68 // gfx::DisplayObserver:
69 virtual void OnDisplayBoundsChanged(const gfx::Display& display) OVERRIDE;
70 virtual void OnDisplayAdded(const gfx::Display& new_display) OVERRIDE;
71 virtual void OnDisplayRemoved(const gfx::Display& old_display) OVERRIDE;
73 // RemovableStorageObserver implementation.
74 virtual void OnRemovableStorageAttached(
75 const storage_monitor::StorageInfo& info) OVERRIDE;
76 virtual void OnRemovableStorageDetached(
77 const storage_monitor::StorageInfo& info) OVERRIDE;
79 // Called from any thread to dispatch the systemInfo event to all extension
80 // processes cross multiple profiles.
81 void DispatchEvent(const std::string& event_name,
82 scoped_ptr<base::ListValue> args);
84 // Called to dispatch the systemInfo.display.onDisplayChanged event.
85 void OnDisplayChanged();
87 // Used to record the event names being watched.
88 std::multiset<std::string> watching_event_set_;
90 bool has_storage_monitor_observer_;
92 DISALLOW_COPY_AND_ASSIGN(SystemInfoEventRouter);
95 static base::LazyInstance<SystemInfoEventRouter>::Leaky
96 g_system_info_event_router = LAZY_INSTANCE_INITIALIZER;
99 SystemInfoEventRouter* SystemInfoEventRouter::GetInstance() {
100 return g_system_info_event_router.Pointer();
103 SystemInfoEventRouter::SystemInfoEventRouter()
104 : has_storage_monitor_observer_(false) {
107 SystemInfoEventRouter::~SystemInfoEventRouter() {
108 if (has_storage_monitor_observer_) {
109 StorageMonitor* storage_monitor = StorageMonitor::GetInstance();
111 storage_monitor->RemoveObserver(this);
115 void SystemInfoEventRouter::AddEventListener(const std::string& event_name) {
116 DCHECK_CURRENTLY_ON(BrowserThread::UI);
118 watching_event_set_.insert(event_name);
119 if (watching_event_set_.count(event_name) > 1)
122 // For system.display event.
123 #if defined(OS_CHROMEOS)
124 if (IsDisplayChangedEvent(event_name))
125 ash::Shell::GetScreen()->AddObserver(this);
128 if (IsSystemStorageEvent(event_name)) {
129 if (!has_storage_monitor_observer_) {
130 has_storage_monitor_observer_ = true;
131 DCHECK(StorageMonitor::GetInstance()->IsInitialized());
132 StorageMonitor::GetInstance()->AddObserver(this);
137 void SystemInfoEventRouter::RemoveEventListener(const std::string& event_name) {
138 DCHECK_CURRENTLY_ON(BrowserThread::UI);
140 std::multiset<std::string>::iterator it =
141 watching_event_set_.find(event_name);
142 if (it != watching_event_set_.end()) {
143 watching_event_set_.erase(it);
144 if (watching_event_set_.count(event_name) > 0)
148 #if defined(OS_CHROMEOS)
149 if (IsDisplayChangedEvent(event_name))
150 ash::Shell::GetScreen()->RemoveObserver(this);
153 if (IsSystemStorageEvent(event_name)) {
154 const std::string& other_event_name =
155 (event_name == system_storage::OnDetached::kEventName) ?
156 system_storage::OnAttached::kEventName :
157 system_storage::OnDetached::kEventName;
158 if (watching_event_set_.count(other_event_name) == 0) {
159 StorageMonitor::GetInstance()->RemoveObserver(this);
160 has_storage_monitor_observer_ = false;
165 void SystemInfoEventRouter::OnRemovableStorageAttached(
166 const storage_monitor::StorageInfo& info) {
167 StorageUnitInfo unit;
168 systeminfo::BuildStorageUnitInfo(info, &unit);
169 scoped_ptr<base::ListValue> args(new base::ListValue);
170 args->Append(unit.ToValue().release());
171 DispatchEvent(system_storage::OnAttached::kEventName, args.Pass());
174 void SystemInfoEventRouter::OnRemovableStorageDetached(
175 const storage_monitor::StorageInfo& info) {
176 scoped_ptr<base::ListValue> args(new base::ListValue);
177 std::string transient_id =
178 StorageMonitor::GetInstance()->GetTransientIdForDeviceId(
180 args->AppendString(transient_id);
182 DispatchEvent(system_storage::OnDetached::kEventName, args.Pass());
185 void SystemInfoEventRouter::OnDisplayBoundsChanged(
186 const gfx::Display& display) {
190 void SystemInfoEventRouter::OnDisplayAdded(const gfx::Display& new_display) {
194 void SystemInfoEventRouter::OnDisplayRemoved(const gfx::Display& old_display) {
198 void SystemInfoEventRouter::OnDisplayChanged() {
199 scoped_ptr<base::ListValue> args(new base::ListValue());
200 DispatchEvent(system_display::OnDisplayChanged::kEventName, args.Pass());
203 void SystemInfoEventRouter::DispatchEvent(const std::string& event_name,
204 scoped_ptr<base::ListValue> args) {
205 g_browser_process->extension_event_router_forwarder()->
206 BroadcastEventToRenderers(event_name, args.Pass(), GURL());
209 void AddEventListener(const std::string& event_name) {
210 SystemInfoEventRouter::GetInstance()->AddEventListener(event_name);
213 void RemoveEventListener(const std::string& event_name) {
214 SystemInfoEventRouter::GetInstance()->RemoveEventListener(event_name);
219 static base::LazyInstance<BrowserContextKeyedAPIFactory<SystemInfoAPI> >
220 g_factory = LAZY_INSTANCE_INITIALIZER;
223 BrowserContextKeyedAPIFactory<SystemInfoAPI>*
224 SystemInfoAPI::GetFactoryInstance() {
225 return g_factory.Pointer();
228 SystemInfoAPI::SystemInfoAPI(content::BrowserContext* context)
229 : browser_context_(context) {
230 EventRouter* router = EventRouter::Get(browser_context_);
231 router->RegisterObserver(this, system_storage::OnAttached::kEventName);
232 router->RegisterObserver(this, system_storage::OnDetached::kEventName);
233 router->RegisterObserver(this, system_display::OnDisplayChanged::kEventName);
236 SystemInfoAPI::~SystemInfoAPI() {
239 void SystemInfoAPI::Shutdown() {
240 EventRouter::Get(browser_context_)->UnregisterObserver(this);
243 void SystemInfoAPI::OnListenerAdded(const EventListenerInfo& details) {
244 if (IsSystemStorageEvent(details.event_name)) {
245 StorageMonitor::GetInstance()->EnsureInitialized(
246 base::Bind(&AddEventListener, details.event_name));
248 AddEventListener(details.event_name);
252 void SystemInfoAPI::OnListenerRemoved(const EventListenerInfo& details) {
253 if (IsSystemStorageEvent(details.event_name)) {
254 StorageMonitor::GetInstance()->EnsureInitialized(
255 base::Bind(&RemoveEventListener, details.event_name));
257 RemoveEventListener(details.event_name);
261 } // namespace extensions