2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include <linux/input.h>
25 #include <gtest/gtest.h>
27 #include <utils/StopWatch.h>
28 #include <utils/Timers.h>
30 #include "TestHelpers.h"
32 // # of milliseconds to fudge stopwatch measurements
33 #define TIMING_TOLERANCE_MS 25
34 #define NO_TIMEOUT (-1)
39 using namespace std::literals::chrono_literals;
41 using InputCbFunc = std::function<void(const std::shared_ptr<InputDeviceNode>&, InputEvent&, nsecs_t)>;
42 using DeviceCbFunc = std::function<void(const std::shared_ptr<InputDeviceNode>&)>;
44 static const InputCbFunc kNoopInputCb = [](const std::shared_ptr<InputDeviceNode>&, InputEvent&, nsecs_t){};
45 static const DeviceCbFunc kNoopDeviceCb = [](const std::shared_ptr<InputDeviceNode>&){};
47 class TestInputCallback : public InputCallbackInterface {
50 mInputCb(kNoopInputCb), mDeviceAddedCb(kNoopDeviceCb), mDeviceRemovedCb(kNoopDeviceCb) {}
51 virtual ~TestInputCallback() = default;
53 void setInputCallback(InputCbFunc cb) { mInputCb = cb; }
54 void setDeviceAddedCallback(DeviceCbFunc cb) { mDeviceAddedCb = cb; }
55 void setDeviceRemovedCallback(DeviceCbFunc cb) { mDeviceRemovedCb = cb; }
57 virtual void onInputEvent(const std::shared_ptr<InputDeviceNode>& node, InputEvent& event,
58 nsecs_t event_time) override {
59 mInputCb(node, event, event_time);
61 virtual void onDeviceAdded(const std::shared_ptr<InputDeviceNode>& node) override {
64 virtual void onDeviceRemoved(const std::shared_ptr<InputDeviceNode>& node) override {
65 mDeviceRemovedCb(node);
70 DeviceCbFunc mDeviceAddedCb;
71 DeviceCbFunc mDeviceRemovedCb;
74 class InputHubTest : public ::testing::Test {
76 virtual void SetUp() {
77 mCallback = std::make_shared<TestInputCallback>();
78 mInputHub = std::make_shared<InputHub>(mCallback);
81 std::shared_ptr<TestInputCallback> mCallback;
82 std::shared_ptr<InputHub> mInputHub;
85 TEST_F(InputHubTest, testWake) {
86 // Call wake() after 100ms.
87 auto f = delay_async(100ms, [&]() { EXPECT_EQ(OK, mInputHub->wake()); });
89 StopWatch stopWatch("poll");
90 EXPECT_EQ(OK, mInputHub->poll());
91 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
93 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
96 TEST_F(InputHubTest, DISABLED_testDeviceAdded) {
97 auto tempDir = std::make_shared<TempDir>();
99 // Expect that this callback will run and set handle and pathname.
100 mCallback->setDeviceAddedCallback(
101 [&](const std::shared_ptr<InputDeviceNode>& node) {
102 pathname = node->getPath();
105 ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
107 // Create a new file in tempDir after 100ms.
108 std::unique_ptr<TempFile> tempFile;
109 std::mutex tempFileMutex;
110 auto f = delay_async(100ms,
112 std::lock_guard<std::mutex> lock(tempFileMutex);
113 tempFile.reset(tempDir->newTempFile());
116 StopWatch stopWatch("poll");
117 EXPECT_EQ(OK, mInputHub->poll());
118 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
121 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
122 std::lock_guard<std::mutex> lock(tempFileMutex);
123 EXPECT_EQ(tempFile->getName(), pathname);
126 TEST_F(InputHubTest, DISABLED_testDeviceRemoved) {
127 // Create a temp dir and file. Save its name and handle (to be filled in
128 // once InputHub scans the dir).
129 auto tempDir = std::make_unique<TempDir>();
130 auto deviceFile = std::unique_ptr<TempFile>(tempDir->newTempFile());
131 std::string tempFileName(deviceFile->getName());
133 std::shared_ptr<InputDeviceNode> tempNode;
134 // Expect that these callbacks will run for the above device file.
135 mCallback->setDeviceAddedCallback(
136 [&](const std::shared_ptr<InputDeviceNode>& node) {
139 mCallback->setDeviceRemovedCallback(
140 [&](const std::shared_ptr<InputDeviceNode>& node) {
141 EXPECT_EQ(tempNode, node);
144 ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
145 // Ensure that tempDir was scanned to find the device.
146 ASSERT_TRUE(tempNode != nullptr);
148 auto f = delay_async(100ms, [&]() { deviceFile.reset(); });
150 StopWatch stopWatch("poll");
151 EXPECT_EQ(OK, mInputHub->poll());
152 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
154 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
157 TEST_F(InputHubTest, DISABLED_testInputEvent) {
158 // Create a temp dir and file. Save its name and handle (to be filled in
159 // once InputHub scans the dir.)
160 auto tempDir = std::make_unique<TempDir>();
161 auto deviceFile = std::unique_ptr<TempFile>(tempDir->newTempFile());
162 std::string tempFileName(deviceFile->getName());
164 // Send a key event corresponding to HOME.
165 struct input_event iev;
171 auto inputDelayMs = 100ms;
172 auto f = delay_async(inputDelayMs, [&] {
173 ssize_t nWrite = TEMP_FAILURE_RETRY(write(deviceFile->getFd(), &iev, sizeof(iev)));
175 ASSERT_EQ(static_cast<ssize_t>(sizeof(iev)), nWrite) << "could not write to "
176 << deviceFile->getFd() << ". errno: " << errno;
179 // Expect this callback to run when the input event is read.
180 nsecs_t expectedWhen = systemTime(CLOCK_MONOTONIC) + ms2ns(inputDelayMs.count());
181 mCallback->setInputCallback(
182 [&](const std::shared_ptr<InputDeviceNode>& node, InputEvent& event,
183 nsecs_t event_time) {
184 EXPECT_NEAR(expectedWhen, event_time, ms2ns(TIMING_TOLERANCE_MS));
185 EXPECT_EQ(s2ns(1), event.when);
186 EXPECT_EQ(tempFileName, node->getPath());
187 EXPECT_EQ(EV_KEY, event.type);
188 EXPECT_EQ(KEY_HOME, event.code);
189 EXPECT_EQ(0x01, event.value);
191 ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
193 StopWatch stopWatch("poll");
194 EXPECT_EQ(OK, mInputHub->poll());
195 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
197 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
200 TEST_F(InputHubTest, DISABLED_testCallbackOrder) {
201 // Create two "devices": one to receive input and the other to go away.
202 auto tempDir = std::make_unique<TempDir>();
203 auto deviceFile1 = std::unique_ptr<TempFile>(tempDir->newTempFile());
204 auto deviceFile2 = std::unique_ptr<TempFile>(tempDir->newTempFile());
205 std::string tempFileName(deviceFile2->getName());
207 bool inputCallbackFinished = false, deviceCallbackFinished = false;
209 // Setup the callback for input events. Should run before the device
211 mCallback->setInputCallback(
212 [&](const std::shared_ptr<InputDeviceNode>&, InputEvent&, nsecs_t) {
213 ASSERT_FALSE(deviceCallbackFinished);
214 inputCallbackFinished = true;
217 // Setup the callback for device removal. Should run after the input
219 mCallback->setDeviceRemovedCallback(
220 [&](const std::shared_ptr<InputDeviceNode>& node) {
221 ASSERT_TRUE(inputCallbackFinished)
222 << "input callback did not run before device changed callback";
223 // Make sure the correct device was removed.
224 EXPECT_EQ(tempFileName, node->getPath());
225 deviceCallbackFinished = true;
227 ASSERT_EQ(OK, mInputHub->registerDevicePath(tempDir->getName()));
229 auto f = delay_async(100ms,
231 // Delete the second device file first.
234 // Then inject an input event into the first device.
235 struct input_event iev;
241 ssize_t nWrite = TEMP_FAILURE_RETRY(write(deviceFile1->getFd(), &iev, sizeof(iev)));
243 ASSERT_EQ(static_cast<ssize_t>(sizeof(iev)), nWrite) << "could not write to "
244 << deviceFile1->getFd() << ". errno: " << errno;
247 StopWatch stopWatch("poll");
248 EXPECT_EQ(OK, mInputHub->poll());
249 int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
251 EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS);
252 EXPECT_TRUE(inputCallbackFinished);
253 EXPECT_TRUE(deviceCallbackFinished);
257 } // namespace android