Loading libs/input/input_flags.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -207,3 +207,10 @@ flag { description: "Allow user to enable key repeats or configure timeout before key repeat and key repeat delay rates." bug: "336585002" } flag { name: "rotary_input_telemetry" namespace: "wear_frameworks" description: "Enable telemetry for rotary input" bug: "370353565" } services/inputflinger/reader/Android.bp +4 −0 Original line number Diff line number Diff line Loading @@ -90,10 +90,14 @@ cc_defaults { "libstatslog", "libstatspull", "libutils", "libstatssocket", ], static_libs: [ "libchrome-gestures", "libui-types", "libexpresslog", "libtextclassifier_hash_static", "libstatslog_express", ], header_libs: [ "libbatteryservice_headers", Loading services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp +51 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ #include "RotaryEncoderInputMapper.h" #include <Counter.h> #include <com_android_input_flags.h> #include <utils/Timers.h> #include <optional> Loading @@ -27,14 +29,26 @@ namespace android { using android::expresslog::Counter; constexpr float kDefaultResolution = 0; constexpr float kDefaultScaleFactor = 1.0f; constexpr int32_t kDefaultMinRotationsToLog = 3; RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDeviceContext& deviceContext, const InputReaderConfiguration& readerConfig) : RotaryEncoderInputMapper(deviceContext, readerConfig, Counter::logIncrement /* telemetryLogCounter */) {} RotaryEncoderInputMapper::RotaryEncoderInputMapper( InputDeviceContext& deviceContext, const InputReaderConfiguration& readerConfig, std::function<void(const char*, int64_t)> telemetryLogCounter) : InputMapper(deviceContext, readerConfig), mSource(AINPUT_SOURCE_ROTARY_ENCODER), mScalingFactor(kDefaultScaleFactor), mOrientation(ui::ROTATION_0) {} mResolution(kDefaultResolution), mOrientation(ui::ROTATION_0), mTelemetryLogCounter(telemetryLogCounter) {} RotaryEncoderInputMapper::~RotaryEncoderInputMapper() {} Loading @@ -51,6 +65,7 @@ void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo& info) { if (!res.has_value()) { ALOGW("Rotary Encoder device configuration file didn't specify resolution!\n"); } mResolution = res.value_or(kDefaultResolution); std::optional<float> scalingFactor = config.getFloat("device.scalingFactor"); if (!scalingFactor.has_value()) { ALOGW("Rotary Encoder device configuration file didn't specify scaling factor," Loading @@ -59,7 +74,22 @@ void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo& info) { } mScalingFactor = scalingFactor.value_or(kDefaultScaleFactor); info.addMotionRange(AMOTION_EVENT_AXIS_SCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, res.value_or(0.0f) * mScalingFactor); mResolution * mScalingFactor); if (com::android::input::flags::rotary_input_telemetry()) { mMinRotationsToLog = config.getInt("rotary_encoder.min_rotations_to_log"); if (!mMinRotationsToLog.has_value()) { ALOGI("Rotary Encoder device configuration file didn't specify min log rotation."); } else if (*mMinRotationsToLog <= 0) { ALOGE("Rotary Encoder device configuration specified non-positive min log rotation " ": %d. Telemetry logging of rotations disabled.", *mMinRotationsToLog); mMinRotationsToLog = {}; } else { ALOGD("Rotary Encoder telemetry enabled. mMinRotationsToLog=%d", *mMinRotationsToLog); } } } } Loading Loading @@ -121,10 +151,29 @@ std::list<NotifyArgs> RotaryEncoderInputMapper::process(const RawEvent& rawEvent return out; } void RotaryEncoderInputMapper::logScroll(float scroll) { if (mResolution <= 0 || !mMinRotationsToLog) return; mUnloggedScrolls += fabs(scroll); // unitsPerRotation = (2 * PI * radians) * (units per radian (i.e. resolution)) const float unitsPerRotation = 2 * M_PI * mResolution; const float scrollsPerMinRotationsToLog = *mMinRotationsToLog * unitsPerRotation; const int32_t numMinRotationsToLog = static_cast<int32_t>(mUnloggedScrolls / scrollsPerMinRotationsToLog); mUnloggedScrolls = std::fmod(mUnloggedScrolls, scrollsPerMinRotationsToLog); if (numMinRotationsToLog) { mTelemetryLogCounter("input.value_rotary_input_device_full_rotation_count", numMinRotationsToLog * (*mMinRotationsToLog)); } } std::list<NotifyArgs> RotaryEncoderInputMapper::sync(nsecs_t when, nsecs_t readTime) { std::list<NotifyArgs> out; float scroll = mRotaryEncoderScrollAccumulator.getRelativeVWheel(); logScroll(scroll); if (mSlopController) { scroll = mSlopController->consumeEvent(when, scroll); } Loading services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h +26 −0 Original line number Diff line number Diff line Loading @@ -46,13 +46,39 @@ private: int32_t mSource; float mScalingFactor; /** Units per rotation, provided via the `device.res` IDC property. */ float mResolution; ui::Rotation mOrientation; /** * The minimum number of rotations to log for telemetry. * Provided via `rotary_encoder.min_rotations_to_log` IDC property. If no value is provided in * the IDC file, or if a non-positive value is provided, the telemetry will be disabled, and * this value is set to the empty optional. */ std::optional<int32_t> mMinRotationsToLog; /** * A function to log count for telemetry. * The char* is the logging key, and the int64_t is the value to log. * Abstracting the actual logging APIs via this function is helpful for simple unit testing. */ std::function<void(const char*, int64_t)> mTelemetryLogCounter; ui::LogicalDisplayId mDisplayId = ui::LogicalDisplayId::INVALID; std::unique_ptr<SlopController> mSlopController; /** Amount of raw scrolls (pre-slop) not yet logged for telemetry. */ float mUnloggedScrolls = 0; explicit RotaryEncoderInputMapper(InputDeviceContext& deviceContext, const InputReaderConfiguration& readerConfig); /** This is a test constructor that allows injecting the expresslog Counter logic. */ RotaryEncoderInputMapper(InputDeviceContext& deviceContext, const InputReaderConfiguration& readerConfig, std::function<void(const char*, int64_t)> expressLogCounter); [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime); /** Logs a given amount of scroll for telemetry. */ void logScroll(float scroll); }; } // namespace android services/inputflinger/tests/RotaryEncoderInputMapper_test.cpp +149 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include <android-base/logging.h> #include <android_companion_virtualdevice_flags.h> #include <com_android_input_flags.h> #include <flag_macros.h> #include <gtest/gtest.h> #include <input/DisplayViewport.h> #include <linux/input-event-codes.h> Loading Loading @@ -100,6 +102,15 @@ protected: EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_HWHEEL_HI_RES)) .WillRepeatedly(Return(false)); } std::map<const char*, int64_t> mTelemetryLogCounts; /** * A fake function for telemetry logging. * Records the log counts in the `mTelemetryLogCounts` map. */ std::function<void(const char*, int64_t)> mTelemetryLogCounter = [this](const char* key, int64_t value) { mTelemetryLogCounts[key] += value; }; }; TEST_F(RotaryEncoderInputMapperTest, ConfigureDisplayIdWithAssociatedViewport) { Loading Loading @@ -187,4 +198,142 @@ TEST_F(RotaryEncoderInputMapperTest, HighResScrollIgnoresRegularScroll) { WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), WithScroll(0.5f))))); } TEST_F_WITH_FLAGS(RotaryEncoderInputMapperTest, RotaryInputTelemetryFlagOff_NoRotationLogging, REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(com::android::input::flags, rotary_input_telemetry))) { mPropertyMap.addProperty("device.res", "3"); mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration, mTelemetryLogCounter); InputDeviceInfo info; mMapper->populateDeviceInfo(info); std::list<NotifyArgs> args; args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 70); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_EQ(mTelemetryLogCounts.find("input.value_rotary_input_device_full_rotation_count"), mTelemetryLogCounts.end()); } TEST_F_WITH_FLAGS(RotaryEncoderInputMapperTest, ZeroResolution_NoRotationLogging, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, rotary_input_telemetry))) { mPropertyMap.addProperty("device.res", "-3"); mPropertyMap.addProperty("rotary_encoder.min_rotations_to_log", "2"); mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration, mTelemetryLogCounter); InputDeviceInfo info; mMapper->populateDeviceInfo(info); std::list<NotifyArgs> args; args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 700); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_EQ(mTelemetryLogCounts.find("input.value_rotary_input_device_full_rotation_count"), mTelemetryLogCounts.end()); } TEST_F_WITH_FLAGS(RotaryEncoderInputMapperTest, NegativeMinLogRotation_NoRotationLogging, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, rotary_input_telemetry))) { mPropertyMap.addProperty("device.res", "3"); mPropertyMap.addProperty("rotary_encoder.min_rotations_to_log", "-2"); mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration, mTelemetryLogCounter); InputDeviceInfo info; mMapper->populateDeviceInfo(info); std::list<NotifyArgs> args; args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 700); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_EQ(mTelemetryLogCounts.find("input.value_rotary_input_device_full_rotation_count"), mTelemetryLogCounts.end()); } TEST_F_WITH_FLAGS(RotaryEncoderInputMapperTest, ZeroMinLogRotation_NoRotationLogging, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, rotary_input_telemetry))) { mPropertyMap.addProperty("device.res", "3"); mPropertyMap.addProperty("rotary_encoder.min_rotations_to_log", "0"); mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration, mTelemetryLogCounter); InputDeviceInfo info; mMapper->populateDeviceInfo(info); std::list<NotifyArgs> args; args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 700); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_EQ(mTelemetryLogCounts.find("input.value_rotary_input_device_full_rotation_count"), mTelemetryLogCounts.end()); } TEST_F_WITH_FLAGS(RotaryEncoderInputMapperTest, NoMinLogRotation_NoRotationLogging, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, rotary_input_telemetry))) { // 3 units per radian, 2 * M_PI * 3 = ~18.85 units per rotation. mPropertyMap.addProperty("device.res", "3"); mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration, mTelemetryLogCounter); InputDeviceInfo info; mMapper->populateDeviceInfo(info); std::list<NotifyArgs> args; args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 700); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_EQ(mTelemetryLogCounts.find("input.value_rotary_input_device_full_rotation_count"), mTelemetryLogCounts.end()); } TEST_F_WITH_FLAGS(RotaryEncoderInputMapperTest, RotationLogging, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, rotary_input_telemetry))) { // 3 units per radian, 2 * M_PI * 3 = ~18.85 units per rotation. // Multiples of `unitsPerRoation`, to easily follow the assertions below. // [18.85, 37.7, 56.55, 75.4, 94.25, 113.1, 131.95, 150.8] mPropertyMap.addProperty("device.res", "3"); mPropertyMap.addProperty("rotary_encoder.min_rotations_to_log", "2"); mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration, mTelemetryLogCounter); InputDeviceInfo info; mMapper->populateDeviceInfo(info); std::list<NotifyArgs> args; args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 15); // total scroll = 15 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_EQ(mTelemetryLogCounts.find("input.value_rotary_input_device_full_rotation_count"), mTelemetryLogCounts.end()); args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 13); // total scroll = 28 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); // Expect 0 since `min_rotations_to_log` = 2, and total scroll 28 only has 1 rotation. ASSERT_EQ(mTelemetryLogCounts.find("input.value_rotary_input_device_full_rotation_count"), mTelemetryLogCounts.end()); args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 10); // total scroll = 38 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); // Total scroll includes >= `min_rotations_to_log` (2), expect log. ASSERT_EQ(mTelemetryLogCounts["input.value_rotary_input_device_full_rotation_count"], 2); args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, -22); // total scroll = 60 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); // Expect no additional telemetry. Total rotation is 3, and total unlogged rotation is 1, which // is less than `min_rotations_to_log`. ASSERT_EQ(mTelemetryLogCounts["input.value_rotary_input_device_full_rotation_count"], 2); args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, -16); // total scroll = 76 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); // Total unlogged rotation >= `min_rotations_to_log` (2), so expect 2 more logged rotation. ASSERT_EQ(mTelemetryLogCounts["input.value_rotary_input_device_full_rotation_count"], 4); args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, -76); // total scroll = 152 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); // Total unlogged scroll >= 4*`min_rotations_to_log`. Expect *all* unlogged rotations to be // logged, even if that's more than multiple of `min_rotations_to_log`. ASSERT_EQ(mTelemetryLogCounts["input.value_rotary_input_device_full_rotation_count"], 8); } } // namespace android No newline at end of file Loading
libs/input/input_flags.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -207,3 +207,10 @@ flag { description: "Allow user to enable key repeats or configure timeout before key repeat and key repeat delay rates." bug: "336585002" } flag { name: "rotary_input_telemetry" namespace: "wear_frameworks" description: "Enable telemetry for rotary input" bug: "370353565" }
services/inputflinger/reader/Android.bp +4 −0 Original line number Diff line number Diff line Loading @@ -90,10 +90,14 @@ cc_defaults { "libstatslog", "libstatspull", "libutils", "libstatssocket", ], static_libs: [ "libchrome-gestures", "libui-types", "libexpresslog", "libtextclassifier_hash_static", "libstatslog_express", ], header_libs: [ "libbatteryservice_headers", Loading
services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp +51 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ #include "RotaryEncoderInputMapper.h" #include <Counter.h> #include <com_android_input_flags.h> #include <utils/Timers.h> #include <optional> Loading @@ -27,14 +29,26 @@ namespace android { using android::expresslog::Counter; constexpr float kDefaultResolution = 0; constexpr float kDefaultScaleFactor = 1.0f; constexpr int32_t kDefaultMinRotationsToLog = 3; RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDeviceContext& deviceContext, const InputReaderConfiguration& readerConfig) : RotaryEncoderInputMapper(deviceContext, readerConfig, Counter::logIncrement /* telemetryLogCounter */) {} RotaryEncoderInputMapper::RotaryEncoderInputMapper( InputDeviceContext& deviceContext, const InputReaderConfiguration& readerConfig, std::function<void(const char*, int64_t)> telemetryLogCounter) : InputMapper(deviceContext, readerConfig), mSource(AINPUT_SOURCE_ROTARY_ENCODER), mScalingFactor(kDefaultScaleFactor), mOrientation(ui::ROTATION_0) {} mResolution(kDefaultResolution), mOrientation(ui::ROTATION_0), mTelemetryLogCounter(telemetryLogCounter) {} RotaryEncoderInputMapper::~RotaryEncoderInputMapper() {} Loading @@ -51,6 +65,7 @@ void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo& info) { if (!res.has_value()) { ALOGW("Rotary Encoder device configuration file didn't specify resolution!\n"); } mResolution = res.value_or(kDefaultResolution); std::optional<float> scalingFactor = config.getFloat("device.scalingFactor"); if (!scalingFactor.has_value()) { ALOGW("Rotary Encoder device configuration file didn't specify scaling factor," Loading @@ -59,7 +74,22 @@ void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo& info) { } mScalingFactor = scalingFactor.value_or(kDefaultScaleFactor); info.addMotionRange(AMOTION_EVENT_AXIS_SCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, res.value_or(0.0f) * mScalingFactor); mResolution * mScalingFactor); if (com::android::input::flags::rotary_input_telemetry()) { mMinRotationsToLog = config.getInt("rotary_encoder.min_rotations_to_log"); if (!mMinRotationsToLog.has_value()) { ALOGI("Rotary Encoder device configuration file didn't specify min log rotation."); } else if (*mMinRotationsToLog <= 0) { ALOGE("Rotary Encoder device configuration specified non-positive min log rotation " ": %d. Telemetry logging of rotations disabled.", *mMinRotationsToLog); mMinRotationsToLog = {}; } else { ALOGD("Rotary Encoder telemetry enabled. mMinRotationsToLog=%d", *mMinRotationsToLog); } } } } Loading Loading @@ -121,10 +151,29 @@ std::list<NotifyArgs> RotaryEncoderInputMapper::process(const RawEvent& rawEvent return out; } void RotaryEncoderInputMapper::logScroll(float scroll) { if (mResolution <= 0 || !mMinRotationsToLog) return; mUnloggedScrolls += fabs(scroll); // unitsPerRotation = (2 * PI * radians) * (units per radian (i.e. resolution)) const float unitsPerRotation = 2 * M_PI * mResolution; const float scrollsPerMinRotationsToLog = *mMinRotationsToLog * unitsPerRotation; const int32_t numMinRotationsToLog = static_cast<int32_t>(mUnloggedScrolls / scrollsPerMinRotationsToLog); mUnloggedScrolls = std::fmod(mUnloggedScrolls, scrollsPerMinRotationsToLog); if (numMinRotationsToLog) { mTelemetryLogCounter("input.value_rotary_input_device_full_rotation_count", numMinRotationsToLog * (*mMinRotationsToLog)); } } std::list<NotifyArgs> RotaryEncoderInputMapper::sync(nsecs_t when, nsecs_t readTime) { std::list<NotifyArgs> out; float scroll = mRotaryEncoderScrollAccumulator.getRelativeVWheel(); logScroll(scroll); if (mSlopController) { scroll = mSlopController->consumeEvent(when, scroll); } Loading
services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h +26 −0 Original line number Diff line number Diff line Loading @@ -46,13 +46,39 @@ private: int32_t mSource; float mScalingFactor; /** Units per rotation, provided via the `device.res` IDC property. */ float mResolution; ui::Rotation mOrientation; /** * The minimum number of rotations to log for telemetry. * Provided via `rotary_encoder.min_rotations_to_log` IDC property. If no value is provided in * the IDC file, or if a non-positive value is provided, the telemetry will be disabled, and * this value is set to the empty optional. */ std::optional<int32_t> mMinRotationsToLog; /** * A function to log count for telemetry. * The char* is the logging key, and the int64_t is the value to log. * Abstracting the actual logging APIs via this function is helpful for simple unit testing. */ std::function<void(const char*, int64_t)> mTelemetryLogCounter; ui::LogicalDisplayId mDisplayId = ui::LogicalDisplayId::INVALID; std::unique_ptr<SlopController> mSlopController; /** Amount of raw scrolls (pre-slop) not yet logged for telemetry. */ float mUnloggedScrolls = 0; explicit RotaryEncoderInputMapper(InputDeviceContext& deviceContext, const InputReaderConfiguration& readerConfig); /** This is a test constructor that allows injecting the expresslog Counter logic. */ RotaryEncoderInputMapper(InputDeviceContext& deviceContext, const InputReaderConfiguration& readerConfig, std::function<void(const char*, int64_t)> expressLogCounter); [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime); /** Logs a given amount of scroll for telemetry. */ void logScroll(float scroll); }; } // namespace android
services/inputflinger/tests/RotaryEncoderInputMapper_test.cpp +149 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #include <android-base/logging.h> #include <android_companion_virtualdevice_flags.h> #include <com_android_input_flags.h> #include <flag_macros.h> #include <gtest/gtest.h> #include <input/DisplayViewport.h> #include <linux/input-event-codes.h> Loading Loading @@ -100,6 +102,15 @@ protected: EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_HWHEEL_HI_RES)) .WillRepeatedly(Return(false)); } std::map<const char*, int64_t> mTelemetryLogCounts; /** * A fake function for telemetry logging. * Records the log counts in the `mTelemetryLogCounts` map. */ std::function<void(const char*, int64_t)> mTelemetryLogCounter = [this](const char* key, int64_t value) { mTelemetryLogCounts[key] += value; }; }; TEST_F(RotaryEncoderInputMapperTest, ConfigureDisplayIdWithAssociatedViewport) { Loading Loading @@ -187,4 +198,142 @@ TEST_F(RotaryEncoderInputMapperTest, HighResScrollIgnoresRegularScroll) { WithMotionAction(AMOTION_EVENT_ACTION_SCROLL), WithScroll(0.5f))))); } TEST_F_WITH_FLAGS(RotaryEncoderInputMapperTest, RotaryInputTelemetryFlagOff_NoRotationLogging, REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(com::android::input::flags, rotary_input_telemetry))) { mPropertyMap.addProperty("device.res", "3"); mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration, mTelemetryLogCounter); InputDeviceInfo info; mMapper->populateDeviceInfo(info); std::list<NotifyArgs> args; args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 70); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_EQ(mTelemetryLogCounts.find("input.value_rotary_input_device_full_rotation_count"), mTelemetryLogCounts.end()); } TEST_F_WITH_FLAGS(RotaryEncoderInputMapperTest, ZeroResolution_NoRotationLogging, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, rotary_input_telemetry))) { mPropertyMap.addProperty("device.res", "-3"); mPropertyMap.addProperty("rotary_encoder.min_rotations_to_log", "2"); mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration, mTelemetryLogCounter); InputDeviceInfo info; mMapper->populateDeviceInfo(info); std::list<NotifyArgs> args; args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 700); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_EQ(mTelemetryLogCounts.find("input.value_rotary_input_device_full_rotation_count"), mTelemetryLogCounts.end()); } TEST_F_WITH_FLAGS(RotaryEncoderInputMapperTest, NegativeMinLogRotation_NoRotationLogging, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, rotary_input_telemetry))) { mPropertyMap.addProperty("device.res", "3"); mPropertyMap.addProperty("rotary_encoder.min_rotations_to_log", "-2"); mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration, mTelemetryLogCounter); InputDeviceInfo info; mMapper->populateDeviceInfo(info); std::list<NotifyArgs> args; args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 700); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_EQ(mTelemetryLogCounts.find("input.value_rotary_input_device_full_rotation_count"), mTelemetryLogCounts.end()); } TEST_F_WITH_FLAGS(RotaryEncoderInputMapperTest, ZeroMinLogRotation_NoRotationLogging, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, rotary_input_telemetry))) { mPropertyMap.addProperty("device.res", "3"); mPropertyMap.addProperty("rotary_encoder.min_rotations_to_log", "0"); mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration, mTelemetryLogCounter); InputDeviceInfo info; mMapper->populateDeviceInfo(info); std::list<NotifyArgs> args; args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 700); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_EQ(mTelemetryLogCounts.find("input.value_rotary_input_device_full_rotation_count"), mTelemetryLogCounts.end()); } TEST_F_WITH_FLAGS(RotaryEncoderInputMapperTest, NoMinLogRotation_NoRotationLogging, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, rotary_input_telemetry))) { // 3 units per radian, 2 * M_PI * 3 = ~18.85 units per rotation. mPropertyMap.addProperty("device.res", "3"); mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration, mTelemetryLogCounter); InputDeviceInfo info; mMapper->populateDeviceInfo(info); std::list<NotifyArgs> args; args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 700); args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_EQ(mTelemetryLogCounts.find("input.value_rotary_input_device_full_rotation_count"), mTelemetryLogCounts.end()); } TEST_F_WITH_FLAGS(RotaryEncoderInputMapperTest, RotationLogging, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags, rotary_input_telemetry))) { // 3 units per radian, 2 * M_PI * 3 = ~18.85 units per rotation. // Multiples of `unitsPerRoation`, to easily follow the assertions below. // [18.85, 37.7, 56.55, 75.4, 94.25, 113.1, 131.95, 150.8] mPropertyMap.addProperty("device.res", "3"); mPropertyMap.addProperty("rotary_encoder.min_rotations_to_log", "2"); mMapper = createInputMapper<RotaryEncoderInputMapper>(*mDeviceContext, mReaderConfiguration, mTelemetryLogCounter); InputDeviceInfo info; mMapper->populateDeviceInfo(info); std::list<NotifyArgs> args; args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 15); // total scroll = 15 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); ASSERT_EQ(mTelemetryLogCounts.find("input.value_rotary_input_device_full_rotation_count"), mTelemetryLogCounts.end()); args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 13); // total scroll = 28 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); // Expect 0 since `min_rotations_to_log` = 2, and total scroll 28 only has 1 rotation. ASSERT_EQ(mTelemetryLogCounts.find("input.value_rotary_input_device_full_rotation_count"), mTelemetryLogCounts.end()); args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, 10); // total scroll = 38 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); // Total scroll includes >= `min_rotations_to_log` (2), expect log. ASSERT_EQ(mTelemetryLogCounts["input.value_rotary_input_device_full_rotation_count"], 2); args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, -22); // total scroll = 60 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); // Expect no additional telemetry. Total rotation is 3, and total unlogged rotation is 1, which // is less than `min_rotations_to_log`. ASSERT_EQ(mTelemetryLogCounts["input.value_rotary_input_device_full_rotation_count"], 2); args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, -16); // total scroll = 76 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); // Total unlogged rotation >= `min_rotations_to_log` (2), so expect 2 more logged rotation. ASSERT_EQ(mTelemetryLogCounts["input.value_rotary_input_device_full_rotation_count"], 4); args += process(ARBITRARY_TIME, EV_REL, REL_WHEEL, -76); // total scroll = 152 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0); // Total unlogged scroll >= 4*`min_rotations_to_log`. Expect *all* unlogged rotations to be // logged, even if that's more than multiple of `min_rotations_to_log`. ASSERT_EQ(mTelemetryLogCounts["input.value_rotary_input_device_full_rotation_count"], 8); } } // namespace android No newline at end of file