Even more native input dispatch work in progress.
Added more tests.
Fixed a regression in Vector.
Fixed bugs in pointer tracking.
Fixed a starvation issue in PollLoop when setting or removing callbacks.
Fixed a couple of policy nits.
Modified the internal representation of MotionEvent to be more
efficient and more consistent.
Added code to skip/cancel virtual key processing when there are multiple
pointers down. This helps to better disambiguate virtual key presses
from stray touches (such as cheek presses).
Change-Id: I2a7d2cce0195afb9125b23378baa94fd2fc6671c
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 62b5f28..5a280ae 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -19,6 +19,9 @@
// Log debug messages about pointers.
#define DEBUG_POINTERS 1
+// Log debug messages about pointer assignment calculations.
+#define DEBUG_POINTER_ASSIGNMENT 0
+
#include <cutils/log.h>
#include <ui/InputReader.h>
@@ -57,6 +60,14 @@
return a < b ? a : b;
}
+template<typename T>
+inline static void swap(T& a, T& b) {
+ T temp = a;
+ a = b;
+ b = temp;
+}
+
+
int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
int32_t mask;
switch (keyCode) {
@@ -188,6 +199,12 @@
jumpyTouchFilter.jumpyPointsDropped = 0;
}
+struct PointerDistanceHeapElement {
+ uint32_t currentPointerIndex : 8;
+ uint32_t lastPointerIndex : 8;
+ uint64_t distance : 48; // squared distance
+};
+
void InputDevice::TouchScreenState::calculatePointerIds() {
uint32_t currentPointerCount = currentTouch.pointerCount;
uint32_t lastPointerCount = lastTouch.pointerCount;
@@ -214,11 +231,7 @@
// We build a heap of squared euclidean distances between current and last pointers
// associated with the current and last pointer indices. Then, we find the best
// match (by distance) for each current pointer.
- struct {
- uint32_t currentPointerIndex : 8;
- uint32_t lastPointerIndex : 8;
- uint64_t distance : 48; // squared distance
- } heap[MAX_POINTERS * MAX_POINTERS];
+ PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS];
uint32_t heapSize = 0;
for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount;
@@ -233,23 +246,45 @@
uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
// Insert new element into the heap (sift up).
+ heap[heapSize].currentPointerIndex = currentPointerIndex;
+ heap[heapSize].lastPointerIndex = lastPointerIndex;
+ heap[heapSize].distance = distance;
heapSize += 1;
- uint32_t insertionIndex = heapSize;
- while (insertionIndex > 1) {
- uint32_t parentIndex = (insertionIndex - 1) / 2;
- if (distance < heap[parentIndex].distance) {
- heap[insertionIndex] = heap[parentIndex];
- insertionIndex = parentIndex;
- } else {
- break;
- }
- }
- heap[insertionIndex].currentPointerIndex = currentPointerIndex;
- heap[insertionIndex].lastPointerIndex = lastPointerIndex;
- heap[insertionIndex].distance = distance;
}
}
+ // Heapify
+ for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) {
+ startIndex -= 1;
+ for (uint32_t parentIndex = startIndex; ;) {
+ uint32_t childIndex = parentIndex * 2 + 1;
+ if (childIndex >= heapSize) {
+ break;
+ }
+
+ if (childIndex + 1 < heapSize
+ && heap[childIndex + 1].distance < heap[childIndex].distance) {
+ childIndex += 1;
+ }
+
+ if (heap[parentIndex].distance <= heap[childIndex].distance) {
+ break;
+ }
+
+ swap(heap[parentIndex], heap[childIndex]);
+ parentIndex = childIndex;
+ }
+ }
+
+#if DEBUG_POINTER_ASSIGNMENT
+ LOGD("calculatePointerIds - initial distance min-heap: size=%d", heapSize);
+ for (size_t i = 0; i < heapSize; i++) {
+ LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
+ i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
+ heap[i].distance);
+ }
+#endif
+
// Pull matches out by increasing order of distance.
// To avoid reassigning pointers that have already been matched, the loop keeps track
// of which last and current pointers have been matched using the matchedXXXBits variables.
@@ -262,7 +297,7 @@
for (;;) {
if (first) {
// The first time through the loop, we just consume the root element of
- // the heap (the one with smalled distance).
+ // the heap (the one with smallest distance).
first = false;
} else {
// Previous iterations consumed the root element of the heap.
@@ -270,10 +305,10 @@
heapSize -= 1;
assert(heapSize > 0);
- // Sift down to find where the element at index heapSize needs to be moved.
- uint32_t rootIndex = 0;
- for (;;) {
- uint32_t childIndex = rootIndex * 2 + 1;
+ // Sift down.
+ heap[0] = heap[heapSize];
+ for (uint32_t parentIndex = 0; ;) {
+ uint32_t childIndex = parentIndex * 2 + 1;
if (childIndex >= heapSize) {
break;
}
@@ -283,14 +318,22 @@
childIndex += 1;
}
- if (heap[heapSize].distance < heap[childIndex].distance) {
+ if (heap[parentIndex].distance <= heap[childIndex].distance) {
break;
}
- heap[rootIndex] = heap[childIndex];
- rootIndex = childIndex;
+ swap(heap[parentIndex], heap[childIndex]);
+ parentIndex = childIndex;
}
- heap[rootIndex] = heap[heapSize];
+
+#if DEBUG_POINTER_ASSIGNMENT
+ LOGD("calculatePointerIds - reduced distance min-heap: size=%d", heapSize);
+ for (size_t i = 0; i < heapSize; i++) {
+ LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
+ i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
+ heap[i].distance);
+ }
+#endif
}
uint32_t currentPointerIndex = heap[0].currentPointerIndex;
@@ -306,6 +349,11 @@
currentTouch.pointers[currentPointerIndex].id = id;
currentTouch.idToIndex[id] = currentPointerIndex;
usedIdBits.markBit(id);
+
+#if DEBUG_POINTER_ASSIGNMENT
+ LOGD("calculatePointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld",
+ lastPointerIndex, currentPointerIndex, id, heap[0].distance);
+#endif
break;
}
}
@@ -320,6 +368,11 @@
currentTouch.idToIndex[id] = currentPointerIndex;
usedIdBits.markBit(id);
+#if DEBUG_POINTER_ASSIGNMENT
+ LOGD("calculatePointerIds - assigned: cur=%d, id=%d",
+ currentPointerIndex, id);
+#endif
+
if (--i == 0) break; // done
matchedCurrentBits.markBit(currentPointerIndex);
}
@@ -1208,8 +1261,10 @@
int32_t x = device->touchScreen.currentTouch.pointers[0].x;
int32_t y = device->touchScreen.currentTouch.pointers[0].y;
- if (device->touchScreen.isPointInsideDisplay(x, y)) {
- // Pointer moved inside the display area. Send key cancellation.
+ if (device->touchScreen.isPointInsideDisplay(x, y)
+ || device->touchScreen.currentTouch.pointerCount != 1) {
+ // Pointer moved inside the display area or another pointer also went down.
+ // Send key cancellation.
device->touchScreen.currentVirtualKey.down = false;
#if DEBUG_VIRTUAL_KEYS
@@ -1227,7 +1282,7 @@
device->touchScreen.lastTouch.clear();
return false; // not consumed
}
- } else if (device->touchScreen.currentTouch.pointerCount > 0
+ } else if (device->touchScreen.currentTouch.pointerCount == 1
&& device->touchScreen.lastTouch.pointerCount == 0) {
int32_t x = device->touchScreen.currentTouch.pointers[0].x;
int32_t y = device->touchScreen.currentTouch.pointers[0].y;