1 /*
2  * Copyright (C) 2019 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 #define LOG_TAG "input_classifier_hal_test"
18 
19 #include <android-base/logging.h>
20 #include <android/hardware/input/classifier/1.0/IInputClassifier.h>
21 #include <android/hardware/input/common/1.0/types.h>
22 #include <gtest/gtest.h>
23 #include <hidl/GtestPrinter.h>
24 #include <hidl/ServiceManagement.h>
25 #include <input/InputDevice.h>
26 #include <unistd.h>
27 
28 using ::android::ReservedInputDeviceId;
29 using ::android::sp;
30 using ::android::hardware::Return;
31 using ::android::hardware::input::classifier::V1_0::IInputClassifier;
32 using ::android::hardware::input::common::V1_0::Action;
33 using ::android::hardware::input::common::V1_0::Axis;
34 using ::android::hardware::input::common::V1_0::Button;
35 using ::android::hardware::input::common::V1_0::EdgeFlag;
36 using ::android::hardware::input::common::V1_0::MotionEvent;
37 using ::android::hardware::input::common::V1_0::PointerCoords;
38 using ::android::hardware::input::common::V1_0::PointerProperties;
39 using ::android::hardware::input::common::V1_0::Source;
40 using ::android::hardware::input::common::V1_0::ToolType;
41 using ::android::hardware::input::common::V1_0::VideoFrame;
42 
getSimpleMotionEvent()43 static MotionEvent getSimpleMotionEvent() {
44     MotionEvent event;
45     event.action = Action::DOWN;
46     event.actionButton = Button::NONE;
47     event.actionIndex = 0;
48     event.buttonState = 0;
49     event.deviceId = 0;
50     event.deviceTimestamp = 0;
51     event.displayId = 1;
52     event.downTime = 2;
53     event.edgeFlags = 0;
54     event.eventTime = 3;
55     event.flags = 0;
56     event.frames = {};
57     event.metaState = 0;
58     event.policyFlags = 0;
59     event.source = Source::TOUCHSCREEN;
60     event.xPrecision = 0;
61     event.yPrecision = 0;
62 
63     PointerCoords coords;
64     coords.bits = Axis::X | Axis::Y;
65     coords.values = {1 /*X*/, 2 /*Y*/};
66     event.pointerCoords = {coords};
67 
68     PointerProperties properties;
69     properties.id = 0;
70     properties.toolType = ToolType::FINGER;
71     event.pointerProperties = {properties};
72 
73     return event;
74 }
75 
76 // The main test class for INPUT CLASSIFIER HIDL HAL 1.0.
77 class InputClassifierHidlTest_1_0 : public ::testing::TestWithParam<std::string> {
78   public:
SetUp()79     virtual void SetUp() override {
80         classifier = IInputClassifier::getService(GetParam());
81         ASSERT_NE(classifier, nullptr);
82     }
83 
TearDown()84     virtual void TearDown() override {}
85 
86     sp<IInputClassifier> classifier;
87 };
88 
89 /**
90  * Call resetDevice(..) for a few common device id values, and make sure that the HAL
91  * can handle the resets gracefully.
92  */
TEST_P(InputClassifierHidlTest_1_0,ResetDevice)93 TEST_P(InputClassifierHidlTest_1_0, ResetDevice) {
94     EXPECT_TRUE(classifier->resetDevice(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID).isOk());
95     EXPECT_TRUE(classifier->resetDevice(ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID).isOk());
96     EXPECT_TRUE(classifier->resetDevice(1).isOk());
97     EXPECT_TRUE(classifier->resetDevice(2).isOk());
98 }
99 
100 /**
101  * Call reset() on the HAL to ensure no fatal failure there.
102  */
TEST_P(InputClassifierHidlTest_1_0,ResetHal)103 TEST_P(InputClassifierHidlTest_1_0, ResetHal) {
104     EXPECT_TRUE(classifier->reset().isOk());
105 }
106 
107 /**
108  * Classify an event without any video frames.
109  */
TEST_P(InputClassifierHidlTest_1_0,Classify_NoVideoFrame)110 TEST_P(InputClassifierHidlTest_1_0, Classify_NoVideoFrame) {
111     // Create a MotionEvent that does not have any video data
112     MotionEvent event = getSimpleMotionEvent();
113 
114     EXPECT_TRUE(classifier->classify(event).isOk());
115     // We are not checking the actual classification here,
116     // because the HAL operation is highly device-specific.
117 
118     // Return HAL to a consistent state by doing a reset
119     classifier->reset();
120 }
121 
122 /**
123  * Classify an event with one video frame. Should be the most common scenario.
124  */
TEST_P(InputClassifierHidlTest_1_0,Classify_OneVideoFrame)125 TEST_P(InputClassifierHidlTest_1_0, Classify_OneVideoFrame) {
126     MotionEvent event = getSimpleMotionEvent();
127     VideoFrame frame;
128     frame.data = {1, 2, 3, 4};
129     frame.height = 2;
130     frame.width = 2;
131     frame.timestamp = event.eventTime;
132     event.frames = {frame};
133 
134     EXPECT_TRUE(classifier->classify(event).isOk());
135     // We are not checking the actual classification here,
136     // because the HAL operation is highly device-specific.
137 
138     // Return HAL to a consistent state by doing a reset
139     classifier->reset();
140 }
141 
142 /**
143  * Classify an event with 2 video frames. This could happen if there's slowness in the system,
144  * or if simply the video rate is somehow higher that the input event rate.
145  * The HAL should be able to handle events with more than 1 video frame.
146  *
147  * The frames should be in chronological order, but it is not guaranteed that they will have
148  * monotonically increasing timestamps. Still, we provide consistent timestamps here since that
149  * is the most realistic mode of operation.
150  */
TEST_P(InputClassifierHidlTest_1_0,Classify_TwoVideoFrames)151 TEST_P(InputClassifierHidlTest_1_0, Classify_TwoVideoFrames) {
152     MotionEvent event = getSimpleMotionEvent();
153     VideoFrame frame1;
154     frame1.data = {1, 2, 3, 4};
155     frame1.height = 2;
156     frame1.width = 2;
157     frame1.timestamp = event.eventTime;
158     VideoFrame frame2 = frame1;
159     frame2.data = {5, 5, 5, -1};
160     frame2.timestamp += 1;
161     event.frames = {frame1, frame2};
162 
163     EXPECT_TRUE(classifier->classify(event).isOk());
164     // We are not checking the actual classification here,
165     // because the HAL operation is highly device-specific.
166 
167     // Return HAL to a consistent state by doing a reset
168     classifier->reset();
169 }
170 
171 INSTANTIATE_TEST_SUITE_P(
172         PerInstance, InputClassifierHidlTest_1_0,
173         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IInputClassifier::descriptor)),
174         android::hardware::PrintInstanceNameToString);
175