| Index: content/browser/device_orientation/provider_impl.cc
|
| diff --git a/content/browser/device_orientation/provider_impl.cc b/content/browser/device_orientation/provider_impl.cc
|
| index 3118093585a95d95477bf0cf4a14c52865b0de1d..ae4088405621893241c9b8530e3fdbfd1b4ef0f7 100644
|
| --- a/content/browser/device_orientation/provider_impl.cc
|
| +++ b/content/browser/device_orientation/provider_impl.cc
|
| @@ -2,7 +2,8 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include <cmath>
|
| +#include "content/browser/device_orientation/provider_impl.h"
|
| +
|
| #include <set>
|
| #include <vector>
|
|
|
| @@ -11,25 +12,9 @@
|
| #include "base/message_loop.h"
|
| #include "base/threading/thread.h"
|
| #include "base/threading/worker_pool.h"
|
| -#include "content/browser/device_orientation/orientation.h"
|
| -#include "content/browser/device_orientation/provider_impl.h"
|
|
|
| namespace {
|
|
|
| -bool IsElementSignificantlyDifferent(bool can_provide_element1,
|
| - bool can_provide_element2,
|
| - double element1,
|
| - double element2) {
|
| - const double kThreshold = 0.1;
|
| -
|
| - if (can_provide_element1 != can_provide_element2)
|
| - return true;
|
| - if (can_provide_element1 &&
|
| - std::fabs(element1 - element2) >= kThreshold)
|
| - return true;
|
| - return false;
|
| -}
|
| -
|
| void DeleteThread(base::Thread* thread) {
|
| thread->Stop();
|
| delete thread;
|
| @@ -46,8 +31,12 @@ class ProviderImpl::PollingThread : public base::Thread {
|
| MessageLoop* creator_loop);
|
| virtual ~PollingThread();
|
|
|
| - // Method for finding a suitable DataFetcher and starting the polling.
|
| - void Initialize(DataFetcherFactory factory);
|
| + // Method for creating a DataFetcher and starting the polling, if the fetcher
|
| + // can provide this type of data.
|
| + void Initialize(DataFetcherFactory factory, DeviceData::Type type);
|
| +
|
| + // Method for adding a type of data to poll for.
|
| + void DoAddPollingDataType(DeviceData::Type type);
|
|
|
| private:
|
| // Method for polling a DataFetcher.
|
| @@ -56,10 +45,8 @@ class ProviderImpl::PollingThread : public base::Thread {
|
|
|
| // Schedule a notification to the |provider_| which lives on a different
|
| // thread (|creator_loop_| is its message loop).
|
| - void ScheduleDoNotify(const Orientation& orientation);
|
| -
|
| - static bool SignificantlyDifferent(const Orientation& orientation1,
|
| - const Orientation& orientation2);
|
| + void ScheduleDoNotify(const DeviceData* device_data,
|
| + DeviceData::Type device_data_type);
|
|
|
| enum { kDesiredSamplingIntervalMs = 100 };
|
| base::TimeDelta SamplingInterval() const;
|
| @@ -69,7 +56,9 @@ class ProviderImpl::PollingThread : public base::Thread {
|
| MessageLoop* creator_loop_;
|
|
|
| scoped_ptr<DataFetcher> data_fetcher_;
|
| - Orientation last_orientation_;
|
| + std::map<DeviceData::Type, scoped_refptr<const DeviceData> >
|
| + last_device_data_map_;
|
| + std::set<DeviceData::Type> polling_data_types_;
|
|
|
| base::WeakPtr<ProviderImpl> provider_;
|
| };
|
| @@ -86,56 +75,76 @@ ProviderImpl::PollingThread::PollingThread(
|
| ProviderImpl::PollingThread::~PollingThread() {
|
| }
|
|
|
| -void ProviderImpl::PollingThread::Initialize(DataFetcherFactory factory) {
|
| +void ProviderImpl::PollingThread::DoAddPollingDataType(DeviceData::Type type) {
|
| + DCHECK(MessageLoop::current() == message_loop());
|
| +
|
| + polling_data_types_.insert(type);
|
| +}
|
| +
|
| +void ProviderImpl::PollingThread::Initialize(DataFetcherFactory factory,
|
| + DeviceData::Type type) {
|
| DCHECK(MessageLoop::current() == message_loop());
|
|
|
| if (factory != NULL) {
|
| - // Try to use factory to create a fetcher that can provide orientation data.
|
| + // Try to use factory to create a fetcher that can provide this type of
|
| + // data. If factory creates a fetcher that provides this type of data,
|
| + // start polling.
|
| scoped_ptr<DataFetcher> fetcher(factory());
|
| - Orientation orientation;
|
|
|
| - if (fetcher.get() && fetcher->GetOrientation(&orientation)) {
|
| - // Pass ownership of fetcher to provider_.
|
| - data_fetcher_.swap(fetcher);
|
| - last_orientation_ = orientation;
|
| + if (fetcher.get()) {
|
| + scoped_refptr<const DeviceData> device_data(fetcher->GetDeviceData(type));
|
| + if (device_data != NULL) {
|
| + // Pass ownership of fetcher to provider_.
|
| + data_fetcher_.swap(fetcher);
|
| + last_device_data_map_[type] = device_data;
|
|
|
| - // Notify observers.
|
| - if (!orientation.is_empty())
|
| - ScheduleDoNotify(orientation);
|
| + // Notify observers.
|
| + ScheduleDoNotify(device_data, type);
|
|
|
| - // Start polling.
|
| - ScheduleDoPoll();
|
| - return;
|
| + // Start polling.
|
| + ScheduleDoPoll();
|
| + return;
|
| + }
|
| }
|
| }
|
|
|
| - // When no orientation data can be provided.
|
| - ScheduleDoNotify(Orientation::Empty());
|
| + // When no device data can be provided.
|
| + ScheduleDoNotify(NULL, type);
|
| }
|
|
|
| void ProviderImpl::PollingThread::ScheduleDoNotify(
|
| - const Orientation& orientation) {
|
| + const DeviceData* device_data, DeviceData::Type device_data_type) {
|
| DCHECK(MessageLoop::current() == message_loop());
|
|
|
| - creator_loop_->PostTask(
|
| - FROM_HERE, base::Bind(&ProviderImpl::DoNotify, provider_, orientation));
|
| + creator_loop_->PostTask(FROM_HERE,
|
| + base::Bind(&ProviderImpl::DoNotify, provider_,
|
| + device_data, device_data_type));
|
| }
|
|
|
| void ProviderImpl::PollingThread::DoPoll() {
|
| DCHECK(MessageLoop::current() == message_loop());
|
|
|
| - Orientation orientation;
|
| - if (!data_fetcher_->GetOrientation(&orientation)) {
|
| - LOG(ERROR) << "Failed to poll device orientation data fetcher.";
|
| + // Poll the fetcher for each type of data.
|
| + typedef std::set<DeviceData::Type>::const_iterator SetIterator;
|
| + for (SetIterator i = polling_data_types_.begin();
|
| + i != polling_data_types_.end(); ++i) {
|
| + DeviceData::Type device_data_type = *i;
|
| + scoped_refptr<const DeviceData> device_data(data_fetcher_->GetDeviceData(
|
| + device_data_type));
|
| +
|
| + if (device_data == NULL) {
|
| + LOG(ERROR) << "Failed to poll device data fetcher.";
|
| + ScheduleDoNotify(NULL, device_data_type);
|
| + continue;
|
| + }
|
|
|
| - ScheduleDoNotify(Orientation::Empty());
|
| - return;
|
| - }
|
| + const DeviceData* old_data = last_device_data_map_[device_data_type];
|
| + if (old_data != NULL && !device_data->ShouldFireEvent(old_data))
|
| + continue;
|
|
|
| - if (!orientation.is_empty() &&
|
| - SignificantlyDifferent(orientation, last_orientation_)) {
|
| - last_orientation_ = orientation;
|
| - ScheduleDoNotify(orientation);
|
| + // Update the last device data of this type and notify observers.
|
| + last_device_data_map_[device_data_type] = device_data;
|
| + ScheduleDoNotify(device_data, device_data_type);
|
| }
|
|
|
| ScheduleDoPoll();
|
| @@ -150,27 +159,6 @@ void ProviderImpl::PollingThread::ScheduleDoPoll() {
|
| SamplingInterval());
|
| }
|
|
|
| -// Returns true if two orientations are considered different enough that
|
| -// observers should be notified of the new orientation.
|
| -bool ProviderImpl::PollingThread::SignificantlyDifferent(
|
| - const Orientation& o1,
|
| - const Orientation& o2) {
|
| - return IsElementSignificantlyDifferent(o1.can_provide_alpha(),
|
| - o2.can_provide_alpha(),
|
| - o1.alpha(),
|
| - o2.alpha()) ||
|
| - IsElementSignificantlyDifferent(o1.can_provide_beta(),
|
| - o2.can_provide_beta(),
|
| - o1.beta(),
|
| - o2.beta()) ||
|
| - IsElementSignificantlyDifferent(o1.can_provide_gamma(),
|
| - o2.can_provide_gamma(),
|
| - o1.gamma(),
|
| - o2.gamma()) ||
|
| - (o1.can_provide_absolute() != o2.can_provide_absolute() ||
|
| - o1.absolute() != o2.absolute());
|
| -}
|
| -
|
| base::TimeDelta ProviderImpl::PollingThread::SamplingInterval() const {
|
| DCHECK(MessageLoop::current() == message_loop());
|
| DCHECK(data_fetcher_.get());
|
| @@ -192,14 +180,32 @@ ProviderImpl::~ProviderImpl() {
|
| Stop();
|
| }
|
|
|
| +void ProviderImpl::ScheduleDoAddPollingDataType(DeviceData::Type type) {
|
| + DCHECK(MessageLoop::current() == creator_loop_);
|
| +
|
| + MessageLoop* polling_loop = polling_thread_->message_loop();
|
| + polling_loop->PostTask(FROM_HERE,
|
| + base::Bind(&PollingThread::DoAddPollingDataType,
|
| + base::Unretained(polling_thread_),
|
| + type));
|
| +}
|
| +
|
| void ProviderImpl::AddObserver(Observer* observer) {
|
| DCHECK(MessageLoop::current() == creator_loop_);
|
|
|
| + DeviceData::Type type = observer->device_data_type();
|
| +
|
| observers_.insert(observer);
|
| if (observers_.size() == 1)
|
| - Start();
|
| - else
|
| - observer->OnOrientationUpdate(last_notification_);
|
| + Start(type);
|
| + else {
|
| + // Notify observer of most recent notification if one exists.
|
| + const DeviceData *last_notification = last_notifications_map_[type];
|
| + if (last_notification != NULL)
|
| + observer->OnDeviceDataUpdate(last_notification, type);
|
| + }
|
| +
|
| + ScheduleDoAddPollingDataType(type);
|
| }
|
|
|
| void ProviderImpl::RemoveObserver(Observer* observer) {
|
| @@ -210,20 +216,20 @@ void ProviderImpl::RemoveObserver(Observer* observer) {
|
| Stop();
|
| }
|
|
|
| -void ProviderImpl::Start() {
|
| +void ProviderImpl::Start(DeviceData::Type type) {
|
| DCHECK(MessageLoop::current() == creator_loop_);
|
| DCHECK(!polling_thread_);
|
|
|
| - polling_thread_ = new PollingThread("Device orientation polling thread",
|
| + polling_thread_ = new PollingThread("Device data polling thread",
|
| weak_factory_.GetWeakPtr(),
|
| creator_loop_);
|
| if (!polling_thread_->Start()) {
|
| - LOG(ERROR) << "Failed to start device orientation polling thread";
|
| + LOG(ERROR) << "Failed to start device data polling thread";
|
| delete polling_thread_;
|
| polling_thread_ = NULL;
|
| return;
|
| }
|
| - ScheduleInitializePollingThread();
|
| + ScheduleInitializePollingThread(type);
|
| }
|
|
|
| void ProviderImpl::Stop() {
|
| @@ -241,30 +247,48 @@ void ProviderImpl::Stop() {
|
| }
|
| }
|
|
|
| -void ProviderImpl::ScheduleInitializePollingThread() {
|
| +void ProviderImpl::ScheduleInitializePollingThread(
|
| + DeviceData::Type device_data_type) {
|
| DCHECK(MessageLoop::current() == creator_loop_);
|
|
|
| MessageLoop* polling_loop = polling_thread_->message_loop();
|
| polling_loop->PostTask(FROM_HERE,
|
| base::Bind(&PollingThread::Initialize,
|
| base::Unretained(polling_thread_),
|
| - factory_));
|
| + factory_,
|
| + device_data_type));
|
| }
|
|
|
| -void ProviderImpl::DoNotify(const Orientation& orientation) {
|
| +void ProviderImpl::DoNotify(const DeviceData* device_data,
|
| + DeviceData::Type device_data_type) {
|
| DCHECK(MessageLoop::current() == creator_loop_);
|
|
|
| - last_notification_ = orientation;
|
| + scoped_refptr<const DeviceData> data(device_data);
|
|
|
| - typedef std::set<Observer*>::const_iterator Iterator;
|
| - for (Iterator i = observers_.begin(); i != observers_.end(); ++i)
|
| - (*i)->OnOrientationUpdate(orientation);
|
| + // Update last notification of this type.
|
| + last_notifications_map_[device_data_type] = data;
|
|
|
| - if (orientation.is_empty()) {
|
| - // Notify observers about failure to provide data exactly once.
|
| - observers_.clear();
|
| - Stop();
|
| + // Notify observers of this type of the new data.
|
| + typedef std::set<Observer*>::const_iterator ConstIterator;
|
| + for (ConstIterator i = observers_.begin(); i != observers_.end(); ++i) {
|
| + if ((*i)->device_data_type() == device_data_type)
|
| + (*i)->OnDeviceDataUpdate(data.get(), device_data_type);
|
| + }
|
| +
|
| + if (data == NULL) {
|
| + // Notify observers exactly once about failure to provide data.
|
| + typedef std::set<Observer*>::iterator Iterator;
|
| + Iterator i = observers_.begin();
|
| + while (i != observers_.end()) {
|
| + Iterator current = i++;
|
| + if ((*current)->device_data_type() == device_data_type)
|
| + observers_.erase(current);
|
| + }
|
| +
|
| + if (observers_.empty())
|
| + Stop();
|
| }
|
| }
|
|
|
| +
|
| } // namespace device_orientation
|
|
|