| /* |
| * Copyright 2024 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "SensorInputMapper.h" |
| |
| #include <cstdint> |
| #include <list> |
| #include <optional> |
| #include <utility> |
| #include <vector> |
| |
| #include <EventHub.h> |
| #include <NotifyArgs.h> |
| #include <ftl/enum.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include <input/Input.h> |
| #include <input/InputDevice.h> |
| #include <input/PrintTools.h> |
| #include <linux/input-event-codes.h> |
| |
| #include "InputMapperTest.h" |
| #include "TestEventMatchers.h" |
| |
| namespace android { |
| |
| using testing::AllOf; |
| using testing::ElementsAre; |
| using testing::Return; |
| using testing::VariantWith; |
| |
| namespace { |
| |
| constexpr int32_t ACCEL_RAW_MIN = -32768; |
| constexpr int32_t ACCEL_RAW_MAX = 32768; |
| constexpr int32_t ACCEL_RAW_FUZZ = 16; |
| constexpr int32_t ACCEL_RAW_FLAT = 0; |
| constexpr int32_t ACCEL_RAW_RESOLUTION = 8192; |
| |
| constexpr int32_t GYRO_RAW_MIN = -2097152; |
| constexpr int32_t GYRO_RAW_MAX = 2097152; |
| constexpr int32_t GYRO_RAW_FUZZ = 16; |
| constexpr int32_t GYRO_RAW_FLAT = 0; |
| constexpr int32_t GYRO_RAW_RESOLUTION = 1024; |
| |
| constexpr float GRAVITY_MS2_UNIT = 9.80665f; |
| constexpr float DEGREE_RADIAN_UNIT = 0.0174533f; |
| |
| } // namespace |
| |
| class SensorInputMapperTest : public InputMapperUnitTest { |
| protected: |
| void SetUp() override { |
| InputMapperUnitTest::SetUp(); |
| EXPECT_CALL(mMockEventHub, getDeviceClasses(EVENTHUB_ID)) |
| .WillRepeatedly(Return(InputDeviceClass::SENSOR)); |
| // The mapper requests info on all ABS axes, including ones which aren't actually used, so |
| // just return nullopt for all axes we don't explicitly set up. |
| EXPECT_CALL(mMockEventHub, getAbsoluteAxisInfo(EVENTHUB_ID, testing::_)) |
| .WillRepeatedly(Return(std::nullopt)); |
| } |
| |
| void setupSensor(int32_t absCode, InputDeviceSensorType type, int32_t sensorDataIndex) { |
| EXPECT_CALL(mMockEventHub, mapSensor(EVENTHUB_ID, absCode)) |
| .WillRepeatedly(Return(std::make_pair(type, sensorDataIndex))); |
| } |
| }; |
| |
| TEST_F(SensorInputMapperTest, GetSources) { |
| mMapper = createInputMapper<SensorInputMapper>(*mDeviceContext, |
| mFakePolicy->getReaderConfiguration()); |
| |
| ASSERT_EQ(static_cast<uint32_t>(AINPUT_SOURCE_SENSOR), mMapper->getSources()); |
| } |
| |
| TEST_F(SensorInputMapperTest, ProcessAccelerometerSensor) { |
| EXPECT_CALL(mMockEventHub, hasMscEvent(EVENTHUB_ID, MSC_TIMESTAMP)) |
| .WillRepeatedly(Return(true)); |
| setupSensor(ABS_X, InputDeviceSensorType::ACCELEROMETER, /*sensorDataIndex=*/0); |
| setupSensor(ABS_Y, InputDeviceSensorType::ACCELEROMETER, /*sensorDataIndex=*/1); |
| setupSensor(ABS_Z, InputDeviceSensorType::ACCELEROMETER, /*sensorDataIndex=*/2); |
| setupAxis(ABS_X, /*valid=*/true, ACCEL_RAW_MIN, ACCEL_RAW_MAX, ACCEL_RAW_RESOLUTION, |
| ACCEL_RAW_FLAT, ACCEL_RAW_FUZZ); |
| setupAxis(ABS_Y, /*valid=*/true, ACCEL_RAW_MIN, ACCEL_RAW_MAX, ACCEL_RAW_RESOLUTION, |
| ACCEL_RAW_FLAT, ACCEL_RAW_FUZZ); |
| setupAxis(ABS_Z, /*valid=*/true, ACCEL_RAW_MIN, ACCEL_RAW_MAX, ACCEL_RAW_RESOLUTION, |
| ACCEL_RAW_FLAT, ACCEL_RAW_FUZZ); |
| mPropertyMap.addProperty("sensor.accelerometer.reportingMode", "0"); |
| mPropertyMap.addProperty("sensor.accelerometer.maxDelay", "100000"); |
| mPropertyMap.addProperty("sensor.accelerometer.minDelay", "5000"); |
| mPropertyMap.addProperty("sensor.accelerometer.power", "1.5"); |
| mMapper = createInputMapper<SensorInputMapper>(*mDeviceContext, |
| mFakePolicy->getReaderConfiguration()); |
| |
| EXPECT_CALL(mMockEventHub, enableDevice(EVENTHUB_ID)); |
| ASSERT_TRUE(mMapper->enableSensor(InputDeviceSensorType::ACCELEROMETER, |
| std::chrono::microseconds(10000), |
| std::chrono::microseconds(0))); |
| std::list<NotifyArgs> args; |
| args += process(ARBITRARY_TIME, EV_ABS, ABS_X, 20000); |
| args += process(ARBITRARY_TIME, EV_ABS, ABS_Y, -20000); |
| args += process(ARBITRARY_TIME, EV_ABS, ABS_Z, 40000); |
| args += process(ARBITRARY_TIME, EV_MSC, MSC_TIMESTAMP, 1000); |
| args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); |
| |
| std::vector<float> values = {20000.0f / ACCEL_RAW_RESOLUTION * GRAVITY_MS2_UNIT, |
| -20000.0f / ACCEL_RAW_RESOLUTION * GRAVITY_MS2_UNIT, |
| 40000.0f / ACCEL_RAW_RESOLUTION * GRAVITY_MS2_UNIT}; |
| |
| ASSERT_EQ(args.size(), 1u); |
| const NotifySensorArgs& arg = std::get<NotifySensorArgs>(args.front()); |
| ASSERT_EQ(arg.source, AINPUT_SOURCE_SENSOR); |
| ASSERT_EQ(arg.deviceId, DEVICE_ID); |
| ASSERT_EQ(arg.sensorType, InputDeviceSensorType::ACCELEROMETER); |
| ASSERT_EQ(arg.accuracy, InputDeviceSensorAccuracy::HIGH); |
| ASSERT_EQ(arg.hwTimestamp, ARBITRARY_TIME); |
| ASSERT_EQ(arg.values, values); |
| mMapper->flushSensor(InputDeviceSensorType::ACCELEROMETER); |
| } |
| |
| TEST_F(SensorInputMapperTest, ProcessGyroscopeSensor) { |
| EXPECT_CALL(mMockEventHub, hasMscEvent(EVENTHUB_ID, MSC_TIMESTAMP)) |
| .WillRepeatedly(Return(true)); |
| setupSensor(ABS_RX, InputDeviceSensorType::GYROSCOPE, /*sensorDataIndex=*/0); |
| setupSensor(ABS_RY, InputDeviceSensorType::GYROSCOPE, /*sensorDataIndex=*/1); |
| setupSensor(ABS_RZ, InputDeviceSensorType::GYROSCOPE, /*sensorDataIndex=*/2); |
| setupAxis(ABS_RX, /*valid=*/true, GYRO_RAW_MIN, GYRO_RAW_MAX, GYRO_RAW_RESOLUTION, |
| GYRO_RAW_FLAT, GYRO_RAW_FUZZ); |
| setupAxis(ABS_RY, /*valid=*/true, GYRO_RAW_MIN, GYRO_RAW_MAX, GYRO_RAW_RESOLUTION, |
| GYRO_RAW_FLAT, GYRO_RAW_FUZZ); |
| setupAxis(ABS_RZ, /*valid=*/true, GYRO_RAW_MIN, GYRO_RAW_MAX, GYRO_RAW_RESOLUTION, |
| GYRO_RAW_FLAT, GYRO_RAW_FUZZ); |
| mPropertyMap.addProperty("sensor.gyroscope.reportingMode", "0"); |
| mPropertyMap.addProperty("sensor.gyroscope.maxDelay", "100000"); |
| mPropertyMap.addProperty("sensor.gyroscope.minDelay", "5000"); |
| mPropertyMap.addProperty("sensor.gyroscope.power", "0.8"); |
| mMapper = createInputMapper<SensorInputMapper>(*mDeviceContext, |
| mFakePolicy->getReaderConfiguration()); |
| |
| EXPECT_CALL(mMockEventHub, enableDevice(EVENTHUB_ID)); |
| ASSERT_TRUE(mMapper->enableSensor(InputDeviceSensorType::GYROSCOPE, |
| std::chrono::microseconds(10000), |
| std::chrono::microseconds(0))); |
| std::list<NotifyArgs> args; |
| args += process(ARBITRARY_TIME, EV_ABS, ABS_RX, 20000); |
| args += process(ARBITRARY_TIME, EV_ABS, ABS_RY, -20000); |
| args += process(ARBITRARY_TIME, EV_ABS, ABS_RZ, 40000); |
| args += process(ARBITRARY_TIME, EV_MSC, MSC_TIMESTAMP, 1000); |
| args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); |
| |
| std::vector<float> values = {20000.0f / GYRO_RAW_RESOLUTION * DEGREE_RADIAN_UNIT, |
| -20000.0f / GYRO_RAW_RESOLUTION * DEGREE_RADIAN_UNIT, |
| 40000.0f / GYRO_RAW_RESOLUTION * DEGREE_RADIAN_UNIT}; |
| |
| ASSERT_EQ(args.size(), 1u); |
| const NotifySensorArgs& arg = std::get<NotifySensorArgs>(args.front()); |
| ASSERT_EQ(arg.source, AINPUT_SOURCE_SENSOR); |
| ASSERT_EQ(arg.deviceId, DEVICE_ID); |
| ASSERT_EQ(arg.sensorType, InputDeviceSensorType::GYROSCOPE); |
| ASSERT_EQ(arg.accuracy, InputDeviceSensorAccuracy::HIGH); |
| ASSERT_EQ(arg.hwTimestamp, ARBITRARY_TIME); |
| ASSERT_EQ(arg.values, values); |
| mMapper->flushSensor(InputDeviceSensorType::GYROSCOPE); |
| } |
| |
| } // namespace android |