Commit 7701bcdb authored by aousterh@chromium.org's avatar aousterh@chromium.org

Refactors DeviceOrientation to make it more extensible

This refactors the ProviderImpl in DeviceOrientation to make it more general.
This will make it easy to add other types of device data (such as DeviceMotion)
in the future and to have them use the same Provider/ProviderImpl.

This is an alternative to http://codereview.chromium.org/10689106.

TBR=avi
BUG=none
TEST=browser_tests:DeviceOrientationBrowserTest.BasicTest,
content_unittests --gtest_filter=DeviceOrientation*


Review URL: https://chromiumcodereview.appspot.com/10755002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149864 0039d316-1c4b-4281-b951-d872f2087c98
parent c0e04e9c
...@@ -24,6 +24,12 @@ AccelerometerMac::~AccelerometerMac() { ...@@ -24,6 +24,12 @@ AccelerometerMac::~AccelerometerMac() {
AccelerometerMac::AccelerometerMac() { AccelerometerMac::AccelerometerMac() {
} }
const DeviceData* AccelerometerMac::GetDeviceData(DeviceData::Type type) {
if (type != DeviceData::kTypeOrientation)
return NULL;
return GetOrientation();
}
// Retrieve per-axis orientation values. // Retrieve per-axis orientation values.
// //
// Axes and angles are defined according to the W3C DeviceOrientation Draft. // Axes and angles are defined according to the W3C DeviceOrientation Draft.
...@@ -33,13 +39,13 @@ AccelerometerMac::AccelerometerMac() { ...@@ -33,13 +39,13 @@ AccelerometerMac::AccelerometerMac() {
// //
// Returns false in case of error. // Returns false in case of error.
// //
bool AccelerometerMac::GetOrientation(Orientation* orientation) { const Orientation* AccelerometerMac::GetOrientation() {
DCHECK(sudden_motion_sensor_.get()); DCHECK(sudden_motion_sensor_.get());
// Retrieve per-axis calibrated values. // Retrieve per-axis calibrated values.
float axis_value[3]; float axis_value[3];
if (!sudden_motion_sensor_->ReadSensorValues(axis_value)) if (!sudden_motion_sensor_->ReadSensorValues(axis_value))
return false; return NULL;
// Transform the accelerometer values to W3C draft angles. // Transform the accelerometer values to W3C draft angles.
// //
...@@ -63,6 +69,8 @@ bool AccelerometerMac::GetOrientation(Orientation* orientation) { ...@@ -63,6 +69,8 @@ bool AccelerometerMac::GetOrientation(Orientation* orientation) {
// //
const double kRad2deg = 180.0 / M_PI; const double kRad2deg = 180.0 / M_PI;
scoped_refptr<Orientation> orientation(new Orientation());
orientation->set_beta(kRad2deg * atan2(-axis_value[1], axis_value[2])); orientation->set_beta(kRad2deg * atan2(-axis_value[1], axis_value[2]));
orientation->set_gamma(kRad2deg * asin(axis_value[0])); orientation->set_gamma(kRad2deg * asin(axis_value[0]));
// TODO(aousterh): should absolute_ be set to false here? // TODO(aousterh): should absolute_ be set to false here?
...@@ -85,7 +93,7 @@ bool AccelerometerMac::GetOrientation(Orientation* orientation) { ...@@ -85,7 +93,7 @@ bool AccelerometerMac::GetOrientation(Orientation* orientation) {
DCHECK_GE(orientation->gamma(), -90.0); DCHECK_GE(orientation->gamma(), -90.0);
DCHECK_LT(orientation->gamma(), 90.0); DCHECK_LT(orientation->gamma(), 90.0);
return true; return orientation;
} }
bool AccelerometerMac::Init() { bool AccelerometerMac::Init() {
......
...@@ -10,23 +10,27 @@ ...@@ -10,23 +10,27 @@
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "content/browser/device_orientation/data_fetcher.h" #include "content/browser/device_orientation/data_fetcher.h"
#include "content/browser/device_orientation/device_data.h"
class SuddenMotionSensor; class SuddenMotionSensor;
namespace device_orientation { namespace device_orientation {
class Orientation;
class AccelerometerMac : public DataFetcher { class AccelerometerMac : public DataFetcher {
public: public:
static DataFetcher* Create(); static DataFetcher* Create();
// Implement DataFetcher. // Implement DataFetcher.
virtual bool GetOrientation(Orientation* orientation) OVERRIDE; virtual const DeviceData* GetDeviceData(DeviceData::Type type) OVERRIDE;
virtual ~AccelerometerMac(); virtual ~AccelerometerMac();
private: private:
AccelerometerMac(); AccelerometerMac();
bool Init(); bool Init();
const Orientation* GetOrientation();
scoped_ptr<SuddenMotionSensor> sudden_motion_sensor_; scoped_ptr<SuddenMotionSensor> sudden_motion_sensor_;
}; };
......
...@@ -5,18 +5,18 @@ ...@@ -5,18 +5,18 @@
#ifndef CONTENT_BROWSER_DEVICE_ORIENTATION_DATA_FETCHER_H_ #ifndef CONTENT_BROWSER_DEVICE_ORIENTATION_DATA_FETCHER_H_
#define CONTENT_BROWSER_DEVICE_ORIENTATION_DATA_FETCHER_H_ #define CONTENT_BROWSER_DEVICE_ORIENTATION_DATA_FETCHER_H_
namespace device_orientation { #include "content/browser/device_orientation/device_data.h"
class Orientation; namespace device_orientation {
class DataFetcher { class DataFetcher {
public: public:
virtual ~DataFetcher() {} virtual ~DataFetcher() {}
// Returns false if there was a fatal error getting the orientation. // Returns NULL if there was a fatal error getting the device data of this
// Returns true otherwise. If the fetcher has orientation data available // type or if this fetcher can never provide this type of data. Otherwise,
// it will fill it in, otherwise the argument will be unaltered. // returns a pointer to a DeviceData containing the most recent data.
virtual bool GetOrientation(Orientation*) = 0; virtual const DeviceData* GetDeviceData(DeviceData::Type type) = 0;
}; };
} // namespace device_orientation } // namespace device_orientation
......
...@@ -54,7 +54,14 @@ DataFetcherImplAndroid::~DataFetcherImplAndroid() { ...@@ -54,7 +54,14 @@ DataFetcherImplAndroid::~DataFetcherImplAndroid() {
Stop(); Stop();
} }
bool DataFetcherImplAndroid::GetOrientation(Orientation* orientation) { const DeviceData* DataFetcherImplAndroid::GetDeviceData(
DeviceData::Type type) {
if (type != DeviceData::kTypeOrientation)
return NULL;
return GetOrientation();
}
const Orientation* DataFetcherImplAndroid::GetOrientation() {
// Do we have a new orientation value? (It's safe to do this outside the lock // Do we have a new orientation value? (It's safe to do this outside the lock
// because we only skip the lock if the value is null. We always enter the // because we only skip the lock if the value is null. We always enter the
// lock if we're going to make use of the new value.) // lock if we're going to make use of the new value.)
...@@ -62,9 +69,9 @@ bool DataFetcherImplAndroid::GetOrientation(Orientation* orientation) { ...@@ -62,9 +69,9 @@ bool DataFetcherImplAndroid::GetOrientation(Orientation* orientation) {
base::AutoLock autolock(next_orientation_lock_); base::AutoLock autolock(next_orientation_lock_);
next_orientation_.swap(current_orientation_); next_orientation_.swap(current_orientation_);
} }
if (current_orientation_.get()) if (!current_orientation_.get())
*orientation = *current_orientation_; return new Orientation();
return true; return current_orientation_.get();
} }
void DataFetcherImplAndroid::GotOrientation( void DataFetcherImplAndroid::GotOrientation(
...@@ -76,7 +83,7 @@ void DataFetcherImplAndroid::GotOrientation( ...@@ -76,7 +83,7 @@ void DataFetcherImplAndroid::GotOrientation(
orientation->set_beta(beta); orientation->set_beta(beta);
orientation->set_gamma(gamma); orientation->set_gamma(gamma);
orientation->set_absolute(true); orientation->set_absolute(true);
next_orientation_.reset(orientation); next_orientation_ = orientation;
} }
bool DataFetcherImplAndroid::Start(int rate_in_milliseconds) { bool DataFetcherImplAndroid::Start(int rate_in_milliseconds) {
......
...@@ -10,17 +10,19 @@ ...@@ -10,17 +10,19 @@
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "content/browser/device_orientation/data_fetcher.h" #include "content/browser/device_orientation/data_fetcher.h"
#include "content/browser/device_orientation/orientation.h" #include "content/browser/device_orientation/device_data.h"
namespace device_orientation { namespace device_orientation {
class Orientation;
// Android implementation of DeviceOrientation API. // Android implementation of DeviceOrientation API.
// Android's SensorManager has a push API, whereas Chrome wants to pull data. // Android's SensorManager has a push API, whereas Chrome wants to pull data.
// To fit them together, we store incoming sensor events in a 1-element buffer. // To fit them together, we store incoming sensor events in a 1-element buffer.
// SensorManager calls SetOrientation() which pushes a new value (discarding the // SensorManager calls SetOrientation() which pushes a new value (discarding the
// previous value if any). Chrome calls GetOrientation() which reads the most // previous value if any). Chrome calls GetDeviceData() which reads the most
// recent value. Repeated calls to GetOrientation() will return the same value. // recent value. Repeated calls to GetDeviceData() will return the same value.
class DataFetcherImplAndroid : public DataFetcher { class DataFetcherImplAndroid : public DataFetcher {
public: public:
...@@ -38,21 +40,22 @@ class DataFetcherImplAndroid : public DataFetcher { ...@@ -38,21 +40,22 @@ class DataFetcherImplAndroid : public DataFetcher {
double alpha, double beta, double gamma); double alpha, double beta, double gamma);
// Implementation of DataFetcher. // Implementation of DataFetcher.
virtual bool GetOrientation(Orientation* orientation) OVERRIDE; virtual const DeviceData* GetDeviceData(DeviceData::Type type) OVERRIDE;
private: private:
DataFetcherImplAndroid(); DataFetcherImplAndroid();
const Orientation* GetOrientation();
// Wrappers for JNI methods. // Wrappers for JNI methods.
bool Start(int rate_in_milliseconds); bool Start(int rate_in_milliseconds);
void Stop(); void Stop();
// Value returned by GetOrientation. // Value returned by GetDeviceData.
scoped_ptr<Orientation> current_orientation_; scoped_refptr<Orientation> current_orientation_;
// 1-element buffer, written by GotOrientation, read by GetOrientation. // 1-element buffer, written by GotOrientation, read by GetDeviceData.
base::Lock next_orientation_lock_; base::Lock next_orientation_lock_;
scoped_ptr<Orientation> next_orientation_; scoped_refptr<Orientation> next_orientation_;
DISALLOW_COPY_AND_ASSIGN(DataFetcherImplAndroid); DISALLOW_COPY_AND_ASSIGN(DataFetcherImplAndroid);
}; };
......
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_DEVICE_ORIENTATION_DEVICE_DATA_H_
#define CONTENT_BROWSER_DEVICE_ORIENTATION_DEVICE_DATA_H_
#include "base/memory/ref_counted.h"
#include "content/common/content_export.h"
namespace IPC {
class Message;
}
namespace device_orientation {
class CONTENT_EXPORT DeviceData :
public base::RefCountedThreadSafe<DeviceData> {
public:
enum Type {
kTypeOrientation,
kTypeTest
};
virtual IPC::Message* CreateIPCMessage(int render_view_id) const = 0;
virtual bool ShouldFireEvent(const DeviceData* other) const = 0;
protected:
DeviceData() {}
virtual ~DeviceData() {}
private:
friend class base::RefCountedThreadSafe<DeviceData>;
DISALLOW_COPY_AND_ASSIGN(DeviceData);
};
} // namespace device_orientation
#endif // CONTENT_BROWSER_DEVICE_ORIENTATION_DEVICE_DATA_H_
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/file_path.h" #include "base/file_path.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "content/browser/device_orientation/device_data.h"
#include "content/browser/device_orientation/orientation.h" #include "content/browser/device_orientation/orientation.h"
#include "content/browser/device_orientation/provider.h" #include "content/browser/device_orientation/provider.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
...@@ -17,20 +19,23 @@ namespace device_orientation { ...@@ -17,20 +19,23 @@ namespace device_orientation {
class MockProvider : public Provider { class MockProvider : public Provider {
public: public:
explicit MockProvider(const Orientation& orientation) MockProvider(const DeviceData* device_data, DeviceData::Type type)
: orientation_(orientation), : device_data_(device_data),
device_data_type_(type),
added_observer_(false), added_observer_(false),
removed_observer_(false) {} removed_observer_(false) {
}
virtual void AddObserver(Observer* observer) { virtual void AddObserver(Observer* observer) {
added_observer_ = true; added_observer_ = true;
observer->OnOrientationUpdate(orientation_); observer->OnDeviceDataUpdate(device_data_.get(), device_data_type_);
} }
virtual void RemoveObserver(Observer* observer) { virtual void RemoveObserver(Observer* observer) {
removed_observer_ = true; removed_observer_ = true;
} }
Orientation orientation_; scoped_refptr<const DeviceData> device_data_;
DeviceData::Type device_data_type_;
bool added_observer_; bool added_observer_;
bool removed_observer_; bool removed_observer_;
...@@ -48,12 +53,13 @@ class DeviceOrientationBrowserTest : public content::ContentBrowserTest { ...@@ -48,12 +53,13 @@ class DeviceOrientationBrowserTest : public content::ContentBrowserTest {
// crbug.com/113952 // crbug.com/113952
IN_PROC_BROWSER_TEST_F(DeviceOrientationBrowserTest, BasicTest) { IN_PROC_BROWSER_TEST_F(DeviceOrientationBrowserTest, BasicTest) {
Orientation test_orientation; scoped_refptr<Orientation> test_orientation(new Orientation());
test_orientation.set_alpha(1); test_orientation->set_alpha(1);
test_orientation.set_beta(2); test_orientation->set_beta(2);
test_orientation.set_gamma(3); test_orientation->set_gamma(3);
test_orientation.set_absolute(true); test_orientation->set_absolute(true);
scoped_refptr<MockProvider> provider(new MockProvider(test_orientation)); scoped_refptr<MockProvider> provider(new MockProvider(
test_orientation, DeviceData::kTypeOrientation));
Provider::SetInstanceForTests(provider.get()); Provider::SetInstanceForTests(provider.get());
// The test page will register an event handler for orientation events, // The test page will register an event handler for orientation events,
......
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/device_orientation/message_filter.h"
#include "content/browser/device_orientation/observer_delegate.h"
#include "content/browser/device_orientation/provider.h"
#include "content/public/browser/browser_thread.h"
using content::BrowserThread;
namespace device_orientation {
MessageFilter::MessageFilter(DeviceData::Type device_data_type)
: provider_(NULL),
device_data_type_(device_data_type) {
}
MessageFilter::~MessageFilter() {
}
void MessageFilter::OnStartUpdating(int render_view_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!provider_)
provider_ = Provider::GetInstance();
observers_map_[render_view_id] = new ObserverDelegate(device_data_type_,
provider_, render_view_id, this);
}
void MessageFilter::OnStopUpdating(int render_view_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
observers_map_.erase(render_view_id);
}
} // namespace device_orientation
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_DEVICE_ORIENTATION_MESSAGE_FILTER_H_
#define CONTENT_BROWSER_DEVICE_ORIENTATION_MESSAGE_FILTER_H_
#include <map>
#include "content/browser/device_orientation/device_data.h"
#include "content/public/browser/browser_message_filter.h"
namespace device_orientation {
// Helper class that observes a Provider and forwards updates to a RenderView.
class ObserverDelegate;
class Provider;
class MessageFilter : public content::BrowserMessageFilter {
public:
// content::BrowserMessageFilter implementation.
virtual bool OnMessageReceived(const IPC::Message& message,
bool* message_was_ok) OVERRIDE = 0;
protected:
MessageFilter(DeviceData::Type device_data_type);
virtual ~MessageFilter();
void OnStartUpdating(int render_view_id);
void OnStopUpdating(int render_view_id);
private:
// map from render_view_id to ObserverDelegate.
std::map<int, scoped_refptr<ObserverDelegate> > observers_map_;
scoped_refptr<Provider> provider_;
DeviceData::Type device_data_type_;
};
} // namespace device_orientation
#endif // CONTENT_BROWSER_DEVICE_ORIENTATION_MESSAGE_FILTER_H_
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/device_orientation/observer_delegate.h"
#include "base/logging.h"
#include "content/browser/device_orientation/device_data.h"
#include "content/browser/device_orientation/orientation.h"
#include "ipc/ipc_sender.h"
namespace device_orientation {
ObserverDelegate::ObserverDelegate(DeviceData::Type device_data_type,
Provider* provider, int render_view_id,
IPC::Sender* sender)
: Observer(device_data_type),
provider_(provider),
render_view_id_(render_view_id),
sender_(sender) {
provider_->AddObserver(this);
}
ObserverDelegate::~ObserverDelegate() {
provider_->RemoveObserver(this);
}
void ObserverDelegate::OnDeviceDataUpdate(
const DeviceData* device_data, DeviceData::Type device_data_type) {
scoped_refptr<const DeviceData> new_device_data(device_data);
if (!new_device_data.get())
new_device_data = EmptyDeviceData(device_data_type);
sender_->Send(new_device_data->CreateIPCMessage(render_view_id_));
}
DeviceData* ObserverDelegate::EmptyDeviceData(DeviceData::Type type) {
DCHECK(type == DeviceData::kTypeOrientation);
return new Orientation();
}
} // namespace device_orientation
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_DEVICE_ORIENTATION_OBSERVER_DELEGATE_H_
#define CONTENT_BROWSER_DEVICE_ORIENTATION_OBSERVER_DELEGATE_H_
#include "content/browser/device_orientation/device_data.h"
#include "content/browser/device_orientation/provider.h"
namespace IPC {
class Sender;
}
namespace device_orientation {
class ObserverDelegate
: public base::RefCounted<ObserverDelegate>, public Provider::Observer {
public:
// Create ObserverDelegate that observes provider and forwards updates to
// render_view_id.
// Will stop observing provider when destructed.
ObserverDelegate(DeviceData::Type device_data_type, Provider* provider,
int render_view_id, IPC::Sender* sender);
// From Provider::Observer.
virtual void OnDeviceDataUpdate(const DeviceData* device_data,
DeviceData::Type device_data_type) OVERRIDE;
private:
static DeviceData* EmptyDeviceData(DeviceData::Type type);
friend class base::RefCounted<ObserverDelegate>;
virtual ~ObserverDelegate();
scoped_refptr<Provider> provider_;
int render_view_id_;
IPC::Sender* sender_; // Weak pointer.
DISALLOW_COPY_AND_ASSIGN(ObserverDelegate);
};
} // namespace device_orientation
#endif // CONTENT_BROWSER_DEVICE_ORIENTATION_OBSERVER_DELEGATE_H_
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/device_orientation/orientation.h"
#include <cmath>
#include "content/common/device_orientation_messages.h"
namespace device_orientation {
Orientation::Orientation()
: can_provide_alpha_(false),
can_provide_beta_(false),
can_provide_gamma_(false),
can_provide_absolute_(false) {
}
Orientation::~Orientation() {
}
IPC::Message* Orientation::CreateIPCMessage(int render_view_id) const {
DeviceOrientationMsg_Updated_Params params;
params.can_provide_alpha = can_provide_alpha_;
params.alpha = alpha_;
params.can_provide_beta = can_provide_beta_;
params.beta = beta_;
params.can_provide_gamma = can_provide_gamma_;
params.gamma = gamma_;
params.can_provide_absolute = can_provide_absolute_;
params.absolute = absolute_;
return new DeviceOrientationMsg_Updated(render_view_id, params);
}
// Returns true if two orientations are considered different enough that
// observers should be notified of the new orientation.
bool Orientation::ShouldFireEvent(const DeviceData* old_data) const {
scoped_refptr<const Orientation> old_orientation(
static_cast<const Orientation*>(old_data));
return IsElementSignificantlyDifferent(can_provide_alpha_,
old_orientation->can_provide_alpha(),
alpha_,
old_orientation->alpha()) ||
IsElementSignificantlyDifferent(can_provide_beta_,
old_orientation->can_provide_beta(),
beta_,
old_orientation->beta()) ||
IsElementSignificantlyDifferent(can_provide_gamma_,
old_orientation->can_provide_gamma(),
gamma_,
old_orientation->gamma()) ||
can_provide_absolute_ != old_orientation->can_provide_absolute() ||
absolute_ != old_orientation->absolute();
}
bool Orientation::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 device_orientation
...@@ -5,52 +5,24 @@ ...@@ -5,52 +5,24 @@
#ifndef CONTENT_BROWSER_DEVICE_ORIENTATION_ORIENTATION_H_ #ifndef CONTENT_BROWSER_DEVICE_ORIENTATION_ORIENTATION_H_
#define CONTENT_BROWSER_DEVICE_ORIENTATION_ORIENTATION_H_ #define CONTENT_BROWSER_DEVICE_ORIENTATION_ORIENTATION_H_
#include "base/compiler_specific.h"
#include "content/browser/device_orientation/device_data.h"
#include "content/common/content_export.h"
namespace device_orientation { namespace device_orientation {
class Orientation {
class Orientation : public DeviceData {
public: public:
// alpha, beta, gamma and absolute are the rotations around the axes as // alpha, beta, gamma and absolute are the rotations around the axes as
// specified in http://dev.w3.org/geo/api/spec-source-orientation.html // specified in http://dev.w3.org/geo/api/spec-source-orientation.html
// //
// can_provide_{alpha,beta,gamma,absolute} is true if data can be provided // can_provide_{alpha,beta,gamma,absolute} is true if data can be provided
// for that variable. // for that variable.
CONTENT_EXPORT Orientation();
Orientation() // From DeviceData.
: alpha_(0), virtual IPC::Message* CreateIPCMessage(int render_view_id) const OVERRIDE;
beta_(0), virtual bool ShouldFireEvent(const DeviceData* old_data) const OVERRIDE;
gamma_(0),
absolute_(false),
can_provide_alpha_(false),
can_provide_beta_(false),
can_provide_gamma_(false),
can_provide_absolute_(false) {
}
Orientation(const Orientation& orientation)
: alpha_(orientation.alpha()),
beta_(orientation.beta()),
gamma_(orientation.gamma()),
absolute_(orientation.absolute()),
can_provide_alpha_(orientation.can_provide_alpha()),
can_provide_beta_(orientation.can_provide_beta()),
can_provide_gamma_(orientation.can_provide_gamma()),
can_provide_absolute_(orientation.can_provide_absolute()) {
}
void operator=(const Orientation& source) {
alpha_ = source.alpha();
beta_ = source.beta();
gamma_ = source.gamma();
absolute_ = source.absolute();
can_provide_alpha_ = source.can_provide_alpha();
can_provide_beta_ = source.can_provide_beta();
can_provide_gamma_ = source.can_provide_gamma();
can_provide_absolute_ = source.can_provide_absolute();
}
static Orientation Empty() { return Orientation(); }
bool is_empty() const {
return !can_provide_alpha_ && !can_provide_beta_ && !can_provide_gamma_
&& !can_provide_absolute_;
}
void set_alpha(double alpha) { void set_alpha(double alpha) {
can_provide_alpha_ = true; can_provide_alpha_ = true;
...@@ -81,6 +53,11 @@ class Orientation { ...@@ -81,6 +53,11 @@ class Orientation {
bool absolute() const { return absolute_; } bool absolute() const { return absolute_; }
private: private:
virtual ~Orientation();
static bool IsElementSignificantlyDifferent(bool can_provide_element1,
bool can_provide_element2, double element1, double element2);
double alpha_; double alpha_;
double beta_; double beta_;
double gamma_; double gamma_;
......
...@@ -4,10 +4,7 @@ ...@@ -4,10 +4,7 @@
#include "content/browser/device_orientation/orientation_message_filter.h" #include "content/browser/device_orientation/orientation_message_filter.h"
#include "base/memory/scoped_ptr.h" #include "content/browser/device_orientation/device_data.h"
#include "content/browser/device_orientation/orientation.h"
#include "content/browser/device_orientation/provider.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/common/device_orientation_messages.h" #include "content/common/device_orientation_messages.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
...@@ -15,66 +12,15 @@ using content::BrowserThread; ...@@ -15,66 +12,15 @@ using content::BrowserThread;
namespace device_orientation { namespace device_orientation {
OrientationMessageFilter::OrientationMessageFilter() : provider_(NULL) { OrientationMessageFilter::OrientationMessageFilter()
: MessageFilter(DeviceData::kTypeOrientation) {
} }
OrientationMessageFilter::~OrientationMessageFilter() { OrientationMessageFilter::~OrientationMessageFilter() {
} }
class OrientationMessageFilter::ObserverDelegate
: public base::RefCounted<ObserverDelegate>, public Provider::Observer {
public:
// Create ObserverDelegate that observes provider and forwards updates to
// render_view_id in process_id.
// Will stop observing provider when destructed.
ObserverDelegate(Provider* provider,
int render_view_id,
IPC::Sender* sender);
// From Provider::Observer.
virtual void OnOrientationUpdate(const Orientation& orientation);
private:
friend class base::RefCounted<ObserverDelegate>;
virtual ~ObserverDelegate();
scoped_refptr<Provider> provider_;
int render_view_id_;
IPC::Sender* sender_; // Weak pointer.
DISALLOW_COPY_AND_ASSIGN(ObserverDelegate);
};
OrientationMessageFilter::ObserverDelegate::ObserverDelegate(Provider* provider,
int render_view_id,
IPC::Sender* sender)
: provider_(provider),
render_view_id_(render_view_id),
sender_(sender) {
provider_->AddObserver(this);
}
OrientationMessageFilter::ObserverDelegate::~ObserverDelegate() {
provider_->RemoveObserver(this);
}
void OrientationMessageFilter::ObserverDelegate::OnOrientationUpdate(
const Orientation& orientation) {
DeviceOrientationMsg_Updated_Params params;
params.can_provide_alpha = orientation.can_provide_alpha();
params.alpha = orientation.alpha();
params.can_provide_beta = orientation.can_provide_beta();
params.beta = orientation.beta();
params.can_provide_gamma = orientation.can_provide_gamma();
params.gamma = orientation.gamma();
params.can_provide_absolute = orientation.can_provide_absolute();
params.absolute = orientation.absolute();
sender_->Send(new DeviceOrientationMsg_Updated(render_view_id_, params));
}
bool OrientationMessageFilter::OnMessageReceived(const IPC::Message& message, bool OrientationMessageFilter::OnMessageReceived(const IPC::Message& message,
bool* message_was_ok) { bool* message_was_ok) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
bool handled = true; bool handled = true;
IPC_BEGIN_MESSAGE_MAP_EX(OrientationMessageFilter, message, *message_was_ok) IPC_BEGIN_MESSAGE_MAP_EX(OrientationMessageFilter, message, *message_was_ok)
...@@ -85,21 +31,4 @@ bool OrientationMessageFilter::OnMessageReceived(const IPC::Message& message, ...@@ -85,21 +31,4 @@ bool OrientationMessageFilter::OnMessageReceived(const IPC::Message& message,
return handled; return handled;
} }
void OrientationMessageFilter::OnStartUpdating(int render_view_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!provider_)
provider_ = Provider::GetInstance();
observers_map_[render_view_id] = new ObserverDelegate(provider_,
render_view_id,
this);
}
void OrientationMessageFilter::OnStopUpdating(int render_view_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
observers_map_.erase(render_view_id);
}
} // namespace device_orientation } // namespace device_orientation
...@@ -7,12 +7,11 @@ ...@@ -7,12 +7,11 @@
#include <map> #include <map>
#include "content/browser/device_orientation/provider.h" #include "content/browser/device_orientation/message_filter.h"
#include "content/public/browser/browser_message_filter.h"
namespace device_orientation { namespace device_orientation {
class OrientationMessageFilter : public content::BrowserMessageFilter { class OrientationMessageFilter : public MessageFilter {
public: public:
OrientationMessageFilter(); OrientationMessageFilter();
...@@ -23,17 +22,6 @@ class OrientationMessageFilter : public content::BrowserMessageFilter { ...@@ -23,17 +22,6 @@ class OrientationMessageFilter : public content::BrowserMessageFilter {
private: private:
virtual ~OrientationMessageFilter(); virtual ~OrientationMessageFilter();
void OnStartUpdating(int render_view_id);
void OnStopUpdating(int render_view_id);
// Helper class that observes a Provider and forwards updates to a RenderView.
class ObserverDelegate;
// map from render_view_id to ObserverDelegate.
std::map<int, scoped_refptr<ObserverDelegate> > observers_map_;
scoped_refptr<Provider> provider_;
DISALLOW_COPY_AND_ASSIGN(OrientationMessageFilter); DISALLOW_COPY_AND_ASSIGN(OrientationMessageFilter);
}; };
......
...@@ -6,23 +6,31 @@ ...@@ -6,23 +6,31 @@
#define CONTENT_BROWSER_DEVICE_ORIENTATION_PROVIDER_H_ #define CONTENT_BROWSER_DEVICE_ORIENTATION_PROVIDER_H_
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "content/browser/device_orientation/device_data.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
namespace device_orientation { namespace device_orientation {
class Orientation;
class CONTENT_EXPORT Provider : public base::RefCountedThreadSafe<Provider> { class CONTENT_EXPORT Provider : public base::RefCountedThreadSafe<Provider> {
public: public:
class Observer { class Observer {
public: public:
// Called when the orientation changes. // Called when device data changes.
// An Observer must not synchronously call Provider::RemoveObserver // An Observer must not synchronously call Provider::RemoveObserver
// or Provider::AddObserver when this is called. // or Provider::AddObserver when this is called.
virtual void OnOrientationUpdate(const Orientation& orientation) = 0; virtual void OnDeviceDataUpdate(const DeviceData* device_data,
DeviceData::Type device_data_type) = 0;
DeviceData::Type device_data_type() { return device_data_type_; }
protected: protected:
Observer(DeviceData::Type device_data_type)
: device_data_type_(device_data_type) {
}
virtual ~Observer() {} virtual ~Observer() {}
private:
// Each Observer observes exactly one type of DeviceData.
DeviceData::Type device_data_type_;
}; };
// Returns a pointer to the singleton instance of this class. // Returns a pointer to the singleton instance of this class.
...@@ -39,8 +47,7 @@ class CONTENT_EXPORT Provider : public base::RefCountedThreadSafe<Provider> { ...@@ -39,8 +47,7 @@ class CONTENT_EXPORT Provider : public base::RefCountedThreadSafe<Provider> {
// Get the current instance. Used for testing. // Get the current instance. Used for testing.
static Provider* GetInstanceForTests(); static Provider* GetInstanceForTests();
// Note: AddObserver may call back synchronously to the observer with // Note: AddObserver may call back synchronously to the observer with data.
// orientation data.
virtual void AddObserver(Observer* observer) = 0; virtual void AddObserver(Observer* observer) = 0;
virtual void RemoveObserver(Observer* observer) = 0; virtual void RemoveObserver(Observer* observer) = 0;
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include <cmath> #include "content/browser/device_orientation/provider_impl.h"
#include <set> #include <set>
#include <vector> #include <vector>
...@@ -11,25 +12,9 @@ ...@@ -11,25 +12,9 @@
#include "base/message_loop.h" #include "base/message_loop.h"
#include "base/threading/thread.h" #include "base/threading/thread.h"
#include "base/threading/worker_pool.h" #include "base/threading/worker_pool.h"
#include "content/browser/device_orientation/orientation.h"
#include "content/browser/device_orientation/provider_impl.h"
namespace { 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) { void DeleteThread(base::Thread* thread) {
thread->Stop(); thread->Stop();
delete thread; delete thread;
...@@ -46,8 +31,12 @@ class ProviderImpl::PollingThread : public base::Thread { ...@@ -46,8 +31,12 @@ class ProviderImpl::PollingThread : public base::Thread {
MessageLoop* creator_loop); MessageLoop* creator_loop);
virtual ~PollingThread(); virtual ~PollingThread();
// Method for finding a suitable DataFetcher and starting the polling. // Method for creating a DataFetcher and starting the polling, if the fetcher
void Initialize(DataFetcherFactory factory); // 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: private:
// Method for polling a DataFetcher. // Method for polling a DataFetcher.
...@@ -56,10 +45,8 @@ class ProviderImpl::PollingThread : public base::Thread { ...@@ -56,10 +45,8 @@ class ProviderImpl::PollingThread : public base::Thread {
// Schedule a notification to the |provider_| which lives on a different // Schedule a notification to the |provider_| which lives on a different
// thread (|creator_loop_| is its message loop). // thread (|creator_loop_| is its message loop).
void ScheduleDoNotify(const Orientation& orientation); void ScheduleDoNotify(const DeviceData* device_data,
DeviceData::Type device_data_type);
static bool SignificantlyDifferent(const Orientation& orientation1,
const Orientation& orientation2);
enum { kDesiredSamplingIntervalMs = 100 }; enum { kDesiredSamplingIntervalMs = 100 };
base::TimeDelta SamplingInterval() const; base::TimeDelta SamplingInterval() const;
...@@ -69,7 +56,9 @@ class ProviderImpl::PollingThread : public base::Thread { ...@@ -69,7 +56,9 @@ class ProviderImpl::PollingThread : public base::Thread {
MessageLoop* creator_loop_; MessageLoop* creator_loop_;
scoped_ptr<DataFetcher> data_fetcher_; 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_; base::WeakPtr<ProviderImpl> provider_;
}; };
...@@ -86,56 +75,76 @@ ProviderImpl::PollingThread::PollingThread( ...@@ -86,56 +75,76 @@ ProviderImpl::PollingThread::PollingThread(
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()); DCHECK(MessageLoop::current() == message_loop());
if (factory != NULL) { 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()); scoped_ptr<DataFetcher> fetcher(factory());
Orientation orientation;
if (fetcher.get() && fetcher->GetOrientation(&orientation)) { if (fetcher.get()) {
// Pass ownership of fetcher to provider_. scoped_refptr<const DeviceData> device_data(fetcher->GetDeviceData(type));
data_fetcher_.swap(fetcher); if (device_data != NULL) {
last_orientation_ = orientation; // Pass ownership of fetcher to provider_.
data_fetcher_.swap(fetcher);
last_device_data_map_[type] = device_data;
// Notify observers. // Notify observers.
if (!orientation.is_empty()) ScheduleDoNotify(device_data, type);
ScheduleDoNotify(orientation);
// Start polling. // Start polling.
ScheduleDoPoll(); ScheduleDoPoll();
return; return;
}
} }
} }
// When no orientation data can be provided. // When no device data can be provided.
ScheduleDoNotify(Orientation::Empty()); ScheduleDoNotify(NULL, type);
} }
void ProviderImpl::PollingThread::ScheduleDoNotify( void ProviderImpl::PollingThread::ScheduleDoNotify(
const Orientation& orientation) { const DeviceData* device_data, DeviceData::Type device_data_type) {
DCHECK(MessageLoop::current() == message_loop()); DCHECK(MessageLoop::current() == message_loop());
creator_loop_->PostTask( creator_loop_->PostTask(FROM_HERE,
FROM_HERE, base::Bind(&ProviderImpl::DoNotify, provider_, orientation)); base::Bind(&ProviderImpl::DoNotify, provider_,
device_data, device_data_type));
} }
void ProviderImpl::PollingThread::DoPoll() { void ProviderImpl::PollingThread::DoPoll() {
DCHECK(MessageLoop::current() == message_loop()); DCHECK(MessageLoop::current() == message_loop());
Orientation orientation; // Poll the fetcher for each type of data.
if (!data_fetcher_->GetOrientation(&orientation)) { typedef std::set<DeviceData::Type>::const_iterator SetIterator;
LOG(ERROR) << "Failed to poll device orientation data fetcher."; 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()); const DeviceData* old_data = last_device_data_map_[device_data_type];
return; if (old_data != NULL && !device_data->ShouldFireEvent(old_data))
} continue;
if (!orientation.is_empty() && // Update the last device data of this type and notify observers.
SignificantlyDifferent(orientation, last_orientation_)) { last_device_data_map_[device_data_type] = device_data;
last_orientation_ = orientation; ScheduleDoNotify(device_data, device_data_type);
ScheduleDoNotify(orientation);
} }
ScheduleDoPoll(); ScheduleDoPoll();
...@@ -150,27 +159,6 @@ void ProviderImpl::PollingThread::ScheduleDoPoll() { ...@@ -150,27 +159,6 @@ void ProviderImpl::PollingThread::ScheduleDoPoll() {
SamplingInterval()); 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 { base::TimeDelta ProviderImpl::PollingThread::SamplingInterval() const {
DCHECK(MessageLoop::current() == message_loop()); DCHECK(MessageLoop::current() == message_loop());
DCHECK(data_fetcher_.get()); DCHECK(data_fetcher_.get());
...@@ -192,14 +180,32 @@ ProviderImpl::~ProviderImpl() { ...@@ -192,14 +180,32 @@ ProviderImpl::~ProviderImpl() {
Stop(); 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) { void ProviderImpl::AddObserver(Observer* observer) {
DCHECK(MessageLoop::current() == creator_loop_); DCHECK(MessageLoop::current() == creator_loop_);
DeviceData::Type type = observer->device_data_type();
observers_.insert(observer); observers_.insert(observer);
if (observers_.size() == 1) if (observers_.size() == 1)
Start(); Start(type);
else else {
observer->OnOrientationUpdate(last_notification_); // 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) { void ProviderImpl::RemoveObserver(Observer* observer) {
...@@ -210,20 +216,20 @@ void ProviderImpl::RemoveObserver(Observer* observer) { ...@@ -210,20 +216,20 @@ void ProviderImpl::RemoveObserver(Observer* observer) {
Stop(); Stop();
} }
void ProviderImpl::Start() { void ProviderImpl::Start(DeviceData::Type type) {
DCHECK(MessageLoop::current() == creator_loop_); DCHECK(MessageLoop::current() == creator_loop_);
DCHECK(!polling_thread_); DCHECK(!polling_thread_);
polling_thread_ = new PollingThread("Device orientation polling thread", polling_thread_ = new PollingThread("Device data polling thread",
weak_factory_.GetWeakPtr(), weak_factory_.GetWeakPtr(),
creator_loop_); creator_loop_);
if (!polling_thread_->Start()) { 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_; delete polling_thread_;
polling_thread_ = NULL; polling_thread_ = NULL;
return; return;
} }
ScheduleInitializePollingThread(); ScheduleInitializePollingThread(type);
} }
void ProviderImpl::Stop() { void ProviderImpl::Stop() {
...@@ -241,30 +247,48 @@ 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_); DCHECK(MessageLoop::current() == creator_loop_);
MessageLoop* polling_loop = polling_thread_->message_loop(); MessageLoop* polling_loop = polling_thread_->message_loop();
polling_loop->PostTask(FROM_HERE, polling_loop->PostTask(FROM_HERE,
base::Bind(&PollingThread::Initialize, base::Bind(&PollingThread::Initialize,
base::Unretained(polling_thread_), 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_); DCHECK(MessageLoop::current() == creator_loop_);
last_notification_ = orientation; scoped_refptr<const DeviceData> data(device_data);
typedef std::set<Observer*>::const_iterator Iterator; // Update last notification of this type.
for (Iterator i = observers_.begin(); i != observers_.end(); ++i) last_notifications_map_[device_data_type] = data;
(*i)->OnOrientationUpdate(orientation);
if (orientation.is_empty()) { // Notify observers of this type of the new data.
// Notify observers about failure to provide data exactly once. typedef std::set<Observer*>::const_iterator ConstIterator;
observers_.clear(); for (ConstIterator i = observers_.begin(); i != observers_.end(); ++i) {
Stop(); 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 } // namespace device_orientation
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef CONTENT_BROWSER_DEVICE_ORIENTATION_PROVIDER_IMPL_H_ #ifndef CONTENT_BROWSER_DEVICE_ORIENTATION_PROVIDER_IMPL_H_
#define CONTENT_BROWSER_DEVICE_ORIENTATION_PROVIDER_IMPL_H_ #define CONTENT_BROWSER_DEVICE_ORIENTATION_PROVIDER_IMPL_H_
#include <map>
#include <set> #include <set>
#include <vector> #include <vector>
...@@ -12,7 +13,7 @@ ...@@ -12,7 +13,7 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/time.h" #include "base/time.h"
#include "content/browser/device_orientation/data_fetcher.h" #include "content/browser/device_orientation/data_fetcher.h"
#include "content/browser/device_orientation/orientation.h" #include "content/browser/device_orientation/device_data.h"
#include "content/browser/device_orientation/provider.h" #include "content/browser/device_orientation/provider.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
...@@ -25,8 +26,8 @@ class ProviderImpl : public Provider { ...@@ -25,8 +26,8 @@ class ProviderImpl : public Provider {
typedef DataFetcher* (*DataFetcherFactory)(); typedef DataFetcher* (*DataFetcherFactory)();
// Create a ProviderImpl that uses the factory to create a DataFetcher that // Create a ProviderImpl that uses the factory to create a DataFetcher that
// can provide orientation data. A NULL DataFetcherFactory indicates that // can provide data. A NULL DataFetcherFactory indicates that there are no
// there are no DataFetchers for this OS. // DataFetchers for this OS.
CONTENT_EXPORT ProviderImpl(DataFetcherFactory factory); CONTENT_EXPORT ProviderImpl(DataFetcherFactory factory);
// From Provider. // From Provider.
...@@ -39,14 +40,19 @@ class ProviderImpl : public Provider { ...@@ -39,14 +40,19 @@ class ProviderImpl : public Provider {
virtual ~ProviderImpl(); virtual ~ProviderImpl();
// Starts or Stops the provider. Called from creator_loop_. // Starts or Stops the provider. Called from creator_loop_.
void Start(); void Start(DeviceData::Type type);
void Stop(); void Stop();
void ScheduleInitializePollingThread(); void ScheduleInitializePollingThread(DeviceData::Type device_data_type);
void ScheduleDoAddPollingDataType(DeviceData::Type type);
// Method for notifying observers of an orientation update. // Method for notifying observers of a data update.
// Runs on the creator_thread_. // Runs on the creator_thread_.
void DoNotify(const Orientation& orientation); void DoNotify(const DeviceData* device_data,
DeviceData::Type device_data_type);
static bool ShouldFireEvent(const DeviceData* old_data,
const DeviceData* new_data, DeviceData::Type device_data_type);
// The Message Loop on which this object was created. // The Message Loop on which this object was created.
// Typically the I/O loop, but may be something else during testing. // Typically the I/O loop, but may be something else during testing.
...@@ -55,8 +61,11 @@ class ProviderImpl : public Provider { ...@@ -55,8 +61,11 @@ class ProviderImpl : public Provider {
// Members below are only to be used from the creator_loop_. // Members below are only to be used from the creator_loop_.
DataFetcherFactory factory_; DataFetcherFactory factory_;
std::set<Observer*> observers_; std::set<Observer*> observers_;
Orientation last_notification_; std::map<DeviceData::Type, scoped_refptr<const DeviceData> >
last_notifications_map_;
// When polling_thread_ is running, members below are only to be used
// from that thread.
base::WeakPtrFactory<ProviderImpl> weak_factory_; base::WeakPtrFactory<ProviderImpl> weak_factory_;
// Polling is done on this background thread. PollingThread is owned by // Polling is done on this background thread. PollingThread is owned by
......
...@@ -2,11 +2,13 @@ ...@@ -2,11 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include <map>
#include <queue> #include <queue>
#include "base/message_loop.h" #include "base/message_loop.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "content/browser/device_orientation/data_fetcher.h" #include "content/browser/device_orientation/data_fetcher.h"
#include "content/browser/device_orientation/device_data.h"
#include "content/browser/device_orientation/orientation.h" #include "content/browser/device_orientation/orientation.h"
#include "content/browser/device_orientation/provider.h" #include "content/browser/device_orientation/provider.h"
#include "content/browser/device_orientation/provider_impl.h" #include "content/browser/device_orientation/provider_impl.h"
...@@ -15,35 +17,96 @@ ...@@ -15,35 +17,96 @@
namespace device_orientation { namespace device_orientation {
namespace { namespace {
// Class for checking expectations on orientation updates from the Provider. // Class for testing multiple types of device data.
class UpdateChecker : public Provider::Observer { class TestData : public DeviceData {
public: public:
explicit UpdateChecker(int* expectations_count_ptr) TestData()
: expectations_count_ptr_(expectations_count_ptr) { : value_(0) {
}
// From DeviceData.
virtual IPC::Message* CreateIPCMessage(int render_view_id) const OVERRIDE {
NOTREACHED();
return NULL;
}
virtual bool ShouldFireEvent(const DeviceData* old_data) const OVERRIDE {
return true;
} }
void set_value(double value) { value_ = value; }
double value() const { return value_; }
private:
virtual ~TestData() { }
double value_;
};
// Class for checking expectations on device_data updates from the Provider.
class UpdateChecker : public Provider::Observer {
public:
UpdateChecker(DeviceData::Type device_data_type,
int *expectations_count_ptr)
: Observer(device_data_type),
expectations_count_ptr_(expectations_count_ptr) {
}
virtual ~UpdateChecker() {} virtual ~UpdateChecker() {}
// From Provider::Observer. // From Provider::Observer.
virtual void OnOrientationUpdate(const Orientation& orientation) { virtual void OnDeviceDataUpdate(const DeviceData* device_data,
DeviceData::Type device_data_type) OVERRIDE = 0;
void AddExpectation(const DeviceData* device_data) {
scoped_refptr<const DeviceData> expected_device_data(device_data);
expectations_queue_.push(expected_device_data);
++(*expectations_count_ptr_);
}
protected:
// Set up by the test fixture, which then blocks while it is accessed
// from OnDeviceDataUpdate which is executed on the test fixture's
// message_loop_.
int* expectations_count_ptr_;
std::queue<scoped_refptr<const DeviceData> > expectations_queue_;
};
// Class for checking expectations on orientation updates from the Provider.
class OrientationUpdateChecker : public UpdateChecker {
public:
explicit OrientationUpdateChecker(int* expectations_count_ptr)
: UpdateChecker(DeviceData::kTypeOrientation, expectations_count_ptr) {
}
virtual ~OrientationUpdateChecker() {}
// From UpdateChecker.
virtual void OnDeviceDataUpdate(const DeviceData* device_data,
DeviceData::Type device_data_type) OVERRIDE {
ASSERT_FALSE(expectations_queue_.empty()); ASSERT_FALSE(expectations_queue_.empty());
ASSERT_EQ(DeviceData::kTypeOrientation, device_data_type);
Orientation expected = expectations_queue_.front(); scoped_refptr<const Orientation> orientation(
static_cast<const Orientation*>(device_data));
if (orientation == NULL)
orientation = new Orientation();
scoped_refptr<const Orientation> expected(static_cast<const Orientation*>(
(expectations_queue_.front().get())));
expectations_queue_.pop(); expectations_queue_.pop();
EXPECT_EQ(expected.can_provide_alpha(), orientation.can_provide_alpha()); EXPECT_EQ(expected->can_provide_alpha(), orientation->can_provide_alpha());
EXPECT_EQ(expected.can_provide_beta(), orientation.can_provide_beta()); EXPECT_EQ(expected->can_provide_beta(), orientation->can_provide_beta());
EXPECT_EQ(expected.can_provide_gamma(), orientation.can_provide_gamma()); EXPECT_EQ(expected->can_provide_gamma(), orientation->can_provide_gamma());
EXPECT_EQ(expected.can_provide_absolute(), EXPECT_EQ(expected->can_provide_absolute(),
orientation.can_provide_absolute()); orientation->can_provide_absolute());
if (expected.can_provide_alpha()) if (expected->can_provide_alpha())
EXPECT_EQ(expected.alpha(), orientation.alpha()); EXPECT_EQ(expected->alpha(), orientation->alpha());
if (expected.can_provide_beta()) if (expected->can_provide_beta())
EXPECT_EQ(expected.beta(), orientation.beta()); EXPECT_EQ(expected->beta(), orientation->beta());
if (expected.can_provide_gamma()) if (expected->can_provide_gamma())
EXPECT_EQ(expected.gamma(), orientation.gamma()); EXPECT_EQ(expected->gamma(), orientation->gamma());
if (expected.can_provide_absolute()) if (expected->can_provide_absolute())
EXPECT_EQ(expected.absolute(), orientation.absolute()); EXPECT_EQ(expected->absolute(), orientation->absolute());
--(*expectations_count_ptr_); --(*expectations_count_ptr_);
...@@ -51,29 +114,49 @@ class UpdateChecker : public Provider::Observer { ...@@ -51,29 +114,49 @@ class UpdateChecker : public Provider::Observer {
MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
} }
} }
};
void AddExpectation(const Orientation& orientation) { // Class for checking expectations on test_data updates from the Provider.
expectations_queue_.push(orientation); class TestDataUpdateChecker : public UpdateChecker {
++(*expectations_count_ptr_); public:
explicit TestDataUpdateChecker(int* expectations_count_ptr)
: UpdateChecker(DeviceData::kTypeTest, expectations_count_ptr) {
} }
private: // From UpdateChecker.
// Set up by the test fixture, which then blocks while it is accessed virtual void OnDeviceDataUpdate(const DeviceData* device_data,
// from OnOrientationUpdate which is executed on the test fixture's DeviceData::Type device_data_type) OVERRIDE {
// message_loop_. ASSERT_FALSE(expectations_queue_.empty());
int* expectations_count_ptr_; ASSERT_EQ(DeviceData::kTypeTest, device_data_type);
std::queue<Orientation> expectations_queue_;
scoped_refptr<const TestData> test_data(
static_cast<const TestData*>(device_data));
if (test_data == NULL)
test_data = new TestData();
scoped_refptr<const TestData> expected(static_cast<const TestData*>(
(expectations_queue_.front().get())));
expectations_queue_.pop();
EXPECT_EQ(expected->value(), test_data->value());
--(*expectations_count_ptr_);
if (*expectations_count_ptr_ == 0) {
MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
}
}
}; };
// Class for injecting test orientation data into the Provider. // Class for injecting test device data into the Provider.
class MockOrientationFactory class MockDeviceDataFactory
: public base::RefCountedThreadSafe<MockOrientationFactory> { : public base::RefCountedThreadSafe<MockDeviceDataFactory> {
public: public:
MockOrientationFactory() MockDeviceDataFactory()
: is_failing_(false) { : is_failing_(false) {
} }
static void SetCurInstance(MockOrientationFactory* instance) { static void SetCurInstance(MockDeviceDataFactory* instance) {
if (instance) { if (instance) {
EXPECT_FALSE(instance_); EXPECT_FALSE(instance_);
} }
...@@ -88,9 +171,9 @@ class MockOrientationFactory ...@@ -88,9 +171,9 @@ class MockOrientationFactory
return new MockDataFetcher(instance_); return new MockDataFetcher(instance_);
} }
void SetOrientation(const Orientation& orientation) { void SetDeviceData(const DeviceData* device_data, DeviceData::Type type) {
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
orientation_ = orientation; device_data_map_[type] = device_data;
} }
void SetFailing(bool is_failing) { void SetFailing(bool is_failing) {
...@@ -99,54 +182,36 @@ class MockOrientationFactory ...@@ -99,54 +182,36 @@ class MockOrientationFactory
} }
private: private:
friend class base::RefCountedThreadSafe<MockOrientationFactory>; friend class base::RefCountedThreadSafe<MockDeviceDataFactory>;
~MockOrientationFactory() { ~MockDeviceDataFactory() {
} }
// Owned by ProviderImpl. Holds a reference back to MockOrientationFactory. // Owned by ProviderImpl. Holds a reference back to MockDeviceDataFactory.
class MockDataFetcher : public DataFetcher { class MockDataFetcher : public DataFetcher {
public: public:
explicit MockDataFetcher(MockOrientationFactory* orientation_factory) explicit MockDataFetcher(MockDeviceDataFactory* device_data_factory)
: orientation_factory_(orientation_factory) { } : device_data_factory_(device_data_factory) { }
// From DataFetcher. Called by the Provider. // From DataFetcher. Called by the Provider.
virtual bool GetOrientation(Orientation* orientation) { virtual const DeviceData* GetDeviceData(DeviceData::Type device_data_type) {
base::AutoLock auto_lock(orientation_factory_->lock_); base::AutoLock auto_lock(device_data_factory_->lock_);
if (orientation_factory_->is_failing_) if (device_data_factory_->is_failing_)
return false; return NULL;
*orientation = orientation_factory_->orientation_; return device_data_factory_->device_data_map_[device_data_type];
return true;
} }
private: private:
scoped_refptr<MockOrientationFactory> orientation_factory_; scoped_refptr<MockDeviceDataFactory> device_data_factory_;
}; };
static MockOrientationFactory* instance_; static MockDeviceDataFactory* instance_;
Orientation orientation_; std::map<DeviceData::Type, scoped_refptr<const DeviceData> > device_data_map_;
bool is_failing_; bool is_failing_;
base::Lock lock_; base::Lock lock_;
}; };
MockOrientationFactory* MockOrientationFactory::instance_; MockDeviceDataFactory* MockDeviceDataFactory::instance_;
// Mock DataFetcher that always fails to provide any orientation data.
class FailingDataFetcher : public DataFetcher {
public:
// Factory method; passed to and called by the ProviderImpl.
static DataFetcher* Create() {
return new FailingDataFetcher();
}
// From DataFetcher.
virtual bool GetOrientation(Orientation* orientation) {
return false;
}
private:
FailingDataFetcher() {}
};
class DeviceOrientationProviderTest : public testing::Test { class DeviceOrientationProviderTest : public testing::Test {
public: public:
...@@ -183,91 +248,105 @@ class DeviceOrientationProviderTest : public testing::Test { ...@@ -183,91 +248,105 @@ class DeviceOrientationProviderTest : public testing::Test {
}; };
TEST_F(DeviceOrientationProviderTest, FailingTest) { TEST_F(DeviceOrientationProviderTest, FailingTest) {
Init(FailingDataFetcher::Create); scoped_refptr<MockDeviceDataFactory> device_data_factory(
new MockDeviceDataFactory());
MockDeviceDataFactory::SetCurInstance(device_data_factory.get());
Init(MockDeviceDataFactory::CreateDataFetcher);
scoped_ptr<UpdateChecker> checker_a( scoped_ptr<OrientationUpdateChecker> checker_a(
new UpdateChecker(&pending_expectations_)); new OrientationUpdateChecker(&pending_expectations_));
scoped_ptr<UpdateChecker> checker_b( scoped_ptr<OrientationUpdateChecker> checker_b(
new UpdateChecker(&pending_expectations_)); new OrientationUpdateChecker(&pending_expectations_));
checker_a->AddExpectation(Orientation::Empty()); checker_a->AddExpectation(new Orientation());
provider_->AddObserver(checker_a.get()); provider_->AddObserver(checker_a.get());
MessageLoop::current()->Run(); MessageLoop::current()->Run();
checker_b->AddExpectation(Orientation::Empty()); checker_b->AddExpectation(new Orientation());
provider_->AddObserver(checker_b.get()); provider_->AddObserver(checker_b.get());
MessageLoop::current()->Run(); MessageLoop::current()->Run();
MockDeviceDataFactory::SetCurInstance(NULL);
} }
TEST_F(DeviceOrientationProviderTest, ProviderIsSingleton) { TEST_F(DeviceOrientationProviderTest, ProviderIsSingleton) {
Init(FailingDataFetcher::Create); scoped_refptr<MockDeviceDataFactory> device_data_factory(
new MockDeviceDataFactory());
MockDeviceDataFactory::SetCurInstance(device_data_factory.get());
Init(MockDeviceDataFactory::CreateDataFetcher);
scoped_refptr<Provider> provider_a(Provider::GetInstance()); scoped_refptr<Provider> provider_a(Provider::GetInstance());
scoped_refptr<Provider> provider_b(Provider::GetInstance()); scoped_refptr<Provider> provider_b(Provider::GetInstance());
EXPECT_EQ(provider_a.get(), provider_b.get()); EXPECT_EQ(provider_a.get(), provider_b.get());
MockDeviceDataFactory::SetCurInstance(NULL);
} }
TEST_F(DeviceOrientationProviderTest, BasicPushTest) { TEST_F(DeviceOrientationProviderTest, BasicPushTest) {
scoped_refptr<MockOrientationFactory> orientation_factory( scoped_refptr<MockDeviceDataFactory> device_data_factory(
new MockOrientationFactory()); new MockDeviceDataFactory());
MockOrientationFactory::SetCurInstance(orientation_factory.get()); MockDeviceDataFactory::SetCurInstance(device_data_factory.get());
Init(MockOrientationFactory::CreateDataFetcher); Init(MockDeviceDataFactory::CreateDataFetcher);
Orientation test_orientation; scoped_refptr<Orientation> test_orientation(new Orientation());
test_orientation.set_alpha(1); test_orientation->set_alpha(1);
test_orientation.set_beta(2); test_orientation->set_beta(2);
test_orientation.set_gamma(3); test_orientation->set_gamma(3);
test_orientation.set_absolute(true); test_orientation->set_absolute(true);
scoped_ptr<UpdateChecker> checker(new UpdateChecker(&pending_expectations_)); scoped_ptr<OrientationUpdateChecker> checker(
new OrientationUpdateChecker(&pending_expectations_));
checker->AddExpectation(test_orientation); checker->AddExpectation(test_orientation);
orientation_factory->SetOrientation(test_orientation); device_data_factory->SetDeviceData(test_orientation,
DeviceData::kTypeOrientation);
provider_->AddObserver(checker.get()); provider_->AddObserver(checker.get());
MessageLoop::current()->Run(); MessageLoop::current()->Run();
provider_->RemoveObserver(checker.get()); provider_->RemoveObserver(checker.get());
MockOrientationFactory::SetCurInstance(NULL); MockDeviceDataFactory::SetCurInstance(NULL);
} }
// Tests multiple observers observing the same type of data.
TEST_F(DeviceOrientationProviderTest, MultipleObserversPushTest) { TEST_F(DeviceOrientationProviderTest, MultipleObserversPushTest) {
scoped_refptr<MockOrientationFactory> orientation_factory( scoped_refptr<MockDeviceDataFactory> device_data_factory(
new MockOrientationFactory()); new MockDeviceDataFactory());
MockOrientationFactory::SetCurInstance(orientation_factory.get()); MockDeviceDataFactory::SetCurInstance(device_data_factory.get());
Init(MockOrientationFactory::CreateDataFetcher); Init(MockDeviceDataFactory::CreateDataFetcher);
Orientation test_orientations[] = {Orientation(), Orientation(), scoped_refptr<Orientation> test_orientations[] = {new Orientation(),
Orientation()}; new Orientation(), new Orientation()};
test_orientations[0].set_alpha(1); test_orientations[0]->set_alpha(1);
test_orientations[0].set_beta(2); test_orientations[0]->set_beta(2);
test_orientations[0].set_gamma(3); test_orientations[0]->set_gamma(3);
test_orientations[0].set_absolute(true); test_orientations[0]->set_absolute(true);
test_orientations[1].set_alpha(4); test_orientations[1]->set_alpha(4);
test_orientations[1].set_beta(5); test_orientations[1]->set_beta(5);
test_orientations[1].set_gamma(6); test_orientations[1]->set_gamma(6);
test_orientations[1].set_absolute(false); test_orientations[1]->set_absolute(false);
test_orientations[2].set_alpha(7); test_orientations[2]->set_alpha(7);
test_orientations[2].set_beta(8); test_orientations[2]->set_beta(8);
test_orientations[2].set_gamma(9); test_orientations[2]->set_gamma(9);
// can't provide absolute // can't provide absolute
scoped_ptr<UpdateChecker> checker_a( scoped_ptr<OrientationUpdateChecker> checker_a(
new UpdateChecker(&pending_expectations_)); new OrientationUpdateChecker(&pending_expectations_));
scoped_ptr<UpdateChecker> checker_b( scoped_ptr<OrientationUpdateChecker> checker_b(
new UpdateChecker(&pending_expectations_)); new OrientationUpdateChecker(&pending_expectations_));
scoped_ptr<UpdateChecker> checker_c( scoped_ptr<OrientationUpdateChecker> checker_c(
new UpdateChecker(&pending_expectations_)); new OrientationUpdateChecker(&pending_expectations_));
checker_a->AddExpectation(test_orientations[0]); checker_a->AddExpectation(test_orientations[0]);
orientation_factory->SetOrientation(test_orientations[0]); device_data_factory->SetDeviceData(test_orientations[0],
DeviceData::kTypeOrientation);
provider_->AddObserver(checker_a.get()); provider_->AddObserver(checker_a.get());
MessageLoop::current()->Run(); MessageLoop::current()->Run();
checker_a->AddExpectation(test_orientations[1]); checker_a->AddExpectation(test_orientations[1]);
checker_b->AddExpectation(test_orientations[0]); checker_b->AddExpectation(test_orientations[0]);
checker_b->AddExpectation(test_orientations[1]); checker_b->AddExpectation(test_orientations[1]);
orientation_factory->SetOrientation(test_orientations[1]); device_data_factory->SetDeviceData(test_orientations[1],
DeviceData::kTypeOrientation);
provider_->AddObserver(checker_b.get()); provider_->AddObserver(checker_b.get());
MessageLoop::current()->Run(); MessageLoop::current()->Run();
...@@ -275,13 +354,49 @@ TEST_F(DeviceOrientationProviderTest, MultipleObserversPushTest) { ...@@ -275,13 +354,49 @@ TEST_F(DeviceOrientationProviderTest, MultipleObserversPushTest) {
checker_b->AddExpectation(test_orientations[2]); checker_b->AddExpectation(test_orientations[2]);
checker_c->AddExpectation(test_orientations[1]); checker_c->AddExpectation(test_orientations[1]);
checker_c->AddExpectation(test_orientations[2]); checker_c->AddExpectation(test_orientations[2]);
orientation_factory->SetOrientation(test_orientations[2]); device_data_factory->SetDeviceData(test_orientations[2],
DeviceData::kTypeOrientation);
provider_->AddObserver(checker_c.get()); provider_->AddObserver(checker_c.get());
MessageLoop::current()->Run(); MessageLoop::current()->Run();
provider_->RemoveObserver(checker_b.get()); provider_->RemoveObserver(checker_b.get());
provider_->RemoveObserver(checker_c.get()); provider_->RemoveObserver(checker_c.get());
MockOrientationFactory::SetCurInstance(NULL); MockDeviceDataFactory::SetCurInstance(NULL);
}
// Test for when the fetcher cannot provide the first type of data but can
// provide the second type.
TEST_F(DeviceOrientationProviderTest, FailingFirstDataTypeTest) {
scoped_refptr<MockDeviceDataFactory> device_data_factory(
new MockDeviceDataFactory());
MockDeviceDataFactory::SetCurInstance(device_data_factory.get());
Init(MockDeviceDataFactory::CreateDataFetcher);
scoped_ptr<TestDataUpdateChecker> test_data_checker(
new TestDataUpdateChecker(&pending_expectations_));
scoped_ptr<OrientationUpdateChecker> orientation_checker(
new OrientationUpdateChecker(&pending_expectations_));
scoped_refptr<Orientation> test_orientation(new Orientation());
test_orientation->set_alpha(1);
test_orientation->set_beta(2);
test_orientation->set_gamma(3);
test_orientation->set_absolute(true);
test_data_checker->AddExpectation(new TestData());
provider_->AddObserver(test_data_checker.get());
MessageLoop::current()->Run();
orientation_checker->AddExpectation(test_orientation);
device_data_factory->SetDeviceData(test_orientation,
DeviceData::kTypeOrientation);
provider_->AddObserver(orientation_checker.get());
MessageLoop::current()->Run();
provider_->RemoveObserver(test_data_checker.get());
provider_->RemoveObserver(orientation_checker.get());
MockDeviceDataFactory::SetCurInstance(NULL);
} }
#if defined(OS_LINUX) || defined(OS_WIN) #if defined(OS_LINUX) || defined(OS_WIN)
...@@ -292,33 +407,36 @@ TEST_F(DeviceOrientationProviderTest, MultipleObserversPushTest) { ...@@ -292,33 +407,36 @@ TEST_F(DeviceOrientationProviderTest, MultipleObserversPushTest) {
#define MAYBE_ObserverNotRemoved ObserverNotRemoved #define MAYBE_ObserverNotRemoved ObserverNotRemoved
#endif #endif
TEST_F(DeviceOrientationProviderTest, MAYBE_ObserverNotRemoved) { TEST_F(DeviceOrientationProviderTest, MAYBE_ObserverNotRemoved) {
scoped_refptr<MockOrientationFactory> orientation_factory( scoped_refptr<MockDeviceDataFactory> device_data_factory(
new MockOrientationFactory()); new MockDeviceDataFactory());
MockOrientationFactory::SetCurInstance(orientation_factory.get()); MockDeviceDataFactory::SetCurInstance(device_data_factory.get());
Init(MockOrientationFactory::CreateDataFetcher); Init(MockDeviceDataFactory::CreateDataFetcher);
Orientation test_orientation; scoped_refptr<Orientation> test_orientation(new Orientation());
test_orientation.set_alpha(1); test_orientation->set_alpha(1);
test_orientation.set_beta(2); test_orientation->set_beta(2);
test_orientation.set_gamma(3); test_orientation->set_gamma(3);
test_orientation.set_absolute(true); test_orientation->set_absolute(true);
Orientation test_orientation2; scoped_refptr<Orientation> test_orientation2(new Orientation());
test_orientation2.set_alpha(4); test_orientation2->set_alpha(4);
test_orientation2.set_beta(5); test_orientation2->set_beta(5);
test_orientation2.set_gamma(6); test_orientation2->set_gamma(6);
test_orientation2.set_absolute(false); test_orientation2->set_absolute(false);
scoped_ptr<UpdateChecker> checker(new UpdateChecker(&pending_expectations_)); scoped_ptr<OrientationUpdateChecker> checker(
new OrientationUpdateChecker(&pending_expectations_));
checker->AddExpectation(test_orientation); checker->AddExpectation(test_orientation);
orientation_factory->SetOrientation(test_orientation); device_data_factory->SetDeviceData(test_orientation,
DeviceData::kTypeOrientation);
provider_->AddObserver(checker.get()); provider_->AddObserver(checker.get());
MessageLoop::current()->Run(); MessageLoop::current()->Run();
checker->AddExpectation(test_orientation2); checker->AddExpectation(test_orientation2);
orientation_factory->SetOrientation(test_orientation2); device_data_factory->SetDeviceData(test_orientation2,
DeviceData::kTypeOrientation);
MessageLoop::current()->Run(); MessageLoop::current()->Run();
MockOrientationFactory::SetCurInstance(NULL); MockDeviceDataFactory::SetCurInstance(NULL);
// Note that checker is not removed. This should not be a problem. // Note that checker is not removed. This should not be a problem.
} }
...@@ -330,83 +448,87 @@ TEST_F(DeviceOrientationProviderTest, MAYBE_ObserverNotRemoved) { ...@@ -330,83 +448,87 @@ TEST_F(DeviceOrientationProviderTest, MAYBE_ObserverNotRemoved) {
#define MAYBE_StartFailing StartFailing #define MAYBE_StartFailing StartFailing
#endif #endif
TEST_F(DeviceOrientationProviderTest, MAYBE_StartFailing) { TEST_F(DeviceOrientationProviderTest, MAYBE_StartFailing) {
scoped_refptr<MockOrientationFactory> orientation_factory( scoped_refptr<MockDeviceDataFactory> device_data_factory(
new MockOrientationFactory()); new MockDeviceDataFactory());
MockOrientationFactory::SetCurInstance(orientation_factory.get()); MockDeviceDataFactory::SetCurInstance(device_data_factory.get());
Init(MockOrientationFactory::CreateDataFetcher); Init(MockDeviceDataFactory::CreateDataFetcher);
Orientation test_orientation; scoped_refptr<Orientation> test_orientation(new Orientation());
test_orientation.set_alpha(1); test_orientation->set_alpha(1);
test_orientation.set_beta(2); test_orientation->set_beta(2);
test_orientation.set_gamma(3); test_orientation->set_gamma(3);
test_orientation.set_absolute(true); test_orientation->set_absolute(true);
scoped_ptr<UpdateChecker> checker_a(new UpdateChecker( scoped_ptr<OrientationUpdateChecker> checker_a(new OrientationUpdateChecker(
&pending_expectations_)); &pending_expectations_));
scoped_ptr<UpdateChecker> checker_b(new UpdateChecker( scoped_ptr<OrientationUpdateChecker> checker_b(new OrientationUpdateChecker(
&pending_expectations_)); &pending_expectations_));
orientation_factory->SetOrientation(test_orientation); device_data_factory->SetDeviceData(test_orientation,
DeviceData::kTypeOrientation);
checker_a->AddExpectation(test_orientation); checker_a->AddExpectation(test_orientation);
provider_->AddObserver(checker_a.get()); provider_->AddObserver(checker_a.get());
MessageLoop::current()->Run(); MessageLoop::current()->Run();
checker_a->AddExpectation(Orientation::Empty()); checker_a->AddExpectation(new Orientation());
orientation_factory->SetFailing(true); device_data_factory->SetFailing(true);
MessageLoop::current()->Run(); MessageLoop::current()->Run();
checker_b->AddExpectation(Orientation::Empty()); checker_b->AddExpectation(new Orientation());
provider_->AddObserver(checker_b.get()); provider_->AddObserver(checker_b.get());
MessageLoop::current()->Run(); MessageLoop::current()->Run();
provider_->RemoveObserver(checker_a.get()); provider_->RemoveObserver(checker_a.get());
provider_->RemoveObserver(checker_b.get()); provider_->RemoveObserver(checker_b.get());
MockOrientationFactory::SetCurInstance(NULL); MockDeviceDataFactory::SetCurInstance(NULL);
} }
TEST_F(DeviceOrientationProviderTest, StartStopStart) { TEST_F(DeviceOrientationProviderTest, StartStopStart) {
scoped_refptr<MockOrientationFactory> orientation_factory( scoped_refptr<MockDeviceDataFactory> device_data_factory(
new MockOrientationFactory()); new MockDeviceDataFactory());
MockOrientationFactory::SetCurInstance(orientation_factory.get()); MockDeviceDataFactory::SetCurInstance(device_data_factory.get());
Init(MockOrientationFactory::CreateDataFetcher); Init(MockDeviceDataFactory::CreateDataFetcher);
Orientation test_orientation; scoped_refptr<Orientation> test_orientation(new Orientation());
test_orientation.set_alpha(1); test_orientation->set_alpha(1);
test_orientation.set_beta(2); test_orientation->set_beta(2);
test_orientation.set_gamma(3); test_orientation->set_gamma(3);
test_orientation.set_absolute(true); test_orientation->set_absolute(true);
Orientation test_orientation2; scoped_refptr<Orientation> test_orientation2(new Orientation());
test_orientation2.set_alpha(4); test_orientation2->set_alpha(4);
test_orientation2.set_beta(5); test_orientation2->set_beta(5);
test_orientation2.set_gamma(6); test_orientation2->set_gamma(6);
test_orientation2.set_absolute(false); test_orientation2->set_absolute(false);
scoped_ptr<UpdateChecker> checker_a(new UpdateChecker( scoped_ptr<OrientationUpdateChecker> checker_a(new OrientationUpdateChecker(
&pending_expectations_)); &pending_expectations_));
scoped_ptr<UpdateChecker> checker_b(new UpdateChecker( scoped_ptr<OrientationUpdateChecker> checker_b(new OrientationUpdateChecker(
&pending_expectations_)); &pending_expectations_));
checker_a->AddExpectation(test_orientation); checker_a->AddExpectation(test_orientation);
orientation_factory->SetOrientation(test_orientation); device_data_factory->SetDeviceData(test_orientation,
DeviceData::kTypeOrientation);
provider_->AddObserver(checker_a.get()); provider_->AddObserver(checker_a.get());
MessageLoop::current()->Run(); MessageLoop::current()->Run();
provider_->RemoveObserver(checker_a.get()); // This stops the Provider. provider_->RemoveObserver(checker_a.get()); // This stops the Provider.
checker_b->AddExpectation(test_orientation2); checker_b->AddExpectation(test_orientation2);
orientation_factory->SetOrientation(test_orientation2); device_data_factory->SetDeviceData(test_orientation2,
DeviceData::kTypeOrientation);
provider_->AddObserver(checker_b.get()); provider_->AddObserver(checker_b.get());
MessageLoop::current()->Run(); MessageLoop::current()->Run();
provider_->RemoveObserver(checker_b.get()); provider_->RemoveObserver(checker_b.get());
MockOrientationFactory::SetCurInstance(NULL); MockDeviceDataFactory::SetCurInstance(NULL);
} }
TEST_F(DeviceOrientationProviderTest, SignificantlyDifferent) { // Tests that Orientation events only fire if the change is significant
scoped_refptr<MockOrientationFactory> orientation_factory( TEST_F(DeviceOrientationProviderTest, OrientationSignificantlyDifferent) {
new MockOrientationFactory()); scoped_refptr<MockDeviceDataFactory> device_data_factory(
MockOrientationFactory::SetCurInstance(orientation_factory.get()); new MockDeviceDataFactory());
Init(MockOrientationFactory::CreateDataFetcher); MockDeviceDataFactory::SetCurInstance(device_data_factory.get());
Init(MockDeviceDataFactory::CreateDataFetcher);
// Values that should be well below or above the implementation's // Values that should be well below or above the implementation's
// significane threshold. // significane threshold.
...@@ -414,49 +536,51 @@ TEST_F(DeviceOrientationProviderTest, SignificantlyDifferent) { ...@@ -414,49 +536,51 @@ TEST_F(DeviceOrientationProviderTest, SignificantlyDifferent) {
const double kSignificantDifference = 30; const double kSignificantDifference = 30;
const double kAlpha = 4, kBeta = 5, kGamma = 6; const double kAlpha = 4, kBeta = 5, kGamma = 6;
Orientation first_orientation; scoped_refptr<Orientation> first_orientation(new Orientation());
first_orientation.set_alpha(kAlpha); first_orientation->set_alpha(kAlpha);
first_orientation.set_beta(kBeta); first_orientation->set_beta(kBeta);
first_orientation.set_gamma(kGamma); first_orientation->set_gamma(kGamma);
first_orientation.set_absolute(true); first_orientation->set_absolute(true);
Orientation second_orientation; scoped_refptr<Orientation> second_orientation(new Orientation());
second_orientation.set_alpha(kAlpha + kInsignificantDifference); second_orientation->set_alpha(kAlpha + kInsignificantDifference);
second_orientation.set_beta(kBeta + kInsignificantDifference); second_orientation->set_beta(kBeta + kInsignificantDifference);
second_orientation.set_gamma(kGamma + kInsignificantDifference); second_orientation->set_gamma(kGamma + kInsignificantDifference);
second_orientation.set_absolute(false); second_orientation->set_absolute(false);
Orientation third_orientation; scoped_refptr<Orientation> third_orientation(new Orientation());
third_orientation.set_alpha(kAlpha + kSignificantDifference); third_orientation->set_alpha(kAlpha + kSignificantDifference);
third_orientation.set_beta(kBeta + kSignificantDifference); third_orientation->set_beta(kBeta + kSignificantDifference);
third_orientation.set_gamma(kGamma + kSignificantDifference); third_orientation->set_gamma(kGamma + kSignificantDifference);
// can't provide absolute // can't provide absolute
scoped_ptr<UpdateChecker> checker_a(new UpdateChecker( scoped_ptr<OrientationUpdateChecker> checker_a(new OrientationUpdateChecker(
&pending_expectations_)); &pending_expectations_));
scoped_ptr<UpdateChecker> checker_b(new UpdateChecker( scoped_ptr<OrientationUpdateChecker> checker_b(new OrientationUpdateChecker(
&pending_expectations_)); &pending_expectations_));
device_data_factory->SetDeviceData(first_orientation,
orientation_factory->SetOrientation(first_orientation); DeviceData::kTypeOrientation);
checker_a->AddExpectation(first_orientation); checker_a->AddExpectation(first_orientation);
provider_->AddObserver(checker_a.get()); provider_->AddObserver(checker_a.get());
MessageLoop::current()->Run(); MessageLoop::current()->Run();
// The observers should not see this insignificantly different orientation. // The observers should not see this insignificantly different orientation.
orientation_factory->SetOrientation(second_orientation); device_data_factory->SetDeviceData(second_orientation,
DeviceData::kTypeOrientation);
checker_b->AddExpectation(first_orientation); checker_b->AddExpectation(first_orientation);
provider_->AddObserver(checker_b.get()); provider_->AddObserver(checker_b.get());
MessageLoop::current()->Run(); MessageLoop::current()->Run();
orientation_factory->SetOrientation(third_orientation); device_data_factory->SetDeviceData(third_orientation,
DeviceData::kTypeOrientation);
checker_a->AddExpectation(third_orientation); checker_a->AddExpectation(third_orientation);
checker_b->AddExpectation(third_orientation); checker_b->AddExpectation(third_orientation);
MessageLoop::current()->Run(); MessageLoop::current()->Run();
provider_->RemoveObserver(checker_a.get()); provider_->RemoveObserver(checker_a.get());
provider_->RemoveObserver(checker_b.get()); provider_->RemoveObserver(checker_b.get());
MockOrientationFactory::SetCurInstance(NULL); MockDeviceDataFactory::SetCurInstance(NULL);
} }
} // namespace } // namespace
......
...@@ -281,9 +281,15 @@ ...@@ -281,9 +281,15 @@
'browser/device_orientation/data_fetcher.h', 'browser/device_orientation/data_fetcher.h',
'browser/device_orientation/data_fetcher_impl_android.cc', 'browser/device_orientation/data_fetcher_impl_android.cc',
'browser/device_orientation/data_fetcher_impl_android.h', 'browser/device_orientation/data_fetcher_impl_android.h',
'browser/device_orientation/orientation.h', 'browser/device_orientation/device_data.h',
'browser/device_orientation/message_filter.cc',
'browser/device_orientation/message_filter.h',
'browser/device_orientation/observer_delegate.cc',
'browser/device_orientation/observer_delegate.h',
'browser/device_orientation/orientation_message_filter.cc', 'browser/device_orientation/orientation_message_filter.cc',
'browser/device_orientation/orientation_message_filter.h', 'browser/device_orientation/orientation_message_filter.h',
'browser/device_orientation/orientation.cc',
'browser/device_orientation/orientation.h',
'browser/device_orientation/provider.cc', 'browser/device_orientation/provider.cc',
'browser/device_orientation/provider.h', 'browser/device_orientation/provider.h',
'browser/device_orientation/provider_impl.cc', 'browser/device_orientation/provider_impl.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment