• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2010 The Android Open Source Project
3 //
4 
5 #include <ui/InputTransport.h>
6 #include <utils/Timers.h>
7 #include <utils/StopWatch.h>
8 #include <gtest/gtest.h>
9 #include <unistd.h>
10 #include <time.h>
11 #include <sys/mman.h>
12 #include <cutils/ashmem.h>
13 
14 #include "../../utils/tests/TestHelpers.h"
15 
16 namespace android {
17 
18 class InputPublisherAndConsumerTest : public testing::Test {
19 protected:
20     sp<InputChannel> serverChannel, clientChannel;
21     InputPublisher* mPublisher;
22     InputConsumer* mConsumer;
23     PreallocatedInputEventFactory mEventFactory;
24 
SetUp()25     virtual void SetUp() {
26         status_t result = InputChannel::openInputChannelPair(String8("channel name"),
27                 serverChannel, clientChannel);
28 
29         mPublisher = new InputPublisher(serverChannel);
30         mConsumer = new InputConsumer(clientChannel);
31     }
32 
TearDown()33     virtual void TearDown() {
34         if (mPublisher) {
35             delete mPublisher;
36             mPublisher = NULL;
37         }
38 
39         if (mConsumer) {
40             delete mConsumer;
41             mConsumer = NULL;
42         }
43 
44         serverChannel.clear();
45         clientChannel.clear();
46     }
47 
48     void Initialize();
49     void PublishAndConsumeKeyEvent();
50     void PublishAndConsumeMotionEvent(
51             size_t samplesToAppendBeforeDispatch = 0,
52             size_t samplesToAppendAfterDispatch = 0);
53 };
54 
TEST_F(InputPublisherAndConsumerTest,GetChannel_ReturnsTheChannel)55 TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
56     EXPECT_EQ(serverChannel.get(), mPublisher->getChannel().get());
57     EXPECT_EQ(clientChannel.get(), mConsumer->getChannel().get());
58 }
59 
Initialize()60 void InputPublisherAndConsumerTest::Initialize() {
61     status_t status;
62 
63     status = mPublisher->initialize();
64     ASSERT_EQ(OK, status)
65             << "publisher initialize should return OK";
66 
67     status = mConsumer->initialize();
68     ASSERT_EQ(OK, status)
69             << "consumer initialize should return OK";
70 }
71 
PublishAndConsumeKeyEvent()72 void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
73     status_t status;
74 
75     const int32_t deviceId = 1;
76     const int32_t source = AINPUT_SOURCE_KEYBOARD;
77     const int32_t action = AKEY_EVENT_ACTION_DOWN;
78     const int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM;
79     const int32_t keyCode = AKEYCODE_ENTER;
80     const int32_t scanCode = 13;
81     const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
82     const int32_t repeatCount = 1;
83     const nsecs_t downTime = 3;
84     const nsecs_t eventTime = 4;
85 
86     status = mPublisher->publishKeyEvent(deviceId, source, action, flags,
87             keyCode, scanCode, metaState, repeatCount, downTime, eventTime);
88     ASSERT_EQ(OK, status)
89             << "publisher publishKeyEvent should return OK";
90 
91     status = mPublisher->sendDispatchSignal();
92     ASSERT_EQ(OK, status)
93             << "publisher sendDispatchSignal should return OK";
94 
95     status = mConsumer->receiveDispatchSignal();
96     ASSERT_EQ(OK, status)
97             << "consumer receiveDispatchSignal should return OK";
98 
99     InputEvent* event;
100     status = mConsumer->consume(& mEventFactory, & event);
101     ASSERT_EQ(OK, status)
102             << "consumer consume should return OK";
103 
104     ASSERT_TRUE(event != NULL)
105             << "consumer should have returned non-NULL event";
106     ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event->getType())
107             << "consumer should have returned a key event";
108 
109     KeyEvent* keyEvent = static_cast<KeyEvent*>(event);
110     EXPECT_EQ(deviceId, keyEvent->getDeviceId());
111     EXPECT_EQ(source, keyEvent->getSource());
112     EXPECT_EQ(action, keyEvent->getAction());
113     EXPECT_EQ(flags, keyEvent->getFlags());
114     EXPECT_EQ(keyCode, keyEvent->getKeyCode());
115     EXPECT_EQ(scanCode, keyEvent->getScanCode());
116     EXPECT_EQ(metaState, keyEvent->getMetaState());
117     EXPECT_EQ(repeatCount, keyEvent->getRepeatCount());
118     EXPECT_EQ(downTime, keyEvent->getDownTime());
119     EXPECT_EQ(eventTime, keyEvent->getEventTime());
120 
121     status = mConsumer->sendFinishedSignal();
122     ASSERT_EQ(OK, status)
123             << "consumer sendFinishedSignal should return OK";
124 
125     status = mPublisher->receiveFinishedSignal();
126     ASSERT_EQ(OK, status)
127             << "publisher receiveFinishedSignal should return OK";
128 
129     status = mPublisher->reset();
130     ASSERT_EQ(OK, status)
131             << "publisher reset should return OK";
132 }
133 
PublishAndConsumeMotionEvent(size_t samplesToAppendBeforeDispatch,size_t samplesToAppendAfterDispatch)134 void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
135         size_t samplesToAppendBeforeDispatch, size_t samplesToAppendAfterDispatch) {
136     status_t status;
137 
138     const int32_t deviceId = 1;
139     const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
140     const int32_t action = AMOTION_EVENT_ACTION_MOVE;
141     const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
142     const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
143     const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
144     const float xOffset = -10;
145     const float yOffset = -20;
146     const float xPrecision = 0.25;
147     const float yPrecision = 0.5;
148     const nsecs_t downTime = 3;
149     const size_t pointerCount = 3;
150     const int32_t pointerIds[pointerCount] = { 2, 0, 1 };
151 
152     Vector<nsecs_t> sampleEventTimes;
153     Vector<PointerCoords> samplePointerCoords;
154 
155     for (size_t i = 0; i <= samplesToAppendAfterDispatch + samplesToAppendBeforeDispatch; i++) {
156         sampleEventTimes.push(i + 10);
157         for (size_t j = 0; j < pointerCount; j++) {
158             samplePointerCoords.push();
159             samplePointerCoords.editTop().x = 100 * i + j;
160             samplePointerCoords.editTop().y = 200 * i + j;
161             samplePointerCoords.editTop().pressure = 0.5 * i + j;
162             samplePointerCoords.editTop().size = 0.7 * i + j;
163             samplePointerCoords.editTop().touchMajor = 1.5 * i + j;
164             samplePointerCoords.editTop().touchMinor = 1.7 * i + j;
165             samplePointerCoords.editTop().toolMajor = 2.5 * i + j;
166             samplePointerCoords.editTop().toolMinor = 2.7 * i + j;
167             samplePointerCoords.editTop().orientation = 3.5 * i + j;
168         }
169     }
170 
171     status = mPublisher->publishMotionEvent(deviceId, source, action, flags, edgeFlags,
172             metaState, xOffset, yOffset, xPrecision, yPrecision,
173             downTime, sampleEventTimes[0], pointerCount, pointerIds, samplePointerCoords.array());
174     ASSERT_EQ(OK, status)
175             << "publisher publishMotionEvent should return OK";
176 
177     for (size_t i = 0; i < samplesToAppendBeforeDispatch; i++) {
178         size_t sampleIndex = i + 1;
179         status = mPublisher->appendMotionSample(sampleEventTimes[sampleIndex],
180                 samplePointerCoords.array() + sampleIndex * pointerCount);
181         ASSERT_EQ(OK, status)
182                 << "publisher appendMotionEvent should return OK";
183     }
184 
185     status = mPublisher->sendDispatchSignal();
186     ASSERT_EQ(OK, status)
187             << "publisher sendDispatchSignal should return OK";
188 
189     for (size_t i = 0; i < samplesToAppendAfterDispatch; i++) {
190         size_t sampleIndex = i + 1 + samplesToAppendBeforeDispatch;
191         status = mPublisher->appendMotionSample(sampleEventTimes[sampleIndex],
192                 samplePointerCoords.array() + sampleIndex * pointerCount);
193         ASSERT_EQ(OK, status)
194                 << "publisher appendMotionEvent should return OK";
195     }
196 
197     status = mConsumer->receiveDispatchSignal();
198     ASSERT_EQ(OK, status)
199             << "consumer receiveDispatchSignal should return OK";
200 
201     InputEvent* event;
202     status = mConsumer->consume(& mEventFactory, & event);
203     ASSERT_EQ(OK, status)
204             << "consumer consume should return OK";
205 
206     ASSERT_TRUE(event != NULL)
207             << "consumer should have returned non-NULL event";
208     ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType())
209             << "consumer should have returned a motion event";
210 
211     size_t lastSampleIndex = samplesToAppendBeforeDispatch + samplesToAppendAfterDispatch;
212 
213     MotionEvent* motionEvent = static_cast<MotionEvent*>(event);
214     EXPECT_EQ(deviceId, motionEvent->getDeviceId());
215     EXPECT_EQ(source, motionEvent->getSource());
216     EXPECT_EQ(action, motionEvent->getAction());
217     EXPECT_EQ(flags, motionEvent->getFlags());
218     EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags());
219     EXPECT_EQ(metaState, motionEvent->getMetaState());
220     EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
221     EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
222     EXPECT_EQ(downTime, motionEvent->getDownTime());
223     EXPECT_EQ(sampleEventTimes[lastSampleIndex], motionEvent->getEventTime());
224     EXPECT_EQ(pointerCount, motionEvent->getPointerCount());
225     EXPECT_EQ(lastSampleIndex, motionEvent->getHistorySize());
226 
227     for (size_t i = 0; i < pointerCount; i++) {
228         SCOPED_TRACE(i);
229         EXPECT_EQ(pointerIds[i], motionEvent->getPointerId(i));
230     }
231 
232     for (size_t sampleIndex = 0; sampleIndex < lastSampleIndex; sampleIndex++) {
233         SCOPED_TRACE(sampleIndex);
234         EXPECT_EQ(sampleEventTimes[sampleIndex],
235                 motionEvent->getHistoricalEventTime(sampleIndex));
236         for (size_t i = 0; i < pointerCount; i++) {
237             SCOPED_TRACE(i);
238             size_t offset = sampleIndex * pointerCount + i;
239             EXPECT_EQ(samplePointerCoords[offset].x,
240                     motionEvent->getHistoricalRawX(i, sampleIndex));
241             EXPECT_EQ(samplePointerCoords[offset].y,
242                     motionEvent->getHistoricalRawY(i, sampleIndex));
243             EXPECT_EQ(samplePointerCoords[offset].x + xOffset,
244                     motionEvent->getHistoricalX(i, sampleIndex));
245             EXPECT_EQ(samplePointerCoords[offset].y + yOffset,
246                     motionEvent->getHistoricalY(i, sampleIndex));
247             EXPECT_EQ(samplePointerCoords[offset].pressure,
248                     motionEvent->getHistoricalPressure(i, sampleIndex));
249             EXPECT_EQ(samplePointerCoords[offset].size,
250                     motionEvent->getHistoricalSize(i, sampleIndex));
251             EXPECT_EQ(samplePointerCoords[offset].touchMajor,
252                     motionEvent->getHistoricalTouchMajor(i, sampleIndex));
253             EXPECT_EQ(samplePointerCoords[offset].touchMinor,
254                     motionEvent->getHistoricalTouchMinor(i, sampleIndex));
255             EXPECT_EQ(samplePointerCoords[offset].toolMajor,
256                     motionEvent->getHistoricalToolMajor(i, sampleIndex));
257             EXPECT_EQ(samplePointerCoords[offset].toolMinor,
258                     motionEvent->getHistoricalToolMinor(i, sampleIndex));
259             EXPECT_EQ(samplePointerCoords[offset].orientation,
260                     motionEvent->getHistoricalOrientation(i, sampleIndex));
261         }
262     }
263 
264     SCOPED_TRACE(lastSampleIndex);
265     EXPECT_EQ(sampleEventTimes[lastSampleIndex], motionEvent->getEventTime());
266     for (size_t i = 0; i < pointerCount; i++) {
267         SCOPED_TRACE(i);
268         size_t offset = lastSampleIndex * pointerCount + i;
269         EXPECT_EQ(samplePointerCoords[offset].x, motionEvent->getRawX(i));
270         EXPECT_EQ(samplePointerCoords[offset].y, motionEvent->getRawY(i));
271         EXPECT_EQ(samplePointerCoords[offset].x + xOffset, motionEvent->getX(i));
272         EXPECT_EQ(samplePointerCoords[offset].y + yOffset, motionEvent->getY(i));
273         EXPECT_EQ(samplePointerCoords[offset].pressure, motionEvent->getPressure(i));
274         EXPECT_EQ(samplePointerCoords[offset].size, motionEvent->getSize(i));
275         EXPECT_EQ(samplePointerCoords[offset].touchMajor, motionEvent->getTouchMajor(i));
276         EXPECT_EQ(samplePointerCoords[offset].touchMinor, motionEvent->getTouchMinor(i));
277         EXPECT_EQ(samplePointerCoords[offset].toolMajor, motionEvent->getToolMajor(i));
278         EXPECT_EQ(samplePointerCoords[offset].toolMinor, motionEvent->getToolMinor(i));
279         EXPECT_EQ(samplePointerCoords[offset].orientation, motionEvent->getOrientation(i));
280     }
281 
282     status = mConsumer->sendFinishedSignal();
283     ASSERT_EQ(OK, status)
284             << "consumer sendFinishedSignal should return OK";
285 
286     status = mPublisher->receiveFinishedSignal();
287     ASSERT_EQ(OK, status)
288             << "publisher receiveFinishedSignal should return OK";
289 
290     status = mPublisher->reset();
291     ASSERT_EQ(OK, status)
292             << "publisher reset should return OK";
293 }
294 
TEST_F(InputPublisherAndConsumerTest,PublishKeyEvent_EndToEnd)295 TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_EndToEnd) {
296     ASSERT_NO_FATAL_FAILURE(Initialize());
297     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
298 }
299 
TEST_F(InputPublisherAndConsumerTest,PublishKeyEvent_WhenNotReset_ReturnsError)300 TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_WhenNotReset_ReturnsError) {
301     status_t status;
302     ASSERT_NO_FATAL_FAILURE(Initialize());
303 
304     status = mPublisher->publishKeyEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
305     ASSERT_EQ(OK, status)
306             << "publisher publishKeyEvent should return OK first time";
307 
308     status = mPublisher->publishKeyEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
309     ASSERT_EQ(INVALID_OPERATION, status)
310             << "publisher publishKeyEvent should return INVALID_OPERATION because "
311                     "the publisher was not reset";
312 }
313 
TEST_F(InputPublisherAndConsumerTest,PublishMotionEvent_EndToEnd)314 TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_EndToEnd) {
315     ASSERT_NO_FATAL_FAILURE(Initialize());
316     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
317 }
318 
TEST_F(InputPublisherAndConsumerTest,PublishMotionEvent_WhenNotReset_ReturnsError)319 TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenNotReset_ReturnsError) {
320     status_t status;
321     ASSERT_NO_FATAL_FAILURE(Initialize());
322 
323     const size_t pointerCount = 1;
324     int32_t pointerIds[pointerCount] = { 0 };
325     PointerCoords pointerCoords[pointerCount] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
326 
327     status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
328             pointerCount, pointerIds, pointerCoords);
329     ASSERT_EQ(OK, status)
330             << "publisher publishMotionEvent should return OK";
331 
332     status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
333             pointerCount, pointerIds, pointerCoords);
334     ASSERT_EQ(INVALID_OPERATION, status)
335             << "publisher publishMotionEvent should return INVALID_OPERATION because ";
336                     "the publisher was not reset";
337 }
338 
TEST_F(InputPublisherAndConsumerTest,PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError)339 TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) {
340     status_t status;
341     ASSERT_NO_FATAL_FAILURE(Initialize());
342 
343     const size_t pointerCount = 0;
344     int32_t pointerIds[pointerCount];
345     PointerCoords pointerCoords[pointerCount];
346 
347     status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
348             pointerCount, pointerIds, pointerCoords);
349     ASSERT_EQ(BAD_VALUE, status)
350             << "publisher publishMotionEvent should return BAD_VALUE";
351 }
352 
TEST_F(InputPublisherAndConsumerTest,PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError)353 TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) {
354     status_t status;
355     ASSERT_NO_FATAL_FAILURE(Initialize());
356 
357     const size_t pointerCount = MAX_POINTERS + 1;
358     int32_t pointerIds[pointerCount];
359     PointerCoords pointerCoords[pointerCount];
360 
361     status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
362             pointerCount, pointerIds, pointerCoords);
363     ASSERT_EQ(BAD_VALUE, status)
364             << "publisher publishMotionEvent should return BAD_VALUE";
365 }
366 
TEST_F(InputPublisherAndConsumerTest,PublishMultipleEvents_EndToEnd)367 TEST_F(InputPublisherAndConsumerTest, PublishMultipleEvents_EndToEnd) {
368     ASSERT_NO_FATAL_FAILURE(Initialize());
369     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
370     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
371     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
372     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
373     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
374 }
375 
TEST_F(InputPublisherAndConsumerTest,AppendMotionSample_WhenCalledBeforeDispatchSignal_AppendsSamples)376 TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenCalledBeforeDispatchSignal_AppendsSamples) {
377     status_t status;
378     ASSERT_NO_FATAL_FAILURE(Initialize());
379     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent(3, 0));
380 }
381 
TEST_F(InputPublisherAndConsumerTest,AppendMotionSample_WhenCalledAfterDispatchSignalAndNotConsumed_AppendsSamples)382 TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenCalledAfterDispatchSignalAndNotConsumed_AppendsSamples) {
383     status_t status;
384     ASSERT_NO_FATAL_FAILURE(Initialize());
385     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent(0, 4));
386 }
387 
TEST_F(InputPublisherAndConsumerTest,AppendMotionSample_WhenNoMotionEventPublished_ReturnsError)388 TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenNoMotionEventPublished_ReturnsError) {
389     status_t status;
390     ASSERT_NO_FATAL_FAILURE(Initialize());
391 
392     PointerCoords pointerCoords[1];
393     status = mPublisher->appendMotionSample(0, pointerCoords);
394     ASSERT_EQ(INVALID_OPERATION, status)
395             << "publisher appendMotionSample should return INVALID_OPERATION";
396 }
397 
TEST_F(InputPublisherAndConsumerTest,AppendMotionSample_WhenPublishedMotionEventIsNotAMove_ReturnsError)398 TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenPublishedMotionEventIsNotAMove_ReturnsError) {
399     status_t status;
400     ASSERT_NO_FATAL_FAILURE(Initialize());
401 
402     const size_t pointerCount = MAX_POINTERS;
403     int32_t pointerIds[pointerCount];
404     PointerCoords pointerCoords[pointerCount];
405 
406     status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_DOWN,
407             0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
408     ASSERT_EQ(OK, status);
409 
410     status = mPublisher->appendMotionSample(0, pointerCoords);
411     ASSERT_EQ(INVALID_OPERATION, status)
412             << "publisher appendMotionSample should return INVALID_OPERATION";
413 }
414 
TEST_F(InputPublisherAndConsumerTest,AppendMotionSample_WhenAlreadyConsumed_ReturnsError)415 TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenAlreadyConsumed_ReturnsError) {
416     status_t status;
417     ASSERT_NO_FATAL_FAILURE(Initialize());
418 
419     const size_t pointerCount = MAX_POINTERS;
420     int32_t pointerIds[pointerCount];
421     PointerCoords pointerCoords[pointerCount];
422 
423     status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
424             0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
425     ASSERT_EQ(OK, status);
426 
427     status = mPublisher->sendDispatchSignal();
428     ASSERT_EQ(OK, status);
429 
430     status = mConsumer->receiveDispatchSignal();
431     ASSERT_EQ(OK, status);
432 
433     InputEvent* event;
434     status = mConsumer->consume(& mEventFactory, & event);
435     ASSERT_EQ(OK, status);
436 
437     status = mPublisher->appendMotionSample(0, pointerCoords);
438     ASSERT_EQ(status_t(FAILED_TRANSACTION), status)
439             << "publisher appendMotionSample should return FAILED_TRANSACTION";
440 }
441 
TEST_F(InputPublisherAndConsumerTest,AppendMotionSample_WhenBufferFull_ReturnsError)442 TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenBufferFull_ReturnsError) {
443     status_t status;
444     ASSERT_NO_FATAL_FAILURE(Initialize());
445 
446     const size_t pointerCount = MAX_POINTERS;
447     int32_t pointerIds[pointerCount];
448     PointerCoords pointerCoords[pointerCount];
449 
450     status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
451             0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
452     ASSERT_EQ(OK, status);
453 
454     for (int count = 1;; count++) {
455         ASSERT_LT(count, 100000) << "should eventually reach OOM";
456 
457         status = mPublisher->appendMotionSample(0, pointerCoords);
458         if (status != OK) {
459             ASSERT_GT(count, 12) << "should be able to add at least a dozen samples";
460             ASSERT_EQ(NO_MEMORY, status)
461                     << "publisher appendMotionSample should return NO_MEMORY when buffer is full";
462             break;
463         }
464     }
465 
466     status = mPublisher->appendMotionSample(0, pointerCoords);
467     ASSERT_EQ(NO_MEMORY, status)
468             << "publisher appendMotionSample should return NO_MEMORY persistently until reset";
469 }
470 
471 } // namespace android
472