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..f9283984534cb979f4f67df43cf746b66b47135d 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> |
@@ -32,8 +31,29 @@ void ProviderImpl::AddObserver(Observer* observer) { |
observers_.insert(observer); |
if (observers_.size() == 1) |
Start(); |
- else |
- observer->OnOrientationUpdate(last_notification_); |
+ |
+ ScheduleDoAddObserverType(observer->device_data_type()); |
+ |
+ if (!data_fetcher_.get()) { |
+ ScheduleInitializePollingThread(observer->device_data_type()); |
+ return; |
+ } |
+ |
+ // Notify observer of most recent notification or newly fetched data |
+ // if this type of data has not been fetched yet |
+ DeviceData* last_notification = last_notifications_map_.Lookup( |
+ observer->device_data_type()); |
+ if (last_notification) |
+ observer->OnDeviceDataUpdate(*last_notification); |
+ else { |
+ scoped_ptr<DeviceData> device_data(EmptyDeviceData( |
+ observer->device_data_type())); |
+ if (!data_fetcher_->GetDeviceData(device_data.get()) || |
+ device_data->IsEmpty()) |
+ DoNotify(device_data.release()); |
+ else |
+ observer->OnDeviceDataUpdate(*device_data); |
+ } |
} |
void ProviderImpl::RemoveObserver(Observer* observer) { |
@@ -48,13 +68,16 @@ void ProviderImpl::Start() { |
DCHECK(MessageLoop::current() == creator_loop_); |
DCHECK(!polling_thread_.get()); |
- polling_thread_.reset(new base::Thread("Device orientation polling thread")); |
+ 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(); |
+ |
+ // reset members used on polling thread |
+ last_device_data_map_.reset(new IDMap<DeviceData, IDMapOwnPointer>); |
+ observer_types_.clear(); |
} |
void ProviderImpl::Stop() { |
@@ -67,24 +90,43 @@ 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; |
+ scoped_ptr<DeviceData> device_data(EmptyDeviceData(device_data_type)); |
- if (fetcher.get() && fetcher->GetOrientation(&orientation)) { |
+ if (fetcher.get() && fetcher->GetDeviceData(device_data.get())) { |
// 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); |
+ if (!device_data->IsEmpty()) |
+ ScheduleDoNotify(device_data.release()); |
// Start polling. |
ScheduleDoPoll(); |
@@ -92,58 +134,95 @@ void ProviderImpl::DoInitializePollingThread( |
} |
} |
- // When no orientation data can be provided. |
- ScheduleDoNotify(Orientation::Empty()); |
+ // When no device data can be provided. |
+ ScheduleDoNotify(EmptyDeviceData(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) { |
DCHECK(MessageLoop::current() == creator_loop_); |
- last_notification_ = orientation; |
+ scoped_ptr<const DeviceData> data(device_data); |
+ DeviceData::DeviceDataType device_data_type = data->device_data_type(); |
+ |
+ // 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); |
+ 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); |
+ } |
- typedef std::set<Observer*>::const_iterator Iterator; |
- for (Iterator i = observers_.begin(), e = observers_.end(); i != e; ++i) |
- (*i)->OnOrientationUpdate(orientation); |
+ if (device_data->IsEmpty()) { |
+ // Notify observers about failure to provide data exactly once |
+ 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) { |
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)); |
} |
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."; |
+ // 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(EmptyDeviceData(device_data_type)); |
- ScheduleDoNotify(Orientation::Empty()); |
- return; |
- } |
+ if (!data_fetcher_->GetDeviceData(device_data.get())) { |
+ LOG(ERROR) << "Failed to poll device data fetcher."; |
- if (!orientation.is_empty() && |
- SignificantlyDifferent(orientation, last_orientation_)) { |
- last_orientation_ = orientation; |
- ScheduleDoNotify(orientation); |
+ ScheduleDoNotify(EmptyDeviceData(device_data_type)); |
+ return; |
+ } |
+ |
+ // 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()); |
+ } |
+ else if (device_data->SignificantlyDifferentFrom(*last_device_data)) { |
+ last_device_data_map_->Remove(device_data_type); |
+ last_device_data_map_->AddWithID(device_data->Clone(), device_data_type); |
+ ScheduleDoNotify(device_data.release()); |
+ } |
} |
ScheduleDoPoll(); |
@@ -159,43 +238,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()); |
@@ -206,4 +248,11 @@ base::TimeDelta ProviderImpl::SamplingInterval() const { |
return base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs); |
} |
+DeviceData* ProviderImpl::EmptyDeviceData(DeviceData::DeviceDataType type) { |
+ if (type == DeviceData::kDeviceOrientationData) |
+ return new Orientation(); |
+ else |
+ return NULL; |
+} |
+ |
} // namespace device_orientation |