~ci-train-bot/mir/mir-ubuntu-zesty-2683

« back to all changes in this revision

Viewing changes to 3rd_party/android-input/android/frameworks/base/services/input/InputTransport.cpp

  • Committer: Bileto Bot
  • Date: 2017-04-13 15:26:17 UTC
  • mfrom: (1160.2883.164 0.27)
  • Revision ID: ci-train-bot@canonical.com-20170413152617-bs7slz07xbzxu2d3
* New upstream release 0.27.0 (https://launchpad.net/mir/+milestone/0.27.0)
  - ABI summary:
    . mirclient ABI unchanged at 9
    . mirserver ABI bumped to 44
    . mircommon ABI unchanged at 7
    . mirplatform ABI bumped to 61
    . mirprotobuf ABI unchanged at 3
    . mirplatformgraphics ABI bumped to 13
    . mirclientplatform ABI unchanged at 5
    . mirinputplatform ABI bumped to 7
    . mircore ABI unchanged at 1
  - Enhancements:
    . Mostly groundwork required to support major enhancements coming in
      future Mir versions.
    . Removed android-input and eliminated the entire "3rd_party/" subtree.
      Now the Mir source tree contains original code only.
    . Added mir_prompt_session_new_fds_for_prompt_providers_sync API.
    . mirout: Added load and save options for keeping display configs
      on disk.
    . mirout: Added "--" support for applying configuration changes under
      Unity8.
    . Fixed failure of DRM hardware cursor {hide(); show(image);}
    . Added server option: "--cursor software" (MIR_SERVER_CURSOR=software)
    . Added letterboxing/black bars support to the GL renderer in preparation
      for generic output cloning.
    . Added client API for getting the logical size of an output.
    . Migrated MirCookie to use SHA-256.
    . Ensure RealKMSOutputConfiguration stays in sync with actual hardware
      state.
    . Added support for drag-and-drop.
    . Lots of other client API enhancements.
    . Minor clean-ups, optimizations and dead code removal.
  - Bugs fixed:
    . [enhancement] Make able to get version information from client /
      server APIs (LP: #1195540)
    . Touch screen coordinates don't rotate with the screen (LP: #1349660)
    . Subpixel order not included in Mir display information (LP: #1393578)
    . [enhancement] Missing client API for relative surface movement (e.g.
      dragging client-decorated windows) (LP: #1420334) . Mir does not reset
      key states when paused or resumed (modifiers get stuck after VT
      switching) (LP: #1536279)
    . Inconsistent behaviour of Num Lock (LP: #1588237)
    . [ FAILED ] NestedInput.nested_event_filter_receives_keyboard_from_host
      (LP: #1613523)
    . Rotating an output left or right without restarting the
      compositor distorts the image (LP: #1643488)
    . support display scaling slider in unity8 (LP: #1645372)
    . [ FAILED ] NestedInputWithMouse.mouse_pointer_coordinates_in_nested_
      server_are_accumulated (LP: #1646375)
    . [ FAILED ] NestedInputWithMouse.mouse_pointer_position_is_in_sync_with_
      host_server (LP: #1646558)
    . abi_check doesn't check mircore (LP: #1649354)
    . Under Unity8, mir_demo_client_target is distorted and input in the
      wrong place on start-up (LP: #1655804)
    . [testsfail] PromptSessionClientAPI.client_pid_is_associated_with_
      session hangs and times out (LP: #1655929)
    . EDID does not change when hotplugging a monitor (LP: #1660017)
    . [regression] Mir 0.26.0 - spinner loading animation, minimize, maximize
      too fast (LP: #1661072)
    . [regression] Unity8 stutters constantly (like half frame rate) using
      Mir 0.26.0 (LP: #1661128)
    . [regression] mir_demo_server refuses to quit on Ctrl+Alt+Backspace or
      Ctrl+C in its terminal (deadlock in DefaultInputDeviceHub::add_device)
      (LP: #1661151)
    . [regression] mirout crashes when connecting to unity8 or any nested
      server: [libprotobuf FATAL
      /usr/include/google/protobuf/repeated_field.h:1408] CHECK failed:
      (index) < (current_size_): (LP: #1661163)
    . [ FAILED ] DefaultInputManagerTest.forwards_pause_continue_state_
      changes_to_platform (LP: #1661187)
    . [regression] Segfault on detect_fd_leaks during acceptance tests (in
      DisplayConfiguration/{DisplayFormatSetting,DisplaySubpixelSetting})
      (LP: #1661498)
    . [regression] Nested server segfaults or rapidly logs exceptions when a
      fullscreen client starts [in mir_presentation_chain_set_dropping_mode
      ... std::exception::what: Operation not permitted] (LP: #1661508)
    . [regression] Windowed clients of nested servers are all black
      (LP: #1661521)
    . mir_window_request_persistent_id_sync seg faults when called twice
      (LP: #1661704)
    . mir_acceptance_tests now takes 10 seconds longer (in r4002 compared to
      r4001) (LP: #1662044)
    . Mir graphics platform ABI broke in series 0.26 but sonames never
      changed (LP: #1662455)
    . libmirclient-dev missing build depndency on libmircore-dev
      (LP: #1662942)
    . [regression] mirscreencast hangs during screencast creation
      (LP: #1662997)
    . [regression] Software clients of nested servers with size >=480x480
      are all black in Mir 0.25.0 and later (or stretched and distorted under
      Unity8) (LP: #1663062)
    . mir_window_spec_set_cursor_name() doesn't trigger
      mir::scene::SurfaceObserver::cursor_image_set_to (LP: #1663197)
    . android complaint during mirscreencast of nested server (LP: #1664562)
    . qtubuntu sends wrong text as part of QKeyEvent (LP: #1664610)
    . Mir server crashed with SIGSEGV in
      mir::compositor::TemporaryBuffer::size() called from
      mir::gl::tessellate_renderable_into_rectangle() (LP: #1664760)
    . mirout reports logical size of a rotated display incorrectly
      (LP: #1665271)
    . Nested servers (Unity8) periodically stutter (half frame rate) with
      Mir 0.26.1 (LP: #1666372)
    . If the only surface in a session cannot take focus the server crashes
      (LP: #1667645)
    . [regression] OSK input shaping no longer works correctly (LP: #1669444)
    . GTK window functions `Always on Top, Move and Resize' don't work in
      Mir/Unity8 (LP: #1669524)
    . [regression] mir_proving_server mode hotkeys (Ctrl+Alt+=/-) cause the
      server to segfault (LP: #1669752)
    . Test takes minutes to complete: MediatingDisplayChangerTest.confirmed_
      configuration_doesnt_revert_after_timeout (LP: #1671033)
    . [ FAILED ] PosixRWMutex.prefer_writer_nonrecursive_prevents_writer_
      starvation (Timeout waiting to acquire write lock) (LP: #1671037)
    . [regression] Mixing screen rotation with mode changes makes the image
      squished (LP: #1672269)
    . unity-system-compositor crashed with SIGSEGV in
      libinput_device_config_accel_is_available() from
      libinput_device_config_accel_set_speed() from
      mir::input::evdev::LibInputDevice::apply_settings() (LP: #1672955)
    . Presentation chains should support various Vulkan presentation modes
      (LP: #1673533)
    . Need an extension for GBM buffers to replace
      mir_buffer_get_buffer_package() (LP: #1673534)
    . cross-compile-chroot.sh (to zesty) fails to build [cannot find -ludev]
      due to libudev.so being in a different directory to where libudev.pc
      searches for it (LP: #1674201)
    . Please transition to Boost 1.62 (LP: #1675138)
    . [regression] Mir is assigning the first output ID = 0 (==
      mir_display_output_id_invalid) (LP: #1675331)
    . Mir sending key repeat events continually to nested shell after VT
      switch (causes Unity8 lockup for a while) (LP: #1675357)
    . mirout commands don't work when followed by -- (LP: #1676320)
    . mir_demo_standalone_render_overlays fails to link (LP: #1677239)
    . [regression] doxygen processing for capnproto/protobuf broken
      (LP: #1679248)
    . mir_window_spec_set_cursor_render_surface does not work (LP: #1679836)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//
2
 
// Copyright 2010 The Android Open Source Project
3
 
//
4
 
// Provides a shared memory transport for input events.
5
 
//
6
 
#define LOG_TAG "InputTransport"
7
 
 
8
 
//#define LOG_NDEBUG 0
9
 
 
10
 
// Log debug messages about channel messages (send message, receive message)
11
 
#define DEBUG_CHANNEL_MESSAGES 0
12
 
 
13
 
// Log debug messages whenever InputChannel objects are created/destroyed
14
 
#define DEBUG_CHANNEL_LIFECYCLE 0
15
 
 
16
 
// Log debug messages about transport actions
17
 
#define DEBUG_TRANSPORT_ACTIONS 0
18
 
 
19
 
// Log debug messages about touch event resampling
20
 
#define DEBUG_RESAMPLING 0
21
 
 
22
 
#include <androidfw/InputTransport.h>
23
 
#include <cutils/log.h>
24
 
#include <std/properties.h>
25
 
#include <errno.h>
26
 
#include <fcntl.h>
27
 
#include <unistd.h>
28
 
#include <sys/types.h>
29
 
#include <sys/socket.h>
30
 
#include <math.h>
31
 
 
32
 
#include <boost/throw_exception.hpp>
33
 
#include <stdexcept>
34
 
 
35
 
 
36
 
namespace android {
37
 
 
38
 
// Nanoseconds per milliseconds.
39
 
static constexpr const std::chrono::nanoseconds NANOS_PER_MS = std::chrono::nanoseconds(1000000);
40
 
 
41
 
// Latency added during resampling.  A few milliseconds doesn't hurt much but
42
 
// reduces the impact of mispredicted touch positions.
43
 
static constexpr const std::chrono::nanoseconds RESAMPLE_LATENCY = std::chrono::nanoseconds(5 * NANOS_PER_MS);
44
 
 
45
 
// Minimum time difference between consecutive samples before attempting to resample.
46
 
static constexpr const std::chrono::nanoseconds RESAMPLE_MIN_DELTA = std::chrono::nanoseconds(2 * NANOS_PER_MS);
47
 
 
48
 
// Maximum time to predict forward from the last known state, to avoid predicting too
49
 
// far into the future.  This time is further bounded by 50% of the last time delta.
50
 
static constexpr const std::chrono::nanoseconds RESAMPLE_MAX_PREDICTION = std::chrono::nanoseconds(8 * NANOS_PER_MS);
51
 
 
52
 
template<typename T>
53
 
inline static T min(const T& a, const T& b) {
54
 
    return a < b ? a : b;
55
 
}
56
 
 
57
 
inline static float lerp(float a, float b, float alpha) {
58
 
    return a + alpha * (b - a);
59
 
}
60
 
 
61
 
// --- InputMessage ---
62
 
 
63
 
InputMessage::InputMessage()
64
 
{
65
 
    memset(this, 0, sizeof(InputMessage));
66
 
}
67
 
 
68
 
InputMessage::InputMessage(uint32_t seq, std::string const& buffer)
69
 
{
70
 
    memset(this, 0, sizeof(InputMessage));
71
 
    header.type = TYPE_BUFFER;
72
 
    header.seq = seq;
73
 
    header.size = buffer.size();
74
 
 
75
 
    if (raw_event_payload < buffer.size())
76
 
        BOOST_THROW_EXCEPTION(std::runtime_error("raw buffer event exceeds payload"));
77
 
    memcpy(body.buffer.buffer, buffer.data(), header.size);
78
 
}
79
 
 
80
 
InputMessage::InputMessage(InputMessage const& cp) = default;
81
 
 
82
 
InputMessage& InputMessage::operator=(InputMessage const& cp) = default;
83
 
 
84
 
bool InputMessage::isValid(size_t actualSize) const {
85
 
    if (size() == actualSize) {
86
 
        switch (header.type) {
87
 
        case TYPE_FINISHED:
88
 
        case TYPE_BUFFER:
89
 
        case TYPE_KEY:
90
 
            return true;
91
 
        case TYPE_MOTION:
92
 
            return body.motion.pointerCount > 0
93
 
                    && body.motion.pointerCount <= MAX_POINTERS;
94
 
        }
95
 
    }
96
 
    return false;
97
 
}
98
 
 
99
 
size_t InputMessage::size() const {
100
 
    switch (header.type) {
101
 
    case TYPE_KEY:
102
 
        return sizeof(Header) + body.key.size();
103
 
    case TYPE_MOTION:
104
 
        return sizeof(Header) + body.motion.size();
105
 
    case TYPE_FINISHED:
106
 
        return sizeof(Header) + body.finished.size();
107
 
    case TYPE_BUFFER:
108
 
        return sizeof(Header) + header.size;
109
 
    }
110
 
    return sizeof(Header);
111
 
}
112
 
// --- InputChannel ---
113
 
 
114
 
InputChannel::InputChannel(const String8& name, int fd) :
115
 
        mName(name), mFd(fd) {
116
 
#if DEBUG_CHANNEL_LIFECYCLE
117
 
    ALOGD("Input channel constructed: name='%s', fd=%d",
118
 
        c_str(mName), fd);
119
 
#endif
120
 
 
121
 
    int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
122
 
    LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
123
 
            "non-blocking.  errno=%d", c_str(mName), errno);
124
 
}
125
 
 
126
 
InputChannel::~InputChannel() {
127
 
#if DEBUG_CHANNEL_LIFECYCLE
128
 
    ALOGD("Input channel destroyed: name='%s', fd=%d",
129
 
        c_str(mName), mFd);
130
 
#endif
131
 
}
132
 
 
133
 
status_t InputChannel::sendMessage(const InputMessage* msg) {
134
 
    size_t msgLength = msg->size();
135
 
    ssize_t nWrite;
136
 
    do {
137
 
        nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
138
 
    } while (nWrite == -1 && errno == EINTR);
139
 
 
140
 
    if (nWrite < 0) {
141
 
        int error = errno;
142
 
#if DEBUG_CHANNEL_MESSAGES
143
 
        ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", c_str(mName),
144
 
                msg->header.type, error);
145
 
#endif
146
 
        if (error == EAGAIN || error == EWOULDBLOCK) {
147
 
            return WOULD_BLOCK;
148
 
        }
149
 
        if (error == EPIPE || error == ENOTCONN) {
150
 
            return DEAD_OBJECT;
151
 
        }
152
 
        return -error;
153
 
    }
154
 
 
155
 
    if (size_t(nWrite) != msgLength) {
156
 
#if DEBUG_CHANNEL_MESSAGES
157
 
        ALOGD("channel '%s' ~ error sending message type %d, send was incomplete",
158
 
            c_str(mName), msg->header.type);
159
 
#endif
160
 
        return DEAD_OBJECT;
161
 
    }
162
 
 
163
 
#if DEBUG_CHANNEL_MESSAGES
164
 
    ALOGD("channel '%s' ~ sent message of type %d", c_str(mName), msg->header.type);
165
 
#endif
166
 
    return OK;
167
 
}
168
 
 
169
 
status_t InputChannel::receiveMessage(InputMessage* msg) {
170
 
    ssize_t nRead;
171
 
    do {
172
 
        nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
173
 
    } while (nRead == -1 && errno == EINTR);
174
 
 
175
 
    if (nRead < 0) {
176
 
        int error = errno;
177
 
#if DEBUG_CHANNEL_MESSAGES
178
 
        ALOGD("channel '%s' ~ receive message failed, errno=%d", c_str(mName), errno);
179
 
#endif
180
 
        if (error == EAGAIN || error == EWOULDBLOCK) {
181
 
            return WOULD_BLOCK;
182
 
        }
183
 
        if (error == EPIPE || error == ENOTCONN) {
184
 
            return DEAD_OBJECT;
185
 
        }
186
 
        return -error;
187
 
    }
188
 
 
189
 
    if (nRead == 0) { // check for EOF
190
 
#if DEBUG_CHANNEL_MESSAGES
191
 
        ALOGD("channel '%s' ~ receive message failed because peer was closed", c_str(mName));
192
 
#endif
193
 
        return DEAD_OBJECT;
194
 
    }
195
 
 
196
 
    if (!msg->isValid(nRead)) {
197
 
#if DEBUG_CHANNEL_MESSAGES
198
 
        ALOGD("channel '%s' ~ received invalid message", c_str(mName));
199
 
#endif
200
 
        return BAD_VALUE;
201
 
    }
202
 
 
203
 
#if DEBUG_CHANNEL_MESSAGES
204
 
    ALOGD("channel '%s' ~ received message of type %d", c_str(mName), msg->header.type);
205
 
#endif
206
 
    return OK;
207
 
}
208
 
 
209
 
 
210
 
// --- InputPublisher ---
211
 
 
212
 
InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
213
 
        mChannel(channel) {
214
 
}
215
 
 
216
 
InputPublisher::~InputPublisher() {
217
 
}
218
 
 
219
 
status_t InputPublisher::publishEventBuffer(uint32_t seq, std::string const& buffer) {
220
 
#if DEBUG_TRANSPORT_ACTIONS
221
 
    ALOGD("channel '%s' publisher ~ publishInputBuffer: seq=%u", c_str(mChannel->getName()), seq);
222
 
#endif
223
 
 
224
 
    if (!seq) {
225
 
        ALOGE("Attempted to publish a buffer with sequence number 0.");
226
 
        return BAD_VALUE;
227
 
    }
228
 
 
229
 
    InputMessage msg(seq, buffer);
230
 
    return mChannel->sendMessage(&msg);
231
 
}
232
 
 
233
 
status_t InputPublisher::publishKeyEvent(
234
 
        uint32_t seq,
235
 
        int32_t deviceId,
236
 
        int32_t source,
237
 
        int32_t action,
238
 
        int32_t flags,
239
 
        int32_t keyCode,
240
 
        int32_t scanCode,
241
 
        int32_t metaState,
242
 
        int32_t repeatCount,
243
 
        mir::cookie::Blob const& cookieBlob,
244
 
        std::chrono::nanoseconds downTime,
245
 
        std::chrono::nanoseconds eventTime) {
246
 
#if DEBUG_TRANSPORT_ACTIONS
247
 
    ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
248
 
            "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
249
 
            "downTime=%lld, eventTime=%lld",
250
 
            c_str(mChannel->getName()), seq,
251
 
            deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
252
 
            downTime, eventTime);
253
 
#endif
254
 
 
255
 
    if (!seq) {
256
 
        ALOGE("Attempted to publish a key event with sequence number 0.");
257
 
        return BAD_VALUE;
258
 
    }
259
 
 
260
 
    InputMessage msg;
261
 
    msg.header.type = InputMessage::TYPE_KEY;
262
 
    msg.header.seq = seq;
263
 
    msg.header.size = sizeof(msg.body.key);
264
 
    msg.body.key.deviceId = deviceId;
265
 
    msg.body.key.source = source;
266
 
    msg.body.key.action = action;
267
 
    msg.body.key.flags = flags;
268
 
    msg.body.key.keyCode = keyCode;
269
 
    msg.body.key.scanCode = scanCode;
270
 
    msg.body.key.metaState = metaState;
271
 
    msg.body.key.repeatCount = repeatCount;
272
 
    msg.body.key.cookieBlob = cookieBlob;
273
 
    msg.body.key.downTime = downTime.count();
274
 
    msg.body.key.eventTime = eventTime.count();
275
 
    return mChannel->sendMessage(&msg);
276
 
}
277
 
 
278
 
status_t InputPublisher::publishMotionEvent(
279
 
        uint32_t seq,
280
 
        int32_t deviceId,
281
 
        int32_t source,
282
 
        int32_t action,
283
 
        int32_t flags,
284
 
        int32_t edgeFlags,
285
 
        int32_t metaState,
286
 
        int32_t buttonState,
287
 
        float xOffset,
288
 
        float yOffset,
289
 
        float xPrecision,
290
 
        float yPrecision,
291
 
        mir::cookie::Blob const& cookieBlob,
292
 
        std::chrono::nanoseconds downTime,
293
 
        std::chrono::nanoseconds eventTime,
294
 
        size_t pointerCount,
295
 
        const PointerProperties* pointerProperties,
296
 
        const PointerCoords* pointerCoords) {
297
 
#if DEBUG_TRANSPORT_ACTIONS
298
 
    ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
299
 
            "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, "
300
 
            "xOffset=%f, yOffset=%f, "
301
 
            "xPrecision=%f, yPrecision=%f,"
302
 
            "downTime=%lld, eventTime=%lld, pointerCount=%d",
303
 
            c_str(mChannel->getName()), seq,
304
 
            deviceId, source, action, flags, edgeFlags, metaState, buttonState,
305
 
            xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
306
 
#endif
307
 
 
308
 
    if (!seq) {
309
 
        ALOGE("Attempted to publish a motion event with sequence number 0.");
310
 
        return BAD_VALUE;
311
 
    }
312
 
 
313
 
    if (pointerCount > MAX_POINTERS || pointerCount < 1) {
314
 
        ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %d.",
315
 
            c_str(mChannel->getName()), pointerCount);
316
 
        return BAD_VALUE;
317
 
    }
318
 
 
319
 
    InputMessage msg;
320
 
    msg.header.type = InputMessage::TYPE_MOTION;
321
 
    msg.header.seq = seq;
322
 
    msg.body.motion.deviceId = deviceId;
323
 
    msg.body.motion.source = source;
324
 
    msg.body.motion.action = action;
325
 
    msg.body.motion.flags = flags;
326
 
    msg.body.motion.edgeFlags = edgeFlags;
327
 
    msg.body.motion.metaState = metaState;
328
 
    msg.body.motion.buttonState = buttonState;
329
 
    msg.body.motion.xOffset = xOffset;
330
 
    msg.body.motion.yOffset = yOffset;
331
 
    msg.body.motion.xPrecision = xPrecision;
332
 
    msg.body.motion.yPrecision = yPrecision;
333
 
    msg.body.motion.cookieBlob = cookieBlob;
334
 
    msg.body.motion.downTime = downTime.count();
335
 
    msg.body.motion.eventTime = eventTime.count();
336
 
    msg.body.motion.pointerCount = pointerCount;
337
 
    for (size_t i = 0; i < pointerCount; i++) {
338
 
        msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
339
 
        msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
340
 
    }
341
 
 
342
 
    msg.header.size = msg.body.motion.size();
343
 
    return mChannel->sendMessage(&msg);
344
 
}
345
 
 
346
 
status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
347
 
#if DEBUG_TRANSPORT_ACTIONS
348
 
    ALOGD("channel '%s' publisher ~ receiveFinishedSignal",
349
 
        c_str(mChannel->getName()));
350
 
#endif
351
 
 
352
 
    InputMessage msg;
353
 
    status_t result = mChannel->receiveMessage(&msg);
354
 
    if (result) {
355
 
        *outSeq = 0;
356
 
        *outHandled = false;
357
 
        return result;
358
 
    }
359
 
    if (msg.header.type != InputMessage::TYPE_FINISHED) {
360
 
        ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer",
361
 
            c_str(mChannel->getName()), msg.header.type);
362
 
        return UNKNOWN_ERROR;
363
 
    }
364
 
    *outSeq = msg.header.seq;
365
 
    *outHandled = msg.body.finished.handled;
366
 
    return OK;
367
 
}
368
 
 
369
 
// --- InputConsumer ---
370
 
 
371
 
InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
372
 
        mResampleTouch(isTouchResamplingEnabled()),
373
 
        mChannel(channel), mMsgDeferred(false) {
374
 
}
375
 
 
376
 
InputConsumer::~InputConsumer() {
377
 
}
378
 
 
379
 
bool InputConsumer::isTouchResamplingEnabled() {
380
 
    char value[PROPERTY_VALUE_MAX];
381
 
    int length = property_get("debug.inputconsumer.resample", value, NULL);
382
 
    if (length > 0) {
383
 
        if (!strcmp("0", value)) {
384
 
            return false;
385
 
        }
386
 
        if (strcmp("1", value)) {
387
 
            ALOGD("Unrecognized property value for 'debug.inputconsumer.resample'.  "
388
 
                    "Use '1' or '0'.");
389
 
        }
390
 
    }
391
 
    return true;
392
 
}
393
 
 
394
 
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
395
 
        bool consumeBatches, std::chrono::nanoseconds frameTime, uint32_t* outSeq, InputEvent** outEvent) {
396
 
#if DEBUG_TRANSPORT_ACTIONS
397
 
    ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld",
398
 
        c_str(mChannel->getName()), consumeBatches ? "true" : "false", frameTime);
399
 
#endif
400
 
 
401
 
    *outSeq = 0;
402
 
    *outEvent = NULL;
403
 
 
404
 
    // Fetch the next input message.
405
 
    // Loop until an event can be returned or no additional events are received.
406
 
    while (!*outEvent) {
407
 
        if (mMsgDeferred) {
408
 
            // mMsg contains a valid input message from the previous call to consume
409
 
            // that has not yet been processed.
410
 
            mMsgDeferred = false;
411
 
        } else {
412
 
            // Receive a fresh message.
413
 
            status_t result = mChannel->receiveMessage(&mMsg);
414
 
            if (result) {
415
 
                // Consume the next batched event unless batches are being held for later.
416
 
                if (consumeBatches || result != WOULD_BLOCK) {
417
 
                    result = consumeBatch(factory, frameTime, outSeq, outEvent);
418
 
                    if (*outEvent) {
419
 
#if DEBUG_TRANSPORT_ACTIONS
420
 
                        ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
421
 
                            c_str(mChannel->getName()), *outSeq);
422
 
#endif
423
 
                        break;
424
 
                    }
425
 
                }
426
 
                return result;
427
 
            }
428
 
        }
429
 
 
430
 
        switch (mMsg.header.type) {
431
 
        case InputMessage::TYPE_BUFFER: {
432
 
            RawBufferEvent* bufferEvent = factory->createRawBufferEvent();
433
 
            if (!bufferEvent) return NO_MEMORY;
434
 
 
435
 
            initializeBufferEvent(bufferEvent, &mMsg);
436
 
            *outSeq = mMsg.header.seq;
437
 
            *outEvent = bufferEvent;
438
 
#if DEBUG_TRANSPORT_ACTIONS
439
 
            ALOGD("channel '%s' consumer ~ consumed buffer event, seq=%u",
440
 
                c_str(mChannel->getName()), *outSeq);
441
 
#endif
442
 
            break;
443
 
        }
444
 
        case InputMessage::TYPE_KEY: {
445
 
            KeyEvent* keyEvent = factory->createKeyEvent();
446
 
            if (!keyEvent) return NO_MEMORY;
447
 
 
448
 
            initializeKeyEvent(keyEvent, &mMsg);
449
 
            *outSeq = mMsg.header.seq;
450
 
            *outEvent = keyEvent;
451
 
#if DEBUG_TRANSPORT_ACTIONS
452
 
            ALOGD("channel '%s' consumer ~ consumed key event, seq=%u",
453
 
                c_str(mChannel->getName()), *outSeq);
454
 
#endif
455
 
            break;
456
 
        }
457
 
 
458
 
        case AINPUT_EVENT_TYPE_MOTION: {
459
 
            ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
460
 
            if (batchIndex >= 0) {
461
 
                Batch& batch = mBatches.editItemAt(batchIndex);
462
 
                if (canAddSample(batch, &mMsg)) {
463
 
                    batch.samples.push(mMsg);
464
 
#if DEBUG_TRANSPORT_ACTIONS
465
 
                    ALOGD("channel '%s' consumer ~ appended to batch event",
466
 
                        c_str(mChannel->getName()));
467
 
#endif
468
 
                    break;
469
 
                } else {
470
 
                    // We cannot append to the batch in progress, so we need to consume
471
 
                    // the previous batch right now and defer the new message until later.
472
 
                    mMsgDeferred = true;
473
 
                    status_t result = consumeSamples(factory,
474
 
                            batch, batch.samples.size(), outSeq, outEvent);
475
 
                    mBatches.removeAt(batchIndex);
476
 
                    if (result) {
477
 
                        return result;
478
 
                    }
479
 
#if DEBUG_TRANSPORT_ACTIONS
480
 
                    ALOGD("channel '%s' consumer ~ consumed batch event and "
481
 
                            "deferred current event, seq=%u",
482
 
                            c_str(mChannel->getName()), *outSeq);
483
 
#endif
484
 
                    break;
485
 
                }
486
 
            }
487
 
 
488
 
            // Start a new batch if needed.
489
 
            if ((mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE
490
 
                 || mMsg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE)
491
 
                && frameTime.count() >= 0) {
492
 
                mBatches.push();
493
 
                Batch& batch = mBatches.editTop();
494
 
                batch.samples.push(mMsg);
495
 
#if DEBUG_TRANSPORT_ACTIONS
496
 
                ALOGD("channel '%s' consumer ~ started batch event",
497
 
                    c_str(mChannel->getName()));
498
 
#endif
499
 
                break;
500
 
            }
501
 
 
502
 
            MotionEvent* motionEvent = factory->createMotionEvent();
503
 
            if (! motionEvent) return NO_MEMORY;
504
 
 
505
 
            updateTouchState(&mMsg);
506
 
            initializeMotionEvent(motionEvent, &mMsg);
507
 
            *outSeq = mMsg.header.seq;
508
 
            *outEvent = motionEvent;
509
 
#if DEBUG_TRANSPORT_ACTIONS
510
 
            ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
511
 
                c_str(mChannel->getName()), *outSeq);
512
 
#endif
513
 
            break;
514
 
        }
515
 
 
516
 
        default:
517
 
            ALOGE("channel '%s' consumer ~ Received unexpected message of type %d",
518
 
                c_str(mChannel->getName()), mMsg.header.type);
519
 
            return UNKNOWN_ERROR;
520
 
        }
521
 
    }
522
 
    return OK;
523
 
}
524
 
 
525
 
status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory,
526
 
        std::chrono::nanoseconds frameTime, uint32_t* outSeq, InputEvent** outEvent) {
527
 
    status_t result;
528
 
    for (size_t i = mBatches.size(); i-- > 0; ) {
529
 
        Batch& batch = mBatches.editItemAt(i);
530
 
        if (frameTime < std::chrono::nanoseconds(0)) {
531
 
            result = consumeSamples(factory, batch, batch.samples.size(),
532
 
                    outSeq, outEvent);
533
 
            mBatches.removeAt(i);
534
 
            return result;
535
 
        }
536
 
 
537
 
        std::chrono::nanoseconds sampleTime = frameTime - RESAMPLE_LATENCY;
538
 
        ssize_t split = findSampleNoLaterThan(batch, sampleTime);
539
 
        if (split < 0) {
540
 
            continue;
541
 
        }
542
 
 
543
 
        result = consumeSamples(factory, batch, split + 1, outSeq, outEvent);
544
 
        const InputMessage* next;
545
 
        if (batch.samples.isEmpty()) {
546
 
            mBatches.removeAt(i);
547
 
            next = NULL;
548
 
        } else {
549
 
            next = &batch.samples.itemAt(0);
550
 
        }
551
 
        if (!result) {
552
 
            resampleTouchState(sampleTime, static_cast<MotionEvent*>(*outEvent), next);
553
 
        }
554
 
        return result;
555
 
    }
556
 
 
557
 
    return WOULD_BLOCK;
558
 
}
559
 
 
560
 
status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory,
561
 
        Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent) {
562
 
    MotionEvent* motionEvent = factory->createMotionEvent();
563
 
    if (! motionEvent) return NO_MEMORY;
564
 
 
565
 
    uint32_t chain = 0;
566
 
    for (size_t i = 0; i < count; i++) {
567
 
        InputMessage& msg = batch.samples.editItemAt(i);
568
 
        updateTouchState(&msg);
569
 
        if (i) {
570
 
            SeqChain seqChain;
571
 
            seqChain.seq = msg.header.seq;
572
 
            seqChain.chain = chain;
573
 
            mSeqChains.push(seqChain);
574
 
            addSample(motionEvent, &msg);
575
 
        } else {
576
 
            initializeMotionEvent(motionEvent, &msg);
577
 
        }
578
 
        chain = msg.header.seq;
579
 
    }
580
 
    batch.samples.removeItemsAt(0, count);
581
 
 
582
 
    *outSeq = chain;
583
 
    *outEvent = motionEvent;
584
 
    return OK;
585
 
}
586
 
 
587
 
void InputConsumer::updateTouchState(InputMessage* msg) {
588
 
    if (!mResampleTouch ||
589
 
            !(msg->body.motion.source & AINPUT_SOURCE_CLASS_POINTER)) {
590
 
        return;
591
 
    }
592
 
 
593
 
    int32_t deviceId = msg->body.motion.deviceId;
594
 
    int32_t source = msg->body.motion.source;
595
 
    std::chrono::nanoseconds eventTime = std::chrono::nanoseconds(msg->body.motion.eventTime);
596
 
 
597
 
    // Update the touch state history to incorporate the new input message.
598
 
    // If the message is in the past relative to the most recently produced resampled
599
 
    // touch, then use the resampled time and coordinates instead.
600
 
    switch (msg->body.motion.action & AMOTION_EVENT_ACTION_MASK) {
601
 
    case AMOTION_EVENT_ACTION_DOWN: {
602
 
        ssize_t index = findTouchState(deviceId, source);
603
 
        if (index < 0) {
604
 
            mTouchStates.push();
605
 
            index = mTouchStates.size() - 1;
606
 
        }
607
 
        TouchState& touchState = mTouchStates.editItemAt(index);
608
 
        touchState.initialize(deviceId, source);
609
 
        touchState.addHistory(msg);
610
 
        break;
611
 
    }
612
 
 
613
 
    case AMOTION_EVENT_ACTION_MOVE: {
614
 
        ssize_t index = findTouchState(deviceId, source);
615
 
        if (index >= 0) {
616
 
            TouchState& touchState = mTouchStates.editItemAt(index);
617
 
            touchState.addHistory(msg);
618
 
            if (eventTime < touchState.lastResample.eventTime) {
619
 
                rewriteMessage(touchState, msg);
620
 
            } else {
621
 
                touchState.lastResample.ids.clear();
622
 
            }
623
 
        }
624
 
        break;
625
 
    }
626
 
 
627
 
    case AMOTION_EVENT_ACTION_POINTER_DOWN: {
628
 
        ssize_t index = findTouchState(deviceId, source);
629
 
        if (index >= 0) {
630
 
            TouchState& touchState = mTouchStates.editItemAt(index);
631
 
            touchState.lastResample.ids.remove(msg->body.motion.getActionId());
632
 
            rewriteMessage(touchState, msg);
633
 
        }
634
 
        break;
635
 
    }
636
 
 
637
 
    case AMOTION_EVENT_ACTION_POINTER_UP: {
638
 
        ssize_t index = findTouchState(deviceId, source);
639
 
        if (index >= 0) {
640
 
            TouchState& touchState = mTouchStates.editItemAt(index);
641
 
            rewriteMessage(touchState, msg);
642
 
            touchState.lastResample.ids.remove(msg->body.motion.getActionId());
643
 
        }
644
 
        break;
645
 
    }
646
 
 
647
 
    case AMOTION_EVENT_ACTION_SCROLL: {
648
 
        ssize_t index = findTouchState(deviceId, source);
649
 
        if (index >= 0) {
650
 
            const TouchState& touchState = mTouchStates.itemAt(index);
651
 
            rewriteMessage(touchState, msg);
652
 
        }
653
 
        break;
654
 
    }
655
 
 
656
 
    case AMOTION_EVENT_ACTION_UP:
657
 
    case AMOTION_EVENT_ACTION_CANCEL: {
658
 
        ssize_t index = findTouchState(deviceId, source);
659
 
        if (index >= 0) {
660
 
            const TouchState& touchState = mTouchStates.itemAt(index);
661
 
            rewriteMessage(touchState, msg);
662
 
            mTouchStates.removeAt(index);
663
 
        }
664
 
        break;
665
 
    }
666
 
    }
667
 
}
668
 
 
669
 
void InputConsumer::rewriteMessage(const TouchState& state, InputMessage* msg) {
670
 
    for (size_t i = 0; i < msg->body.motion.pointerCount; i++) {
671
 
        uint32_t id = msg->body.motion.pointers[i].properties.id;
672
 
        if (state.lastResample.ids.contains(id)) {
673
 
            PointerCoords& msgCoords = msg->body.motion.pointers[i].coords;
674
 
            const PointerCoords& resampleCoords = state.lastResample.getPointerById(id);
675
 
#if DEBUG_RESAMPLING
676
 
            ALOGD("[%d] - rewrite (%0.3f, %0.3f), old (%0.3f, %0.3f)", id,
677
 
                    resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_X),
678
 
                    resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_Y),
679
 
                    msgCoords.getAxisValue(AMOTION_EVENT_AXIS_X),
680
 
                    msgCoords.getAxisValue(AMOTION_EVENT_AXIS_Y));
681
 
#endif
682
 
            msgCoords.setAxisValue(AMOTION_EVENT_AXIS_X, resampleCoords.getX());
683
 
            msgCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, resampleCoords.getY());
684
 
        }
685
 
    }
686
 
}
687
 
 
688
 
void InputConsumer::resampleTouchState(std::chrono::nanoseconds sampleTime, MotionEvent* event,
689
 
    const InputMessage* next) {
690
 
    if (!mResampleTouch
691
 
            || !(event->getSource() & AINPUT_SOURCE_CLASS_POINTER)
692
 
            || event->getAction() != AMOTION_EVENT_ACTION_MOVE) {
693
 
        return;
694
 
    }
695
 
 
696
 
    ssize_t index = findTouchState(event->getDeviceId(), event->getSource());
697
 
    if (index < 0) {
698
 
#if DEBUG_RESAMPLING
699
 
        ALOGD("Not resampled, no touch state for device.");
700
 
#endif
701
 
        return;
702
 
    }
703
 
 
704
 
    TouchState& touchState = mTouchStates.editItemAt(index);
705
 
    if (touchState.historySize < 1) {
706
 
#if DEBUG_RESAMPLING
707
 
        ALOGD("Not resampled, no history for device.");
708
 
#endif
709
 
        return;
710
 
    }
711
 
 
712
 
    // Ensure that the current sample has all of the pointers that need to be reported.
713
 
    const History* current = touchState.getHistory(0);
714
 
    size_t pointerCount = event->getPointerCount();
715
 
    for (size_t i = 0; i < pointerCount; i++) {
716
 
        uint32_t id = event->getPointerId(i);
717
 
        if (!current->ids.contains(id)) {
718
 
#if DEBUG_RESAMPLING
719
 
            ALOGD("Not resampled, missing id %d", id);
720
 
#endif
721
 
            return;
722
 
        }
723
 
    }
724
 
 
725
 
    // Find the data to use for resampling.
726
 
    const History* other;
727
 
    History future;
728
 
    float alpha;
729
 
    if (next) {
730
 
        // Interpolate between current sample and future sample.
731
 
        // So current->eventTime <= sampleTime <= future.eventTime.
732
 
        future.initializeFrom(next);
733
 
        other = &future;
734
 
        std::chrono::nanoseconds delta = future.eventTime - current->eventTime;
735
 
        if (delta < RESAMPLE_MIN_DELTA) {
736
 
#if DEBUG_RESAMPLING
737
 
            ALOGD("Not resampled, delta time is %lld ns.", delta);
738
 
#endif
739
 
            return;
740
 
        }
741
 
        alpha = (float)((sampleTime - current->eventTime).count()) / delta.count();
742
 
    } else if (touchState.historySize >= 2) {
743
 
        // Extrapolate future sample using current sample and past sample.
744
 
        // So other->eventTime <= current->eventTime <= sampleTime.
745
 
        other = touchState.getHistory(1);
746
 
        std::chrono::nanoseconds delta = current->eventTime - other->eventTime;
747
 
        if (delta < RESAMPLE_MIN_DELTA) {
748
 
#if DEBUG_RESAMPLING
749
 
            ALOGD("Not resampled, delta time is %lld ns.", delta);
750
 
#endif
751
 
            return;
752
 
        }
753
 
        std::chrono::nanoseconds maxPredict = current->eventTime + std::chrono::nanoseconds(min(delta.count()/2, RESAMPLE_MAX_PREDICTION.count()));
754
 
        if (sampleTime > maxPredict) {
755
 
#if DEBUG_RESAMPLING
756
 
            ALOGD("Sample time is too far in the future, adjusting prediction "
757
 
                    "from %lld to %lld ns.",
758
 
                    sampleTime - current->eventTime, maxPredict - current->eventTime);
759
 
#endif
760
 
            sampleTime = maxPredict;
761
 
        }
762
 
        alpha = (float)((current->eventTime - sampleTime).count()) / delta.count();
763
 
    } else {
764
 
#if DEBUG_RESAMPLING
765
 
        ALOGD("Not resampled, insufficient data.");
766
 
#endif
767
 
        return;
768
 
    }
769
 
 
770
 
    // Resample touch coordinates.
771
 
    touchState.lastResample.eventTime = sampleTime;
772
 
    touchState.lastResample.ids.clear();
773
 
    bool coords_resampled = false;
774
 
    for (size_t i = 0; i < pointerCount; i++) {
775
 
        uint32_t id = event->getPointerId(i);
776
 
        touchState.lastResample.idToIndex[id] = i;
777
 
        touchState.lastResample.ids.insert(id);
778
 
        PointerCoords& resampledCoords = touchState.lastResample.pointers[i];
779
 
        const PointerCoords& currentCoords = current->getPointerById(id);
780
 
        if (other->ids.contains(id)
781
 
                && shouldResampleTool(event->getToolType(i))) {
782
 
            const PointerCoords& otherCoords = other->getPointerById(id);
783
 
            resampledCoords.copyFrom(currentCoords);
784
 
            resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_X,
785
 
                    lerp(currentCoords.getX(), otherCoords.getX(), alpha));
786
 
            resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_Y,
787
 
                    lerp(currentCoords.getY(), otherCoords.getY(), alpha));
788
 
            coords_resampled = true;
789
 
            // No coordinate resampling for tooltype mouse - if we intend to
790
 
            // change that we must also resample RX, RY, HSCROLL, VSCROLL
791
 
#if DEBUG_RESAMPLING
792
 
            ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f), "
793
 
                    "other (%0.3f, %0.3f), alpha %0.3f",
794
 
                    id, resampledCoords.getX(), resampledCoords.getY(),
795
 
                    currentCoords.getX(), currentCoords.getY(),
796
 
                    otherCoords.getX(), otherCoords.getY(),
797
 
                    alpha);
798
 
#endif
799
 
        } else {
800
 
            // Before calling this method currentCoords was already part of the
801
 
            // event -> no need to add them to the event.
802
 
            resampledCoords.copyFrom(currentCoords);
803
 
#if DEBUG_RESAMPLING
804
 
            ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f)",
805
 
                    id, resampledCoords.getX(), resampledCoords.getY(),
806
 
                    currentCoords.getX(), currentCoords.getY());
807
 
#endif
808
 
        }
809
 
    }
810
 
 
811
 
    if (coords_resampled)
812
 
        event->addSample(sampleTime, touchState.lastResample.pointers);
813
 
}
814
 
 
815
 
bool InputConsumer::shouldResampleTool(int32_t toolType) {
816
 
    return toolType == AMOTION_EVENT_TOOL_TYPE_FINGER
817
 
            || toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
818
 
}
819
 
 
820
 
status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
821
 
#if DEBUG_TRANSPORT_ACTIONS
822
 
    ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s",
823
 
        c_str(mChannel->getName()), seq, handled ? "true" : "false");
824
 
#endif
825
 
 
826
 
    if (!seq) {
827
 
        ALOGE("Attempted to send a finished signal with sequence number 0.");
828
 
        return BAD_VALUE;
829
 
    }
830
 
 
831
 
    // Send finished signals for the batch sequence chain first.
832
 
    size_t seqChainCount = mSeqChains.size();
833
 
    if (seqChainCount) {
834
 
        uint32_t currentSeq = seq;
835
 
        uint32_t chainSeqs[seqChainCount];
836
 
        size_t chainIndex = 0;
837
 
        for (size_t i = seqChainCount; i-- > 0; ) {
838
 
             const SeqChain& seqChain = mSeqChains.itemAt(i);
839
 
             if (seqChain.seq == currentSeq) {
840
 
                 currentSeq = seqChain.chain;
841
 
                 chainSeqs[chainIndex++] = currentSeq;
842
 
                 mSeqChains.removeAt(i);
843
 
             }
844
 
        }
845
 
        status_t status = OK;
846
 
        while (!status && chainIndex-- > 0) {
847
 
            status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);
848
 
        }
849
 
        if (status) {
850
 
            // An error occurred so at least one signal was not sent, reconstruct the chain.
851
 
            do {
852
 
                SeqChain seqChain;
853
 
                seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq;
854
 
                seqChain.chain = chainSeqs[chainIndex];
855
 
                mSeqChains.push(seqChain);
856
 
            } while (chainIndex-- > 0);
857
 
            return status;
858
 
        }
859
 
    }
860
 
 
861
 
    // Send finished signal for the last message in the batch.
862
 
    return sendUnchainedFinishedSignal(seq, handled);
863
 
}
864
 
 
865
 
status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
866
 
    InputMessage msg;
867
 
    msg.header.type = InputMessage::TYPE_FINISHED;
868
 
    msg.header.size = sizeof(msg.body.finished);
869
 
    msg.header.seq = seq;
870
 
    msg.body.finished.handled = handled;
871
 
    return mChannel->sendMessage(&msg);
872
 
}
873
 
 
874
 
bool InputConsumer::hasDeferredEvent() const {
875
 
    return mMsgDeferred;
876
 
}
877
 
 
878
 
bool InputConsumer::hasPendingBatch() const {
879
 
    return !mBatches.isEmpty();
880
 
}
881
 
 
882
 
ssize_t InputConsumer::findBatch(int32_t deviceId, int32_t source) const {
883
 
    for (size_t i = 0; i < mBatches.size(); i++) {
884
 
        const Batch& batch = mBatches.itemAt(i);
885
 
        const InputMessage& head = batch.samples.itemAt(0);
886
 
        if (head.body.motion.deviceId == deviceId && head.body.motion.source == source) {
887
 
            return i;
888
 
        }
889
 
    }
890
 
    return -1;
891
 
}
892
 
 
893
 
ssize_t InputConsumer::findTouchState(int32_t deviceId, int32_t source) const {
894
 
    for (size_t i = 0; i < mTouchStates.size(); i++) {
895
 
        const TouchState& touchState = mTouchStates.itemAt(i);
896
 
        if (touchState.deviceId == deviceId && touchState.source == source) {
897
 
            return i;
898
 
        }
899
 
    }
900
 
    return -1;
901
 
}
902
 
 
903
 
void InputConsumer::initializeBufferEvent(RawBufferEvent* event, const InputMessage* msg) {
904
 
    event->buffer.assign(msg->body.buffer.buffer, msg->body.buffer.buffer + msg->header.size);
905
 
}
906
 
 
907
 
void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) {
908
 
    event->initialize(
909
 
            msg->body.key.deviceId,
910
 
            msg->body.key.source,
911
 
            msg->body.key.action,
912
 
            msg->body.key.flags,
913
 
            msg->body.key.keyCode,
914
 
            msg->body.key.scanCode,
915
 
            msg->body.key.metaState,
916
 
            msg->body.key.repeatCount,
917
 
            msg->body.key.cookieBlob,
918
 
            std::chrono::nanoseconds(msg->body.key.downTime),
919
 
            std::chrono::nanoseconds(msg->body.key.eventTime));
920
 
}
921
 
 
922
 
void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
923
 
    size_t pointerCount = msg->body.motion.pointerCount;
924
 
    PointerProperties pointerProperties[pointerCount];
925
 
    PointerCoords pointerCoords[pointerCount];
926
 
    for (size_t i = 0; i < pointerCount; i++) {
927
 
        pointerProperties[i].copyFrom(msg->body.motion.pointers[i].properties);
928
 
        pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
929
 
    }
930
 
 
931
 
    event->initialize(
932
 
            msg->body.motion.deviceId,
933
 
            msg->body.motion.source,
934
 
            msg->body.motion.action,
935
 
            msg->body.motion.flags,
936
 
            msg->body.motion.edgeFlags,
937
 
            msg->body.motion.metaState,
938
 
            msg->body.motion.buttonState,
939
 
            msg->body.motion.xOffset,
940
 
            msg->body.motion.yOffset,
941
 
            msg->body.motion.xPrecision,
942
 
            msg->body.motion.yPrecision,
943
 
            msg->body.motion.cookieBlob,
944
 
            std::chrono::nanoseconds(msg->body.motion.downTime),
945
 
            std::chrono::nanoseconds(msg->body.motion.eventTime),
946
 
            pointerCount,
947
 
            pointerProperties,
948
 
            pointerCoords);
949
 
}
950
 
 
951
 
void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) {
952
 
    size_t pointerCount = msg->body.motion.pointerCount;
953
 
    PointerCoords pointerCoords[pointerCount];
954
 
    for (size_t i = 0; i < pointerCount; i++) {
955
 
        pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
956
 
    }
957
 
 
958
 
    event->setMetaState(event->getMetaState() | msg->body.motion.metaState);
959
 
    event->addSample(std::chrono::nanoseconds(msg->body.motion.eventTime), pointerCoords);
960
 
}
961
 
 
962
 
bool InputConsumer::canAddSample(const Batch& batch, const InputMessage *msg) {
963
 
    const InputMessage& head = batch.samples.itemAt(0);
964
 
    size_t pointerCount = msg->body.motion.pointerCount;
965
 
    if (head.body.motion.pointerCount != pointerCount
966
 
            || head.body.motion.action != msg->body.motion.action) {
967
 
        return false;
968
 
    }
969
 
    for (size_t i = 0; i < pointerCount; i++) {
970
 
        if (head.body.motion.pointers[i].properties
971
 
                != msg->body.motion.pointers[i].properties) {
972
 
            return false;
973
 
        }
974
 
    }
975
 
    return true;
976
 
}
977
 
 
978
 
ssize_t InputConsumer::findSampleNoLaterThan(const Batch& batch, std::chrono::nanoseconds time) {
979
 
    size_t numSamples = batch.samples.size();
980
 
    size_t index = 0;
981
 
    while (index < numSamples
982
 
           && batch.samples.itemAt(index).body.motion.eventTime <= time.count()) {
983
 
        index += 1;
984
 
    }
985
 
    return ssize_t(index) - 1;
986
 
}
987
 
 
988
 
} // namespace android