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

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: 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
32 observers_.insert(observer); 31 observers_.insert(observer);
33 if (observers_.size() == 1) 32 if (observers_.size() == 1)
34 Start(); 33 Start();
35 else 34
36 observer->OnOrientationUpdate(last_notification_); 35 ScheduleDoAddObserverType(observer->device_data_type());
36
37 if (!data_fetcher_.get()) {
38 ScheduleInitializePollingThread(observer->device_data_type());
39 return;
40 }
41
42 // Notify observer of most recent notification or newly fetched data
43 // if this type of data has not been fetched yet
44 DeviceData* last_notification = last_notifications_map_.Lookup(
45 observer->device_data_type());
46 if (last_notification)
47 observer->OnDeviceDataUpdate(*last_notification);
48 else {
49 scoped_ptr<DeviceData> device_data(EmptyDeviceData(
50 observer->device_data_type()));
51 if (!data_fetcher_->GetDeviceData(device_data.get()) ||
52 device_data->IsEmpty())
53 DoNotify(device_data.release());
54 else
55 observer->OnDeviceDataUpdate(*device_data);
56 }
37 } 57 }
38 58
39 void ProviderImpl::RemoveObserver(Observer* observer) { 59 void ProviderImpl::RemoveObserver(Observer* observer) {
40 DCHECK(MessageLoop::current() == creator_loop_); 60 DCHECK(MessageLoop::current() == creator_loop_);
41 61
42 observers_.erase(observer); 62 observers_.erase(observer);
43 if (observers_.empty()) 63 if (observers_.empty())
44 Stop(); 64 Stop();
45 } 65 }
46 66
47 void ProviderImpl::Start() { 67 void ProviderImpl::Start() {
48 DCHECK(MessageLoop::current() == creator_loop_); 68 DCHECK(MessageLoop::current() == creator_loop_);
49 DCHECK(!polling_thread_.get()); 69 DCHECK(!polling_thread_.get());
50 70
51 polling_thread_.reset(new base::Thread("Device orientation polling thread")); 71 polling_thread_.reset(new base::Thread("Device data polling thread"));
52 if (!polling_thread_->Start()) { 72 if (!polling_thread_->Start()) {
53 LOG(ERROR) << "Failed to start device orientation polling thread"; 73 LOG(ERROR) << "Failed to start device data polling thread";
54 polling_thread_.reset(); 74 polling_thread_.reset();
55 return; 75 return;
56 } 76 }
57 ScheduleInitializePollingThread(); 77
78 // reset members used on polling thread
79 last_device_data_map_.reset(new IDMap<DeviceData, IDMapOwnPointer>);
80 observer_types_.clear();
58 } 81 }
59 82
60 void ProviderImpl::Stop() { 83 void ProviderImpl::Stop() {
61 DCHECK(MessageLoop::current() == creator_loop_); 84 DCHECK(MessageLoop::current() == creator_loop_);
62 85
63 // TODO(hans): Don't join the thread. See crbug.com/72286. 86 // TODO(hans): Don't join the thread. See crbug.com/72286.
64 base::ThreadRestrictions::ScopedAllowIO allow_io; 87 base::ThreadRestrictions::ScopedAllowIO allow_io;
65 88
66 polling_thread_.reset(); 89 polling_thread_.reset();
67 data_fetcher_.reset(); 90 data_fetcher_.reset();
68 } 91 }
69 92
93 void ProviderImpl::DoAddObserverType(
94 DeviceData::DeviceDataType device_data_type) {
95 DCHECK(MessageLoop::current() == polling_thread_->message_loop());
96
97 observer_types_.insert(device_data_type);
98 }
99
100 void ProviderImpl::ScheduleDoAddObserverType(
101 DeviceData::DeviceDataType device_data_type) {
102 DCHECK(MessageLoop::current() == creator_loop_);
103
104 MessageLoop* polling_loop = polling_thread_->message_loop();
105 polling_loop->PostTask(FROM_HERE,
106 base::Bind(&ProviderImpl::DoAddObserverType,
107 this,
108 device_data_type));
109 }
110
70 void ProviderImpl::DoInitializePollingThread( 111 void ProviderImpl::DoInitializePollingThread(
71 const std::vector<DataFetcherFactory>& factories) { 112 const std::vector<DataFetcherFactory>& factories,
113 DeviceData::DeviceDataType device_data_type) {
72 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); 114 DCHECK(MessageLoop::current() == polling_thread_->message_loop());
73 115
74 typedef std::vector<DataFetcherFactory>::const_iterator Iterator; 116 typedef std::vector<DataFetcherFactory>::const_iterator Iterator;
75 for (Iterator i = factories_.begin(), e = factories_.end(); i != e; ++i) { 117 for (Iterator i = factories_.begin(), e = factories_.end(); i != e; ++i) {
76 DataFetcherFactory factory = *i; 118 DataFetcherFactory factory = *i;
77 scoped_ptr<DataFetcher> fetcher(factory()); 119 scoped_ptr<DataFetcher> fetcher(factory());
78 Orientation orientation; 120 scoped_ptr<DeviceData> device_data(EmptyDeviceData(device_data_type));
79 121
80 if (fetcher.get() && fetcher->GetOrientation(&orientation)) { 122 if (fetcher.get() && fetcher->GetDeviceData(device_data.get())) {
81 // Pass ownership of fetcher to provider_. 123 // Pass ownership of fetcher to provider_.
82 data_fetcher_.swap(fetcher); 124 data_fetcher_.swap(fetcher);
83 last_orientation_ = orientation; 125 last_device_data_map_->AddWithID(device_data->Clone(), device_data_type);
84 126
85 // Notify observers. 127 // Notify observers.
86 if (!orientation.is_empty()) 128 if (!device_data->IsEmpty())
87 ScheduleDoNotify(orientation); 129 ScheduleDoNotify(device_data.release());
88 130
89 // Start polling. 131 // Start polling.
90 ScheduleDoPoll(); 132 ScheduleDoPoll();
91 return; 133 return;
92 } 134 }
93 } 135 }
94 136
95 // When no orientation data can be provided. 137 // When no device data can be provided.
96 ScheduleDoNotify(Orientation::Empty()); 138 ScheduleDoNotify(EmptyDeviceData(device_data_type));
97 } 139 }
98 140
99 void ProviderImpl::ScheduleInitializePollingThread() { 141 void ProviderImpl::ScheduleInitializePollingThread(
142 DeviceData::DeviceDataType device_data_type) {
100 DCHECK(MessageLoop::current() == creator_loop_); 143 DCHECK(MessageLoop::current() == creator_loop_);
101 144
102 MessageLoop* polling_loop = polling_thread_->message_loop(); 145 MessageLoop* polling_loop = polling_thread_->message_loop();
103 polling_loop->PostTask(FROM_HERE, 146 polling_loop->PostTask(FROM_HERE,
104 base::Bind(&ProviderImpl::DoInitializePollingThread, 147 base::Bind(&ProviderImpl::DoInitializePollingThread,
105 this, 148 this,
106 factories_)); 149 factories_,
150 device_data_type));
107 } 151 }
108 152
109 void ProviderImpl::DoNotify(const Orientation& orientation) { 153 void ProviderImpl::DoNotify(const DeviceData* device_data) {
110 DCHECK(MessageLoop::current() == creator_loop_); 154 DCHECK(MessageLoop::current() == creator_loop_);
111 155
112 last_notification_ = orientation; 156 scoped_ptr<const DeviceData> data(device_data);
157 DeviceData::DeviceDataType device_data_type = data->device_data_type();
113 158
114 typedef std::set<Observer*>::const_iterator Iterator; 159 // update last notification of this type
115 for (Iterator i = observers_.begin(), e = observers_.end(); i != e; ++i) 160 DeviceData* last_notification = last_notifications_map_.Lookup(
116 (*i)->OnOrientationUpdate(orientation); 161 device_data_type);
162 if (last_notification)
163 last_notifications_map_.Remove(device_data_type);
164 last_notifications_map_.AddWithID(data->Clone(), device_data_type);
117 165
118 if (orientation.is_empty()) { 166 // notify observers of this type of the new data
119 // Notify observers about failure to provide data exactly once. 167 typedef std::set<Observer*>::const_iterator ConstIterator;
120 observers_.clear(); 168 for (ConstIterator i = observers_.begin(), e = observers_.end();
121 Stop(); 169 i != e; ++i) {
170 if ((*i)->device_data_type() == device_data_type)
171 (*i)->OnDeviceDataUpdate(*data);
172 }
173
174 if (device_data->IsEmpty()) {
175 // Notify observers about failure to provide data exactly once
176 typedef std::set<Observer*>::iterator Iterator;
177 Iterator i = observers_.begin();
178 while (i != observers_.end()) {
179 Iterator current = i++;
180 if ((*current)->device_data_type() == device_data_type)
181 observers_.erase(current);
182 }
183
184 if (observers_.empty())
185 Stop();
122 } 186 }
123 } 187 }
124 188
125 void ProviderImpl::ScheduleDoNotify(const Orientation& orientation) { 189 void ProviderImpl::ScheduleDoNotify(const DeviceData* device_data) {
126 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); 190 DCHECK(MessageLoop::current() == polling_thread_->message_loop());
127 191
128 creator_loop_->PostTask( 192 creator_loop_->PostTask(FROM_HERE,
129 FROM_HERE, base::Bind(&ProviderImpl::DoNotify, this, orientation)); 193 base::Bind(&ProviderImpl::DoNotify, this,
194 device_data));
130 } 195 }
131 196
132 void ProviderImpl::DoPoll() { 197 void ProviderImpl::DoPoll() {
133 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); 198 DCHECK(MessageLoop::current() == polling_thread_->message_loop());
134 199
135 Orientation orientation; 200 // Poll the fetcher for each type of data
136 if (!data_fetcher_->GetOrientation(&orientation)) { 201 typedef std::set<DeviceData::DeviceDataType>::const_iterator SetIterator;
137 LOG(ERROR) << "Failed to poll device orientation data fetcher."; 202 for (SetIterator i = observer_types_.begin(), e = observer_types_.end();
203 i != e; ++i) {
204 DeviceData::DeviceDataType device_data_type = *i;
205 scoped_ptr<DeviceData> device_data(EmptyDeviceData(device_data_type));
138 206
139 ScheduleDoNotify(Orientation::Empty()); 207 if (!data_fetcher_->GetDeviceData(device_data.get())) {
140 return; 208 LOG(ERROR) << "Failed to poll device data fetcher.";
141 }
142 209
143 if (!orientation.is_empty() && 210 ScheduleDoNotify(EmptyDeviceData(device_data_type));
144 SignificantlyDifferent(orientation, last_orientation_)) { 211 return;
145 last_orientation_ = orientation; 212 }
146 ScheduleDoNotify(orientation); 213
214 // Update the last device data of this type and notify observers
215 DeviceData* last_device_data = last_device_data_map_->Lookup(
216 device_data_type);
217 if (!last_device_data) {
218 last_device_data_map_->AddWithID(device_data->Clone(), device_data_type);
219 ScheduleDoNotify(device_data.release());
220 }
221 else if (device_data->SignificantlyDifferentFrom(*last_device_data)) {
222 last_device_data_map_->Remove(device_data_type);
223 last_device_data_map_->AddWithID(device_data->Clone(), device_data_type);
224 ScheduleDoNotify(device_data.release());
225 }
147 } 226 }
148 227
149 ScheduleDoPoll(); 228 ScheduleDoPoll();
150 } 229 }
151 230
152 void ProviderImpl::ScheduleDoPoll() { 231 void ProviderImpl::ScheduleDoPoll() {
153 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); 232 DCHECK(MessageLoop::current() == polling_thread_->message_loop());
154 233
155 MessageLoop* polling_loop = polling_thread_->message_loop(); 234 MessageLoop* polling_loop = polling_thread_->message_loop();
156 polling_loop->PostDelayedTask( 235 polling_loop->PostDelayedTask(
157 FROM_HERE, 236 FROM_HERE,
158 base::Bind(&ProviderImpl::DoPoll, weak_factory_.GetWeakPtr()), 237 base::Bind(&ProviderImpl::DoPoll, weak_factory_.GetWeakPtr()),
159 SamplingInterval()); 238 SamplingInterval());
160 } 239 }
161 240
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 { 241 base::TimeDelta ProviderImpl::SamplingInterval() const {
200 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); 242 DCHECK(MessageLoop::current() == polling_thread_->message_loop());
201 DCHECK(data_fetcher_.get()); 243 DCHECK(data_fetcher_.get());
202 244
203 // TODO(erg): There used to be unused code here, that called a default 245 // TODO(erg): There used to be unused code here, that called a default
204 // implementation on the DataFetcherInterface that was never defined. I'm 246 // implementation on the DataFetcherInterface that was never defined. I'm
205 // removing unused methods from headers. 247 // removing unused methods from headers.
206 return base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs); 248 return base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs);
207 } 249 }
208 250
251 DeviceData* ProviderImpl::EmptyDeviceData(DeviceData::DeviceDataType type) {
252 if (type == DeviceData::kDeviceOrientationData)
253 return new Orientation();
254 else
255 return NULL;
256 }
257
209 } // namespace device_orientation 258 } // namespace device_orientation
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698