1 /*
2 * Copyright 2022 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 "InputMapperTest.h"
18
19 #include <InputReaderBase.h>
20 #include <gtest/gtest.h>
21 #include <ui/Rotation.h>
22 #include <utils/Timers.h>
23
24 #include "NotifyArgs.h"
25
26 namespace android {
27
28 using testing::_;
29 using testing::NiceMock;
30 using testing::Return;
31 using testing::ReturnRef;
32
SetUp(int bus,bool isExternal)33 void InputMapperUnitTest::SetUp(int bus, bool isExternal) {
34 mFakePolicy = sp<FakeInputReaderPolicy>::make();
35
36 EXPECT_CALL(mMockInputReaderContext, getPolicy()).WillRepeatedly(Return(mFakePolicy.get()));
37
38 EXPECT_CALL(mMockInputReaderContext, getEventHub()).WillRepeatedly(Return(&mMockEventHub));
39
40 mIdentifier.name = "device";
41 mIdentifier.location = "USB1";
42 mIdentifier.bus = bus;
43 EXPECT_CALL(mMockEventHub, getDeviceIdentifier(EVENTHUB_ID))
44 .WillRepeatedly(Return(mIdentifier));
45 EXPECT_CALL(mMockEventHub, getConfiguration(EVENTHUB_ID)).WillRepeatedly([&](int32_t) {
46 return mPropertyMap;
47 });
48
49 mDevice =
50 std::make_unique<NiceMock<MockInputDevice>>(&mMockInputReaderContext, DEVICE_ID,
51 /*generation=*/2, mIdentifier, isExternal);
52 ON_CALL((*mDevice), getConfiguration).WillByDefault(ReturnRef(mPropertyMap));
53 mDeviceContext = std::make_unique<InputDeviceContext>(*mDevice, EVENTHUB_ID);
54 }
55
setupAxis(int axis,bool valid,int32_t min,int32_t max,int32_t resolution,int32_t flat,int32_t fuzz)56 void InputMapperUnitTest::setupAxis(int axis, bool valid, int32_t min, int32_t max,
57 int32_t resolution, int32_t flat, int32_t fuzz) {
58 EXPECT_CALL(mMockEventHub, getAbsoluteAxisInfo(EVENTHUB_ID, axis))
59 .WillRepeatedly(Return(valid ? std::optional<RawAbsoluteAxisInfo>{{
60 .minValue = min,
61 .maxValue = max,
62 .flat = flat,
63 .fuzz = fuzz,
64 .resolution = resolution,
65 }}
66 : std::nullopt));
67 }
68
expectScanCodes(bool present,std::set<int> scanCodes)69 void InputMapperUnitTest::expectScanCodes(bool present, std::set<int> scanCodes) {
70 for (const auto& scanCode : scanCodes) {
71 EXPECT_CALL(mMockEventHub, hasScanCode(EVENTHUB_ID, scanCode))
72 .WillRepeatedly(testing::Return(present));
73 }
74 }
75
setScanCodeState(KeyState state,std::set<int> scanCodes)76 void InputMapperUnitTest::setScanCodeState(KeyState state, std::set<int> scanCodes) {
77 for (const auto& scanCode : scanCodes) {
78 EXPECT_CALL(mMockEventHub, getScanCodeState(EVENTHUB_ID, scanCode))
79 .WillRepeatedly(testing::Return(static_cast<int>(state)));
80 }
81 }
82
setKeyCodeState(KeyState state,std::set<int> keyCodes)83 void InputMapperUnitTest::setKeyCodeState(KeyState state, std::set<int> keyCodes) {
84 for (const auto& keyCode : keyCodes) {
85 EXPECT_CALL(mMockEventHub, getKeyCodeState(EVENTHUB_ID, keyCode))
86 .WillRepeatedly(testing::Return(static_cast<int>(state)));
87 }
88 }
89
setSwitchState(int32_t state,std::set<int32_t> switchCodes)90 void InputMapperUnitTest::setSwitchState(int32_t state, std::set<int32_t> switchCodes) {
91 for (const auto& switchCode : switchCodes) {
92 EXPECT_CALL(mMockEventHub, getSwitchState(EVENTHUB_ID, switchCode))
93 .WillRepeatedly(testing::Return(static_cast<int>(state)));
94 }
95 }
96
process(int32_t type,int32_t code,int32_t value)97 std::list<NotifyArgs> InputMapperUnitTest::process(int32_t type, int32_t code, int32_t value) {
98 nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
99 return process(when, type, code, value);
100 }
101
process(nsecs_t when,int32_t type,int32_t code,int32_t value)102 std::list<NotifyArgs> InputMapperUnitTest::process(nsecs_t when, int32_t type, int32_t code,
103 int32_t value) {
104 return process(when, when, type, code, value);
105 }
106
process(nsecs_t when,nsecs_t readTime,int32_t type,int32_t code,int32_t value)107 std::list<NotifyArgs> InputMapperUnitTest::process(nsecs_t when, nsecs_t readTime, int32_t type,
108 int32_t code, int32_t value) {
109 RawEvent event;
110 event.when = when;
111 event.readTime = readTime;
112 event.deviceId = mMapper->getDeviceContext().getEventHubId();
113 event.type = type;
114 event.code = code;
115 event.value = value;
116 return mMapper->process(event);
117 }
118
119 const char* InputMapperTest::DEVICE_NAME = "device";
120 const char* InputMapperTest::DEVICE_LOCATION = "USB1";
121 const ftl::Flags<InputDeviceClass> InputMapperTest::DEVICE_CLASSES =
122 ftl::Flags<InputDeviceClass>(0); // not needed for current tests
123
SetUp(ftl::Flags<InputDeviceClass> classes,int bus)124 void InputMapperTest::SetUp(ftl::Flags<InputDeviceClass> classes, int bus) {
125 mFakeEventHub = std::make_unique<FakeEventHub>();
126 mFakePolicy = sp<FakeInputReaderPolicy>::make();
127 mFakeListener = std::make_unique<TestInputListener>();
128 mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy, *mFakeListener);
129 mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes, bus);
130 // Consume the device reset notification generated when adding a new device.
131 mFakeListener->assertNotifyDeviceResetWasCalled();
132 }
133
SetUp()134 void InputMapperTest::SetUp() {
135 SetUp(DEVICE_CLASSES);
136 }
137
TearDown()138 void InputMapperTest::TearDown() {
139 mFakeListener.reset();
140 mFakePolicy.clear();
141 }
142
addConfigurationProperty(const char * key,const char * value)143 void InputMapperTest::addConfigurationProperty(const char* key, const char* value) {
144 mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, key, value);
145 }
146
configureDevice(ConfigurationChanges changes)147 std::list<NotifyArgs> InputMapperTest::configureDevice(ConfigurationChanges changes) {
148 using namespace ftl::flag_operators;
149 if (!changes.any() ||
150 (changes.any(InputReaderConfiguration::Change::DISPLAY_INFO |
151 InputReaderConfiguration::Change::POINTER_CAPTURE |
152 InputReaderConfiguration::Change::DEVICE_TYPE))) {
153 mReader->requestRefreshConfiguration(changes);
154 mReader->loopOnce();
155 }
156 std::list<NotifyArgs> out =
157 mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes);
158 // Loop the reader to flush the input listener queue.
159 for (const NotifyArgs& args : out) {
160 mFakeListener->notify(args);
161 }
162 mReader->loopOnce();
163 return out;
164 }
165
newDevice(int32_t deviceId,const std::string & name,const std::string & location,int32_t eventHubId,ftl::Flags<InputDeviceClass> classes,int bus)166 std::shared_ptr<InputDevice> InputMapperTest::newDevice(int32_t deviceId, const std::string& name,
167 const std::string& location,
168 int32_t eventHubId,
169 ftl::Flags<InputDeviceClass> classes,
170 int bus) {
171 InputDeviceIdentifier identifier;
172 identifier.name = name;
173 identifier.location = location;
174 identifier.bus = bus;
175 std::shared_ptr<InputDevice> device =
176 std::make_shared<InputDevice>(mReader->getContext(), deviceId, DEVICE_GENERATION,
177 identifier);
178 mReader->pushNextDevice(device);
179 mFakeEventHub->addDevice(eventHubId, name, classes, bus);
180 mReader->loopOnce();
181 return device;
182 }
183
setDisplayInfoAndReconfigure(ui::LogicalDisplayId displayId,int32_t width,int32_t height,ui::Rotation orientation,const std::string & uniqueId,std::optional<uint8_t> physicalPort,ViewportType viewportType)184 void InputMapperTest::setDisplayInfoAndReconfigure(ui::LogicalDisplayId displayId, int32_t width,
185 int32_t height, ui::Rotation orientation,
186 const std::string& uniqueId,
187 std::optional<uint8_t> physicalPort,
188 ViewportType viewportType) {
189 DisplayViewport viewport =
190 createViewport(displayId, width, height, orientation, /* isActive= */ true, uniqueId,
191 physicalPort, viewportType);
192 mFakePolicy->addDisplayViewport(viewport);
193 configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO);
194 }
195
clearViewports()196 void InputMapperTest::clearViewports() {
197 mFakePolicy->clearViewports();
198 }
199
process(InputMapper & mapper,nsecs_t when,nsecs_t readTime,int32_t type,int32_t code,int32_t value)200 std::list<NotifyArgs> InputMapperTest::process(InputMapper& mapper, nsecs_t when, nsecs_t readTime,
201 int32_t type, int32_t code, int32_t value) {
202 RawEvent event;
203 event.when = when;
204 event.readTime = readTime;
205 event.deviceId = mapper.getDeviceContext().getEventHubId();
206 event.type = type;
207 event.code = code;
208 event.value = value;
209 std::list<NotifyArgs> processArgList = mapper.process(event);
210 for (const NotifyArgs& args : processArgList) {
211 mFakeListener->notify(args);
212 }
213 // Loop the reader to flush the input listener queue.
214 mReader->loopOnce();
215 return processArgList;
216 }
217
resetMapper(InputMapper & mapper,nsecs_t when)218 void InputMapperTest::resetMapper(InputMapper& mapper, nsecs_t when) {
219 const auto resetArgs = mapper.reset(when);
220 for (const auto args : resetArgs) {
221 mFakeListener->notify(args);
222 }
223 // Loop the reader to flush the input listener queue.
224 mReader->loopOnce();
225 }
226
handleTimeout(InputMapper & mapper,nsecs_t when)227 std::list<NotifyArgs> InputMapperTest::handleTimeout(InputMapper& mapper, nsecs_t when) {
228 std::list<NotifyArgs> generatedArgs = mapper.timeoutExpired(when);
229 for (const NotifyArgs& args : generatedArgs) {
230 mFakeListener->notify(args);
231 }
232 // Loop the reader to flush the input listener queue.
233 mReader->loopOnce();
234 return generatedArgs;
235 }
236
assertMotionRange(const InputDeviceInfo & info,int32_t axis,uint32_t source,float min,float max,float flat,float fuzz)237 void assertMotionRange(const InputDeviceInfo& info, int32_t axis, uint32_t source, float min,
238 float max, float flat, float fuzz) {
239 const InputDeviceInfo::MotionRange* range = info.getMotionRange(axis, source);
240 ASSERT_TRUE(range != nullptr) << "Axis: " << axis << " Source: " << source;
241 ASSERT_EQ(axis, range->axis) << "Axis: " << axis << " Source: " << source;
242 ASSERT_EQ(source, range->source) << "Axis: " << axis << " Source: " << source;
243 ASSERT_NEAR(min, range->min, EPSILON) << "Axis: " << axis << " Source: " << source;
244 ASSERT_NEAR(max, range->max, EPSILON) << "Axis: " << axis << " Source: " << source;
245 ASSERT_NEAR(flat, range->flat, EPSILON) << "Axis: " << axis << " Source: " << source;
246 ASSERT_NEAR(fuzz, range->fuzz, EPSILON) << "Axis: " << axis << " Source: " << source;
247 }
248
assertPointerCoords(const PointerCoords & coords,float x,float y,float pressure,float size,float touchMajor,float touchMinor,float toolMajor,float toolMinor,float orientation,float distance,float scaledAxisEpsilon)249 void assertPointerCoords(const PointerCoords& coords, float x, float y, float pressure, float size,
250 float touchMajor, float touchMinor, float toolMajor, float toolMinor,
251 float orientation, float distance, float scaledAxisEpsilon) {
252 ASSERT_NEAR(x, coords.getAxisValue(AMOTION_EVENT_AXIS_X), scaledAxisEpsilon);
253 ASSERT_NEAR(y, coords.getAxisValue(AMOTION_EVENT_AXIS_Y), scaledAxisEpsilon);
254 ASSERT_NEAR(pressure, coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), EPSILON);
255 ASSERT_NEAR(size, coords.getAxisValue(AMOTION_EVENT_AXIS_SIZE), EPSILON);
256 ASSERT_NEAR(touchMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), scaledAxisEpsilon);
257 ASSERT_NEAR(touchMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), scaledAxisEpsilon);
258 ASSERT_NEAR(toolMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), scaledAxisEpsilon);
259 ASSERT_NEAR(toolMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), scaledAxisEpsilon);
260 ASSERT_NEAR(orientation, coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), EPSILON);
261 ASSERT_NEAR(distance, coords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), EPSILON);
262 }
263
264 } // namespace android
265