OLD | NEW |
---|---|
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 <cmath> |
6 #include <set> | 6 #include <set> |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
12 #include "base/threading/thread.h" | 12 #include "base/threading/thread.h" |
13 #include "base/threading/thread_restrictions.h" | 13 #include "base/threading/worker_pool.h" |
14 #include "content/browser/device_orientation/orientation.h" | 14 #include "content/browser/device_orientation/orientation.h" |
15 #include "content/browser/device_orientation/provider_impl.h" | 15 #include "content/browser/device_orientation/provider_impl.h" |
16 | 16 |
17 namespace { | |
18 | |
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) { | |
34 delete thread; | |
35 } | |
36 | |
37 } | |
38 | |
17 namespace device_orientation { | 39 namespace device_orientation { |
18 | 40 |
19 ProviderImpl::ProviderImpl(const DataFetcherFactory factories[]) | 41 class ProviderImpl::PollingThread : public base::Thread { |
20 : creator_loop_(MessageLoop::current()), | 42 public: |
21 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { | 43 explicit PollingThread(const char* name, |
hans
2012/07/30 12:56:40
nit: no need for explicit here, I think
| |
22 for (const DataFetcherFactory* fp = factories; *fp; ++fp) | 44 base::WeakPtr<ProviderImpl> provider, |
23 factories_.push_back(*fp); | 45 MessageLoop* creator_loop); |
46 virtual ~PollingThread() OVERRIDE; | |
47 | |
48 // Method for finding a suitable DataFetcher and starting the polling. | |
49 void InitializePollingThread( | |
hans
2012/07/30 12:56:40
since it's a member of PollingThread, I think just
| |
50 const std::vector<DataFetcherFactory>& factories); | |
51 | |
52 private: | |
53 // Method for polling a DataFetcher. | |
54 void DoPoll(); | |
55 void ScheduleDoPoll(); | |
56 | |
57 // Schedule a notification to the |provider_| which lives on a different | |
58 // thread (|creator_loop_| is its message loop). | |
59 void ScheduleDoNotify(const Orientation& orientation); | |
60 | |
61 static bool SignificantlyDifferent(const Orientation& orientation1, | |
62 const Orientation& orientation2); | |
63 | |
64 enum { kDesiredSamplingIntervalMs = 100 }; | |
65 base::TimeDelta SamplingInterval() const; | |
66 | |
67 // The Message Loop on which this object was created. | |
68 // Typically the I/O loop, but may be something else during testing. | |
69 MessageLoop* creator_loop_; | |
70 | |
71 scoped_ptr<DataFetcher> data_fetcher_; | |
72 Orientation last_orientation_; | |
73 | |
74 base::WeakPtr<ProviderImpl> provider_; | |
75 }; | |
76 | |
77 ProviderImpl::PollingThread::PollingThread( | |
78 const char* name, | |
79 base::WeakPtr<ProviderImpl> provider, | |
80 MessageLoop* creator_loop) | |
81 : base::Thread(name), | |
hans
2012/07/30 12:56:40
nit indentation looks off here: there should be fo
| |
82 creator_loop_(creator_loop), | |
83 provider_(provider) { | |
24 } | 84 } |
25 | 85 |
26 ProviderImpl::~ProviderImpl() { | 86 ProviderImpl::PollingThread::~PollingThread() { |
27 } | 87 } |
28 | 88 |
29 void ProviderImpl::AddObserver(Observer* observer) { | 89 void ProviderImpl::PollingThread::InitializePollingThread( |
30 DCHECK(MessageLoop::current() == creator_loop_); | |
31 | |
32 observers_.insert(observer); | |
33 if (observers_.size() == 1) | |
34 Start(); | |
35 else | |
36 observer->OnOrientationUpdate(last_notification_); | |
37 } | |
38 | |
39 void ProviderImpl::RemoveObserver(Observer* observer) { | |
40 DCHECK(MessageLoop::current() == creator_loop_); | |
41 | |
42 observers_.erase(observer); | |
43 if (observers_.empty()) | |
44 Stop(); | |
45 } | |
46 | |
47 void ProviderImpl::Start() { | |
48 DCHECK(MessageLoop::current() == creator_loop_); | |
49 DCHECK(!polling_thread_.get()); | |
50 | |
51 polling_thread_.reset(new base::Thread("Device orientation polling thread")); | |
52 if (!polling_thread_->Start()) { | |
53 LOG(ERROR) << "Failed to start device orientation polling thread"; | |
54 polling_thread_.reset(); | |
55 return; | |
56 } | |
57 ScheduleInitializePollingThread(); | |
58 } | |
59 | |
60 void ProviderImpl::Stop() { | |
61 DCHECK(MessageLoop::current() == creator_loop_); | |
62 | |
63 // TODO(hans): Don't join the thread. See crbug.com/72286. | |
64 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
65 | |
66 polling_thread_.reset(); | |
67 data_fetcher_.reset(); | |
68 } | |
69 | |
70 void ProviderImpl::DoInitializePollingThread( | |
71 const std::vector<DataFetcherFactory>& factories) { | 90 const std::vector<DataFetcherFactory>& factories) { |
72 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); | 91 DCHECK(MessageLoop::current() == message_loop()); |
73 | 92 |
74 typedef std::vector<DataFetcherFactory>::const_iterator Iterator; | 93 typedef std::vector<DataFetcherFactory>::const_iterator Iterator; |
75 for (Iterator i = factories_.begin(), e = factories_.end(); i != e; ++i) { | 94 for (Iterator i = factories.begin(), e = factories.end(); i != e; ++i) { |
hans
2012/07/30 12:56:40
nit: since you're touching this line anyway, feel
| |
76 DataFetcherFactory factory = *i; | 95 DataFetcherFactory factory = *i; |
77 scoped_ptr<DataFetcher> fetcher(factory()); | 96 scoped_ptr<DataFetcher> fetcher(factory()); |
78 Orientation orientation; | 97 Orientation orientation; |
79 | 98 |
80 if (fetcher.get() && fetcher->GetOrientation(&orientation)) { | 99 if (fetcher.get() && fetcher->GetOrientation(&orientation)) { |
81 // Pass ownership of fetcher to provider_. | 100 // Pass ownership of fetcher to provider_. |
82 data_fetcher_.swap(fetcher); | 101 data_fetcher_.swap(fetcher); |
83 last_orientation_ = orientation; | 102 last_orientation_ = orientation; |
84 | 103 |
85 // Notify observers. | 104 // Notify observers. |
86 if (!orientation.is_empty()) | 105 if (!orientation.is_empty()) |
87 ScheduleDoNotify(orientation); | 106 ScheduleDoNotify(orientation); |
88 | 107 |
89 // Start polling. | 108 // Start polling. |
90 ScheduleDoPoll(); | 109 ScheduleDoPoll(); |
91 return; | 110 return; |
92 } | 111 } |
93 } | 112 } |
94 | 113 |
95 // When no orientation data can be provided. | 114 // When no orientation data can be provided. |
96 ScheduleDoNotify(Orientation::Empty()); | 115 ScheduleDoNotify(Orientation::Empty()); |
97 } | 116 } |
98 | 117 |
99 void ProviderImpl::ScheduleInitializePollingThread() { | 118 void ProviderImpl::PollingThread::ScheduleDoNotify( |
100 DCHECK(MessageLoop::current() == creator_loop_); | 119 const Orientation& orientation) { |
120 DCHECK(MessageLoop::current() == message_loop()); | |
101 | 121 |
102 MessageLoop* polling_loop = polling_thread_->message_loop(); | 122 creator_loop_->PostTask( |
103 polling_loop->PostTask(FROM_HERE, | 123 FROM_HERE, base::Bind(&ProviderImpl::DoNotify, provider_, orientation)); |
104 base::Bind(&ProviderImpl::DoInitializePollingThread, | |
105 this, | |
106 factories_)); | |
107 } | 124 } |
108 | 125 |
109 void ProviderImpl::DoNotify(const Orientation& orientation) { | 126 void ProviderImpl::PollingThread::DoPoll() { |
110 DCHECK(MessageLoop::current() == creator_loop_); | 127 DCHECK(MessageLoop::current() == message_loop()); |
111 | |
112 last_notification_ = orientation; | |
113 | |
114 typedef std::set<Observer*>::const_iterator Iterator; | |
115 for (Iterator i = observers_.begin(), e = observers_.end(); i != e; ++i) | |
116 (*i)->OnOrientationUpdate(orientation); | |
117 | |
118 if (orientation.is_empty()) { | |
119 // Notify observers about failure to provide data exactly once. | |
120 observers_.clear(); | |
121 Stop(); | |
122 } | |
123 } | |
124 | |
125 void ProviderImpl::ScheduleDoNotify(const Orientation& orientation) { | |
126 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); | |
127 | |
128 creator_loop_->PostTask( | |
129 FROM_HERE, base::Bind(&ProviderImpl::DoNotify, this, orientation)); | |
130 } | |
131 | |
132 void ProviderImpl::DoPoll() { | |
133 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); | |
134 | 128 |
135 Orientation orientation; | 129 Orientation orientation; |
136 if (!data_fetcher_->GetOrientation(&orientation)) { | 130 if (!data_fetcher_->GetOrientation(&orientation)) { |
137 LOG(ERROR) << "Failed to poll device orientation data fetcher."; | 131 LOG(ERROR) << "Failed to poll device orientation data fetcher."; |
138 | 132 |
139 ScheduleDoNotify(Orientation::Empty()); | 133 ScheduleDoNotify(Orientation::Empty()); |
140 return; | 134 return; |
141 } | 135 } |
142 | 136 |
143 if (!orientation.is_empty() && | 137 if (!orientation.is_empty() && |
144 SignificantlyDifferent(orientation, last_orientation_)) { | 138 SignificantlyDifferent(orientation, last_orientation_)) { |
145 last_orientation_ = orientation; | 139 last_orientation_ = orientation; |
146 ScheduleDoNotify(orientation); | 140 ScheduleDoNotify(orientation); |
147 } | 141 } |
148 | 142 |
149 ScheduleDoPoll(); | 143 ScheduleDoPoll(); |
150 } | 144 } |
151 | 145 |
152 void ProviderImpl::ScheduleDoPoll() { | 146 void ProviderImpl::PollingThread::ScheduleDoPoll() { |
153 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); | 147 DCHECK(MessageLoop::current() == message_loop()); |
154 | 148 |
155 MessageLoop* polling_loop = polling_thread_->message_loop(); | 149 message_loop()->PostDelayedTask( |
156 polling_loop->PostDelayedTask( | |
157 FROM_HERE, | 150 FROM_HERE, |
158 base::Bind(&ProviderImpl::DoPoll, weak_factory_.GetWeakPtr()), | 151 base::Bind(&PollingThread::DoPoll, base::Unretained(this)), |
159 SamplingInterval()); | 152 SamplingInterval()); |
160 } | 153 } |
161 | 154 |
162 namespace { | |
163 | |
164 bool IsElementSignificantlyDifferent(bool can_provide_element1, | |
165 bool can_provide_element2, | |
166 double element1, | |
167 double element2) { | |
168 const double kThreshold = 0.1; | |
169 | |
170 if (can_provide_element1 != can_provide_element2) | |
171 return true; | |
172 if (can_provide_element1 && | |
173 std::fabs(element1 - element2) >= kThreshold) | |
174 return true; | |
175 return false; | |
176 } | |
177 } // namespace | |
178 | |
179 // Returns true if two orientations are considered different enough that | 155 // Returns true if two orientations are considered different enough that |
180 // observers should be notified of the new orientation. | 156 // observers should be notified of the new orientation. |
181 bool ProviderImpl::SignificantlyDifferent(const Orientation& o1, | 157 bool ProviderImpl::PollingThread::SignificantlyDifferent( |
182 const Orientation& o2) { | 158 const Orientation& o1, |
159 const Orientation& o2) { | |
183 return IsElementSignificantlyDifferent(o1.can_provide_alpha(), | 160 return IsElementSignificantlyDifferent(o1.can_provide_alpha(), |
184 o2.can_provide_alpha(), | 161 o2.can_provide_alpha(), |
185 o1.alpha(), | 162 o1.alpha(), |
186 o2.alpha()) || | 163 o2.alpha()) || |
187 IsElementSignificantlyDifferent(o1.can_provide_beta(), | 164 IsElementSignificantlyDifferent(o1.can_provide_beta(), |
188 o2.can_provide_beta(), | 165 o2.can_provide_beta(), |
189 o1.beta(), | 166 o1.beta(), |
190 o2.beta()) || | 167 o2.beta()) || |
191 IsElementSignificantlyDifferent(o1.can_provide_gamma(), | 168 IsElementSignificantlyDifferent(o1.can_provide_gamma(), |
192 o2.can_provide_gamma(), | 169 o2.can_provide_gamma(), |
193 o1.gamma(), | 170 o1.gamma(), |
194 o2.gamma()) || | 171 o2.gamma()) || |
195 (o1.can_provide_absolute() != o2.can_provide_absolute() || | 172 (o1.can_provide_absolute() != o2.can_provide_absolute() || |
196 o1.absolute() != o2.absolute()); | 173 o1.absolute() != o2.absolute()); |
197 } | 174 } |
198 | 175 |
199 base::TimeDelta ProviderImpl::SamplingInterval() const { | 176 base::TimeDelta ProviderImpl::PollingThread::SamplingInterval() const { |
200 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); | 177 DCHECK(MessageLoop::current() == message_loop()); |
201 DCHECK(data_fetcher_.get()); | 178 DCHECK(data_fetcher_.get()); |
202 | 179 |
203 // TODO(erg): There used to be unused code here, that called a default | 180 // TODO(erg): There used to be unused code here, that called a default |
204 // implementation on the DataFetcherInterface that was never defined. I'm | 181 // implementation on the DataFetcherInterface that was never defined. I'm |
205 // removing unused methods from headers. | 182 // removing unused methods from headers. |
206 return base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs); | 183 return base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs); |
207 } | 184 } |
208 | 185 |
186 ProviderImpl::ProviderImpl(const DataFetcherFactory factories[]) | |
187 : creator_loop_(MessageLoop::current()), | |
188 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), | |
189 polling_thread_(NULL) { | |
190 for (const DataFetcherFactory* fp = factories; *fp; ++fp) | |
191 factories_.push_back(*fp); | |
192 } | |
193 | |
194 ProviderImpl::~ProviderImpl() { | |
195 DCHECK(observers_.empty()); | |
196 DCHECK(!polling_thread_); | |
197 } | |
198 | |
199 void ProviderImpl::AddObserver(Observer* observer) { | |
200 DCHECK(MessageLoop::current() == creator_loop_); | |
201 | |
202 observers_.insert(observer); | |
203 if (observers_.size() == 1) | |
204 Start(); | |
205 else | |
206 observer->OnOrientationUpdate(last_notification_); | |
207 } | |
208 | |
209 void ProviderImpl::RemoveObserver(Observer* observer) { | |
210 DCHECK(MessageLoop::current() == creator_loop_); | |
211 | |
212 observers_.erase(observer); | |
213 if (observers_.empty()) | |
214 Stop(); | |
215 } | |
216 | |
217 void ProviderImpl::Start() { | |
218 DCHECK(MessageLoop::current() == creator_loop_); | |
219 DCHECK(!polling_thread_); | |
220 | |
221 polling_thread_ = new PollingThread("Device orientation polling thread", | |
222 weak_factory_.GetWeakPtr(), | |
223 creator_loop_); | |
224 if (!polling_thread_->Start()) { | |
225 LOG(ERROR) << "Failed to start device orientation polling thread"; | |
226 delete polling_thread_; | |
227 polling_thread_ = NULL; | |
228 return; | |
229 } | |
230 ScheduleInitializePollingThread(); | |
231 } | |
232 | |
233 void ProviderImpl::Stop() { | |
234 DCHECK(MessageLoop::current() == creator_loop_); | |
235 | |
236 weak_factory_.InvalidateWeakPtrs(); | |
237 if (polling_thread_) { | |
238 polling_thread_->StopSoon(); | |
239 bool posted = base::WorkerPool::PostTask( | |
240 FROM_HERE, | |
241 base::Bind(&DeleteThread, base::Unretained(polling_thread_)), | |
242 true /* task is slow */); | |
243 DCHECK(posted); | |
244 polling_thread_ = NULL; | |
245 } | |
246 } | |
247 | |
248 void ProviderImpl::ScheduleInitializePollingThread() { | |
249 DCHECK(MessageLoop::current() == creator_loop_); | |
250 | |
251 MessageLoop* polling_loop = polling_thread_->message_loop(); | |
252 polling_loop->PostTask(FROM_HERE, | |
253 base::Bind(&PollingThread::InitializePollingThread, | |
254 base::Unretained(polling_thread_), | |
255 factories_)); | |
256 } | |
257 | |
258 void ProviderImpl::DoNotify(const Orientation& orientation) { | |
259 DCHECK(MessageLoop::current() == creator_loop_); | |
260 | |
261 last_notification_ = orientation; | |
262 | |
263 typedef std::set<Observer*>::const_iterator Iterator; | |
264 for (Iterator i = observers_.begin(), e = observers_.end(); i != e; ++i) | |
hans
2012/07/30 12:56:40
nit: since you're touching this line anyway, feel
| |
265 (*i)->OnOrientationUpdate(orientation); | |
266 | |
267 if (orientation.is_empty()) { | |
268 // Notify observers about failure to provide data exactly once. | |
269 observers_.clear(); | |
270 Stop(); | |
271 } | |
272 } | |
273 | |
209 } // namespace device_orientation | 274 } // namespace device_orientation |
OLD | NEW |