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

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: Moves construction of DeviceData objects out of ProviderImpl Created 8 years, 5 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>
6 #include <set> 5 #include <set>
7 #include <vector> 6 #include <vector>
8 7
9 #include "base/bind.h" 8 #include "base/bind.h"
10 #include "base/logging.h" 9 #include "base/logging.h"
11 #include "base/message_loop.h" 10 #include "base/message_loop.h"
12 #include "base/threading/thread.h" 11 #include "base/threading/thread.h"
13 #include "base/threading/thread_restrictions.h" 12 #include "base/threading/thread_restrictions.h"
14 #include "content/browser/device_orientation/orientation.h" 13 #include "content/browser/device_orientation/orientation.h"
15 #include "content/browser/device_orientation/provider_impl.h" 14 #include "content/browser/device_orientation/provider_impl.h"
16 15
17 namespace device_orientation { 16 namespace device_orientation {
18 17
19 ProviderImpl::ProviderImpl(const DataFetcherFactory factories[]) 18 ProviderImpl::ProviderImpl(const DataFetcherFactory factories[])
20 : creator_loop_(MessageLoop::current()), 19 : creator_loop_(MessageLoop::current()),
21 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { 20 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
22 for (const DataFetcherFactory* fp = factories; *fp; ++fp) 21 for (const DataFetcherFactory* fp = factories; *fp; ++fp)
23 factories_.push_back(*fp); 22 factories_.push_back(*fp);
24 } 23 }
25 24
26 ProviderImpl::~ProviderImpl() { 25 ProviderImpl::~ProviderImpl() {
27 } 26 }
28 27
29 void ProviderImpl::AddObserver(Observer* observer) { 28 void ProviderImpl::AddObserver(Observer* observer) {
30 DCHECK(MessageLoop::current() == creator_loop_); 29 DCHECK(MessageLoop::current() == creator_loop_);
31 30
31 DeviceData::DeviceDataType device_data_type = observer->device_data_type();
32
32 observers_.insert(observer); 33 observers_.insert(observer);
33 if (observers_.size() == 1) 34 if (observers_.size() == 1)
34 Start(); 35 Start();
35 else 36
36 observer->OnOrientationUpdate(last_notification_); 37 ScheduleDoAddObserverType(device_data_type);
38
39 if (!data_fetcher_.get()) {
40 ScheduleInitializePollingThread(device_data_type);
41 return;
42 }
43
44 // Notify observer of most recent notification if one exists.
45 DeviceData* last_notification = last_notifications_map_.Lookup(
46 device_data_type);
47 if (last_notification)
48 observer->OnDeviceDataUpdate(last_notification);
37 } 49 }
38 50
39 void ProviderImpl::RemoveObserver(Observer* observer) { 51 void ProviderImpl::RemoveObserver(Observer* observer) {
40 DCHECK(MessageLoop::current() == creator_loop_); 52 DCHECK(MessageLoop::current() == creator_loop_);
41 53
42 observers_.erase(observer); 54 observers_.erase(observer);
43 if (observers_.empty()) 55 if (observers_.empty())
44 Stop(); 56 Stop();
45 } 57 }
46 58
47 void ProviderImpl::Start() { 59 void ProviderImpl::Start() {
48 DCHECK(MessageLoop::current() == creator_loop_); 60 DCHECK(MessageLoop::current() == creator_loop_);
49 DCHECK(!polling_thread_.get()); 61 DCHECK(!polling_thread_.get());
50 62
51 polling_thread_.reset(new base::Thread("Device orientation polling thread")); 63 // Reset members used on polling thread.
64 last_device_data_map_.reset(new IDMap<DeviceData, IDMapOwnPointer>);
65 observer_types_.clear();
66
67 polling_thread_.reset(new base::Thread("Device data polling thread"));
52 if (!polling_thread_->Start()) { 68 if (!polling_thread_->Start()) {
53 LOG(ERROR) << "Failed to start device orientation polling thread"; 69 LOG(ERROR) << "Failed to start device data polling thread";
54 polling_thread_.reset(); 70 polling_thread_.reset();
55 return; 71 return;
56 } 72 }
57 ScheduleInitializePollingThread();
58 } 73 }
59 74
60 void ProviderImpl::Stop() { 75 void ProviderImpl::Stop() {
61 DCHECK(MessageLoop::current() == creator_loop_); 76 DCHECK(MessageLoop::current() == creator_loop_);
62 77
63 // TODO(hans): Don't join the thread. See crbug.com/72286. 78 // TODO(hans): Don't join the thread. See crbug.com/72286.
64 base::ThreadRestrictions::ScopedAllowIO allow_io; 79 base::ThreadRestrictions::ScopedAllowIO allow_io;
65 80
66 polling_thread_.reset(); 81 polling_thread_.reset();
67 data_fetcher_.reset(); 82 data_fetcher_.reset();
68 } 83 }
69 84
85 void ProviderImpl::DoAddObserverType(
86 DeviceData::DeviceDataType device_data_type) {
87 DCHECK(MessageLoop::current() == polling_thread_->message_loop());
88
89 observer_types_.insert(device_data_type);
90 }
91
92 void ProviderImpl::ScheduleDoAddObserverType(
93 DeviceData::DeviceDataType device_data_type) {
94 DCHECK(MessageLoop::current() == creator_loop_);
95
96 MessageLoop* polling_loop = polling_thread_->message_loop();
97 polling_loop->PostTask(FROM_HERE,
98 base::Bind(&ProviderImpl::DoAddObserverType,
99 this,
100 device_data_type));
101 }
102
70 void ProviderImpl::DoInitializePollingThread( 103 void ProviderImpl::DoInitializePollingThread(
71 const std::vector<DataFetcherFactory>& factories) { 104 const std::vector<DataFetcherFactory>& factories,
105 DeviceData::DeviceDataType device_data_type) {
72 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); 106 DCHECK(MessageLoop::current() == polling_thread_->message_loop());
73 107
74 typedef std::vector<DataFetcherFactory>::const_iterator Iterator; 108 typedef std::vector<DataFetcherFactory>::const_iterator Iterator;
75 for (Iterator i = factories_.begin(), e = factories_.end(); i != e; ++i) { 109 for (Iterator i = factories_.begin(), e = factories_.end(); i != e; ++i) {
76 DataFetcherFactory factory = *i; 110 DataFetcherFactory factory = *i;
77 scoped_ptr<DataFetcher> fetcher(factory()); 111 scoped_ptr<DataFetcher> fetcher(factory());
78 Orientation orientation;
79 112
80 if (fetcher.get() && fetcher->GetOrientation(&orientation)) { 113 if (!fetcher.get())
114 continue;
115
116 scoped_ptr<DeviceData> device_data(fetcher->GetDeviceData(
117 device_data_type));
118 if (device_data != NULL) {
81 // Pass ownership of fetcher to provider_. 119 // Pass ownership of fetcher to provider_.
82 data_fetcher_.swap(fetcher); 120 data_fetcher_.swap(fetcher);
83 last_orientation_ = orientation; 121 last_device_data_map_->AddWithID(device_data->Clone(), device_data_type);
84 122
85 // Notify observers. 123 // Notify observers.
86 if (!orientation.is_empty()) 124 ScheduleDoNotify(device_data.release(), device_data_type);
87 ScheduleDoNotify(orientation);
88 125
89 // Start polling. 126 // Start polling.
90 ScheduleDoPoll(); 127 ScheduleDoPoll();
91 return; 128 return;
92 } 129 }
93 } 130 }
94 131
95 // When no orientation data can be provided. 132 // When no device data can be provided.
96 ScheduleDoNotify(Orientation::Empty()); 133 ScheduleDoNotify(NULL, device_data_type);
97 } 134 }
98 135
99 void ProviderImpl::ScheduleInitializePollingThread() { 136 void ProviderImpl::ScheduleInitializePollingThread(
137 DeviceData::DeviceDataType device_data_type) {
100 DCHECK(MessageLoop::current() == creator_loop_); 138 DCHECK(MessageLoop::current() == creator_loop_);
101 139
102 MessageLoop* polling_loop = polling_thread_->message_loop(); 140 MessageLoop* polling_loop = polling_thread_->message_loop();
103 polling_loop->PostTask(FROM_HERE, 141 polling_loop->PostTask(FROM_HERE,
104 base::Bind(&ProviderImpl::DoInitializePollingThread, 142 base::Bind(&ProviderImpl::DoInitializePollingThread,
105 this, 143 this,
106 factories_)); 144 factories_,
145 device_data_type));
107 } 146 }
108 147
109 void ProviderImpl::DoNotify(const Orientation& orientation) { 148 void ProviderImpl::DoNotify(const DeviceData* device_data,
149 DeviceData::DeviceDataType device_data_type) {
110 DCHECK(MessageLoop::current() == creator_loop_); 150 DCHECK(MessageLoop::current() == creator_loop_);
111 151
112 last_notification_ = orientation; 152 scoped_ptr<const DeviceData> data(device_data);
113 153
114 typedef std::set<Observer*>::const_iterator Iterator; 154 // Update last notification of this type.
115 for (Iterator i = observers_.begin(), e = observers_.end(); i != e; ++i) 155 DeviceData* last_notification = last_notifications_map_.Lookup(
116 (*i)->OnOrientationUpdate(orientation); 156 device_data_type);
157 if (last_notification)
158 last_notifications_map_.Remove(device_data_type);
159 if (data != NULL)
160 last_notifications_map_.AddWithID(data->Clone(), device_data_type);
117 161
118 if (orientation.is_empty()) { 162 // Notify observers of this type of the new data.
119 // Notify observers about failure to provide data exactly once. 163 typedef std::set<Observer*>::const_iterator ConstIterator;
120 observers_.clear(); 164 for (ConstIterator i = observers_.begin(), e = observers_.end();
121 Stop(); 165 i != e; ++i) {
166 if ((*i)->device_data_type() == device_data_type)
167 (*i)->OnDeviceDataUpdate(data.get());
168 }
169
170 if (data == NULL) {
171 // Notify observers exactly once about failure to provide data.
172 typedef std::set<Observer*>::iterator Iterator;
173 Iterator i = observers_.begin();
174 while (i != observers_.end()) {
175 Iterator current = i++;
176 if ((*current)->device_data_type() == device_data_type)
177 observers_.erase(current);
178 }
179
180 if (observers_.empty())
181 Stop();
122 } 182 }
123 } 183 }
124 184
125 void ProviderImpl::ScheduleDoNotify(const Orientation& orientation) { 185 void ProviderImpl::ScheduleDoNotify(const DeviceData* device_data,
186 DeviceData::DeviceDataType device_data_type) {
126 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); 187 DCHECK(MessageLoop::current() == polling_thread_->message_loop());
127 188
128 creator_loop_->PostTask( 189 creator_loop_->PostTask(FROM_HERE,
129 FROM_HERE, base::Bind(&ProviderImpl::DoNotify, this, orientation)); 190 base::Bind(&ProviderImpl::DoNotify, this,
191 device_data, device_data_type));
130 } 192 }
131 193
132 void ProviderImpl::DoPoll() { 194 void ProviderImpl::DoPoll() {
133 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); 195 DCHECK(MessageLoop::current() == polling_thread_->message_loop());
134 196
135 Orientation orientation; 197 // Poll the fetcher for each type of data
136 if (!data_fetcher_->GetOrientation(&orientation)) { 198 typedef std::set<DeviceData::DeviceDataType>::const_iterator SetIterator;
137 LOG(ERROR) << "Failed to poll device orientation data fetcher."; 199 for (SetIterator i = observer_types_.begin(), e = observer_types_.end();
200 i != e; ++i) {
201 DeviceData::DeviceDataType device_data_type = *i;
202 scoped_ptr<DeviceData> device_data(data_fetcher_->GetDeviceData(
203 device_data_type));
138 204
139 ScheduleDoNotify(Orientation::Empty()); 205 if (device_data == NULL) {
140 return; 206 LOG(ERROR) << "Failed to poll device data fetcher.";
141 } 207 ScheduleDoNotify(NULL, device_data_type);
208 return;
bulach 2012/07/12 10:43:27 hmm, I think now that we're traversing all the dif
aousterh 2012/07/12 17:13:57 Good point. Done.
209 }
142 210
143 if (!orientation.is_empty() && 211 // Update the last device data of this type and notify observers
144 SignificantlyDifferent(orientation, last_orientation_)) { 212 DeviceData* last_device_data = last_device_data_map_->Lookup(
145 last_orientation_ = orientation; 213 device_data_type);
146 ScheduleDoNotify(orientation); 214 if (!last_device_data) {
215 last_device_data_map_->AddWithID(device_data->Clone(), device_data_type);
216 ScheduleDoNotify(device_data.release(), device_data_type);
217 }
218 else if (device_data->SignificantlyDifferentFrom(*last_device_data)) {
bulach 2012/07/12 10:43:27 nit: else on the line above with }
aousterh 2012/07/12 17:13:57 Done.
219 last_device_data_map_->Remove(device_data_type);
220 last_device_data_map_->AddWithID(device_data->Clone(), device_data_type);
221 ScheduleDoNotify(device_data.release(), device_data_type);
222 }
147 } 223 }
148 224
149 ScheduleDoPoll(); 225 ScheduleDoPoll();
150 } 226 }
151 227
152 void ProviderImpl::ScheduleDoPoll() { 228 void ProviderImpl::ScheduleDoPoll() {
153 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); 229 DCHECK(MessageLoop::current() == polling_thread_->message_loop());
154 230
155 MessageLoop* polling_loop = polling_thread_->message_loop(); 231 MessageLoop* polling_loop = polling_thread_->message_loop();
156 polling_loop->PostDelayedTask( 232 polling_loop->PostDelayedTask(
157 FROM_HERE, 233 FROM_HERE,
158 base::Bind(&ProviderImpl::DoPoll, weak_factory_.GetWeakPtr()), 234 base::Bind(&ProviderImpl::DoPoll, weak_factory_.GetWeakPtr()),
159 SamplingInterval()); 235 SamplingInterval());
160 } 236 }
161 237
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
180 // observers should be notified of the new orientation.
181 bool ProviderImpl::SignificantlyDifferent(const Orientation& o1,
182 const Orientation& o2) {
183 return IsElementSignificantlyDifferent(o1.can_provide_alpha(),
184 o2.can_provide_alpha(),
185 o1.alpha(),
186 o2.alpha()) ||
187 IsElementSignificantlyDifferent(o1.can_provide_beta(),
188 o2.can_provide_beta(),
189 o1.beta(),
190 o2.beta()) ||
191 IsElementSignificantlyDifferent(o1.can_provide_gamma(),
192 o2.can_provide_gamma(),
193 o1.gamma(),
194 o2.gamma()) ||
195 (o1.can_provide_absolute() != o2.can_provide_absolute() ||
196 o1.absolute() != o2.absolute());
197 }
198
199 base::TimeDelta ProviderImpl::SamplingInterval() const { 238 base::TimeDelta ProviderImpl::SamplingInterval() const {
200 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); 239 DCHECK(MessageLoop::current() == polling_thread_->message_loop());
201 DCHECK(data_fetcher_.get()); 240 DCHECK(data_fetcher_.get());
202 241
203 // TODO(erg): There used to be unused code here, that called a default 242 // TODO(erg): There used to be unused code here, that called a default
204 // implementation on the DataFetcherInterface that was never defined. I'm 243 // implementation on the DataFetcherInterface that was never defined. I'm
205 // removing unused methods from headers. 244 // removing unused methods from headers.
206 return base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs); 245 return base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs);
207 } 246 }
208 247
209 } // namespace device_orientation 248 } // namespace device_orientation
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698