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/browser/storage_monitor/removable_storage_observer.h"
19 #include "chrome/browser/storage_monitor/storage_info.h"
20 #include "chrome/browser/storage_monitor/storage_monitor.h"
21 #include "chrome/common/extensions/api/system_display.h"
22 #include "chrome/common/extensions/api/system_storage.h"
23 #include "ui/gfx/display_observer.h"
26 #include "ash/shell.h"
27 #include "ui/gfx/screen.h"
30 namespace extensions {
32 using api::system_storage::StorageUnitInfo;
33 using content::BrowserThread;
35 namespace system_display = api::system_display;
36 namespace system_storage = api::system_storage;
41 bool IsDisplayChangedEvent(const std::string& event_name) {
42 return event_name == system_display::OnDisplayChanged::kEventName;
46 bool IsSystemStorageEvent(const std::string& event_name) {
47 return (event_name == system_storage::OnAttached::kEventName ||
48 event_name == system_storage::OnDetached::kEventName);
51 // Event router for systemInfo API. It is a singleton instance shared by
53 class SystemInfoEventRouter : public gfx::DisplayObserver,
54 public RemovableStorageObserver {
56 static SystemInfoEventRouter* GetInstance();
58 SystemInfoEventRouter();
59 virtual ~SystemInfoEventRouter();
61 // Add/remove event listener for the |event_name| event.
62 void AddEventListener(const std::string& event_name);
63 void RemoveEventListener(const std::string& event_name);
66 // gfx::DisplayObserver:
67 virtual void OnDisplayBoundsChanged(const gfx::Display& display) OVERRIDE;
68 virtual void OnDisplayAdded(const gfx::Display& new_display) OVERRIDE;
69 virtual void OnDisplayRemoved(const gfx::Display& old_display) OVERRIDE;
71 // RemovableStorageObserver implementation.
72 virtual void OnRemovableStorageAttached(const StorageInfo& info) OVERRIDE;
73 virtual void OnRemovableStorageDetached(const StorageInfo& info) OVERRIDE;
75 // Called from any thread to dispatch the systemInfo event to all extension
76 // processes cross multiple profiles.
77 void DispatchEvent(const std::string& event_name,
78 scoped_ptr<base::ListValue> args);
80 // Called to dispatch the systemInfo.display.onDisplayChanged event.
81 void OnDisplayChanged();
83 // Used to record the event names being watched.
84 std::multiset<std::string> watching_event_set_;
86 bool has_storage_monitor_observer_;
88 DISALLOW_COPY_AND_ASSIGN(SystemInfoEventRouter);
91 static base::LazyInstance<SystemInfoEventRouter>::Leaky
92 g_system_info_event_router = LAZY_INSTANCE_INITIALIZER;
95 SystemInfoEventRouter* SystemInfoEventRouter::GetInstance() {
96 return g_system_info_event_router.Pointer();
99 SystemInfoEventRouter::SystemInfoEventRouter()
100 : has_storage_monitor_observer_(false) {
103 SystemInfoEventRouter::~SystemInfoEventRouter() {
104 if (has_storage_monitor_observer_) {
105 StorageMonitor* storage_monitor = StorageMonitor::GetInstance();
107 storage_monitor->RemoveObserver(this);
111 void SystemInfoEventRouter::AddEventListener(const std::string& event_name) {
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
114 watching_event_set_.insert(event_name);
115 if (watching_event_set_.count(event_name) > 1)
118 // For systemInfo.display event.
120 if (IsDisplayChangedEvent(event_name))
121 ash::Shell::GetScreen()->AddObserver(this);
124 if (IsSystemStorageEvent(event_name)) {
125 if (!has_storage_monitor_observer_) {
126 has_storage_monitor_observer_ = true;
127 DCHECK(StorageMonitor::GetInstance()->IsInitialized());
128 StorageMonitor::GetInstance()->AddObserver(this);
133 void SystemInfoEventRouter::RemoveEventListener(const std::string& event_name) {
134 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
136 std::multiset<std::string>::iterator it =
137 watching_event_set_.find(event_name);
138 if (it != watching_event_set_.end()) {
139 watching_event_set_.erase(it);
140 if (watching_event_set_.count(event_name) > 0)
145 if (IsDisplayChangedEvent(event_name))
146 ash::Shell::GetScreen()->RemoveObserver(this);
149 if (IsSystemStorageEvent(event_name)) {
150 const std::string& other_event_name =
151 (event_name == system_storage::OnDetached::kEventName) ?
152 system_storage::OnAttached::kEventName :
153 system_storage::OnDetached::kEventName;
154 if (watching_event_set_.count(other_event_name) == 0) {
155 StorageMonitor::GetInstance()->RemoveObserver(this);
156 has_storage_monitor_observer_ = false;
161 void SystemInfoEventRouter::OnRemovableStorageAttached(
162 const StorageInfo& info) {
163 StorageUnitInfo unit;
164 systeminfo::BuildStorageUnitInfo(info, &unit);
165 scoped_ptr<base::ListValue> args(new base::ListValue);
166 args->Append(unit.ToValue().release());
167 DispatchEvent(system_storage::OnAttached::kEventName, args.Pass());
170 void SystemInfoEventRouter::OnRemovableStorageDetached(
171 const StorageInfo& info) {
172 scoped_ptr<base::ListValue> args(new base::ListValue);
173 std::string transient_id =
174 StorageMonitor::GetInstance()->GetTransientIdForDeviceId(
176 args->AppendString(transient_id);
178 DispatchEvent(system_storage::OnDetached::kEventName, args.Pass());
181 void SystemInfoEventRouter::OnDisplayBoundsChanged(
182 const gfx::Display& display) {
186 void SystemInfoEventRouter::OnDisplayAdded(const gfx::Display& new_display) {
190 void SystemInfoEventRouter::OnDisplayRemoved(const gfx::Display& old_display) {
194 void SystemInfoEventRouter::OnDisplayChanged() {
195 scoped_ptr<base::ListValue> args(new base::ListValue());
196 DispatchEvent(system_display::OnDisplayChanged::kEventName, args.Pass());
199 void SystemInfoEventRouter::DispatchEvent(const std::string& event_name,
200 scoped_ptr<base::ListValue> args) {
201 g_browser_process->extension_event_router_forwarder()->
202 BroadcastEventToRenderers(event_name, args.Pass(), GURL());
205 void AddEventListener(const std::string& event_name) {
206 SystemInfoEventRouter::GetInstance()->AddEventListener(event_name);
209 void RemoveEventListener(const std::string& event_name) {
210 SystemInfoEventRouter::GetInstance()->RemoveEventListener(event_name);
215 static base::LazyInstance<ProfileKeyedAPIFactory<SystemInfoAPI> >
216 g_factory = LAZY_INSTANCE_INITIALIZER;
219 ProfileKeyedAPIFactory<SystemInfoAPI>* SystemInfoAPI::GetFactoryInstance() {
220 return g_factory.Pointer();
223 SystemInfoAPI::SystemInfoAPI(Profile* profile) : profile_(profile) {
224 EventRouter* router = ExtensionSystem::Get(profile_)->event_router();
225 router->RegisterObserver(this, system_storage::OnAttached::kEventName);
226 router->RegisterObserver(this, system_storage::OnDetached::kEventName);
227 router->RegisterObserver(this, system_display::OnDisplayChanged::kEventName);
230 SystemInfoAPI::~SystemInfoAPI() {
233 void SystemInfoAPI::Shutdown() {
234 ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
237 void SystemInfoAPI::OnListenerAdded(const EventListenerInfo& details) {
238 if (IsSystemStorageEvent(details.event_name)) {
239 StorageMonitor::GetInstance()->EnsureInitialized(
240 base::Bind(&AddEventListener, details.event_name));
242 AddEventListener(details.event_name);
246 void SystemInfoAPI::OnListenerRemoved(const EventListenerInfo& details) {
247 if (IsSystemStorageEvent(details.event_name)) {
248 StorageMonitor::GetInstance()->EnsureInitialized(
249 base::Bind(&RemoveEventListener, details.event_name));
251 RemoveEventListener(details.event_name);
255 } // namespace extensions