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 fab78a11a42733926495eaa1902bc52d879a21bb..9f12832ea980be2fa33ad0ac98e014fd71b1d185 100644 |
--- a/content/browser/device_orientation/provider_impl.cc |
+++ b/content/browser/device_orientation/provider_impl.cc |
@@ -2,7 +2,6 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include <cmath> |
#include <set> |
#include <vector> |
@@ -29,11 +28,24 @@ ProviderImpl::~ProviderImpl() { |
void ProviderImpl::AddObserver(Observer* observer) { |
DCHECK(MessageLoop::current() == creator_loop_); |
+ DeviceData::DeviceDataType device_data_type = observer->device_data_type(); |
+ |
observers_.insert(observer); |
if (observers_.size() == 1) |
Start(); |
- else |
- observer->OnOrientationUpdate(last_notification_); |
+ |
+ ScheduleDoAddObserverType(device_data_type); |
+ |
+ if (!data_fetcher_.get()) { |
+ ScheduleInitializePollingThread(device_data_type); |
+ return; |
+ } |
+ |
+ // Notify observer of most recent notification if one exists. |
+ DeviceData* last_notification = last_notifications_map_.Lookup( |
+ device_data_type); |
+ if (last_notification) |
+ observer->OnDeviceDataUpdate(last_notification); |
} |
void ProviderImpl::RemoveObserver(Observer* observer) { |
@@ -48,13 +60,16 @@ void ProviderImpl::Start() { |
DCHECK(MessageLoop::current() == creator_loop_); |
DCHECK(!polling_thread_.get()); |
- polling_thread_.reset(new base::Thread("Device orientation polling thread")); |
+ // Reset members used on polling thread. |
+ last_device_data_map_.reset(new IDMap<DeviceData, IDMapOwnPointer>); |
+ observer_types_.clear(); |
+ |
+ polling_thread_.reset(new base::Thread("Device data polling thread")); |
if (!polling_thread_->Start()) { |
- LOG(ERROR) << "Failed to start device orientation polling thread"; |
+ LOG(ERROR) << "Failed to start device data polling thread"; |
polling_thread_.reset(); |
return; |
} |
- ScheduleInitializePollingThread(); |
} |
void ProviderImpl::Stop() { |
@@ -67,24 +82,46 @@ void ProviderImpl::Stop() { |
data_fetcher_.reset(); |
} |
+void ProviderImpl::DoAddObserverType( |
+ DeviceData::DeviceDataType device_data_type) { |
+ DCHECK(MessageLoop::current() == polling_thread_->message_loop()); |
+ |
+ observer_types_.insert(device_data_type); |
+} |
+ |
+void ProviderImpl::ScheduleDoAddObserverType( |
+ DeviceData::DeviceDataType device_data_type) { |
+ DCHECK(MessageLoop::current() == creator_loop_); |
+ |
+ MessageLoop* polling_loop = polling_thread_->message_loop(); |
+ polling_loop->PostTask(FROM_HERE, |
+ base::Bind(&ProviderImpl::DoAddObserverType, |
+ this, |
+ device_data_type)); |
+} |
+ |
void ProviderImpl::DoInitializePollingThread( |
- const std::vector<DataFetcherFactory>& factories) { |
+ const std::vector<DataFetcherFactory>& factories, |
+ DeviceData::DeviceDataType device_data_type) { |
DCHECK(MessageLoop::current() == polling_thread_->message_loop()); |
typedef std::vector<DataFetcherFactory>::const_iterator Iterator; |
for (Iterator i = factories_.begin(), e = factories_.end(); i != e; ++i) { |
DataFetcherFactory factory = *i; |
scoped_ptr<DataFetcher> fetcher(factory()); |
- Orientation orientation; |
- if (fetcher.get() && fetcher->GetOrientation(&orientation)) { |
+ if (!fetcher.get()) |
+ continue; |
+ |
+ scoped_ptr<DeviceData> device_data(fetcher->GetDeviceData( |
+ device_data_type)); |
+ if (device_data != NULL) { |
// Pass ownership of fetcher to provider_. |
data_fetcher_.swap(fetcher); |
- last_orientation_ = orientation; |
+ last_device_data_map_->AddWithID(device_data->Clone(), device_data_type); |
// Notify observers. |
- if (!orientation.is_empty()) |
- ScheduleDoNotify(orientation); |
+ ScheduleDoNotify(device_data.release(), device_data_type); |
// Start polling. |
ScheduleDoPoll(); |
@@ -92,58 +129,97 @@ void ProviderImpl::DoInitializePollingThread( |
} |
} |
- // When no orientation data can be provided. |
- ScheduleDoNotify(Orientation::Empty()); |
+ // When no device data can be provided. |
+ ScheduleDoNotify(NULL, device_data_type); |
} |
-void ProviderImpl::ScheduleInitializePollingThread() { |
+void ProviderImpl::ScheduleInitializePollingThread( |
+ DeviceData::DeviceDataType device_data_type) { |
DCHECK(MessageLoop::current() == creator_loop_); |
MessageLoop* polling_loop = polling_thread_->message_loop(); |
polling_loop->PostTask(FROM_HERE, |
base::Bind(&ProviderImpl::DoInitializePollingThread, |
this, |
- factories_)); |
+ factories_, |
+ device_data_type)); |
} |
-void ProviderImpl::DoNotify(const Orientation& orientation) { |
+void ProviderImpl::DoNotify(const DeviceData* device_data, |
+ DeviceData::DeviceDataType device_data_type) { |
DCHECK(MessageLoop::current() == creator_loop_); |
- last_notification_ = orientation; |
+ scoped_ptr<const DeviceData> data(device_data); |
+ |
+ // Update last notification of this type. |
+ DeviceData* last_notification = last_notifications_map_.Lookup( |
+ device_data_type); |
+ if (last_notification) |
+ last_notifications_map_.Remove(device_data_type); |
+ if (data != NULL) |
+ last_notifications_map_.AddWithID(data->Clone(), device_data_type); |
+ |
+ // Notify observers of this type of the new data. |
+ typedef std::set<Observer*>::const_iterator ConstIterator; |
+ for (ConstIterator i = observers_.begin(), e = observers_.end(); |
+ i != e; ++i) { |
+ if ((*i)->device_data_type() == device_data_type) |
+ (*i)->OnDeviceDataUpdate(data.get()); |
+ } |
- typedef std::set<Observer*>::const_iterator Iterator; |
- for (Iterator i = observers_.begin(), e = observers_.end(); i != e; ++i) |
- (*i)->OnOrientationUpdate(orientation); |
+ 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 (orientation.is_empty()) { |
- // Notify observers about failure to provide data exactly once. |
- observers_.clear(); |
- Stop(); |
+ if (observers_.empty()) |
+ Stop(); |
} |
} |
-void ProviderImpl::ScheduleDoNotify(const Orientation& orientation) { |
+void ProviderImpl::ScheduleDoNotify(const DeviceData* device_data, |
+ DeviceData::DeviceDataType device_data_type) { |
DCHECK(MessageLoop::current() == polling_thread_->message_loop()); |
- creator_loop_->PostTask( |
- FROM_HERE, base::Bind(&ProviderImpl::DoNotify, this, orientation)); |
+ creator_loop_->PostTask(FROM_HERE, |
+ base::Bind(&ProviderImpl::DoNotify, this, |
+ device_data, device_data_type)); |
} |
void ProviderImpl::DoPoll() { |
DCHECK(MessageLoop::current() == polling_thread_->message_loop()); |
- Orientation orientation; |
- if (!data_fetcher_->GetOrientation(&orientation)) { |
- LOG(ERROR) << "Failed to poll device orientation data fetcher."; |
- |
- ScheduleDoNotify(Orientation::Empty()); |
- return; |
- } |
+ // Poll the fetcher for each type of data |
+ typedef std::set<DeviceData::DeviceDataType>::const_iterator SetIterator; |
+ for (SetIterator i = observer_types_.begin(), e = observer_types_.end(); |
+ i != e; ++i) { |
+ DeviceData::DeviceDataType device_data_type = *i; |
+ scoped_ptr<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); |
+ return; |
bulach
2012/07/12 10:43:27
hmm, I think now that we're traversing all the dif
aousterh
2012/07/12 17:13:57
Good point. Done.
|
+ } |
- if (!orientation.is_empty() && |
- SignificantlyDifferent(orientation, last_orientation_)) { |
- last_orientation_ = orientation; |
- ScheduleDoNotify(orientation); |
+ // Update the last device data of this type and notify observers |
+ DeviceData* last_device_data = last_device_data_map_->Lookup( |
+ device_data_type); |
+ if (!last_device_data) { |
+ last_device_data_map_->AddWithID(device_data->Clone(), device_data_type); |
+ ScheduleDoNotify(device_data.release(), device_data_type); |
+ } |
+ else if (device_data->SignificantlyDifferentFrom(*last_device_data)) { |
bulach
2012/07/12 10:43:27
nit: else on the line above with }
aousterh
2012/07/12 17:13:57
Done.
|
+ last_device_data_map_->Remove(device_data_type); |
+ last_device_data_map_->AddWithID(device_data->Clone(), device_data_type); |
+ ScheduleDoNotify(device_data.release(), device_data_type); |
+ } |
} |
ScheduleDoPoll(); |
@@ -159,43 +235,6 @@ void ProviderImpl::ScheduleDoPoll() { |
SamplingInterval()); |
} |
-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; |
-} |
-} // namespace |
- |
-// Returns true if two orientations are considered different enough that |
-// observers should be notified of the new orientation. |
-bool ProviderImpl::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::SamplingInterval() const { |
DCHECK(MessageLoop::current() == polling_thread_->message_loop()); |
DCHECK(data_fetcher_.get()); |