Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / system_info / system_info_api.cc
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.
4
5 #include "chrome/browser/extensions/api/system_info/system_info_api.h"
6
7 #include <set>
8
9 #include "base/bind.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"
25
26 #if defined(OS_CHROMEOS)
27 #include "ash/shell.h"
28 #include "ui/gfx/screen.h"
29 #endif
30
31 namespace extensions {
32
33 using api::system_storage::StorageUnitInfo;
34 using content::BrowserThread;
35 using storage_monitor::StorageMonitor;
36
37 namespace system_display = api::system_display;
38 namespace system_storage = api::system_storage;
39
40 namespace {
41
42 #if defined(OS_CHROMEOS)
43 bool IsDisplayChangedEvent(const std::string& event_name) {
44   return event_name == system_display::OnDisplayChanged::kEventName;
45 }
46 #endif
47
48 bool IsSystemStorageEvent(const std::string& event_name) {
49   return (event_name == system_storage::OnAttached::kEventName ||
50           event_name == system_storage::OnDetached::kEventName);
51 }
52
53 // Event router for systemInfo API. It is a singleton instance shared by
54 // multiple profiles.
55 class SystemInfoEventRouter : public gfx::DisplayObserver,
56                               public storage_monitor::RemovableStorageObserver {
57  public:
58   static SystemInfoEventRouter* GetInstance();
59
60   SystemInfoEventRouter();
61   virtual ~SystemInfoEventRouter();
62
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);
66
67  private:
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;
72
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;
78
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);
83
84   // Called to dispatch the systemInfo.display.onDisplayChanged event.
85   void OnDisplayChanged();
86
87   // Used to record the event names being watched.
88   std::multiset<std::string> watching_event_set_;
89
90   bool has_storage_monitor_observer_;
91
92   DISALLOW_COPY_AND_ASSIGN(SystemInfoEventRouter);
93 };
94
95 static base::LazyInstance<SystemInfoEventRouter>::Leaky
96     g_system_info_event_router = LAZY_INSTANCE_INITIALIZER;
97
98 // static
99 SystemInfoEventRouter* SystemInfoEventRouter::GetInstance() {
100   return g_system_info_event_router.Pointer();
101 }
102
103 SystemInfoEventRouter::SystemInfoEventRouter()
104     : has_storage_monitor_observer_(false) {
105 }
106
107 SystemInfoEventRouter::~SystemInfoEventRouter() {
108   if (has_storage_monitor_observer_) {
109     StorageMonitor* storage_monitor = StorageMonitor::GetInstance();
110     if (storage_monitor)
111       storage_monitor->RemoveObserver(this);
112   }
113 }
114
115 void SystemInfoEventRouter::AddEventListener(const std::string& event_name) {
116   DCHECK_CURRENTLY_ON(BrowserThread::UI);
117
118   watching_event_set_.insert(event_name);
119   if (watching_event_set_.count(event_name) > 1)
120     return;
121
122   // For system.display event.
123 #if defined(OS_CHROMEOS)
124   if (IsDisplayChangedEvent(event_name))
125     ash::Shell::GetScreen()->AddObserver(this);
126 #endif
127
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);
133     }
134   }
135 }
136
137 void SystemInfoEventRouter::RemoveEventListener(const std::string& event_name) {
138   DCHECK_CURRENTLY_ON(BrowserThread::UI);
139
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)
145       return;
146   }
147
148 #if defined(OS_CHROMEOS)
149   if (IsDisplayChangedEvent(event_name))
150     ash::Shell::GetScreen()->RemoveObserver(this);
151 #endif
152
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;
161     }
162   }
163 }
164
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());
172 }
173
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(
179           info.device_id());
180   args->AppendString(transient_id);
181
182   DispatchEvent(system_storage::OnDetached::kEventName, args.Pass());
183 }
184
185 void SystemInfoEventRouter::OnDisplayBoundsChanged(
186     const gfx::Display& display) {
187   OnDisplayChanged();
188 }
189
190 void SystemInfoEventRouter::OnDisplayAdded(const gfx::Display& new_display) {
191   OnDisplayChanged();
192 }
193
194 void SystemInfoEventRouter::OnDisplayRemoved(const gfx::Display& old_display) {
195   OnDisplayChanged();
196 }
197
198 void SystemInfoEventRouter::OnDisplayChanged() {
199   scoped_ptr<base::ListValue> args(new base::ListValue());
200   DispatchEvent(system_display::OnDisplayChanged::kEventName, args.Pass());
201 }
202
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());
207 }
208
209 void AddEventListener(const std::string& event_name) {
210   SystemInfoEventRouter::GetInstance()->AddEventListener(event_name);
211 }
212
213 void RemoveEventListener(const std::string& event_name) {
214   SystemInfoEventRouter::GetInstance()->RemoveEventListener(event_name);
215 }
216
217 }  // namespace
218
219 static base::LazyInstance<BrowserContextKeyedAPIFactory<SystemInfoAPI> >
220     g_factory = LAZY_INSTANCE_INITIALIZER;
221
222 // static
223 BrowserContextKeyedAPIFactory<SystemInfoAPI>*
224 SystemInfoAPI::GetFactoryInstance() {
225   return g_factory.Pointer();
226 }
227
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);
234 }
235
236 SystemInfoAPI::~SystemInfoAPI() {
237 }
238
239 void SystemInfoAPI::Shutdown() {
240   EventRouter::Get(browser_context_)->UnregisterObserver(this);
241 }
242
243 void SystemInfoAPI::OnListenerAdded(const EventListenerInfo& details) {
244   if (IsSystemStorageEvent(details.event_name)) {
245     StorageMonitor::GetInstance()->EnsureInitialized(
246         base::Bind(&AddEventListener, details.event_name));
247   } else {
248     AddEventListener(details.event_name);
249   }
250 }
251
252 void SystemInfoAPI::OnListenerRemoved(const EventListenerInfo& details) {
253   if (IsSystemStorageEvent(details.event_name)) {
254     StorageMonitor::GetInstance()->EnsureInitialized(
255         base::Bind(&RemoveEventListener, details.event_name));
256   } else {
257     RemoveEventListener(details.event_name);
258   }
259 }
260
261 }  // namespace extensions