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