Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(311)

Side by Side Diff: content/browser/device_orientation/provider_impl.cc

Issue 10755002: Refactors DeviceOrientation to make it more extensible (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Small changes to appease try bots Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <cmath> 5 #include "content/browser/device_orientation/provider_impl.h"
6
6 #include <set> 7 #include <set>
7 #include <vector> 8 #include <vector>
8 9
9 #include "base/bind.h" 10 #include "base/bind.h"
10 #include "base/logging.h" 11 #include "base/logging.h"
11 #include "base/message_loop.h" 12 #include "base/message_loop.h"
12 #include "base/threading/thread.h" 13 #include "base/threading/thread.h"
13 #include "base/threading/worker_pool.h" 14 #include "base/threading/worker_pool.h"
14 #include "content/browser/device_orientation/orientation.h"
15 #include "content/browser/device_orientation/provider_impl.h"
16 15
17 namespace { 16 namespace {
18 17
19 bool IsElementSignificantlyDifferent(bool can_provide_element1,
20 bool can_provide_element2,
21 double element1,
22 double element2) {
23 const double kThreshold = 0.1;
24
25 if (can_provide_element1 != can_provide_element2)
26 return true;
27 if (can_provide_element1 &&
28 std::fabs(element1 - element2) >= kThreshold)
29 return true;
30 return false;
31 }
32
33 void DeleteThread(base::Thread* thread) { 18 void DeleteThread(base::Thread* thread) {
34 thread->Stop(); 19 thread->Stop();
35 delete thread; 20 delete thread;
36 } 21 }
37 22
38 } 23 }
39 24
40 namespace device_orientation { 25 namespace device_orientation {
41 26
42 class ProviderImpl::PollingThread : public base::Thread { 27 class ProviderImpl::PollingThread : public base::Thread {
43 public: 28 public:
44 PollingThread(const char* name, 29 PollingThread(const char* name,
45 base::WeakPtr<ProviderImpl> provider, 30 base::WeakPtr<ProviderImpl> provider,
46 MessageLoop* creator_loop); 31 MessageLoop* creator_loop);
47 virtual ~PollingThread(); 32 virtual ~PollingThread();
48 33
49 // Method for finding a suitable DataFetcher and starting the polling. 34 // Method for creating a DataFetcher and starting the polling, if the fetcher
50 void Initialize(DataFetcherFactory factory); 35 // can provide this type of data.
36 void Initialize(DataFetcherFactory factory, DeviceData::Type type);
37
38 // Method for adding a type of data to poll for.
39 void DoAddPollingDataType(DeviceData::Type type);
51 40
52 private: 41 private:
53 // Method for polling a DataFetcher. 42 // Method for polling a DataFetcher.
54 void DoPoll(); 43 void DoPoll();
55 void ScheduleDoPoll(); 44 void ScheduleDoPoll();
56 45
57 // Schedule a notification to the |provider_| which lives on a different 46 // Schedule a notification to the |provider_| which lives on a different
58 // thread (|creator_loop_| is its message loop). 47 // thread (|creator_loop_| is its message loop).
59 void ScheduleDoNotify(const Orientation& orientation); 48 void ScheduleDoNotify(const DeviceData* device_data,
60 49 DeviceData::Type device_data_type);
61 static bool SignificantlyDifferent(const Orientation& orientation1,
62 const Orientation& orientation2);
63 50
64 enum { kDesiredSamplingIntervalMs = 100 }; 51 enum { kDesiredSamplingIntervalMs = 100 };
65 base::TimeDelta SamplingInterval() const; 52 base::TimeDelta SamplingInterval() const;
66 53
67 // The Message Loop on which this object was created. 54 // The Message Loop on which this object was created.
68 // Typically the I/O loop, but may be something else during testing. 55 // Typically the I/O loop, but may be something else during testing.
69 MessageLoop* creator_loop_; 56 MessageLoop* creator_loop_;
70 57
71 scoped_ptr<DataFetcher> data_fetcher_; 58 scoped_ptr<DataFetcher> data_fetcher_;
72 Orientation last_orientation_; 59 std::map<DeviceData::Type, scoped_refptr<const DeviceData> >
60 last_device_data_map_;
61 std::set<DeviceData::Type> polling_data_types_;
73 62
74 base::WeakPtr<ProviderImpl> provider_; 63 base::WeakPtr<ProviderImpl> provider_;
75 }; 64 };
76 65
77 ProviderImpl::PollingThread::PollingThread( 66 ProviderImpl::PollingThread::PollingThread(
78 const char* name, 67 const char* name,
79 base::WeakPtr<ProviderImpl> provider, 68 base::WeakPtr<ProviderImpl> provider,
80 MessageLoop* creator_loop) 69 MessageLoop* creator_loop)
81 : base::Thread(name), 70 : base::Thread(name),
82 creator_loop_(creator_loop), 71 creator_loop_(creator_loop),
83 provider_(provider) { 72 provider_(provider) {
84 } 73 }
85 74
86 ProviderImpl::PollingThread::~PollingThread() { 75 ProviderImpl::PollingThread::~PollingThread() {
87 } 76 }
88 77
89 void ProviderImpl::PollingThread::Initialize(DataFetcherFactory factory) { 78 void ProviderImpl::PollingThread::DoAddPollingDataType(DeviceData::Type type) {
79 DCHECK(MessageLoop::current() == message_loop());
80
81 polling_data_types_.insert(type);
82 }
83
84 void ProviderImpl::PollingThread::Initialize(DataFetcherFactory factory,
85 DeviceData::Type type) {
90 DCHECK(MessageLoop::current() == message_loop()); 86 DCHECK(MessageLoop::current() == message_loop());
91 87
92 if (factory != NULL) { 88 if (factory != NULL) {
93 // Try to use factory to create a fetcher that can provide orientation data. 89 // Try to use factory to create a fetcher that can provide this type of
90 // data. If factory creates a fetcher that provides this type of data,
91 // start polling.
94 scoped_ptr<DataFetcher> fetcher(factory()); 92 scoped_ptr<DataFetcher> fetcher(factory());
95 Orientation orientation;
96 93
97 if (fetcher.get() && fetcher->GetOrientation(&orientation)) { 94 if (fetcher.get()) {
98 // Pass ownership of fetcher to provider_. 95 scoped_refptr<const DeviceData> device_data(fetcher->GetDeviceData(type));
99 data_fetcher_.swap(fetcher); 96 if (device_data != NULL) {
100 last_orientation_ = orientation; 97 // Pass ownership of fetcher to provider_.
98 data_fetcher_.swap(fetcher);
99 last_device_data_map_[type] = device_data;
101 100
102 // Notify observers. 101 // Notify observers.
103 if (!orientation.is_empty()) 102 ScheduleDoNotify(device_data, type);
104 ScheduleDoNotify(orientation);
105 103
106 // Start polling. 104 // Start polling.
107 ScheduleDoPoll(); 105 ScheduleDoPoll();
108 return; 106 return;
107 }
109 } 108 }
110 } 109 }
111 110
112 // When no orientation data can be provided. 111 // When no device data can be provided.
113 ScheduleDoNotify(Orientation::Empty()); 112 ScheduleDoNotify(NULL, type);
114 } 113 }
115 114
116 void ProviderImpl::PollingThread::ScheduleDoNotify( 115 void ProviderImpl::PollingThread::ScheduleDoNotify(
117 const Orientation& orientation) { 116 const DeviceData* device_data, DeviceData::Type device_data_type) {
118 DCHECK(MessageLoop::current() == message_loop()); 117 DCHECK(MessageLoop::current() == message_loop());
119 118
120 creator_loop_->PostTask( 119 creator_loop_->PostTask(FROM_HERE,
121 FROM_HERE, base::Bind(&ProviderImpl::DoNotify, provider_, orientation)); 120 base::Bind(&ProviderImpl::DoNotify, provider_,
121 device_data, device_data_type));
122 } 122 }
123 123
124 void ProviderImpl::PollingThread::DoPoll() { 124 void ProviderImpl::PollingThread::DoPoll() {
125 DCHECK(MessageLoop::current() == message_loop()); 125 DCHECK(MessageLoop::current() == message_loop());
126 126
127 Orientation orientation; 127 // Poll the fetcher for each type of data.
128 if (!data_fetcher_->GetOrientation(&orientation)) { 128 typedef std::set<DeviceData::Type>::const_iterator SetIterator;
129 LOG(ERROR) << "Failed to poll device orientation data fetcher."; 129 for (SetIterator i = polling_data_types_.begin();
130 i != polling_data_types_.end(); ++i) {
131 DeviceData::Type device_data_type = *i;
132 scoped_refptr<const DeviceData> device_data(data_fetcher_->GetDeviceData(
133 device_data_type));
130 134
131 ScheduleDoNotify(Orientation::Empty()); 135 if (device_data == NULL) {
132 return; 136 LOG(ERROR) << "Failed to poll device data fetcher.";
133 } 137 ScheduleDoNotify(NULL, device_data_type);
138 continue;
139 }
134 140
135 if (!orientation.is_empty() && 141 const DeviceData* old_data = last_device_data_map_[device_data_type];
136 SignificantlyDifferent(orientation, last_orientation_)) { 142 if (old_data != NULL && !device_data->ShouldFireEvent(old_data))
137 last_orientation_ = orientation; 143 continue;
138 ScheduleDoNotify(orientation); 144
145 // Update the last device data of this type and notify observers.
146 last_device_data_map_[device_data_type] = device_data;
147 ScheduleDoNotify(device_data, device_data_type);
139 } 148 }
140 149
141 ScheduleDoPoll(); 150 ScheduleDoPoll();
142 } 151 }
143 152
144 void ProviderImpl::PollingThread::ScheduleDoPoll() { 153 void ProviderImpl::PollingThread::ScheduleDoPoll() {
145 DCHECK(MessageLoop::current() == message_loop()); 154 DCHECK(MessageLoop::current() == message_loop());
146 155
147 message_loop()->PostDelayedTask( 156 message_loop()->PostDelayedTask(
148 FROM_HERE, 157 FROM_HERE,
149 base::Bind(&PollingThread::DoPoll, base::Unretained(this)), 158 base::Bind(&PollingThread::DoPoll, base::Unretained(this)),
150 SamplingInterval()); 159 SamplingInterval());
151 } 160 }
152 161
153 // Returns true if two orientations are considered different enough that
154 // observers should be notified of the new orientation.
155 bool ProviderImpl::PollingThread::SignificantlyDifferent(
156 const Orientation& o1,
157 const Orientation& o2) {
158 return IsElementSignificantlyDifferent(o1.can_provide_alpha(),
159 o2.can_provide_alpha(),
160 o1.alpha(),
161 o2.alpha()) ||
162 IsElementSignificantlyDifferent(o1.can_provide_beta(),
163 o2.can_provide_beta(),
164 o1.beta(),
165 o2.beta()) ||
166 IsElementSignificantlyDifferent(o1.can_provide_gamma(),
167 o2.can_provide_gamma(),
168 o1.gamma(),
169 o2.gamma()) ||
170 (o1.can_provide_absolute() != o2.can_provide_absolute() ||
171 o1.absolute() != o2.absolute());
172 }
173
174 base::TimeDelta ProviderImpl::PollingThread::SamplingInterval() const { 162 base::TimeDelta ProviderImpl::PollingThread::SamplingInterval() const {
175 DCHECK(MessageLoop::current() == message_loop()); 163 DCHECK(MessageLoop::current() == message_loop());
176 DCHECK(data_fetcher_.get()); 164 DCHECK(data_fetcher_.get());
177 165
178 // TODO(erg): There used to be unused code here, that called a default 166 // TODO(erg): There used to be unused code here, that called a default
179 // implementation on the DataFetcherInterface that was never defined. I'm 167 // implementation on the DataFetcherInterface that was never defined. I'm
180 // removing unused methods from headers. 168 // removing unused methods from headers.
181 return base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs); 169 return base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs);
182 } 170 }
183 171
184 ProviderImpl::ProviderImpl(DataFetcherFactory factory) 172 ProviderImpl::ProviderImpl(DataFetcherFactory factory)
185 : creator_loop_(MessageLoop::current()), 173 : creator_loop_(MessageLoop::current()),
186 factory_(factory), 174 factory_(factory),
187 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), 175 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
188 polling_thread_(NULL) { 176 polling_thread_(NULL) {
189 } 177 }
190 178
191 ProviderImpl::~ProviderImpl() { 179 ProviderImpl::~ProviderImpl() {
192 Stop(); 180 Stop();
193 } 181 }
194 182
183 void ProviderImpl::ScheduleDoAddPollingDataType(DeviceData::Type type) {
184 DCHECK(MessageLoop::current() == creator_loop_);
185
186 MessageLoop* polling_loop = polling_thread_->message_loop();
187 polling_loop->PostTask(FROM_HERE,
188 base::Bind(&PollingThread::DoAddPollingDataType,
189 base::Unretained(polling_thread_),
190 type));
191 }
192
195 void ProviderImpl::AddObserver(Observer* observer) { 193 void ProviderImpl::AddObserver(Observer* observer) {
196 DCHECK(MessageLoop::current() == creator_loop_); 194 DCHECK(MessageLoop::current() == creator_loop_);
197 195
196 DeviceData::Type type = observer->device_data_type();
197
198 observers_.insert(observer); 198 observers_.insert(observer);
199 if (observers_.size() == 1) 199 if (observers_.size() == 1)
200 Start(); 200 Start(type);
201 else 201 else {
202 observer->OnOrientationUpdate(last_notification_); 202 // Notify observer of most recent notification if one exists.
203 const DeviceData *last_notification = last_notifications_map_[type];
204 if (last_notification != NULL)
205 observer->OnDeviceDataUpdate(last_notification, type);
206 }
207
208 ScheduleDoAddPollingDataType(type);
203 } 209 }
204 210
205 void ProviderImpl::RemoveObserver(Observer* observer) { 211 void ProviderImpl::RemoveObserver(Observer* observer) {
206 DCHECK(MessageLoop::current() == creator_loop_); 212 DCHECK(MessageLoop::current() == creator_loop_);
207 213
208 observers_.erase(observer); 214 observers_.erase(observer);
209 if (observers_.empty()) 215 if (observers_.empty())
210 Stop(); 216 Stop();
211 } 217 }
212 218
213 void ProviderImpl::Start() { 219 void ProviderImpl::Start(DeviceData::Type type) {
214 DCHECK(MessageLoop::current() == creator_loop_); 220 DCHECK(MessageLoop::current() == creator_loop_);
215 DCHECK(!polling_thread_); 221 DCHECK(!polling_thread_);
216 222
217 polling_thread_ = new PollingThread("Device orientation polling thread", 223 polling_thread_ = new PollingThread("Device data polling thread",
218 weak_factory_.GetWeakPtr(), 224 weak_factory_.GetWeakPtr(),
219 creator_loop_); 225 creator_loop_);
220 if (!polling_thread_->Start()) { 226 if (!polling_thread_->Start()) {
221 LOG(ERROR) << "Failed to start device orientation polling thread"; 227 LOG(ERROR) << "Failed to start device data polling thread";
222 delete polling_thread_; 228 delete polling_thread_;
223 polling_thread_ = NULL; 229 polling_thread_ = NULL;
224 return; 230 return;
225 } 231 }
226 ScheduleInitializePollingThread(); 232 ScheduleInitializePollingThread(type);
227 } 233 }
228 234
229 void ProviderImpl::Stop() { 235 void ProviderImpl::Stop() {
230 DCHECK(MessageLoop::current() == creator_loop_); 236 DCHECK(MessageLoop::current() == creator_loop_);
231 237
232 weak_factory_.InvalidateWeakPtrs(); 238 weak_factory_.InvalidateWeakPtrs();
233 if (polling_thread_) { 239 if (polling_thread_) {
234 polling_thread_->StopSoon(); 240 polling_thread_->StopSoon();
235 bool posted = base::WorkerPool::PostTask( 241 bool posted = base::WorkerPool::PostTask(
236 FROM_HERE, 242 FROM_HERE,
237 base::Bind(&DeleteThread, base::Unretained(polling_thread_)), 243 base::Bind(&DeleteThread, base::Unretained(polling_thread_)),
238 true /* task is slow */); 244 true /* task is slow */);
239 DCHECK(posted); 245 DCHECK(posted);
240 polling_thread_ = NULL; 246 polling_thread_ = NULL;
241 } 247 }
242 } 248 }
243 249
244 void ProviderImpl::ScheduleInitializePollingThread() { 250 void ProviderImpl::ScheduleInitializePollingThread(
251 DeviceData::Type device_data_type) {
245 DCHECK(MessageLoop::current() == creator_loop_); 252 DCHECK(MessageLoop::current() == creator_loop_);
246 253
247 MessageLoop* polling_loop = polling_thread_->message_loop(); 254 MessageLoop* polling_loop = polling_thread_->message_loop();
248 polling_loop->PostTask(FROM_HERE, 255 polling_loop->PostTask(FROM_HERE,
249 base::Bind(&PollingThread::Initialize, 256 base::Bind(&PollingThread::Initialize,
250 base::Unretained(polling_thread_), 257 base::Unretained(polling_thread_),
251 factory_)); 258 factory_,
259 device_data_type));
252 } 260 }
253 261
254 void ProviderImpl::DoNotify(const Orientation& orientation) { 262 void ProviderImpl::DoNotify(const DeviceData* device_data,
263 DeviceData::Type device_data_type) {
255 DCHECK(MessageLoop::current() == creator_loop_); 264 DCHECK(MessageLoop::current() == creator_loop_);
256 265
257 last_notification_ = orientation; 266 scoped_refptr<const DeviceData> data(device_data);
258 267
259 typedef std::set<Observer*>::const_iterator Iterator; 268 // Update last notification of this type.
260 for (Iterator i = observers_.begin(); i != observers_.end(); ++i) 269 last_notifications_map_[device_data_type] = data;
261 (*i)->OnOrientationUpdate(orientation);
262 270
263 if (orientation.is_empty()) { 271 // Notify observers of this type of the new data.
264 // Notify observers about failure to provide data exactly once. 272 typedef std::set<Observer*>::const_iterator ConstIterator;
265 observers_.clear(); 273 for (ConstIterator i = observers_.begin(); i != observers_.end(); ++i) {
266 Stop(); 274 if ((*i)->device_data_type() == device_data_type)
275 (*i)->OnDeviceDataUpdate(data.get(), device_data_type);
276 }
277
278 if (data == NULL) {
279 // Notify observers exactly once about failure to provide data.
280 typedef std::set<Observer*>::iterator Iterator;
281 Iterator i = observers_.begin();
282 while (i != observers_.end()) {
283 Iterator current = i++;
284 if ((*current)->device_data_type() == device_data_type)
285 observers_.erase(current);
286 }
287
288 if (observers_.empty())
289 Stop();
267 } 290 }
268 } 291 }
269 292
293
270 } // namespace device_orientation 294 } // namespace device_orientation
OLDNEW
« no previous file with comments | « content/browser/device_orientation/provider_impl.h ('k') | content/browser/device_orientation/provider_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698