OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <cmath> | |
6 #include <set> | |
7 #include <vector> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/message_loop.h" | |
11 #include "base/task.h" | |
12 #include "base/threading/thread.h" | |
13 #include "base/threading/thread_restrictions.h" | |
14 #include "chrome/browser/device_orientation/orientation.h" | |
15 #include "chrome/browser/device_orientation/provider_impl.h" | |
16 | |
17 namespace device_orientation { | |
18 | |
19 ProviderImpl::ProviderImpl(const DataFetcherFactory factories[]) | |
20 : creator_loop_(MessageLoop::current()), | |
21 ALLOW_THIS_IN_INITIALIZER_LIST(do_poll_method_factory_(this)) { | |
22 for (const DataFetcherFactory* fp = factories; *fp; ++fp) | |
23 factories_.push_back(*fp); | |
24 } | |
25 | |
26 ProviderImpl::~ProviderImpl() { | |
27 } | |
28 | |
29 void ProviderImpl::AddObserver(Observer* observer) { | |
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 std::vector<DataFetcherFactory> factories) { | |
72 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); | |
73 | |
74 typedef std::vector<DataFetcherFactory>::const_iterator Iterator; | |
75 for (Iterator i = factories_.begin(), e = factories_.end(); i != e; ++i) { | |
76 DataFetcherFactory factory = *i; | |
77 scoped_ptr<DataFetcher> fetcher(factory()); | |
78 Orientation orientation; | |
79 | |
80 if (fetcher.get() && fetcher->GetOrientation(&orientation)) { | |
81 // Pass ownership of fetcher to provider_. | |
82 data_fetcher_.swap(fetcher); | |
83 last_orientation_ = orientation; | |
84 | |
85 // Notify observers. | |
86 ScheduleDoNotify(orientation); | |
87 | |
88 // Start polling. | |
89 ScheduleDoPoll(); | |
90 return; | |
91 } | |
92 } | |
93 | |
94 // When no orientation data can be provided. | |
95 ScheduleDoNotify(Orientation::Empty()); | |
96 } | |
97 | |
98 void ProviderImpl::ScheduleInitializePollingThread() { | |
99 DCHECK(MessageLoop::current() == creator_loop_); | |
100 | |
101 Task* task = NewRunnableMethod(this, | |
102 &ProviderImpl::DoInitializePollingThread, | |
103 factories_); | |
104 MessageLoop* polling_loop = polling_thread_->message_loop(); | |
105 polling_loop->PostTask(FROM_HERE, task); | |
106 } | |
107 | |
108 void ProviderImpl::DoNotify(const Orientation& orientation) { | |
109 DCHECK(MessageLoop::current() == creator_loop_); | |
110 | |
111 last_notification_ = orientation; | |
112 | |
113 typedef std::set<Observer*>::const_iterator Iterator; | |
114 for (Iterator i = observers_.begin(), e = observers_.end(); i != e; ++i) | |
115 (*i)->OnOrientationUpdate(orientation); | |
116 | |
117 if (orientation.IsEmpty()) { | |
118 // Notify observers about failure to provide data exactly once. | |
119 observers_.clear(); | |
120 Stop(); | |
121 } | |
122 } | |
123 | |
124 void ProviderImpl::ScheduleDoNotify(const Orientation& orientation) { | |
125 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); | |
126 | |
127 Task* task = NewRunnableMethod(this, &ProviderImpl::DoNotify, orientation); | |
128 creator_loop_->PostTask(FROM_HERE, task); | |
129 } | |
130 | |
131 void ProviderImpl::DoPoll() { | |
132 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); | |
133 | |
134 Orientation orientation; | |
135 if (!data_fetcher_->GetOrientation(&orientation)) { | |
136 LOG(ERROR) << "Failed to poll device orientation data fetcher."; | |
137 | |
138 ScheduleDoNotify(Orientation::Empty()); | |
139 return; | |
140 } | |
141 | |
142 if (SignificantlyDifferent(orientation, last_orientation_)) { | |
143 last_orientation_ = orientation; | |
144 ScheduleDoNotify(orientation); | |
145 } | |
146 | |
147 ScheduleDoPoll(); | |
148 } | |
149 | |
150 void ProviderImpl::ScheduleDoPoll() { | |
151 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); | |
152 | |
153 Task* task = do_poll_method_factory_.NewRunnableMethod(&ProviderImpl::DoPoll); | |
154 MessageLoop* polling_loop = polling_thread_->message_loop(); | |
155 polling_loop->PostDelayedTask(FROM_HERE, task, SamplingIntervalMs()); | |
156 } | |
157 | |
158 namespace { | |
159 | |
160 bool IsElementSignificantlyDifferent(bool can_provide_element1, | |
161 bool can_provide_element2, | |
162 double element1, | |
163 double element2) { | |
164 const double kThreshold = 0.1; | |
165 | |
166 if (can_provide_element1 != can_provide_element2) | |
167 return true; | |
168 if (can_provide_element1 && | |
169 std::fabs(element1 - element2) >= kThreshold) | |
170 return true; | |
171 return false; | |
172 } | |
173 } // namespace | |
174 | |
175 // Returns true if two orientations are considered different enough that | |
176 // observers should be notified of the new orientation. | |
177 bool ProviderImpl::SignificantlyDifferent(const Orientation& o1, | |
178 const Orientation& o2) { | |
179 return IsElementSignificantlyDifferent(o1.can_provide_alpha_, | |
180 o2.can_provide_alpha_, | |
181 o1.alpha_, | |
182 o2.alpha_) || | |
183 IsElementSignificantlyDifferent(o1.can_provide_beta_, | |
184 o2.can_provide_beta_, | |
185 o1.beta_, | |
186 o2.beta_) || | |
187 IsElementSignificantlyDifferent(o1.can_provide_gamma_, | |
188 o2.can_provide_gamma_, | |
189 o1.gamma_, | |
190 o2.gamma_); | |
191 } | |
192 | |
193 int ProviderImpl::SamplingIntervalMs() const { | |
194 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); | |
195 DCHECK(data_fetcher_.get()); | |
196 | |
197 // TODO(erg): There used to be unused code here, that called a default | |
198 // implementation on the DataFetcherInterface that was never defined. I'm | |
199 // removing unused methods from headers. | |
200 return kDesiredSamplingIntervalMs; | |
201 } | |
202 | |
203 } // namespace device_orientation | |
OLD | NEW |