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/extensions/api/dial/dial_api.h"
6
7 #include <vector>
8
9 #include "base/time/time.h"
10 #include "chrome/browser/extensions/api/dial/dial_api_factory.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/common/extensions/api/dial.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "extensions/browser/event_router.h"
15 #include "extensions/browser/extension_system.h"
16
17 using base::TimeDelta;
18 using content::BrowserThread;
19
20 namespace {
21
22 // How often to poll for devices.
23 const int kDialRefreshIntervalSecs = 120;
24
25 // We prune a device if it does not respond after this time.
26 const int kDialExpirationSecs = 240;
27
28 // The maximum number of devices retained at once in the registry.
29 const size_t kDialMaxDevices = 256;
30
31 } // namespace
32
33 namespace extensions {
34
35 namespace dial = api::dial;
36
DialAPI(Profile * profile)37 DialAPI::DialAPI(Profile* profile)
38 : RefcountedBrowserContextKeyedService(BrowserThread::IO),
39 profile_(profile) {
40 EventRouter::Get(profile)
41 ->RegisterObserver(this, dial::OnDeviceList::kEventName);
42 }
43
~DialAPI()44 DialAPI::~DialAPI() {}
45
dial_registry()46 DialRegistry* DialAPI::dial_registry() {
47 DCHECK_CURRENTLY_ON(BrowserThread::IO);
48 if (!dial_registry_.get()) {
49 dial_registry_.reset(new DialRegistry(this,
50 TimeDelta::FromSeconds(kDialRefreshIntervalSecs),
51 TimeDelta::FromSeconds(kDialExpirationSecs),
52 kDialMaxDevices));
53 }
54 return dial_registry_.get();
55 }
56
OnListenerAdded(const EventListenerInfo & details)57 void DialAPI::OnListenerAdded(const EventListenerInfo& details) {
58 DCHECK_CURRENTLY_ON(BrowserThread::UI);
59 BrowserThread::PostTask(
60 BrowserThread::IO, FROM_HERE,
61 base::Bind(&DialAPI::NotifyListenerAddedOnIOThread, this));
62 }
63
OnListenerRemoved(const EventListenerInfo & details)64 void DialAPI::OnListenerRemoved(const EventListenerInfo& details) {
65 DCHECK_CURRENTLY_ON(BrowserThread::UI);
66 BrowserThread::PostTask(
67 BrowserThread::IO, FROM_HERE,
68 base::Bind(&DialAPI::NotifyListenerRemovedOnIOThread, this));
69 }
70
NotifyListenerAddedOnIOThread()71 void DialAPI::NotifyListenerAddedOnIOThread() {
72 DCHECK_CURRENTLY_ON(BrowserThread::IO);
73 VLOG(2) << "DIAL device event listener added.";
74 dial_registry()->OnListenerAdded();
75 }
76
NotifyListenerRemovedOnIOThread()77 void DialAPI::NotifyListenerRemovedOnIOThread() {
78 DCHECK_CURRENTLY_ON(BrowserThread::IO);
79 VLOG(2) << "DIAL device event listener removed";
80 dial_registry()->OnListenerRemoved();
81 }
82
OnDialDeviceEvent(const DialRegistry::DeviceList & devices)83 void DialAPI::OnDialDeviceEvent(const DialRegistry::DeviceList& devices) {
84 DCHECK_CURRENTLY_ON(BrowserThread::IO);
85 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
86 base::Bind(&DialAPI::SendEventOnUIThread, this, devices));
87 }
88
OnDialError(const DialRegistry::DialErrorCode code)89 void DialAPI::OnDialError(const DialRegistry::DialErrorCode code) {
90 DCHECK_CURRENTLY_ON(BrowserThread::IO);
91 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
92 base::Bind(&DialAPI::SendErrorOnUIThread, this, code));
93 }
94
SendEventOnUIThread(const DialRegistry::DeviceList & devices)95 void DialAPI::SendEventOnUIThread(const DialRegistry::DeviceList& devices) {
96 DCHECK_CURRENTLY_ON(BrowserThread::UI);
97
98 std::vector<linked_ptr<api::dial::DialDevice> > args;
99 for (DialRegistry::DeviceList::const_iterator it = devices.begin();
100 it != devices.end(); ++it) {
101 linked_ptr<api::dial::DialDevice> api_device =
102 make_linked_ptr(new api::dial::DialDevice);
103 it->FillDialDevice(api_device.get());
104 args.push_back(api_device);
105 }
106 scoped_ptr<base::ListValue> results = api::dial::OnDeviceList::Create(args);
107 scoped_ptr<Event> event(
108 new Event(dial::OnDeviceList::kEventName, results.Pass()));
109 EventRouter::Get(profile_)->BroadcastEvent(event.Pass());
110 }
111
SendErrorOnUIThread(const DialRegistry::DialErrorCode code)112 void DialAPI::SendErrorOnUIThread(const DialRegistry::DialErrorCode code) {
113 DCHECK_CURRENTLY_ON(BrowserThread::UI);
114
115 api::dial::DialError dial_error;
116 switch (code) {
117 case DialRegistry::DIAL_NO_LISTENERS:
118 dial_error.code = api::dial::DIAL_ERROR_CODE_NO_LISTENERS;
119 break;
120 case DialRegistry::DIAL_NO_INTERFACES:
121 dial_error.code = api::dial::DIAL_ERROR_CODE_NO_VALID_NETWORK_INTERFACES;
122 break;
123 case DialRegistry::DIAL_CELLULAR_NETWORK:
124 dial_error.code = api::dial::DIAL_ERROR_CODE_CELLULAR_NETWORK;
125 break;
126 case DialRegistry::DIAL_NETWORK_DISCONNECTED:
127 dial_error.code = api::dial::DIAL_ERROR_CODE_NETWORK_DISCONNECTED;
128 break;
129 case DialRegistry::DIAL_SOCKET_ERROR:
130 dial_error.code = api::dial::DIAL_ERROR_CODE_SOCKET_ERROR;
131 break;
132 default:
133 dial_error.code = api::dial::DIAL_ERROR_CODE_UNKNOWN;
134 break;
135 }
136
137 scoped_ptr<base::ListValue> results = api::dial::OnError::Create(dial_error);
138 scoped_ptr<Event> event(new Event(dial::OnError::kEventName, results.Pass()));
139 EventRouter::Get(profile_)->BroadcastEvent(event.Pass());
140 }
141
ShutdownOnUIThread()142 void DialAPI::ShutdownOnUIThread() {}
143
144 namespace api {
145
DialDiscoverNowFunction()146 DialDiscoverNowFunction::DialDiscoverNowFunction()
147 : dial_(NULL), result_(false) {
148 }
149
Prepare()150 bool DialDiscoverNowFunction::Prepare() {
151 DCHECK_CURRENTLY_ON(BrowserThread::UI);
152 DCHECK(browser_context());
153 dial_ = DialAPIFactory::GetForBrowserContext(browser_context()).get();
154 return true;
155 }
156
Work()157 void DialDiscoverNowFunction::Work() {
158 DCHECK_CURRENTLY_ON(BrowserThread::IO);
159 result_ = dial_->dial_registry()->DiscoverNow();
160 }
161
Respond()162 bool DialDiscoverNowFunction::Respond() {
163 DCHECK_CURRENTLY_ON(BrowserThread::UI);
164 SetResult(new base::FundamentalValue(result_));
165 return true;
166 }
167
168 } // namespace api
169
170 } // namespace extensions
171