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 #include "../InputClassifier.h"
18 #include <gtest/gtest.h>
19 #include <gui/constants.h>
20 
21 #include "TestInputListener.h"
22 
23 #include <android/hardware/input/classifier/1.0/IInputClassifier.h>
24 
25 using namespace android::hardware::input;
26 using android::hardware::Return;
27 using android::hardware::Void;
28 using android::hardware::input::common::V1_0::Classification;
29 
30 namespace android {
31 
32 // --- InputClassifierTest ---
33 
generateBasicMotionArgs()34 static NotifyMotionArgs generateBasicMotionArgs() {
35     // Create a basic motion event for testing
36     PointerProperties properties;
37     properties.id = 0;
38     properties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
39 
40     PointerCoords coords;
41     coords.clear();
42     coords.setAxisValue(AMOTION_EVENT_AXIS_X, 1);
43     coords.setAxisValue(AMOTION_EVENT_AXIS_Y, 1);
44     static constexpr nsecs_t downTime = 2;
45     NotifyMotionArgs motionArgs(1 /*sequenceNum*/, downTime /*eventTime*/, 2 /*readTime*/,
46                                 3 /*deviceId*/, AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT,
47                                 4 /*policyFlags*/, AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/,
48                                 0 /*flags*/, AMETA_NONE, 0 /*buttonState*/,
49                                 MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
50                                 1 /*pointerCount*/, &properties, &coords, 0 /*xPrecision*/,
51                                 0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION,
52                                 AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime,
53                                 {} /*videoFrames*/);
54     return motionArgs;
55 }
56 
57 class InputClassifierTest : public testing::Test {
58 protected:
59     sp<InputClassifierInterface> mClassifier;
60     sp<TestInputListener> mTestListener;
61 
SetUp()62     virtual void SetUp() override {
63         mTestListener = new TestInputListener();
64         mClassifier = new InputClassifier(mTestListener);
65     }
66 
TearDown()67     virtual void TearDown() override {
68         mClassifier.clear();
69         mTestListener.clear();
70     }
71 };
72 
73 /**
74  * Create a basic configuration change and send it to input classifier.
75  * Expect that the event is received by the next input stage, unmodified.
76  */
TEST_F(InputClassifierTest,SendToNextStage_NotifyConfigurationChangedArgs)77 TEST_F(InputClassifierTest, SendToNextStage_NotifyConfigurationChangedArgs) {
78     // Create a basic configuration change and send to classifier
79     NotifyConfigurationChangedArgs args(1/*sequenceNum*/, 2/*eventTime*/);
80 
81     mClassifier->notifyConfigurationChanged(&args);
82     NotifyConfigurationChangedArgs outArgs;
83     ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled(&outArgs));
84     ASSERT_EQ(args, outArgs);
85 }
86 
TEST_F(InputClassifierTest,SendToNextStage_NotifyKeyArgs)87 TEST_F(InputClassifierTest, SendToNextStage_NotifyKeyArgs) {
88     // Create a basic key event and send to classifier
89     NotifyKeyArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 21 /*readTime*/, 3 /*deviceId*/,
90                        AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_DEFAULT, 0 /*policyFlags*/,
91                        AKEY_EVENT_ACTION_DOWN, 4 /*flags*/, AKEYCODE_HOME, 5 /*scanCode*/,
92                        AMETA_NONE, 6 /*downTime*/);
93 
94     mClassifier->notifyKey(&args);
95     NotifyKeyArgs outArgs;
96     ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(&outArgs));
97     ASSERT_EQ(args, outArgs);
98 }
99 
100 
101 /**
102  * Create a basic motion event and send it to input classifier.
103  * Expect that the event is received by the next input stage, unmodified.
104  */
TEST_F(InputClassifierTest,SendToNextStage_NotifyMotionArgs)105 TEST_F(InputClassifierTest, SendToNextStage_NotifyMotionArgs) {
106     NotifyMotionArgs motionArgs = generateBasicMotionArgs();
107     mClassifier->notifyMotion(&motionArgs);
108     NotifyMotionArgs args;
109     ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
110     ASSERT_EQ(motionArgs, args);
111 }
112 
113 /**
114  * Create a basic switch event and send it to input classifier.
115  * Expect that the event is received by the next input stage, unmodified.
116  */
TEST_F(InputClassifierTest,SendToNextStage_NotifySwitchArgs)117 TEST_F(InputClassifierTest, SendToNextStage_NotifySwitchArgs) {
118     NotifySwitchArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*policyFlags*/, 4/*switchValues*/,
119             5/*switchMask*/);
120 
121     mClassifier->notifySwitch(&args);
122     NotifySwitchArgs outArgs;
123     ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifySwitchWasCalled(&outArgs));
124     ASSERT_EQ(args, outArgs);
125 }
126 
127 /**
128  * Create a basic device reset event and send it to input classifier.
129  * Expect that the event is received by the next input stage, unmodified.
130  */
TEST_F(InputClassifierTest,SendToNextStage_NotifyDeviceResetArgs)131 TEST_F(InputClassifierTest, SendToNextStage_NotifyDeviceResetArgs) {
132     NotifyDeviceResetArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*deviceId*/);
133 
134     mClassifier->notifyDeviceReset(&args);
135     NotifyDeviceResetArgs outArgs;
136     ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyDeviceResetWasCalled(&outArgs));
137     ASSERT_EQ(args, outArgs);
138 }
139 
TEST_F(InputClassifierTest,SetMotionClassifier_Enabled)140 TEST_F(InputClassifierTest, SetMotionClassifier_Enabled) {
141     mClassifier->setMotionClassifierEnabled(true);
142 }
143 
TEST_F(InputClassifierTest,SetMotionClassifier_Disabled)144 TEST_F(InputClassifierTest, SetMotionClassifier_Disabled) {
145     mClassifier->setMotionClassifierEnabled(false);
146 }
147 
148 /**
149  * Try to break it by calling setMotionClassifierEnabled multiple times.
150  */
TEST_F(InputClassifierTest,SetMotionClassifier_Multiple)151 TEST_F(InputClassifierTest, SetMotionClassifier_Multiple) {
152     mClassifier->setMotionClassifierEnabled(true);
153     mClassifier->setMotionClassifierEnabled(true);
154     mClassifier->setMotionClassifierEnabled(true);
155     mClassifier->setMotionClassifierEnabled(false);
156     mClassifier->setMotionClassifierEnabled(false);
157     mClassifier->setMotionClassifierEnabled(true);
158     mClassifier->setMotionClassifierEnabled(true);
159     mClassifier->setMotionClassifierEnabled(true);
160 }
161 
162 /**
163  * A minimal implementation of IInputClassifier.
164  */
165 struct TestHal : public android::hardware::input::classifier::V1_0::IInputClassifier {
classifyandroid::TestHal166     Return<Classification> classify(
167             const android::hardware::input::common::V1_0::MotionEvent& event) override {
168         return Classification::NONE;
169     };
resetandroid::TestHal170     Return<void> reset() override { return Void(); };
resetDeviceandroid::TestHal171     Return<void> resetDevice(int32_t deviceId) override { return Void(); };
172 };
173 
174 /**
175  * An entity that will be subscribed to the HAL death.
176  */
177 class TestDeathRecipient : public android::hardware::hidl_death_recipient {
178 public:
serviceDied(uint64_t cookie,const wp<android::hidl::base::V1_0::IBase> & who)179     virtual void serviceDied(uint64_t cookie,
180                              const wp<android::hidl::base::V1_0::IBase>& who) override{};
181 };
182 
183 // --- MotionClassifierTest ---
184 
185 class MotionClassifierTest : public testing::Test {
186 protected:
187     std::unique_ptr<MotionClassifierInterface> mMotionClassifier;
188 
SetUp()189     virtual void SetUp() override {
190         mMotionClassifier = MotionClassifier::create(new TestDeathRecipient());
191         if (mMotionClassifier == nullptr) {
192             // If the device running this test does not have IInputClassifier service,
193             // use the test HAL instead.
194             // Using 'new' to access non-public constructor
195             mMotionClassifier =
196                     std::unique_ptr<MotionClassifier>(new MotionClassifier(new TestHal()));
197         }
198     }
199 };
200 
201 /**
202  * Since MotionClassifier creates a new thread to communicate with HAL,
203  * it's not really expected to ever exit. However, for testing purposes,
204  * we need to ensure that it is able to exit cleanly.
205  * If the thread is not properly cleaned up, it will generate SIGABRT.
206  * The logic for exiting the thread and cleaning up the resources is inside
207  * the destructor. Here, we just make sure the destructor does not crash.
208  */
TEST_F(MotionClassifierTest,Destructor_DoesNotCrash)209 TEST_F(MotionClassifierTest, Destructor_DoesNotCrash) {
210     mMotionClassifier = nullptr;
211 }
212 
213 /**
214  * Make sure MotionClassifier can handle events that don't have any
215  * video frames.
216  */
TEST_F(MotionClassifierTest,Classify_NoVideoFrames)217 TEST_F(MotionClassifierTest, Classify_NoVideoFrames) {
218     NotifyMotionArgs motionArgs = generateBasicMotionArgs();
219 
220     // We are not checking the return value, because we can't be making assumptions
221     // about the HAL operation, since it will be highly hardware-dependent
222     ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
223 }
224 
225 /**
226  * Make sure nothing crashes when a videoFrame is sent.
227  */
TEST_F(MotionClassifierTest,Classify_OneVideoFrame)228 TEST_F(MotionClassifierTest, Classify_OneVideoFrame) {
229     NotifyMotionArgs motionArgs = generateBasicMotionArgs();
230 
231     std::vector<int16_t> videoData = {1, 2, 3, 4};
232     timeval timestamp = { 1, 1};
233     TouchVideoFrame frame(2, 2, std::move(videoData), timestamp);
234     motionArgs.videoFrames = {frame};
235 
236     // We are not checking the return value, because we can't be making assumptions
237     // about the HAL operation, since it will be highly hardware-dependent
238     ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
239 }
240 
241 /**
242  * Make sure nothing crashes when 2 videoFrames are sent.
243  */
TEST_F(MotionClassifierTest,Classify_TwoVideoFrames)244 TEST_F(MotionClassifierTest, Classify_TwoVideoFrames) {
245     NotifyMotionArgs motionArgs = generateBasicMotionArgs();
246 
247     std::vector<int16_t> videoData1 = {1, 2, 3, 4};
248     timeval timestamp1 = { 1, 1};
249     TouchVideoFrame frame1(2, 2, std::move(videoData1), timestamp1);
250 
251     std::vector<int16_t> videoData2 = {6, 6, 6, 6};
252     timeval timestamp2 = { 1, 2};
253     TouchVideoFrame frame2(2, 2, std::move(videoData2), timestamp2);
254 
255     motionArgs.videoFrames = {frame1, frame2};
256 
257     // We are not checking the return value, because we can't be making assumptions
258     // about the HAL operation, since it will be highly hardware-dependent
259     ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
260 }
261 
262 /**
263  * Make sure MotionClassifier does not crash when it is reset.
264  */
TEST_F(MotionClassifierTest,Reset_DoesNotCrash)265 TEST_F(MotionClassifierTest, Reset_DoesNotCrash) {
266     ASSERT_NO_FATAL_FAILURE(mMotionClassifier->reset());
267 }
268 
269 /**
270  * Make sure MotionClassifier does not crash when a device is reset.
271  */
TEST_F(MotionClassifierTest,DeviceReset_DoesNotCrash)272 TEST_F(MotionClassifierTest, DeviceReset_DoesNotCrash) {
273     NotifyDeviceResetArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*deviceId*/);
274     ASSERT_NO_FATAL_FAILURE(mMotionClassifier->reset(args));
275 }
276 
277 } // namespace android
278