• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "TouchpadInputMapper.h"
18 
19 #include <android-base/logging.h>
20 #include <gtest/gtest.h>
21 #include <input/AccelerationCurve.h>
22 
23 #include <log/log.h>
24 #include <thread>
25 #include "InputMapperTest.h"
26 #include "InterfaceMocks.h"
27 #include "TestConstants.h"
28 #include "TestEventMatchers.h"
29 
30 #define TAG "TouchpadInputMapper_test"
31 
32 namespace android {
33 
34 using testing::Return;
35 using testing::VariantWith;
36 constexpr auto ACTION_DOWN = AMOTION_EVENT_ACTION_DOWN;
37 constexpr auto ACTION_UP = AMOTION_EVENT_ACTION_UP;
38 constexpr auto BUTTON_PRESS = AMOTION_EVENT_ACTION_BUTTON_PRESS;
39 constexpr auto BUTTON_RELEASE = AMOTION_EVENT_ACTION_BUTTON_RELEASE;
40 constexpr auto HOVER_MOVE = AMOTION_EVENT_ACTION_HOVER_MOVE;
41 constexpr auto HOVER_ENTER = AMOTION_EVENT_ACTION_HOVER_ENTER;
42 constexpr auto HOVER_EXIT = AMOTION_EVENT_ACTION_HOVER_EXIT;
43 constexpr ui::LogicalDisplayId DISPLAY_ID = ui::LogicalDisplayId::DEFAULT;
44 constexpr int32_t DISPLAY_WIDTH = 480;
45 constexpr int32_t DISPLAY_HEIGHT = 800;
46 constexpr std::optional<uint8_t> NO_PORT = std::nullopt; // no physical port is specified
47 
48 /**
49  * Unit tests for TouchpadInputMapper.
50  */
51 class TouchpadInputMapperTest : public InputMapperUnitTest {
52 protected:
SetUp()53     void SetUp() override {
54         InputMapperUnitTest::SetUp();
55 
56         // Present scan codes: BTN_TOUCH and BTN_TOOL_FINGER
57         expectScanCodes(/*present=*/true,
58                         {BTN_LEFT, BTN_RIGHT, BTN_TOOL_FINGER, BTN_TOOL_QUINTTAP, BTN_TOUCH,
59                          BTN_TOOL_DOUBLETAP, BTN_TOOL_TRIPLETAP, BTN_TOOL_QUADTAP});
60         // Missing scan codes that the mapper checks for.
61         expectScanCodes(/*present=*/false,
62                         {BTN_TOOL_PEN, BTN_TOOL_RUBBER, BTN_TOOL_BRUSH, BTN_TOOL_PENCIL,
63                          BTN_TOOL_AIRBRUSH});
64 
65         // Current scan code state - all keys are UP by default
66         setScanCodeState(KeyState::UP, {BTN_TOUCH,          BTN_STYLUS,
67                                         BTN_STYLUS2,        BTN_0,
68                                         BTN_TOOL_FINGER,    BTN_TOOL_PEN,
69                                         BTN_TOOL_RUBBER,    BTN_TOOL_BRUSH,
70                                         BTN_TOOL_PENCIL,    BTN_TOOL_AIRBRUSH,
71                                         BTN_TOOL_MOUSE,     BTN_TOOL_LENS,
72                                         BTN_TOOL_DOUBLETAP, BTN_TOOL_TRIPLETAP,
73                                         BTN_TOOL_QUADTAP,   BTN_TOOL_QUINTTAP,
74                                         BTN_LEFT,           BTN_RIGHT,
75                                         BTN_MIDDLE,         BTN_BACK,
76                                         BTN_SIDE,           BTN_FORWARD,
77                                         BTN_EXTRA,          BTN_TASK});
78 
79         setKeyCodeState(KeyState::UP,
80                         {AKEYCODE_STYLUS_BUTTON_PRIMARY, AKEYCODE_STYLUS_BUTTON_SECONDARY});
81 
82         // Key mappings
83         EXPECT_CALL(mMockEventHub,
84                     mapKey(EVENTHUB_ID, BTN_LEFT, /*usageCode=*/0, /*metaState=*/0, testing::_,
85                            testing::_, testing::_))
86                 .WillRepeatedly(Return(NAME_NOT_FOUND));
87 
88         // Input properties - only INPUT_PROP_BUTTONPAD
89         EXPECT_CALL(mMockEventHub, hasInputProperty(EVENTHUB_ID, INPUT_PROP_BUTTONPAD))
90                 .WillRepeatedly(Return(true));
91         EXPECT_CALL(mMockEventHub, hasInputProperty(EVENTHUB_ID, INPUT_PROP_SEMI_MT))
92                 .WillRepeatedly(Return(false));
93 
94         // Axes that the device has
95         setupAxis(ABS_MT_SLOT, /*valid=*/true, /*min=*/0, /*max=*/4, /*resolution=*/0);
96         setupAxis(ABS_MT_POSITION_X, /*valid=*/true, /*min=*/0, /*max=*/2000, /*resolution=*/24);
97         setupAxis(ABS_MT_POSITION_Y, /*valid=*/true, /*min=*/0, /*max=*/1000, /*resolution=*/24);
98         setupAxis(ABS_MT_PRESSURE, /*valid=*/true, /*min*/ 0, /*max=*/255, /*resolution=*/0);
99         // Axes that the device does not have
100         setupAxis(ABS_MT_ORIENTATION, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
101         setupAxis(ABS_MT_TOUCH_MAJOR, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
102         setupAxis(ABS_MT_TOUCH_MINOR, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
103         setupAxis(ABS_MT_WIDTH_MAJOR, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
104         setupAxis(ABS_MT_WIDTH_MINOR, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
105         setupAxis(ABS_MT_TRACKING_ID, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
106         setupAxis(ABS_MT_DISTANCE, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
107         setupAxis(ABS_MT_TOOL_TYPE, /*valid=*/false, /*min=*/0, /*max=*/0, /*resolution=*/0);
108 
109         EXPECT_CALL(mMockEventHub, getAbsoluteAxisValue(EVENTHUB_ID, ABS_MT_SLOT))
110                 .WillRepeatedly(Return(0));
111         EXPECT_CALL(mMockEventHub, getMtSlotValues(EVENTHUB_ID, testing::_, testing::_))
112                 .WillRepeatedly([]() -> base::Result<std::vector<int32_t>> {
113                     return base::ResultError("Axis not supported", NAME_NOT_FOUND);
114                 });
115         mMapper = createInputMapper<TouchpadInputMapper>(*mDeviceContext, mReaderConfiguration);
116     }
117 };
118 
119 /**
120  * Start moving the finger and then click the left touchpad button. Check whether HOVER_EXIT is
121  * generated when hovering stops. Currently, it is not.
122  * In the current implementation, HOVER_MOVE and ACTION_DOWN events are not sent out right away,
123  * but only after the button is released.
124  */
TEST_F(TouchpadInputMapperTest,HoverAndLeftButtonPress)125 TEST_F(TouchpadInputMapperTest, HoverAndLeftButtonPress) {
126     mFakePolicy->setDefaultPointerDisplayId(DISPLAY_ID);
127     DisplayViewport viewport =
128             createViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0,
129                            /*isActive=*/true, "local:0", NO_PORT, ViewportType::INTERNAL);
130     mFakePolicy->addDisplayViewport(viewport);
131     std::list<NotifyArgs> args;
132 
133     args += mMapper->reconfigure(systemTime(SYSTEM_TIME_MONOTONIC), mReaderConfiguration,
134                                  InputReaderConfiguration::Change::DISPLAY_INFO);
135     ASSERT_THAT(args, testing::IsEmpty());
136 
137     args += process(EV_ABS, ABS_MT_TRACKING_ID, 1);
138     args += process(EV_KEY, BTN_TOUCH, 1);
139     setScanCodeState(KeyState::DOWN, {BTN_TOOL_FINGER});
140     args += process(EV_KEY, BTN_TOOL_FINGER, 1);
141     args += process(EV_ABS, ABS_MT_POSITION_X, 50);
142     args += process(EV_ABS, ABS_MT_POSITION_Y, 50);
143     args += process(EV_ABS, ABS_MT_PRESSURE, 1);
144     args += process(EV_SYN, SYN_REPORT, 0);
145     ASSERT_THAT(args, testing::IsEmpty());
146 
147     // Without this sleep, the test fails.
148     // TODO(b/284133337): Figure out whether this can be removed
149     std::this_thread::sleep_for(std::chrono::milliseconds(20));
150 
151     args += process(EV_KEY, BTN_LEFT, 1);
152     setScanCodeState(KeyState::DOWN, {BTN_LEFT});
153     args += process(EV_SYN, SYN_REPORT, 0);
154 
155     args += process(EV_KEY, BTN_LEFT, 0);
156     setScanCodeState(KeyState::UP, {BTN_LEFT});
157     args += process(EV_SYN, SYN_REPORT, 0);
158     ASSERT_THAT(args,
159                 ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_ENTER)),
160                             VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)),
161                             VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_EXIT)),
162                             VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)),
163                             VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_PRESS)),
164                             VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)),
165                             VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)),
166                             VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_ENTER))));
167 
168     // Liftoff
169     args.clear();
170     args += process(EV_ABS, ABS_MT_PRESSURE, 0);
171     args += process(EV_ABS, ABS_MT_TRACKING_ID, -1);
172     args += process(EV_KEY, BTN_TOUCH, 0);
173     setScanCodeState(KeyState::UP, {BTN_TOOL_FINGER});
174     args += process(EV_KEY, BTN_TOOL_FINGER, 0);
175     args += process(EV_SYN, SYN_REPORT, 0);
176     ASSERT_THAT(args, testing::IsEmpty());
177 }
178 
TEST_F(TouchpadInputMapperTest,TouchpadHardwareState)179 TEST_F(TouchpadInputMapperTest, TouchpadHardwareState) {
180     mReaderConfiguration.shouldNotifyTouchpadHardwareState = true;
181     std::list<NotifyArgs> args =
182             mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
183                                  InputReaderConfiguration::Change::TOUCHPAD_SETTINGS);
184 
185     args += process(EV_ABS, ABS_MT_TRACKING_ID, 1);
186     args += process(EV_KEY, BTN_TOUCH, 1);
187     setScanCodeState(KeyState::DOWN, {BTN_TOOL_FINGER});
188     args += process(EV_KEY, BTN_TOOL_FINGER, 1);
189     args += process(EV_ABS, ABS_MT_POSITION_X, 50);
190     args += process(EV_ABS, ABS_MT_POSITION_Y, 50);
191     args += process(EV_ABS, ABS_MT_PRESSURE, 1);
192     args += process(EV_SYN, SYN_REPORT, 0);
193 
194     mFakePolicy->assertTouchpadHardwareStateNotified();
195 }
196 
TEST_F(TouchpadInputMapperTest,TouchpadAccelerationDisabled)197 TEST_F(TouchpadInputMapperTest, TouchpadAccelerationDisabled) {
198     mReaderConfiguration.touchpadAccelerationEnabled = false;
199     mReaderConfiguration.touchpadPointerSpeed = 3;
200 
201     std::list<NotifyArgs> args =
202             mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
203                                  InputReaderConfiguration::Change::TOUCHPAD_SETTINGS);
204     auto* touchpadMapper = static_cast<TouchpadInputMapper*>(mMapper.get());
205 
206     const auto accelCurvePropsDisabled =
207             touchpadMapper->getGesturePropertyForTesting("Pointer Accel Curve");
208     ASSERT_TRUE(accelCurvePropsDisabled.has_value());
209     std::vector<double> curveValuesDisabled = accelCurvePropsDisabled.value().getRealValues();
210     std::vector<AccelerationCurveSegment> curve =
211             createFlatAccelerationCurve(mReaderConfiguration.touchpadPointerSpeed);
212     double expectedBaseGain = curve[0].baseGain;
213     ASSERT_EQ(curveValuesDisabled[0], std::numeric_limits<double>::infinity());
214     ASSERT_EQ(curveValuesDisabled[1], 0);
215     ASSERT_NEAR(curveValuesDisabled[2], expectedBaseGain, EPSILON);
216     ASSERT_EQ(curveValuesDisabled[3], 0);
217 }
218 
TEST_F(TouchpadInputMapperTest,TouchpadAccelerationEnabled)219 TEST_F(TouchpadInputMapperTest, TouchpadAccelerationEnabled) {
220     // Enable touchpad acceleration.
221     mReaderConfiguration.touchpadAccelerationEnabled = true;
222     mReaderConfiguration.touchpadPointerSpeed = 3;
223 
224     std::list<NotifyArgs> args =
225             mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
226                                  InputReaderConfiguration::Change::TOUCHPAD_SETTINGS);
227     ASSERT_THAT(args, testing::IsEmpty());
228 
229     auto* touchpadMapper = static_cast<TouchpadInputMapper*>(mMapper.get());
230 
231     // Get the acceleration curve properties when acceleration is enabled.
232     const auto accelCurvePropsEnabled =
233             touchpadMapper->getGesturePropertyForTesting("Pointer Accel Curve");
234     ASSERT_TRUE(accelCurvePropsEnabled.has_value());
235 
236     // Get the curve values.
237     std::vector<double> curveValuesEnabled = accelCurvePropsEnabled.value().getRealValues();
238 
239     // Use createAccelerationCurveForPointerSensitivity to get expected curve segments.
240     std::vector<AccelerationCurveSegment> expectedCurveSegments =
241             createAccelerationCurveForPointerSensitivity(mReaderConfiguration.touchpadPointerSpeed);
242 
243     // Iterate through the segments and compare the values.
244     for (size_t i = 0; i < expectedCurveSegments.size(); ++i) {
245         // Check max speed.
246         if (std::isinf(expectedCurveSegments[i].maxPointerSpeedMmPerS)) {
247             ASSERT_TRUE(std::isinf(curveValuesEnabled[i * 4 + 0]));
248         } else {
249             ASSERT_NEAR(curveValuesEnabled[i * 4 + 0],
250                         expectedCurveSegments[i].maxPointerSpeedMmPerS, EPSILON);
251         }
252 
253         // Check that the x^2 term is zero.
254         ASSERT_NEAR(curveValuesEnabled[i * 4 + 1], 0, EPSILON);
255         ASSERT_NEAR(curveValuesEnabled[i * 4 + 2], expectedCurveSegments[i].baseGain, EPSILON);
256         ASSERT_NEAR(curveValuesEnabled[i * 4 + 3], expectedCurveSegments[i].reciprocal, EPSILON);
257     }
258 }
259 
260 } // namespace android
261