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 "extensions/browser/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 "components/storage_monitor/removable_storage_observer.h"
16 #include "components/storage_monitor/storage_info.h"
17 #include "components/storage_monitor/storage_monitor.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "extensions/browser/api/system_display/display_info_provider.h"
20 #include "extensions/browser/api/system_storage/storage_info_provider.h"
21 #include "extensions/browser/extensions_browser_client.h"
22 #include "extensions/common/api/system_display.h"
23 #include "extensions/common/api/system_storage.h"
24 #include "ui/gfx/display_observer.h"
25 #include "ui/gfx/screen.h"
27 namespace extensions
{
29 using core_api::system_storage::StorageUnitInfo
;
30 using content::BrowserThread
;
31 using storage_monitor::StorageMonitor
;
33 namespace system_display
= core_api::system_display
;
34 namespace system_storage
= core_api::system_storage
;
38 bool IsDisplayChangedEvent(const std::string
& event_name
) {
39 return event_name
== system_display::OnDisplayChanged::kEventName
;
42 bool IsSystemStorageEvent(const std::string
& event_name
) {
43 return (event_name
== system_storage::OnAttached::kEventName
||
44 event_name
== system_storage::OnDetached::kEventName
);
47 // Event router for systemInfo API. It is a singleton instance shared by
49 class SystemInfoEventRouter
: public gfx::DisplayObserver
,
50 public storage_monitor::RemovableStorageObserver
{
52 static SystemInfoEventRouter
* GetInstance();
54 SystemInfoEventRouter();
55 ~SystemInfoEventRouter() override
;
57 // Add/remove event listener for the |event_name| event.
58 void AddEventListener(const std::string
& event_name
);
59 void RemoveEventListener(const std::string
& event_name
);
62 // gfx::DisplayObserver:
63 void OnDisplayAdded(const gfx::Display
& new_display
) override
;
64 void OnDisplayRemoved(const gfx::Display
& old_display
) override
;
65 void OnDisplayMetricsChanged(const gfx::Display
& display
,
66 uint32_t metrics
) override
;
68 // RemovableStorageObserver implementation.
69 void OnRemovableStorageAttached(
70 const storage_monitor::StorageInfo
& info
) override
;
71 void OnRemovableStorageDetached(
72 const storage_monitor::StorageInfo
& info
) override
;
74 // Called from any thread to dispatch the systemInfo event to all extension
75 // processes cross multiple profiles.
76 void DispatchEvent(const std::string
& event_name
,
77 scoped_ptr
<base::ListValue
> args
);
79 // Called to dispatch the systemInfo.display.onDisplayChanged event.
80 void OnDisplayChanged();
82 // Used to record the event names being watched.
83 std::multiset
<std::string
> watching_event_set_
;
85 bool has_storage_monitor_observer_
;
87 DISALLOW_COPY_AND_ASSIGN(SystemInfoEventRouter
);
90 static base::LazyInstance
<SystemInfoEventRouter
>::Leaky
91 g_system_info_event_router
= LAZY_INSTANCE_INITIALIZER
;
94 SystemInfoEventRouter
* SystemInfoEventRouter::GetInstance() {
95 return g_system_info_event_router
.Pointer();
98 SystemInfoEventRouter::SystemInfoEventRouter()
99 : has_storage_monitor_observer_(false) {
102 SystemInfoEventRouter::~SystemInfoEventRouter() {
103 if (has_storage_monitor_observer_
) {
104 StorageMonitor
* storage_monitor
= StorageMonitor::GetInstance();
106 storage_monitor
->RemoveObserver(this);
110 void SystemInfoEventRouter::AddEventListener(const std::string
& event_name
) {
111 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
113 watching_event_set_
.insert(event_name
);
114 if (watching_event_set_
.count(event_name
) > 1)
117 if (IsDisplayChangedEvent(event_name
)) {
118 gfx::Screen
* screen
= DisplayInfoProvider::Get()->GetActiveScreen();
120 screen
->AddObserver(this);
123 if (IsSystemStorageEvent(event_name
)) {
124 if (!has_storage_monitor_observer_
) {
125 has_storage_monitor_observer_
= true;
126 DCHECK(StorageMonitor::GetInstance()->IsInitialized());
127 StorageMonitor::GetInstance()->AddObserver(this);
132 void SystemInfoEventRouter::RemoveEventListener(const std::string
& event_name
) {
133 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
135 std::multiset
<std::string
>::iterator it
=
136 watching_event_set_
.find(event_name
);
137 if (it
!= watching_event_set_
.end()) {
138 watching_event_set_
.erase(it
);
139 if (watching_event_set_
.count(event_name
) > 0)
143 if (IsDisplayChangedEvent(event_name
)) {
144 gfx::Screen
* screen
= DisplayInfoProvider::Get()->GetActiveScreen();
146 screen
->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 storage_monitor::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 storage_monitor::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::OnDisplayAdded(const gfx::Display
& new_display
) {
185 void SystemInfoEventRouter::OnDisplayRemoved(const gfx::Display
& old_display
) {
189 void SystemInfoEventRouter::OnDisplayMetricsChanged(const gfx::Display
& 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 ExtensionsBrowserClient::Get()->BroadcastEventToRenderers(event_name
,
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
<BrowserContextKeyedAPIFactory
<SystemInfoAPI
> >
216 g_factory
= LAZY_INSTANCE_INITIALIZER
;
219 BrowserContextKeyedAPIFactory
<SystemInfoAPI
>*
220 SystemInfoAPI::GetFactoryInstance() {
221 return g_factory
.Pointer();
224 SystemInfoAPI::SystemInfoAPI(content::BrowserContext
* context
)
225 : browser_context_(context
) {
226 EventRouter
* router
= EventRouter::Get(browser_context_
);
227 router
->RegisterObserver(this, system_storage::OnAttached::kEventName
);
228 router
->RegisterObserver(this, system_storage::OnDetached::kEventName
);
229 router
->RegisterObserver(this, system_display::OnDisplayChanged::kEventName
);
232 SystemInfoAPI::~SystemInfoAPI() {
235 void SystemInfoAPI::Shutdown() {
236 EventRouter::Get(browser_context_
)->UnregisterObserver(this);
239 void SystemInfoAPI::OnListenerAdded(const EventListenerInfo
& details
) {
240 if (IsSystemStorageEvent(details
.event_name
)) {
241 StorageMonitor::GetInstance()->EnsureInitialized(
242 base::Bind(&AddEventListener
, details
.event_name
));
244 AddEventListener(details
.event_name
);
248 void SystemInfoAPI::OnListenerRemoved(const EventListenerInfo
& details
) {
249 if (IsSystemStorageEvent(details
.event_name
)) {
250 StorageMonitor::GetInstance()->EnsureInitialized(
251 base::Bind(&RemoveEventListener
, details
.event_name
));
253 RemoveEventListener(details
.event_name
);
257 } // namespace extensions