Skip to content

Commit 771526c

Browse files
author
Jeff Brown
committed
Resample touch events on frame boundaries.
Bug: 6375101 Change-Id: I8774e366306bb2b6b4e42b913525bf25b0380ec3
1 parent 330314c commit 771526c

File tree

9 files changed

+393
-74
lines changed

9 files changed

+393
-74
lines changed

core/java/android/view/InputEventReceiver.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ private static native int nativeInit(InputEventReceiver receiver,
4646
InputChannel inputChannel, MessageQueue messageQueue);
4747
private static native void nativeDispose(int receiverPtr);
4848
private static native void nativeFinishInputEvent(int receiverPtr, int seq, boolean handled);
49-
private static native void nativeConsumeBatchedInputEvents(int receiverPtr);
49+
private static native void nativeConsumeBatchedInputEvents(int receiverPtr,
50+
long frameTimeNanos);
5051

5152
/**
5253
* Creates an input event receiver bound to the specified input channel.
@@ -114,7 +115,7 @@ public void onInputEvent(InputEvent event) {
114115
* immediately (such as a pointer up event).
115116
*/
116117
public void onBatchedInputEventPending() {
117-
consumeBatchedInputEvents();
118+
consumeBatchedInputEvents(-1);
118119
}
119120

120121
/**
@@ -150,13 +151,16 @@ public final void finishInputEvent(InputEvent event, boolean handled) {
150151
*
151152
* This method forces all batched input events to be delivered immediately.
152153
* Should be called just before animating or drawing a new frame in the UI.
154+
*
155+
* @param frameTimeNanos The time in the {@link System#nanoTime()} time base
156+
* when the current display frame started rendering, or -1 if unknown.
153157
*/
154-
public final void consumeBatchedInputEvents() {
158+
public final void consumeBatchedInputEvents(long frameTimeNanos) {
155159
if (mReceiverPtr == 0) {
156160
Log.w(TAG, "Attempted to consume batched input events but the input event "
157161
+ "receiver has already been disposed.");
158162
} else {
159-
nativeConsumeBatchedInputEvents(mReceiverPtr);
163+
nativeConsumeBatchedInputEvents(mReceiverPtr, frameTimeNanos);
160164
}
161165
}
162166

core/java/android/view/ViewRootImpl.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4204,11 +4204,11 @@ void unscheduleConsumeBatchedInput() {
42044204
}
42054205
}
42064206

