| // Copyright 2017 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 <memory> |
| |
| #include "base/bind_helpers.h" |
| #include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/ref_counted.h" |
| #include "mojo/public/cpp/bindings/binding.h" |
| #include "services/device/device_service_test_base.h" |
| #include "services/device/generic_sensor/absolute_orientation_euler_angles_fusion_algorithm_using_accelerometer_and_magnetometer.h" |
| #include "services/device/generic_sensor/fake_platform_sensor_and_provider.h" |
| #include "services/device/generic_sensor/linear_acceleration_fusion_algorithm_using_accelerometer.h" |
| #include "services/device/generic_sensor/platform_sensor.h" |
| #include "services/device/generic_sensor/platform_sensor_fusion.h" |
| #include "services/device/generic_sensor/platform_sensor_provider.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using ::testing::_; |
| using ::testing::Invoke; |
| using ::testing::Return; |
| |
| namespace device { |
| |
| using mojom::SensorType; |
| |
| class PlatformSensorFusionTest : public DeviceServiceTestBase { |
| public: |
| PlatformSensorFusionTest() { |
| provider_ = std::make_unique<FakePlatformSensorProvider>(); |
| PlatformSensorProvider::SetProviderForTesting(provider_.get()); |
| } |
| |
| protected: |
| void AccelerometerCallback(scoped_refptr<PlatformSensor> sensor) { |
| accelerometer_callback_called_ = true; |
| accelerometer_ = static_cast<FakePlatformSensor*>(sensor.get()); |
| } |
| |
| void MagnetometerCallback(scoped_refptr<PlatformSensor> sensor) { |
| magnetometer_callback_called_ = true; |
| magnetometer_ = static_cast<FakePlatformSensor*>(sensor.get()); |
| } |
| |
| void PlatformSensorFusionCallback(scoped_refptr<PlatformSensor> sensor) { |
| platform_sensor_fusion_callback_called_ = true; |
| fusion_sensor_ = static_cast<PlatformSensorFusion*>(sensor.get()); |
| } |
| |
| void CreateAccelerometer() { |
| auto callback = base::Bind(&PlatformSensorFusionTest::AccelerometerCallback, |
| base::Unretained(this)); |
| provider_->CreateSensor(SensorType::ACCELEROMETER, callback); |
| EXPECT_TRUE(accelerometer_callback_called_); |
| EXPECT_TRUE(accelerometer_); |
| EXPECT_EQ(SensorType::ACCELEROMETER, accelerometer_->GetType()); |
| } |
| |
| void CreateMagnetometer() { |
| auto callback = base::Bind(&PlatformSensorFusionTest::MagnetometerCallback, |
| base::Unretained(this)); |
| provider_->CreateSensor(SensorType::MAGNETOMETER, callback); |
| EXPECT_TRUE(magnetometer_callback_called_); |
| EXPECT_TRUE(magnetometer_); |
| EXPECT_EQ(SensorType::MAGNETOMETER, magnetometer_->GetType()); |
| } |
| |
| void CreateLinearAccelerationFusionSensor() { |
| auto fusion_algorithm = |
| std::make_unique<LinearAccelerationFusionAlgorithmUsingAccelerometer>(); |
| CreateFusionSensor(std::move(fusion_algorithm)); |
| } |
| |
| void CreateAbsoluteOrientationEulerAnglesFusionSensor() { |
| auto fusion_algorithm = std::make_unique< |
| AbsoluteOrientationEulerAnglesFusionAlgorithmUsingAccelerometerAndMagnetometer>(); |
| CreateFusionSensor(std::move(fusion_algorithm)); |
| } |
| |
| void CreateFusionSensor( |
| std::unique_ptr<PlatformSensorFusionAlgorithm> fusion_algorithm) { |
| auto callback = |
| base::Bind(&PlatformSensorFusionTest::PlatformSensorFusionCallback, |
| base::Unretained(this)); |
| SensorType type = fusion_algorithm->fused_type(); |
| PlatformSensorFusion::Create(provider_->GetSensorReadingBuffer(type), |
| provider_.get(), std::move(fusion_algorithm), |
| callback); |
| EXPECT_TRUE(platform_sensor_fusion_callback_called_); |
| } |
| |
| std::unique_ptr<FakePlatformSensorProvider> provider_; |
| bool accelerometer_callback_called_ = false; |
| scoped_refptr<FakePlatformSensor> accelerometer_; |
| bool magnetometer_callback_called_ = false; |
| scoped_refptr<FakePlatformSensor> magnetometer_; |
| bool platform_sensor_fusion_callback_called_ = false; |
| scoped_refptr<PlatformSensorFusion> fusion_sensor_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(PlatformSensorFusionTest); |
| }; |
| |
| // The following code tests creating a fusion sensor that needs one source |
| // sensor. |
| |
| TEST_F(PlatformSensorFusionTest, SourceSensorAlreadyExists) { |
| EXPECT_FALSE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| CreateAccelerometer(); |
| // Now the source sensor already exists. |
| EXPECT_TRUE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| |
| CreateLinearAccelerationFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::LINEAR_ACCELERATION, fusion_sensor_->GetType()); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, SourceSensorWorksSeparately) { |
| CreateAccelerometer(); |
| EXPECT_TRUE(accelerometer_); |
| EXPECT_FALSE(accelerometer_->IsActiveForTesting()); |
| |
| auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>(); |
| accelerometer_->AddClient(client.get()); |
| accelerometer_->StartListening(client.get(), PlatformSensorConfiguration(10)); |
| EXPECT_TRUE(accelerometer_->IsActiveForTesting()); |
| |
| CreateLinearAccelerationFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::LINEAR_ACCELERATION, fusion_sensor_->GetType()); |
| EXPECT_FALSE(fusion_sensor_->IsActiveForTesting()); |
| |
| fusion_sensor_->AddClient(client.get()); |
| fusion_sensor_->StartListening(client.get(), PlatformSensorConfiguration(10)); |
| EXPECT_TRUE(fusion_sensor_->IsActiveForTesting()); |
| |
| fusion_sensor_->StopListening(client.get(), PlatformSensorConfiguration(10)); |
| EXPECT_FALSE(fusion_sensor_->IsActiveForTesting()); |
| |
| EXPECT_TRUE(accelerometer_->IsActiveForTesting()); |
| |
| accelerometer_->RemoveClient(client.get()); |
| EXPECT_FALSE(accelerometer_->IsActiveForTesting()); |
| |
| fusion_sensor_->RemoveClient(client.get()); |
| } |
| |
| namespace { |
| |
| void CheckConfigsCountForClient(const scoped_refptr<PlatformSensor>& sensor, |
| PlatformSensor::Client* client, |
| size_t expected_count) { |
| auto client_entry = sensor->GetConfigMapForTesting().find(client); |
| if (sensor->GetConfigMapForTesting().end() == client_entry) { |
| EXPECT_EQ(0u, expected_count); |
| return; |
| } |
| EXPECT_EQ(expected_count, client_entry->second.size()); |
| } |
| |
| } // namespace |
| |
| TEST_F(PlatformSensorFusionTest, SourceSensorDoesNotKeepOutdatedConfigs) { |
| CreateAccelerometer(); |
| EXPECT_TRUE(accelerometer_); |
| |
| CreateLinearAccelerationFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::LINEAR_ACCELERATION, fusion_sensor_->GetType()); |
| |
| auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>( |
| fusion_sensor_); |
| fusion_sensor_->StartListening(client.get(), PlatformSensorConfiguration(10)); |
| fusion_sensor_->StartListening(client.get(), PlatformSensorConfiguration(20)); |
| fusion_sensor_->StartListening(client.get(), PlatformSensorConfiguration(30)); |
| |
| EXPECT_EQ(1u, fusion_sensor_->GetConfigMapForTesting().size()); |
| EXPECT_EQ(1u, accelerometer_->GetConfigMapForTesting().size()); |
| |
| CheckConfigsCountForClient(fusion_sensor_, client.get(), 3u); |
| // Fusion sensor is a client for its sources, however it must keep only |
| // one active configuration for them at a time. |
| CheckConfigsCountForClient(accelerometer_, fusion_sensor_.get(), 1u); |
| |
| fusion_sensor_->StopListening(client.get(), PlatformSensorConfiguration(30)); |
| fusion_sensor_->StopListening(client.get(), PlatformSensorConfiguration(20)); |
| |
| CheckConfigsCountForClient(fusion_sensor_, client.get(), 1u); |
| CheckConfigsCountForClient(accelerometer_, fusion_sensor_.get(), 1u); |
| |
| fusion_sensor_->StopListening(client.get(), PlatformSensorConfiguration(10)); |
| |
| CheckConfigsCountForClient(fusion_sensor_, client.get(), 0u); |
| CheckConfigsCountForClient(accelerometer_, fusion_sensor_.get(), 0u); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, AllSourceSensorsStoppedOnSingleSourceFailure) { |
| CreateAccelerometer(); |
| EXPECT_TRUE(accelerometer_); |
| |
| CreateMagnetometer(); |
| EXPECT_TRUE(magnetometer_); |
| // Magnetometer will be started after Accelerometer for the given |
| // sensor fusion algorithm. |
| ON_CALL(*magnetometer_, StartSensor(_)).WillByDefault(Return(false)); |
| |
| CreateAbsoluteOrientationEulerAnglesFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES, |
| fusion_sensor_->GetType()); |
| |
| auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>( |
| fusion_sensor_); |
| fusion_sensor_->StartListening(client.get(), PlatformSensorConfiguration(10)); |
| |
| EXPECT_FALSE(fusion_sensor_->IsActiveForTesting()); |
| EXPECT_FALSE(accelerometer_->IsActiveForTesting()); |
| EXPECT_FALSE(magnetometer_->IsActiveForTesting()); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, SourceSensorNeedsToBeCreated) { |
| EXPECT_FALSE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| |
| CreateLinearAccelerationFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::LINEAR_ACCELERATION, fusion_sensor_->GetType()); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, SourceSensorIsNotAvailable) { |
| // Accelerometer is not available. |
| ON_CALL(*provider_, DoCreateSensorInternal(SensorType::ACCELEROMETER, _, _)) |
| .WillByDefault(Invoke( |
| [](mojom::SensorType, scoped_refptr<PlatformSensor>, |
| const FakePlatformSensorProvider::CreateSensorCallback& callback) { |
| callback.Run(nullptr); |
| })); |
| |
| CreateLinearAccelerationFusionSensor(); |
| EXPECT_FALSE(fusion_sensor_); |
| } |
| |
| // The following code tests creating a fusion sensor that needs two source |
| // sensors. |
| |
| TEST_F(PlatformSensorFusionTest, BothSourceSensorsAlreadyExist) { |
| EXPECT_FALSE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| CreateAccelerometer(); |
| EXPECT_TRUE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| |
| EXPECT_FALSE(provider_->GetSensor(SensorType::MAGNETOMETER)); |
| CreateMagnetometer(); |
| EXPECT_TRUE(provider_->GetSensor(SensorType::MAGNETOMETER)); |
| |
| CreateAbsoluteOrientationEulerAnglesFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES, |
| fusion_sensor_->GetType()); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, BothSourceSensorsNeedToBeCreated) { |
| EXPECT_FALSE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| EXPECT_FALSE(provider_->GetSensor(SensorType::MAGNETOMETER)); |
| |
| CreateAbsoluteOrientationEulerAnglesFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES, |
| fusion_sensor_->GetType()); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, BothSourceSensorsAreNotAvailable) { |
| // Failure. |
| ON_CALL(*provider_, DoCreateSensorInternal(_, _, _)) |
| .WillByDefault(Invoke( |
| [](mojom::SensorType, scoped_refptr<PlatformSensor>, |
| const FakePlatformSensorProvider::CreateSensorCallback& callback) { |
| callback.Run(nullptr); |
| })); |
| |
| CreateAbsoluteOrientationEulerAnglesFusionSensor(); |
| EXPECT_FALSE(fusion_sensor_); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, |
| OneSourceSensorAlreadyExistsTheOtherSourceSensorNeedsToBeCreated) { |
| EXPECT_FALSE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| CreateAccelerometer(); |
| EXPECT_TRUE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| EXPECT_FALSE(provider_->GetSensor(SensorType::MAGNETOMETER)); |
| |
| CreateAbsoluteOrientationEulerAnglesFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES, |
| fusion_sensor_->GetType()); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, |
| OneSourceSensorAlreadyExistsTheOtherSourceSensorIsNotAvailable) { |
| EXPECT_FALSE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| CreateAccelerometer(); |
| EXPECT_TRUE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| |
| // Magnetometer is not available. |
| ON_CALL(*provider_, DoCreateSensorInternal(SensorType::MAGNETOMETER, _, _)) |
| .WillByDefault(Invoke( |
| [](mojom::SensorType, scoped_refptr<PlatformSensor>, |
| const FakePlatformSensorProvider::CreateSensorCallback& callback) { |
| callback.Run(nullptr); |
| })); |
| |
| CreateAbsoluteOrientationEulerAnglesFusionSensor(); |
| EXPECT_FALSE(fusion_sensor_); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, |
| OneSourceSensorNeedsToBeCreatedTheOtherSourceSensorIsNotAvailable) { |
| EXPECT_FALSE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| // Magnetometer is not available. |
| ON_CALL(*provider_, DoCreateSensorInternal(SensorType::MAGNETOMETER, _, _)) |
| .WillByDefault(Invoke( |
| [](mojom::SensorType, scoped_refptr<PlatformSensor>, |
| const FakePlatformSensorProvider::CreateSensorCallback& callback) { |
| callback.Run(nullptr); |
| })); |
| |
| CreateAbsoluteOrientationEulerAnglesFusionSensor(); |
| EXPECT_FALSE(fusion_sensor_); |
| } |
| |
| TEST_F(PlatformSensorFusionTest, |
| FusionSensorMaximumSupportedFrequencyIsTheMaximumOfItsSourceSensors) { |
| EXPECT_FALSE(provider_->GetSensor(SensorType::ACCELEROMETER)); |
| CreateAccelerometer(); |
| scoped_refptr<PlatformSensor> accelerometer = |
| provider_->GetSensor(SensorType::ACCELEROMETER); |
| EXPECT_TRUE(accelerometer); |
| static_cast<FakePlatformSensor*>(accelerometer.get()) |
| ->set_maximum_supported_frequency(30.0); |
| |
| EXPECT_FALSE(provider_->GetSensor(SensorType::MAGNETOMETER)); |
| CreateMagnetometer(); |
| scoped_refptr<PlatformSensor> magnetometer = |
| provider_->GetSensor(SensorType::MAGNETOMETER); |
| EXPECT_TRUE(magnetometer); |
| static_cast<FakePlatformSensor*>(magnetometer.get()) |
| ->set_maximum_supported_frequency(20.0); |
| |
| CreateAbsoluteOrientationEulerAnglesFusionSensor(); |
| EXPECT_TRUE(fusion_sensor_); |
| EXPECT_EQ(SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES, |
| fusion_sensor_->GetType()); |
| EXPECT_EQ(30.0, fusion_sensor_->GetMaximumSupportedFrequency()); |
| auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>( |
| fusion_sensor_); |
| EXPECT_TRUE(fusion_sensor_->StartListening( |
| client.get(), PlatformSensorConfiguration(30.0))); |
| } |
| |
| } // namespace device |