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

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

Powered by Google App Engine
This is Rietveld 408576698