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.
5 #include "content/browser/device_orientation/provider_impl.h"
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "base/message_loop.h"
13 #include "base/threading/thread.h"
14 #include "base/threading/worker_pool.h"
18 void DeleteThread(base::Thread
* thread
) {
26 class ProviderImpl::PollingThread
: public base::Thread
{
28 PollingThread(const char* name
,
29 base::WeakPtr
<ProviderImpl
> provider
,
30 base::MessageLoop
* creator_loop
);
31 virtual ~PollingThread();
33 // Method for creating a DataFetcher and starting the polling, if the fetcher
34 // can provide this type of data.
35 void Initialize(DataFetcherFactory factory
, DeviceData::Type type
);
37 // Method for adding a type of data to poll for.
38 void DoAddPollingDataType(DeviceData::Type type
);
41 // Method for polling a DataFetcher.
43 void ScheduleDoPoll();
45 // Schedule a notification to the |provider_| which lives on a different
46 // thread (|creator_loop_| is its message loop).
47 void ScheduleDoNotify(const scoped_refptr
<const DeviceData
>& device_data
,
48 DeviceData::Type device_data_type
);
50 enum { kDesiredSamplingIntervalMs
= 100 };
51 base::TimeDelta
SamplingInterval() const;
53 // The Message Loop on which this object was created.
54 // Typically the I/O loop, but may be something else during testing.
55 base::MessageLoop
* creator_loop_
;
57 scoped_ptr
<DataFetcher
> data_fetcher_
;
58 std::map
<DeviceData::Type
, scoped_refptr
<const DeviceData
> >
59 last_device_data_map_
;
60 std::set
<DeviceData::Type
> polling_data_types_
;
62 base::WeakPtr
<ProviderImpl
> provider_
;
65 ProviderImpl::PollingThread::PollingThread(const char* name
,
66 base::WeakPtr
<ProviderImpl
> provider
,
67 base::MessageLoop
* creator_loop
)
68 : base::Thread(name
), creator_loop_(creator_loop
), provider_(provider
) {}
70 ProviderImpl::PollingThread::~PollingThread() {
74 void ProviderImpl::PollingThread::DoAddPollingDataType(DeviceData::Type type
) {
75 DCHECK(base::MessageLoop::current() == message_loop());
77 polling_data_types_
.insert(type
);
80 void ProviderImpl::PollingThread::Initialize(DataFetcherFactory factory
,
81 DeviceData::Type type
) {
82 DCHECK(base::MessageLoop::current() == message_loop());
84 if (factory
!= NULL
) {
85 // Try to use factory to create a fetcher that can provide this type of
86 // data. If factory creates a fetcher that provides this type of data,
88 scoped_ptr
<DataFetcher
> fetcher(factory());
91 scoped_refptr
<const DeviceData
> device_data(fetcher
->GetDeviceData(type
));
92 if (device_data
.get() != NULL
) {
93 // Pass ownership of fetcher to provider_.
94 data_fetcher_
.swap(fetcher
);
95 last_device_data_map_
[type
] = device_data
;
98 ScheduleDoNotify(device_data
, type
);
107 // When no device data can be provided.
108 ScheduleDoNotify(NULL
, type
);
111 void ProviderImpl::PollingThread::ScheduleDoNotify(
112 const scoped_refptr
<const DeviceData
>& device_data
,
113 DeviceData::Type device_data_type
) {
114 DCHECK(base::MessageLoop::current() == message_loop());
116 creator_loop_
->PostTask(FROM_HERE
,
117 base::Bind(&ProviderImpl::DoNotify
, provider_
,
118 device_data
, device_data_type
));
121 void ProviderImpl::PollingThread::DoPoll() {
122 DCHECK(base::MessageLoop::current() == message_loop());
124 // Poll the fetcher for each type of data.
125 typedef std::set
<DeviceData::Type
>::const_iterator SetIterator
;
126 for (SetIterator i
= polling_data_types_
.begin();
127 i
!= polling_data_types_
.end(); ++i
) {
128 DeviceData::Type device_data_type
= *i
;
129 scoped_refptr
<const DeviceData
> device_data(data_fetcher_
->GetDeviceData(
132 if (device_data
.get() == NULL
) {
133 LOG(ERROR
) << "Failed to poll device data fetcher.";
134 ScheduleDoNotify(NULL
, device_data_type
);
138 const DeviceData
* old_data
= last_device_data_map_
[device_data_type
].get();
139 if (old_data
!= NULL
&& !device_data
->ShouldFireEvent(old_data
))
142 // Update the last device data of this type and notify observers.
143 last_device_data_map_
[device_data_type
] = device_data
;
144 ScheduleDoNotify(device_data
, device_data_type
);
150 void ProviderImpl::PollingThread::ScheduleDoPoll() {
151 DCHECK(base::MessageLoop::current() == message_loop());
153 message_loop()->PostDelayedTask(
155 base::Bind(&PollingThread::DoPoll
, base::Unretained(this)),
159 base::TimeDelta
ProviderImpl::PollingThread::SamplingInterval() const {
160 DCHECK(base::MessageLoop::current() == message_loop());
161 DCHECK(data_fetcher_
.get());
163 // TODO(erg): There used to be unused code here, that called a default
164 // implementation on the DataFetcherInterface that was never defined. I'm
165 // removing unused methods from headers.
166 return base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs
);
169 ProviderImpl::ProviderImpl(DataFetcherFactory factory
)
170 : creator_loop_(base::MessageLoop::current()),
173 polling_thread_(NULL
) {
176 ProviderImpl::~ProviderImpl() {
180 void ProviderImpl::ScheduleDoAddPollingDataType(DeviceData::Type type
) {
181 DCHECK(base::MessageLoop::current() == creator_loop_
);
183 base::MessageLoop
* polling_loop
= polling_thread_
->message_loop();
184 polling_loop
->PostTask(FROM_HERE
,
185 base::Bind(&PollingThread::DoAddPollingDataType
,
186 base::Unretained(polling_thread_
),
190 void ProviderImpl::AddObserver(Observer
* observer
) {
191 DCHECK(base::MessageLoop::current() == creator_loop_
);
193 DeviceData::Type type
= observer
->device_data_type();
195 observers_
.insert(observer
);
196 if (observers_
.size() == 1)
199 // Notify observer of most recent notification if one exists.
200 const DeviceData
* last_notification
= last_notifications_map_
[type
].get();
201 if (last_notification
!= NULL
)
202 observer
->OnDeviceDataUpdate(last_notification
, type
);
205 ScheduleDoAddPollingDataType(type
);
208 void ProviderImpl::RemoveObserver(Observer
* observer
) {
209 DCHECK(base::MessageLoop::current() == creator_loop_
);
211 observers_
.erase(observer
);
212 if (observers_
.empty())
216 void ProviderImpl::Start(DeviceData::Type type
) {
217 DCHECK(base::MessageLoop::current() == creator_loop_
);
218 DCHECK(!polling_thread_
);
220 polling_thread_
= new PollingThread("Device data polling thread",
221 weak_factory_
.GetWeakPtr(),
224 polling_thread_
->init_com_with_mta(true);
226 if (!polling_thread_
->Start()) {
227 LOG(ERROR
) << "Failed to start device data polling thread";
228 delete polling_thread_
;
229 polling_thread_
= NULL
;
232 ScheduleInitializePollingThread(type
);
235 void ProviderImpl::Stop() {
236 DCHECK(base::MessageLoop::current() == creator_loop_
);
238 weak_factory_
.InvalidateWeakPtrs();
239 if (polling_thread_
) {
240 polling_thread_
->StopSoon();
241 bool posted
= base::WorkerPool::PostTask(
243 base::Bind(&DeleteThread
, base::Unretained(polling_thread_
)),
244 true /* task is slow */);
246 polling_thread_
= NULL
;
250 void ProviderImpl::ScheduleInitializePollingThread(
251 DeviceData::Type device_data_type
) {
252 DCHECK(base::MessageLoop::current() == creator_loop_
);
254 base::MessageLoop
* polling_loop
= polling_thread_
->message_loop();
255 polling_loop
->PostTask(FROM_HERE
,
256 base::Bind(&PollingThread::Initialize
,
257 base::Unretained(polling_thread_
),
262 void ProviderImpl::DoNotify(const scoped_refptr
<const DeviceData
>& data
,
263 DeviceData::Type device_data_type
) {
264 DCHECK(base::MessageLoop::current() == creator_loop_
);
266 // Update last notification of this type.
267 last_notifications_map_
[device_data_type
] = data
;
269 // Notify observers of this type of the new data.
270 typedef std::set
<Observer
*>::const_iterator ConstIterator
;
271 for (ConstIterator i
= observers_
.begin(); i
!= observers_
.end(); ++i
) {
272 if ((*i
)->device_data_type() == device_data_type
)
273 (*i
)->OnDeviceDataUpdate(data
.get(), device_data_type
);
276 if (data
.get() == NULL
) {
277 // Notify observers exactly once about failure to provide data.
278 typedef std::set
<Observer
*>::iterator Iterator
;
279 Iterator i
= observers_
.begin();
280 while (i
!= observers_
.end()) {
281 Iterator current
= i
++;
282 if ((*current
)->device_data_type() == device_data_type
)
283 observers_
.erase(current
);
286 if (observers_
.empty())
292 } // namespace content