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/task.h" |
| 11 #include "chrome/browser/chrome_thread.h" |
| 12 #include "chrome/browser/device_orientation/orientation.h" |
| 13 #include "chrome/browser/device_orientation/provider_impl.h" |
| 14 |
| 15 namespace device_orientation { |
| 16 |
| 17 ProviderImpl::ProviderImpl(MessageLoop* message_loop, |
| 18 const DataFetcherFactory factories[]) |
| 19 : creator_loop_(message_loop), |
| 20 ALLOW_THIS_IN_INITIALIZER_LIST(do_poll_method_factory_(this)) { |
| 21 for (const DataFetcherFactory* fp = factories; *fp; ++fp) |
| 22 factories_.push_back(*fp); |
| 23 } |
| 24 |
| 25 ProviderImpl::~ProviderImpl() { |
| 26 } |
| 27 |
| 28 void ProviderImpl::AddObserver(Observer* observer) { |
| 29 DCHECK(MessageLoop::current() == creator_loop_); |
| 30 |
| 31 observers_.insert(observer); |
| 32 if (observers_.size() == 1) |
| 33 Start(); |
| 34 else |
| 35 observer->OnOrientationUpdate(last_notification_); |
| 36 } |
| 37 |
| 38 void ProviderImpl::RemoveObserver(Observer* observer) { |
| 39 DCHECK(MessageLoop::current() == creator_loop_); |
| 40 |
| 41 observers_.erase(observer); |
| 42 if (observers_.empty()) |
| 43 Stop(); |
| 44 } |
| 45 |
| 46 void ProviderImpl::Start() { |
| 47 DCHECK(MessageLoop::current() == creator_loop_); |
| 48 DCHECK(!polling_thread_.get()); |
| 49 |
| 50 polling_thread_.reset(new base::Thread("Device orientation polling thread")); |
| 51 if (!polling_thread_->Start()) { |
| 52 LOG(ERROR) << "Failed to start device orientation polling thread"; |
| 53 polling_thread_.reset(); |
| 54 return; |
| 55 } |
| 56 ScheduleInitializePollingThread(); |
| 57 } |
| 58 |
| 59 void ProviderImpl::Stop() { |
| 60 DCHECK(MessageLoop::current() == creator_loop_); |
| 61 polling_thread_.reset(); |
| 62 data_fetcher_.reset(); |
| 63 } |
| 64 |
| 65 void ProviderImpl::DoInitializePollingThread( |
| 66 std::vector<DataFetcherFactory> factories) { |
| 67 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); |
| 68 |
| 69 typedef std::vector<DataFetcherFactory>::const_iterator Iterator; |
| 70 for (Iterator i = factories_.begin(), e = factories_.end(); i != e; ++i) { |
| 71 DataFetcherFactory factory = *i; |
| 72 scoped_ptr<DataFetcher> fetcher(factory()); |
| 73 Orientation orientation; |
| 74 |
| 75 if (fetcher.get() && fetcher->GetOrientation(&orientation)) { |
| 76 // Pass ownership of fetcher to provider_. |
| 77 data_fetcher_.swap(fetcher); |
| 78 last_orientation_ = orientation; |
| 79 |
| 80 // Notify observers. |
| 81 ScheduleDoNotify(orientation); |
| 82 |
| 83 // Start polling. |
| 84 ScheduleDoPoll(); |
| 85 return; |
| 86 } |
| 87 } |
| 88 |
| 89 // When no orientation data can be provided. |
| 90 ScheduleDoNotify(Orientation::Empty()); |
| 91 } |
| 92 |
| 93 void ProviderImpl::ScheduleInitializePollingThread() { |
| 94 DCHECK(MessageLoop::current() == creator_loop_); |
| 95 |
| 96 Task* task = NewRunnableMethod(this, |
| 97 &ProviderImpl::DoInitializePollingThread, |
| 98 factories_); |
| 99 MessageLoop* polling_loop = polling_thread_->message_loop(); |
| 100 polling_loop->PostTask(FROM_HERE, task); |
| 101 } |
| 102 |
| 103 void ProviderImpl::DoNotify(Orientation orientation) { |
| 104 DCHECK(MessageLoop::current() == creator_loop_); |
| 105 |
| 106 last_notification_ = orientation; |
| 107 |
| 108 typedef std::set<Observer*>::const_iterator Iterator; |
| 109 for (Iterator i = observers_.begin(), e = observers_.end(); i != e; ++i) |
| 110 (*i)->OnOrientationUpdate(orientation); |
| 111 |
| 112 if (orientation.IsEmpty()) { |
| 113 // Notify observers about failure to provide data exactly once. |
| 114 observers_.clear(); |
| 115 Stop(); |
| 116 } |
| 117 } |
| 118 |
| 119 void ProviderImpl::ScheduleDoNotify(Orientation orientation) { |
| 120 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); |
| 121 |
| 122 Task* task = NewRunnableMethod(this, &ProviderImpl::DoNotify, orientation); |
| 123 creator_loop_->PostTask(FROM_HERE, task); |
| 124 } |
| 125 |
| 126 void ProviderImpl::DoPoll() { |
| 127 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); |
| 128 |
| 129 Orientation orientation; |
| 130 if (!data_fetcher_->GetOrientation(&orientation)) { |
| 131 LOG(ERROR) << "Failed to poll device orientation data fetcher."; |
| 132 |
| 133 ScheduleDoNotify(Orientation::Empty()); |
| 134 return; |
| 135 } |
| 136 |
| 137 if (SignificantlyDifferent(orientation, last_orientation_)) { |
| 138 last_orientation_ = orientation; |
| 139 ScheduleDoNotify(orientation); |
| 140 } |
| 141 |
| 142 ScheduleDoPoll(); |
| 143 } |
| 144 |
| 145 void ProviderImpl::ScheduleDoPoll() { |
| 146 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); |
| 147 |
| 148 Task* task = do_poll_method_factory_.NewRunnableMethod(&ProviderImpl::DoPoll); |
| 149 MessageLoop* polling_loop = polling_thread_->message_loop(); |
| 150 polling_loop->PostDelayedTask(FROM_HERE, task, SamplingIntervalMs()); |
| 151 } |
| 152 |
| 153 namespace { |
| 154 bool IsElementSignificantlyDifferent(bool can_provide_element1, |
| 155 bool can_provide_element2, |
| 156 double element1, |
| 157 double element2) { |
| 158 const double kThreshold = 0.1; |
| 159 |
| 160 if (can_provide_element1 != can_provide_element2) |
| 161 return true; |
| 162 if (can_provide_element1 && |
| 163 std::fabs(element1 - element2) >= kThreshold) |
| 164 return true; |
| 165 return false; |
| 166 } |
| 167 } // namespace |
| 168 |
| 169 // Returns true if two orientations are considered different enough that |
| 170 // observers should be notified of the new orientation. |
| 171 bool ProviderImpl::SignificantlyDifferent(const Orientation& o1, |
| 172 const Orientation& o2) { |
| 173 return IsElementSignificantlyDifferent(o1.can_provide_alpha_, |
| 174 o2.can_provide_alpha_, |
| 175 o1.alpha_, |
| 176 o2.alpha_) || |
| 177 IsElementSignificantlyDifferent(o1.can_provide_beta_, |
| 178 o2.can_provide_beta_, |
| 179 o1.beta_, |
| 180 o2.beta_) || |
| 181 IsElementSignificantlyDifferent(o1.can_provide_gamma_, |
| 182 o2.can_provide_gamma_, |
| 183 o1.gamma_, |
| 184 o2.gamma_); |
| 185 } |
| 186 |
| 187 int ProviderImpl::SamplingIntervalMs() const { |
| 188 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); |
| 189 DCHECK(data_fetcher_.get()); |
| 190 |
| 191 int fetcher_interval = data_fetcher_->MinSamplingIntervalMs(); |
| 192 |
| 193 if (fetcher_interval > kDesiredSamplingIntervalMs) |
| 194 return fetcher_interval; |
| 195 else |
| 196 return kDesiredSamplingIntervalMs; |
| 197 } |
| 198 |
| 199 } // namespace device_orientation |
OLD | NEW |