4207-
void doConsumeBatchedInput() {
4207+
void doConsumeBatchedInput(long frameTimeNanos) {
42084208
if (mConsumeBatchedInputScheduled) {
42094209
mConsumeBatchedInputScheduled = false;
42104210
if (mInputEventReceiver != null) {
4211-
mInputEventReceiver.consumeBatchedInputEvents();
4211+
mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos);
42124212
}
42134213
doProcessInputEvents();
42144214
}
@@ -4248,7 +4248,7 @@ public void dispose() {
42484248
final class ConsumeBatchedInputRunnable implements Runnable {
42494249
@Override
42504250
public void run() {
4251-
doConsumeBatchedInput();
4251+
doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
42524252
}
42534253
}
42544254
final ConsumeBatchedInputRunnable mConsumedBatchedInputRunnable =

core/jni/android_app_NativeActivity.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
207207

208208
uint32_t consumerSeq;
209209
InputEvent* myEvent = NULL;
210-
status_t res = mConsumer.consume(&mPooledInputEventFactory, true /*consumeBatches*/,
210+
status_t res = mConsumer.consume(&mPooledInputEventFactory, true /*consumeBatches*/, -1,
211211
&consumerSeq, &myEvent);
212212
if (res != android::OK) {
213213
if (res != android::WOULD_BLOCK) {

core/jni/android_view_InputEventReceiver.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ class NativeInputEventReceiver : public RefBase {
5252

5353
status_t initialize();
5454
status_t finishInputEvent(uint32_t seq, bool handled);
55-
status_t consumeEvents(JNIEnv* env, bool consumeBatches);
55+
status_t consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime);
5656

5757
protected:
5858
virtual ~NativeInputEventReceiver();
@@ -130,15 +130,16 @@ int NativeInputEventReceiver::handleReceiveCallback(int receiveFd, int events, v
130130
}
131131

132132
JNIEnv* env = AndroidRuntime::getJNIEnv();
133-
status_t status = r->consumeEvents(env, false /*consumeBatches*/);
133+
status_t status = r->consumeEvents(env, false /*consumeBatches*/, -1);
134134
r->mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
135135
return status == OK || status == NO_MEMORY ? 1 : 0;
136136
}
137137

138-
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, bool consumeBatches) {
138+
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
139+
bool consumeBatches, nsecs_t frameTime) {
139140
#if DEBUG_DISPATCH_CYCLE
140-
ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s.", getInputChannelName(),
141-
consumeBatches ? "true" : "false");
141+
ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s, frameTime=%lld.",
142+
getInputChannelName(), consumeBatches ? "true" : "false", frameTime);
142143
#endif
143144

144145
if (consumeBatches) {
@@ -150,7 +151,7 @@ status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, bool consumeBatche
150151
uint32_t seq;
151152
InputEvent* inputEvent;
152153
status_t status = mInputConsumer.consume(&mInputEventFactory,
153-
consumeBatches, &seq, &inputEvent);
154+
consumeBatches, frameTime, &seq, &inputEvent);
154155
if (status) {
155156
if (status == WOULD_BLOCK) {
156157
if (!skipCallbacks && !mBatchedInputEventPending
@@ -270,10 +271,11 @@ static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr,
270271
}
271272
}
272273

273-
static void nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jint receiverPtr) {
274+
static void nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jint receiverPtr,
275+
jlong frameTimeNanos) {
274276
sp<NativeInputEventReceiver> receiver =
275277
reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
276-
status_t status = receiver->consumeEvents(env, true /*consumeBatches*/);
278+
status_t status = receiver->consumeEvents(env, true /*consumeBatches*/, frameTimeNanos);
277279
if (status && status != DEAD_OBJECT && !env->ExceptionCheck()) {
278280
String8 message;
279281
message.appendFormat("Failed to consume batched input event. status=%d", status);
@@ -291,7 +293,7 @@ static JNINativeMethod gMethods[] = {
291293
(void*)nativeDispose },
292294
{ "nativeFinishInputEvent", "(IIZ)V",
293295
(void*)nativeFinishInputEvent },
294-
{ "nativeConsumeBatchedInputEvents", "(I)V",
296+
{ "nativeConsumeBatchedInputEvents", "(IJ)V",
295297
(void*)nativeConsumeBatchedInputEvents },
296298
};
297299

include/androidfw/Input.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ struct PointerCoords {
208208
status_t setAxisValue(int32_t axis, float value);
209209

210210
void scale(float scale);
211+
void lerp(const PointerCoords& a, const PointerCoords& b, float alpha);
211212

212213
inline float getX() const {
213214
return getAxisValue(AMOTION_EVENT_AXIS_X);

include/androidfw/InputTransport.h

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <utils/RefBase.h>
3434
#include <utils/String8.h>
3535
#include <utils/Vector.h>
36+
#include <utils/BitSet.h>
3637

3738
namespace android {
3839

@@ -271,6 +272,9 @@ class InputConsumer {
271272
* If consumeBatches is true, then events are still batched but they are consumed
272273
* immediately as soon as the input channel is exhausted.
273274
*
275+
* The frameTime parameter specifies the time when the current display frame started
276+
* rendering in the CLOCK_MONOTONIC time base, or -1 if unknown.
277+
*
274278
* The returned sequence number is never 0 unless the operation failed.
275279
*
276280
* Returns OK on success.
@@ -280,7 +284,7 @@ class InputConsumer {
280284
* Other errors probably indicate that the channel is broken.
281285
*/
282286
status_t consume(InputEventFactoryInterface* factory, bool consumeBatches,
283-
uint32_t* outSeq, InputEvent** outEvent);
287+
nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
284288

285289
/* Sends a finished signal to the publisher to inform it that the message
286290
* with the specified sequence number has finished being process and whether
@@ -298,7 +302,7 @@ class InputConsumer {
298302
* has a deferred event to be processed. Deferred events are somewhat special in
299303
* that they have already been removed from the input channel. If the input channel
300304
* becomes empty, the client may need to do extra work to ensure that it processes
301-
* the deferred event despite the fact that the inptu channel's file descriptor
305+
* the deferred event despite the fact that the input channel's file descriptor
302306
* is not readable.
303307
*
304308
* One option is simply to call consume() in a loop until it returns WOULD_BLOCK.
@@ -329,11 +333,55 @@ class InputConsumer {
329333

330334
// Batched motion events per device and source.
331335
struct Batch {
332-
uint32_t seq; // sequence number of last input message batched in the event
333-
MotionEvent event;
336+
Vector<InputMessage> samples;
334337
};
335338
Vector<Batch> mBatches;
336339

340+
// Touch state per device and source, only for sources of class pointer.
341+
struct History {
342+
nsecs_t eventTime;
343+
BitSet32 idBits;
344+
PointerCoords pointers[MAX_POINTERS];
345+
346+
void initializeFrom(const InputMessage* msg) {
347+
eventTime = msg->body.motion.eventTime;
348+
idBits.clear();
349+
for (size_t i = 0; i < msg->body.motion.pointerCount; i++) {
350+
uint32_t id = msg->body.motion.pointers[i].properties.id;
351+
idBits.markBit(id);
352+
size_t index = idBits.getIndexOfBit(id);
353+
pointers[index].copyFrom(msg->body.motion.pointers[i].coords);
354+
}
355+
}
356+
};
357+
struct TouchState {
358+
int32_t deviceId;
359+
int32_t source;
360+
size_t historyCurrent;
361+
size_t historySize;
362+
History history[2];
363+
364+
void initialize(int32_t deviceId, int32_t source) {
365+
this->deviceId = deviceId;
366+
this->source = source;
367+
historyCurrent = 0;
368+
historySize = 0;
369+
}
370+
371+
void addHistory(const InputMessage* msg) {
372+
historyCurrent ^= 1;
373+
if (historySize < 2) {
374+
historySize += 1;
375+
}
376+
history[historyCurrent].initializeFrom(msg);
377+
}
378+
379+
const History* getHistory(size_t index) const {
380+
return &history[(historyCurrent + index) & 1];
381+
}
382+
};
383+
Vector<TouchState> mTouchStates;
384+
337385
// Chain of batched sequence numbers. When multiple input messages are combined into
338386
// a batch, we append a record here that associates the last sequence number in the
339387
// batch with the previous one. When the finished signal is sent, we traverse the
@@ -344,13 +392,26 @@ class InputConsumer {
344392
};
345393
Vector<SeqChain> mSeqChains;
346394

395+
status_t consumeBatch(InputEventFactoryInterface* factory,
396+
nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
397+
status_t consumeSamples(InputEventFactoryInterface* factory,
398+
Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent);
399+
400+
void updateTouchState(InputMessage* msg);
401+
void resampleTouchState(nsecs_t frameTime, MotionEvent* event,
402+
const InputMessage *next);
403+
347404
ssize_t findBatch(int32_t deviceId, int32_t source) const;
405+
ssize_t findTouchState(int32_t deviceId, int32_t source) const;
406+
348407
status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled);
349408

350409
static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg);
351410
static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg);
352-
static bool canAppendSamples(const MotionEvent* event, const InputMessage* msg);
353-
static void appendSamples(MotionEvent* event, const InputMessage* msg);
411+
static void addSample(MotionEvent* event, const InputMessage* msg);
412+
static bool canAddSample(const Batch& batch, const InputMessage* msg);
413+
static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time);
414+
static bool shouldResampleTool(int32_t toolType);
354415
};
355416

356417
} // namespace android

libs/androidfw/Input.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,26 @@ void PointerCoords::scale(float scaleFactor) {
229229
scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor);
230230
}
231231

232+
void PointerCoords::lerp(const PointerCoords& a, const PointerCoords& b, float alpha) {
233+
bits = 0;
234+
for (uint64_t bitsRemaining = a.bits | b.bits; bitsRemaining; ) {
235+
int32_t axis = __builtin_ctz(bitsRemaining);
236+
uint64_t axisBit = 1LL << axis;
237+
bitsRemaining &= ~axisBit;
238+
if (a.bits & axisBit) {
239+
if (b.bits & axisBit) {
240+
float aval = a.getAxisValue(axis);
241+
float bval = b.getAxisValue(axis);
242+
setAxisValue(axis, aval + alpha * (bval - aval));
243+
} else {
244+
setAxisValue(axis, a.getAxisValue(axis));
245+
}
246+
} else {
247+
setAxisValue(axis, b.getAxisValue(axis));
248+
}
249+
}
250+
}
251+
232252
#ifdef HAVE_ANDROID_OS
233253
status_t PointerCoords::readFromParcel(Parcel* parcel) {
234254
bits = parcel->readInt64();

0 commit comments

Comments
 (0)