/* * Copyright 2023 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 "../InputDeviceMetricsSource.h" #include #include #include #include #include #include #include #include namespace android { namespace { constexpr auto ALL_USAGE_SOURCES = ftl::enum_range(); constexpr uint32_t TOUCHSCREEN = AINPUT_SOURCE_TOUCHSCREEN; constexpr uint32_t STYLUS = AINPUT_SOURCE_STYLUS; constexpr uint32_t KEY_SOURCES = AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD | AINPUT_SOURCE_GAMEPAD; constexpr int32_t POINTER_1_DOWN = AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); } // namespace // --- InputDeviceMetricsSourceDeviceClassificationTest --- class DeviceClassificationFixture : public ::testing::Test, public ::testing::WithParamInterface {}; TEST_P(DeviceClassificationFixture, ValidClassifications) { const InputDeviceUsageSource usageSource = GetParam(); // Use a switch to ensure a test is added for all source classifications. switch (usageSource) { case InputDeviceUsageSource::UNKNOWN: { ASSERT_EQ(InputDeviceUsageSource::UNKNOWN, getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_NONE, KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, TOUCHSCREEN) .build())); std::set srcs{InputDeviceUsageSource::UNKNOWN}; ASSERT_EQ(srcs, getUsageSourcesForMotionArgs( MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_KEYBOARD) .pointer(PointerBuilder(/*id=*/1, ToolType::PALM) .x(100) .y(200)) .build())); break; } case InputDeviceUsageSource::BUTTONS: { ASSERT_EQ(InputDeviceUsageSource::BUTTONS, getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) .keyCode(AKEYCODE_STYLUS_BUTTON_TAIL) .build())); break; } case InputDeviceUsageSource::KEYBOARD: { ASSERT_EQ(InputDeviceUsageSource::KEYBOARD, getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_ALPHABETIC, KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) .build())); break; } case InputDeviceUsageSource::DPAD: { ASSERT_EQ(InputDeviceUsageSource::DPAD, getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) .keyCode(AKEYCODE_DPAD_CENTER) .build())); ASSERT_EQ(InputDeviceUsageSource::DPAD, getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_ALPHABETIC, KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) .keyCode(AKEYCODE_DPAD_CENTER) .build())); break; } case InputDeviceUsageSource::GAMEPAD: { ASSERT_EQ(InputDeviceUsageSource::GAMEPAD, getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) .keyCode(AKEYCODE_BUTTON_A) .build())); ASSERT_EQ(InputDeviceUsageSource::GAMEPAD, getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_ALPHABETIC, KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) .keyCode(AKEYCODE_BUTTON_A) .build())); break; } case InputDeviceUsageSource::JOYSTICK: { std::set srcs{InputDeviceUsageSource::JOYSTICK}; ASSERT_EQ(srcs, getUsageSourcesForMotionArgs( MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_JOYSTICK) .pointer(PointerBuilder(/*id=*/1, ToolType::UNKNOWN) .axis(AMOTION_EVENT_AXIS_GAS, 1.f)) .build())); break; } case InputDeviceUsageSource::MOUSE: { std::set srcs{InputDeviceUsageSource::MOUSE}; ASSERT_EQ(srcs, getUsageSourcesForMotionArgs( MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(/*id=*/1, ToolType::MOUSE) .x(100) .y(200)) .build())); break; } case InputDeviceUsageSource::MOUSE_CAPTURED: { std::set srcs{InputDeviceUsageSource::MOUSE_CAPTURED}; ASSERT_EQ(srcs, getUsageSourcesForMotionArgs( MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE_RELATIVE) .pointer(PointerBuilder(/*id=*/1, ToolType::MOUSE) .x(100) .y(200) .axis(AMOTION_EVENT_AXIS_RELATIVE_X, 100) .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, 200)) .build())); break; } case InputDeviceUsageSource::TOUCHPAD: { std::set srcs{InputDeviceUsageSource::TOUCHPAD}; ASSERT_EQ(srcs, getUsageSourcesForMotionArgs( MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER) .x(100) .y(200)) .build())); break; } case InputDeviceUsageSource::TOUCHPAD_CAPTURED: { std::set srcs{InputDeviceUsageSource::TOUCHPAD_CAPTURED}; ASSERT_EQ(srcs, getUsageSourcesForMotionArgs( MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHPAD) .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER) .x(100) .y(200) .axis(AMOTION_EVENT_AXIS_RELATIVE_X, 1) .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, 2)) .build())); break; } case InputDeviceUsageSource::ROTARY_ENCODER: { std::set srcs{InputDeviceUsageSource::ROTARY_ENCODER}; ASSERT_EQ(srcs, getUsageSourcesForMotionArgs( MotionArgsBuilder(AMOTION_EVENT_ACTION_SCROLL, AINPUT_SOURCE_ROTARY_ENCODER) .pointer(PointerBuilder(/*id=*/1, ToolType::UNKNOWN) .axis(AMOTION_EVENT_AXIS_SCROLL, 10) .axis(AMOTION_EVENT_AXIS_VSCROLL, 10)) .build())); break; } case InputDeviceUsageSource::STYLUS_DIRECT: { std::set srcs{InputDeviceUsageSource::STYLUS_DIRECT}; ASSERT_EQ(srcs, getUsageSourcesForMotionArgs( MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, STYLUS | TOUCHSCREEN) .pointer(PointerBuilder(/*id=*/1, ToolType::STYLUS) .x(100) .y(200)) .build())); break; } case InputDeviceUsageSource::STYLUS_INDIRECT: { std::set srcs{InputDeviceUsageSource::STYLUS_INDIRECT}; ASSERT_EQ(srcs, getUsageSourcesForMotionArgs( MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, STYLUS | TOUCHSCREEN | AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(/*id=*/1, ToolType::STYLUS) .x(100) .y(200)) .build())); break; } case InputDeviceUsageSource::STYLUS_FUSED: { std::set srcs{InputDeviceUsageSource::STYLUS_FUSED}; ASSERT_EQ(srcs, getUsageSourcesForMotionArgs( MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_BLUETOOTH_STYLUS | TOUCHSCREEN) .pointer(PointerBuilder(/*id=*/1, ToolType::STYLUS) .x(100) .y(200)) .build())); break; } case InputDeviceUsageSource::TOUCH_NAVIGATION: { std::set srcs{InputDeviceUsageSource::TOUCH_NAVIGATION}; ASSERT_EQ(srcs, getUsageSourcesForMotionArgs( MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCH_NAVIGATION) .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER) .x(100) .y(200)) .build())); break; } case InputDeviceUsageSource::TOUCHSCREEN: { std::set srcs{InputDeviceUsageSource::TOUCHSCREEN}; ASSERT_EQ(srcs, getUsageSourcesForMotionArgs( MotionArgsBuilder(POINTER_1_DOWN, TOUCHSCREEN) .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER) .x(100) .y(200)) .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER) .x(300) .y(400)) .build())); break; } case InputDeviceUsageSource::TRACKBALL: { std::set srcs{InputDeviceUsageSource::TRACKBALL}; ASSERT_EQ(srcs, getUsageSourcesForMotionArgs( MotionArgsBuilder(AMOTION_EVENT_ACTION_SCROLL, AINPUT_SOURCE_TRACKBALL) .pointer(PointerBuilder(/*id=*/1, ToolType::UNKNOWN) .axis(AMOTION_EVENT_AXIS_VSCROLL, 100) .axis(AMOTION_EVENT_AXIS_HSCROLL, 200)) .build())); break; } } } INSTANTIATE_TEST_SUITE_P(InputDeviceMetricsSourceDeviceClassificationTest, DeviceClassificationFixture, ::testing::ValuesIn(ALL_USAGE_SOURCES.begin(), ALL_USAGE_SOURCES.end()), [](const testing::TestParamInfo& testParamInfo) { return ftl::enum_string(testParamInfo.param); }); TEST(InputDeviceMetricsSourceDeviceClassificationTest, MixedClassificationTouchscreenStylus) { std::set srcs{InputDeviceUsageSource::TOUCHSCREEN, InputDeviceUsageSource::STYLUS_DIRECT}; ASSERT_EQ(srcs, getUsageSourcesForMotionArgs( MotionArgsBuilder(POINTER_1_DOWN, TOUCHSCREEN | STYLUS) .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(100).y(200)) .pointer(PointerBuilder(/*id=*/2, ToolType::STYLUS).x(300).y(400)) .build())); } } // namespace android