am 82e4373e
: Merge "Use touch pad gestures to manipulate the pointer. (DO NOT MERGE)" into honeycomb-mr2
* commit '82e4373ed3775395a23d161e58c003e82511921a': Use touch pad gestures to manipulate the pointer. (DO NOT MERGE)
This commit is contained in:
@ -27,6 +27,7 @@
|
|||||||
#include <utils/Timers.h>
|
#include <utils/Timers.h>
|
||||||
#include <utils/RefBase.h>
|
#include <utils/RefBase.h>
|
||||||
#include <utils/String8.h>
|
#include <utils/String8.h>
|
||||||
|
#include <utils/BitSet.h>
|
||||||
|
|
||||||
#ifdef HAVE_ANDROID_OS
|
#ifdef HAVE_ANDROID_OS
|
||||||
class SkMatrix;
|
class SkMatrix;
|
||||||
@ -210,6 +211,13 @@ struct PointerCoords {
|
|||||||
status_t writeToParcel(Parcel* parcel) const;
|
status_t writeToParcel(Parcel* parcel) const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool operator==(const PointerCoords& other) const;
|
||||||
|
inline bool operator!=(const PointerCoords& other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
void copyFrom(const PointerCoords& other);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void tooManyAxes(int axis);
|
void tooManyAxes(int axis);
|
||||||
};
|
};
|
||||||
@ -544,6 +552,53 @@ private:
|
|||||||
MotionEvent mMotionEvent;
|
MotionEvent mMotionEvent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculates the velocity of pointer motions over time.
|
||||||
|
* Uses essentially the same algorithm as android.view.VelocityTracker.
|
||||||
|
*/
|
||||||
|
class VelocityTracker {
|
||||||
|
public:
|
||||||
|
struct Position {
|
||||||
|
float x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
VelocityTracker();
|
||||||
|
|
||||||
|
// Resets the velocity tracker state.
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
// Adds movement information for a set of pointers.
|
||||||
|
// The idBits bitfield specifies the pointer ids of the pointers whose positions
|
||||||
|
// are included in the movement.
|
||||||
|
// The positions array contains position information for each pointer in order by
|
||||||
|
// increasing id. Its size should be equal to the number of one bits in idBits.
|
||||||
|
void addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions);
|
||||||
|
|
||||||
|
// Gets the velocity of the specified pointer id in position units per second.
|
||||||
|
// Returns false and sets the velocity components to zero if there is no movement
|
||||||
|
// information for the pointer.
|
||||||
|
bool getVelocity(uint32_t id, float* outVx, float* outVy) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Number of samples to keep.
|
||||||
|
static const uint32_t HISTORY_SIZE = 10;
|
||||||
|
|
||||||
|
// Oldest sample to consider when calculating the velocity.
|
||||||
|
static const nsecs_t MAX_AGE = 200 * 1000000; // 200 ms
|
||||||
|
|
||||||
|
// The minimum duration between samples when estimating velocity.
|
||||||
|
static const nsecs_t MIN_DURATION = 5 * 1000000; // 5 ms
|
||||||
|
|
||||||
|
struct Movement {
|
||||||
|
nsecs_t eventTime;
|
||||||
|
BitSet32 idBits;
|
||||||
|
Position positions[MAX_POINTERS];
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t mIndex;
|
||||||
|
Movement mMovements[HISTORY_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Describes the characteristics and capabilities of an input device.
|
* Describes the characteristics and capabilities of an input device.
|
||||||
*/
|
*/
|
||||||
|
@ -61,6 +61,12 @@ struct BitSet32 {
|
|||||||
// Result is undefined if all bits are marked.
|
// Result is undefined if all bits are marked.
|
||||||
inline uint32_t firstUnmarkedBit() const { return __builtin_clz(~ value); }
|
inline uint32_t firstUnmarkedBit() const { return __builtin_clz(~ value); }
|
||||||
|
|
||||||
|
// Gets the index of the specified bit in the set, which is the number of
|
||||||
|
// marked bits that appear before the specified bit.
|
||||||
|
inline uint32_t getIndexOfBit(uint32_t n) const {
|
||||||
|
return __builtin_popcount(value & ~(0xffffffffUL >> n));
|
||||||
|
}
|
||||||
|
|
||||||
inline bool operator== (const BitSet32& other) const { return value == other.value; }
|
inline bool operator== (const BitSet32& other) const { return value == other.value; }
|
||||||
inline bool operator!= (const BitSet32& other) const { return value != other.value; }
|
inline bool operator!= (const BitSet32& other) const { return value != other.value; }
|
||||||
};
|
};
|
||||||
|
@ -7,8 +7,12 @@
|
|||||||
|
|
||||||
//#define LOG_NDEBUG 0
|
//#define LOG_NDEBUG 0
|
||||||
|
|
||||||
|
// Log debug messages about keymap probing.
|
||||||
#define DEBUG_PROBE 0
|
#define DEBUG_PROBE 0
|
||||||
|
|
||||||
|
// Log debug messages about velocity tracking.
|
||||||
|
#define DEBUG_VELOCITY 0
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -347,6 +351,27 @@ void PointerCoords::tooManyAxes(int axis) {
|
|||||||
"cannot contain more than %d axis values.", axis, int(MAX_AXES));
|
"cannot contain more than %d axis values.", axis, int(MAX_AXES));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PointerCoords::operator==(const PointerCoords& other) const {
|
||||||
|
if (bits != other.bits) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint32_t count = __builtin_popcountll(bits);
|
||||||
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
|
if (values[i] != other.values[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PointerCoords::copyFrom(const PointerCoords& other) {
|
||||||
|
bits = other.bits;
|
||||||
|
uint32_t count = __builtin_popcountll(bits);
|
||||||
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
|
values[i] = other.values[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- MotionEvent ---
|
// --- MotionEvent ---
|
||||||
|
|
||||||
@ -633,6 +658,135 @@ bool MotionEvent::isTouchEvent(int32_t source, int32_t action) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- VelocityTracker ---
|
||||||
|
|
||||||
|
VelocityTracker::VelocityTracker() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VelocityTracker::clear() {
|
||||||
|
mIndex = 0;
|
||||||
|
mMovements[0].idBits.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) {
|
||||||
|
if (++mIndex == HISTORY_SIZE) {
|
||||||
|
mIndex = 0;
|
||||||
|
}
|
||||||
|
Movement& movement = mMovements[mIndex];
|
||||||
|
movement.eventTime = eventTime;
|
||||||
|
movement.idBits = idBits;
|
||||||
|
uint32_t count = idBits.count();
|
||||||
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
|
movement.positions[i] = positions[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG_VELOCITY
|
||||||
|
LOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x", eventTime, idBits.value);
|
||||||
|
for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) {
|
||||||
|
uint32_t id = iterBits.firstMarkedBit();
|
||||||
|
uint32_t index = idBits.getIndexOfBit(id);
|
||||||
|
iterBits.clearBit(id);
|
||||||
|
float vx, vy;
|
||||||
|
bool available = getVelocity(id, &vx, &vy);
|
||||||
|
if (available) {
|
||||||
|
LOGD(" %d: position (%0.3f, %0.3f), velocity (%0.3f, %0.3f), speed %0.3f",
|
||||||
|
id, positions[index].x, positions[index].y, vx, vy, sqrtf(vx * vx + vy * vy));
|
||||||
|
} else {
|
||||||
|
assert(vx == 0 && vy == 0);
|
||||||
|
LOGD(" %d: position (%0.3f, %0.3f), velocity not available",
|
||||||
|
id, positions[index].x, positions[index].y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
|
||||||
|
const Movement& newestMovement = mMovements[mIndex];
|
||||||
|
if (newestMovement.idBits.hasBit(id)) {
|
||||||
|
// Find the oldest sample that contains the pointer and that is not older than MAX_AGE.
|
||||||
|
nsecs_t minTime = newestMovement.eventTime - MAX_AGE;
|
||||||
|
uint32_t oldestIndex = mIndex;
|
||||||
|
uint32_t numTouches = 1;
|
||||||
|
do {
|
||||||
|
uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1;
|
||||||
|
const Movement& nextOldestMovement = mMovements[nextOldestIndex];
|
||||||
|
if (!nextOldestMovement.idBits.hasBit(id)
|
||||||
|
|| nextOldestMovement.eventTime < minTime) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
oldestIndex = nextOldestIndex;
|
||||||
|
} while (++numTouches < HISTORY_SIZE);
|
||||||
|
|
||||||
|
// If we have a lot of samples, skip the last received sample since it is
|
||||||
|
// probably pretty noisy compared to the sum of all of the traces already acquired.
|
||||||
|
//
|
||||||
|
// NOTE: This condition exists in the android.view.VelocityTracker and imposes a
|
||||||
|
// bias against the most recent data.
|
||||||
|
if (numTouches > 3) {
|
||||||
|
numTouches -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate an exponentially weighted moving average of the velocity at different
|
||||||
|
// points in time measured relative to the oldest samples. This is essentially
|
||||||
|
// an IIR filter.
|
||||||
|
//
|
||||||
|
// One problem with this algorithm is that the sample data may be poorly conditioned.
|
||||||
|
// Sometimes samples arrive very close together in time which can cause us to
|
||||||
|
// overestimate the velocity at that time point. Most samples might be measured
|
||||||
|
// 16ms apart but some consecutive samples could be only 0.5sm apart due to
|
||||||
|
// the way they are reported by the hardware or driver (sometimes in bursts or with
|
||||||
|
// significant jitter). The instantaneous velocity for those samples 0.5ms apart will
|
||||||
|
// be calculated to be 32 times what it should have been.
|
||||||
|
// To work around this effect, we impose a minimum duration on the samples.
|
||||||
|
//
|
||||||
|
// FIXME: Samples close together in time can have an disproportionately large
|
||||||
|
// impact on the result because all samples are equally weighted. The average should
|
||||||
|
// instead take the time factor into account.
|
||||||
|
//
|
||||||
|
// FIXME: The minimum duration condition does not exist in
|
||||||
|
// android.view.VelocityTracker yet. It is less important there because sample times
|
||||||
|
// are truncated to the millisecond so back to back samples will often appear to be
|
||||||
|
// zero milliseconds apart and will be ignored if they are the oldest ones.
|
||||||
|
float accumVx = 0;
|
||||||
|
float accumVy = 0;
|
||||||
|
uint32_t index = oldestIndex;
|
||||||
|
uint32_t samplesUsed = 0;
|
||||||
|
const Movement& oldestMovement = mMovements[oldestIndex];
|
||||||
|
const Position& oldestPosition =
|
||||||
|
oldestMovement.positions[oldestMovement.idBits.getIndexOfBit(id)];
|
||||||
|
while (numTouches-- > 1) {
|
||||||
|
if (++index == HISTORY_SIZE) {
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
const Movement& movement = mMovements[index];
|
||||||
|
nsecs_t duration = movement.eventTime - oldestMovement.eventTime;
|
||||||
|
if (duration > MIN_DURATION) {
|
||||||
|
const Position& position = movement.positions[movement.idBits.getIndexOfBit(id)];
|
||||||
|
float scale = 1000000000.0f / duration; // one over time delta in seconds
|
||||||
|
float vx = (position.x - oldestPosition.x) * scale;
|
||||||
|
float vy = (position.y - oldestPosition.y) * scale;
|
||||||
|
accumVx = accumVx == 0 ? vx : (accumVx + vx) * 0.5f;
|
||||||
|
accumVy = accumVy == 0 ? vy : (accumVy + vy) * 0.5f;
|
||||||
|
samplesUsed += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we used at least one sample.
|
||||||
|
if (samplesUsed != 0) {
|
||||||
|
*outVx = accumVx;
|
||||||
|
*outVy = accumVy;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No data available for this pointer.
|
||||||
|
*outVx = 0;
|
||||||
|
*outVy = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- InputDeviceInfo ---
|
// --- InputDeviceInfo ---
|
||||||
|
|
||||||
InputDeviceInfo::InputDeviceInfo() {
|
InputDeviceInfo::InputDeviceInfo() {
|
||||||
|
@ -406,7 +406,7 @@ status_t InputPublisher::publishMotionEvent(
|
|||||||
|
|
||||||
for (size_t i = 0; i < pointerCount; i++) {
|
for (size_t i = 0; i < pointerCount; i++) {
|
||||||
mSharedMessage->motion.pointerIds[i] = pointerIds[i];
|
mSharedMessage->motion.pointerIds[i] = pointerIds[i];
|
||||||
mSharedMessage->motion.sampleData[0].coords[i] = pointerCoords[i];
|
mSharedMessage->motion.sampleData[0].coords[i].copyFrom(pointerCoords[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache essential information about the motion event to ensure that a malicious consumer
|
// Cache essential information about the motion event to ensure that a malicious consumer
|
||||||
@ -475,7 +475,7 @@ status_t InputPublisher::appendMotionSample(
|
|||||||
|
|
||||||
mMotionEventSampleDataTail->eventTime = eventTime;
|
mMotionEventSampleDataTail->eventTime = eventTime;
|
||||||
for (size_t i = 0; i < mMotionEventPointerCount; i++) {
|
for (size_t i = 0; i < mMotionEventPointerCount; i++) {
|
||||||
mMotionEventSampleDataTail->coords[i] = pointerCoords[i];
|
mMotionEventSampleDataTail->coords[i].copyFrom(pointerCoords[i]);
|
||||||
}
|
}
|
||||||
mMotionEventSampleDataTail = newTail;
|
mMotionEventSampleDataTail = newTail;
|
||||||
|
|
||||||
|
@ -2178,8 +2178,8 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet
|
|||||||
if (pointerIds.hasBit(pointerId)) {
|
if (pointerIds.hasBit(pointerId)) {
|
||||||
splitPointerIndexMap[splitPointerCount] = originalPointerIndex;
|
splitPointerIndexMap[splitPointerCount] = originalPointerIndex;
|
||||||
splitPointerIds[splitPointerCount] = pointerId;
|
splitPointerIds[splitPointerCount] = pointerId;
|
||||||
splitPointerCoords[splitPointerCount] =
|
splitPointerCoords[splitPointerCount].copyFrom(
|
||||||
originalMotionEntry->firstSample.pointerCoords[originalPointerIndex];
|
originalMotionEntry->firstSample.pointerCoords[originalPointerIndex]);
|
||||||
splitPointerCount += 1;
|
splitPointerCount += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2242,8 +2242,8 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet
|
|||||||
for (uint32_t splitPointerIndex = 0; splitPointerIndex < splitPointerCount;
|
for (uint32_t splitPointerIndex = 0; splitPointerIndex < splitPointerCount;
|
||||||
splitPointerIndex++) {
|
splitPointerIndex++) {
|
||||||
uint32_t originalPointerIndex = splitPointerIndexMap[splitPointerIndex];
|
uint32_t originalPointerIndex = splitPointerIndexMap[splitPointerIndex];
|
||||||
splitPointerCoords[splitPointerIndex] =
|
splitPointerCoords[splitPointerIndex].copyFrom(
|
||||||
originalMotionSample->pointerCoords[originalPointerIndex];
|
originalMotionSample->pointerCoords[originalPointerIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
mAllocator.appendMotionSample(splitMotionEntry, originalMotionSample->eventTime,
|
mAllocator.appendMotionSample(splitMotionEntry, originalMotionSample->eventTime,
|
||||||
@ -3497,7 +3497,7 @@ InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry(nsec
|
|||||||
entry->lastSample = & entry->firstSample;
|
entry->lastSample = & entry->firstSample;
|
||||||
for (uint32_t i = 0; i < pointerCount; i++) {
|
for (uint32_t i = 0; i < pointerCount; i++) {
|
||||||
entry->pointerIds[i] = pointerIds[i];
|
entry->pointerIds[i] = pointerIds[i];
|
||||||
entry->firstSample.pointerCoords[i] = pointerCoords[i];
|
entry->firstSample.pointerCoords[i].copyFrom(pointerCoords[i]);
|
||||||
}
|
}
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
@ -3601,7 +3601,7 @@ void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry,
|
|||||||
sample->eventTime = eventTime;
|
sample->eventTime = eventTime;
|
||||||
uint32_t pointerCount = motionEntry->pointerCount;
|
uint32_t pointerCount = motionEntry->pointerCount;
|
||||||
for (uint32_t i = 0; i < pointerCount; i++) {
|
for (uint32_t i = 0; i < pointerCount; i++) {
|
||||||
sample->pointerCoords[i] = pointerCoords[i];
|
sample->pointerCoords[i].copyFrom(pointerCoords[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
sample->next = NULL;
|
sample->next = NULL;
|
||||||
@ -3738,7 +3738,7 @@ void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry*
|
|||||||
pointerCount = entry->pointerCount;
|
pointerCount = entry->pointerCount;
|
||||||
for (uint32_t i = 0; i < entry->pointerCount; i++) {
|
for (uint32_t i = 0; i < entry->pointerCount; i++) {
|
||||||
pointerIds[i] = entry->pointerIds[i];
|
pointerIds[i] = entry->pointerIds[i];
|
||||||
pointerCoords[i] = entry->lastSample->pointerCoords[i];
|
pointerCoords[i].copyFrom(entry->lastSample->pointerCoords[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -558,6 +558,8 @@ public:
|
|||||||
virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
|
virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
|
||||||
const int32_t* keyCodes, uint8_t* outFlags);
|
const int32_t* keyCodes, uint8_t* outFlags);
|
||||||
|
|
||||||
|
virtual void fadePointer();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Mutex mLock;
|
Mutex mLock;
|
||||||
|
|
||||||
@ -611,10 +613,12 @@ protected:
|
|||||||
PointerData pointers[MAX_POINTERS];
|
PointerData pointers[MAX_POINTERS];
|
||||||
BitSet32 idBits;
|
BitSet32 idBits;
|
||||||
uint32_t idToIndex[MAX_POINTER_ID + 1];
|
uint32_t idToIndex[MAX_POINTER_ID + 1];
|
||||||
|
uint32_t buttonState;
|
||||||
|
|
||||||
void copyFrom(const TouchData& other) {
|
void copyFrom(const TouchData& other) {
|
||||||
pointerCount = other.pointerCount;
|
pointerCount = other.pointerCount;
|
||||||
idBits = other.idBits;
|
idBits = other.idBits;
|
||||||
|
buttonState = other.buttonState;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < pointerCount; i++) {
|
for (uint32_t i = 0; i < pointerCount; i++) {
|
||||||
pointers[i] = other.pointers[i];
|
pointers[i] = other.pointers[i];
|
||||||
@ -627,17 +631,20 @@ protected:
|
|||||||
inline void clear() {
|
inline void clear() {
|
||||||
pointerCount = 0;
|
pointerCount = 0;
|
||||||
idBits.clear();
|
idBits.clear();
|
||||||
|
buttonState = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Input sources supported by the device.
|
// Input sources supported by the device.
|
||||||
uint32_t mTouchSource; // sources when reporting touch data
|
uint32_t mTouchSource; // sources when reporting touch data
|
||||||
|
uint32_t mPointerSource; // sources when reporting pointer gestures
|
||||||
|
|
||||||
// Immutable configuration parameters.
|
// Immutable configuration parameters.
|
||||||
struct Parameters {
|
struct Parameters {
|
||||||
enum DeviceType {
|
enum DeviceType {
|
||||||
DEVICE_TYPE_TOUCH_SCREEN,
|
DEVICE_TYPE_TOUCH_SCREEN,
|
||||||
DEVICE_TYPE_TOUCH_PAD,
|
DEVICE_TYPE_TOUCH_PAD,
|
||||||
|
DEVICE_TYPE_POINTER,
|
||||||
};
|
};
|
||||||
|
|
||||||
DeviceType deviceType;
|
DeviceType deviceType;
|
||||||
@ -735,11 +742,17 @@ protected:
|
|||||||
|
|
||||||
// Current and previous touch sample data.
|
// Current and previous touch sample data.
|
||||||
TouchData mCurrentTouch;
|
TouchData mCurrentTouch;
|
||||||
|
PointerCoords mCurrentTouchCoords[MAX_POINTERS];
|
||||||
|
|
||||||
TouchData mLastTouch;
|
TouchData mLastTouch;
|
||||||
|
PointerCoords mLastTouchCoords[MAX_POINTERS];
|
||||||
|
|
||||||
// The time the primary pointer last went down.
|
// The time the primary pointer last went down.
|
||||||
nsecs_t mDownTime;
|
nsecs_t mDownTime;
|
||||||
|
|
||||||
|
// The pointer controller, or null if the device is not a pointer.
|
||||||
|
sp<PointerControllerInterface> mPointerController;
|
||||||
|
|
||||||
struct LockedState {
|
struct LockedState {
|
||||||
Vector<VirtualKey> virtualKeys;
|
Vector<VirtualKey> virtualKeys;
|
||||||
|
|
||||||
@ -804,6 +817,17 @@ protected:
|
|||||||
int32_t keyCode;
|
int32_t keyCode;
|
||||||
int32_t scanCode;
|
int32_t scanCode;
|
||||||
} currentVirtualKey;
|
} currentVirtualKey;
|
||||||
|
|
||||||
|
// Scale factor for gesture based pointer movements.
|
||||||
|
float pointerGestureXMovementScale;
|
||||||
|
float pointerGestureYMovementScale;
|
||||||
|
|
||||||
|
// Scale factor for gesture based zooming and other freeform motions.
|
||||||
|
float pointerGestureXZoomScale;
|
||||||
|
float pointerGestureYZoomScale;
|
||||||
|
|
||||||
|
// The maximum swipe width squared.
|
||||||
|
int32_t pointerGestureMaxSwipeWidthSquared;
|
||||||
} mLocked;
|
} mLocked;
|
||||||
|
|
||||||
virtual void configureParameters();
|
virtual void configureParameters();
|
||||||
@ -869,13 +893,148 @@ private:
|
|||||||
uint64_t distance : 48; // squared distance
|
uint64_t distance : 48; // squared distance
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PointerGesture {
|
||||||
|
enum Mode {
|
||||||
|
// No fingers, button is not pressed.
|
||||||
|
// Nothing happening.
|
||||||
|
NEUTRAL,
|
||||||
|
|
||||||
|
// No fingers, button is not pressed.
|
||||||
|
// Tap detected.
|
||||||
|
// Emits DOWN and UP events at the pointer location.
|
||||||
|
TAP,
|
||||||
|
|
||||||
|
// Button is pressed.
|
||||||
|
// Pointer follows the active finger if there is one. Other fingers are ignored.
|
||||||
|
// Emits DOWN, MOVE and UP events at the pointer location.
|
||||||
|
CLICK_OR_DRAG,
|
||||||
|
|
||||||
|
// Exactly one finger, button is not pressed.
|
||||||
|
// Pointer follows the active finger.
|
||||||
|
// Emits HOVER_MOVE events at the pointer location.
|
||||||
|
HOVER,
|
||||||
|
|
||||||
|
// More than two fingers involved but they haven't moved enough for us
|
||||||
|
// to figure out what is intended.
|
||||||
|
INDETERMINATE_MULTITOUCH,
|
||||||
|
|
||||||
|
// Exactly two fingers moving in the same direction, button is not pressed.
|
||||||
|
// Pointer does not move.
|
||||||
|
// Emits DOWN, MOVE and UP events with a single pointer coordinate that
|
||||||
|
// follows the midpoint between both fingers.
|
||||||
|
// The centroid is fixed when entering this state.
|
||||||
|
SWIPE,
|
||||||
|
|
||||||
|
// Two or more fingers moving in arbitrary directions, button is not pressed.
|
||||||
|
// Pointer does not move.
|
||||||
|
// Emits DOWN, POINTER_DOWN, MOVE, POINTER_UP and UP events that follow
|
||||||
|
// each finger individually relative to the initial centroid of the finger.
|
||||||
|
// The centroid is fixed when entering this state.
|
||||||
|
FREEFORM,
|
||||||
|
|
||||||
|
// Waiting for quiet time to end before starting the next gesture.
|
||||||
|
QUIET,
|
||||||
|
};
|
||||||
|
|
||||||
|
// The active pointer id from the raw touch data.
|
||||||
|
int32_t activeTouchId; // -1 if none
|
||||||
|
|
||||||
|
// The active pointer id from the gesture last delivered to the application.
|
||||||
|
int32_t activeGestureId; // -1 if none
|
||||||
|
|
||||||
|
// Pointer coords and ids for the current and previous pointer gesture.
|
||||||
|
Mode currentGestureMode;
|
||||||
|
uint32_t currentGesturePointerCount;
|
||||||
|
BitSet32 currentGestureIdBits;
|
||||||
|
uint32_t currentGestureIdToIndex[MAX_POINTER_ID + 1];
|
||||||
|
PointerCoords currentGestureCoords[MAX_POINTERS];
|
||||||
|
|
||||||
|
Mode lastGestureMode;
|
||||||
|
uint32_t lastGesturePointerCount;
|
||||||
|
BitSet32 lastGestureIdBits;
|
||||||
|
uint32_t lastGestureIdToIndex[MAX_POINTER_ID + 1];
|
||||||
|
PointerCoords lastGestureCoords[MAX_POINTERS];
|
||||||
|
|
||||||
|
// Tracks for all pointers originally went down.
|
||||||
|
TouchData touchOrigin;
|
||||||
|
|
||||||
|
// Describes how touch ids are mapped to gesture ids for freeform gestures.
|
||||||
|
uint32_t freeformTouchToGestureIdMap[MAX_POINTER_ID + 1];
|
||||||
|
|
||||||
|
// Initial centroid of the movement.
|
||||||
|
// Used to calculate how far the touch pointers have moved since the gesture started.
|
||||||
|
int32_t initialCentroidX;
|
||||||
|
int32_t initialCentroidY;
|
||||||
|
|
||||||
|
// Initial pointer location.
|
||||||
|
// Used to track where the pointer was when the gesture started.
|
||||||
|
float initialPointerX;
|
||||||
|
float initialPointerY;
|
||||||
|
|
||||||
|
// Time the pointer gesture last went down.
|
||||||
|
nsecs_t downTime;
|
||||||
|
|
||||||
|
// Time we started waiting for a tap gesture.
|
||||||
|
nsecs_t tapTime;
|
||||||
|
|
||||||
|
// Time we started waiting for quiescence.
|
||||||
|
nsecs_t quietTime;
|
||||||
|
|
||||||
|
// A velocity tracker for determining whether to switch active pointers during drags.
|
||||||
|
VelocityTracker velocityTracker;
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
activeTouchId = -1;
|
||||||
|
activeGestureId = -1;
|
||||||
|
currentGestureMode = NEUTRAL;
|
||||||
|
currentGesturePointerCount = 0;
|
||||||
|
currentGestureIdBits.clear();
|
||||||
|
lastGestureMode = NEUTRAL;
|
||||||
|
lastGesturePointerCount = 0;
|
||||||
|
lastGestureIdBits.clear();
|
||||||
|
touchOrigin.clear();
|
||||||
|
initialCentroidX = 0;
|
||||||
|
initialCentroidY = 0;
|
||||||
|
initialPointerX = 0;
|
||||||
|
initialPointerY = 0;
|
||||||
|
downTime = 0;
|
||||||
|
velocityTracker.clear();
|
||||||
|
resetTapTime();
|
||||||
|
resetQuietTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetTapTime() {
|
||||||
|
tapTime = LLONG_MIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetQuietTime() {
|
||||||
|
quietTime = LLONG_MIN;
|
||||||
|
}
|
||||||
|
} mPointerGesture;
|
||||||
|
|
||||||
void initializeLocked();
|
void initializeLocked();
|
||||||
|
|
||||||
TouchResult consumeOffScreenTouches(nsecs_t when, uint32_t policyFlags);
|
TouchResult consumeOffScreenTouches(nsecs_t when, uint32_t policyFlags);
|
||||||
void dispatchTouches(nsecs_t when, uint32_t policyFlags);
|
void dispatchTouches(nsecs_t when, uint32_t policyFlags);
|
||||||
void dispatchTouch(nsecs_t when, uint32_t policyFlags, TouchData* touch,
|
void prepareTouches(int32_t* outEdgeFlags, float* outXPrecision, float* outYPrecision);
|
||||||
BitSet32 idBits, uint32_t changedId, uint32_t pointerCount,
|
void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags);
|
||||||
int32_t motionEventAction);
|
void preparePointerGestures(nsecs_t when,
|
||||||
|
bool* outCancelPreviousGesture, bool* outFinishPreviousGesture);
|
||||||
|
|
||||||
|
// Dispatches a motion event.
|
||||||
|
// If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the
|
||||||
|
// method will take care of setting the index and transmuting the action to DOWN or UP
|
||||||
|
// it is the first / last pointer to go down / up.
|
||||||
|
void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
|
||||||
|
int32_t action, int32_t flags, uint32_t metaState, int32_t edgeFlags,
|
||||||
|
const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits,
|
||||||
|
int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime);
|
||||||
|
|
||||||
|
// Updates pointer coords for pointers with specified ids that have moved.
|
||||||
|
// Returns true if any of them changed.
|
||||||
|
bool updateMovedPointerCoords(const PointerCoords* inCoords, const uint32_t* inIdToIndex,
|
||||||
|
PointerCoords* outCoords, const uint32_t* outIdToIndex, BitSet32 idBits) const;
|
||||||
|
|
||||||
void suppressSwipeOntoVirtualKeys(nsecs_t when);
|
void suppressSwipeOntoVirtualKeys(nsecs_t when);
|
||||||
|
|
||||||
bool isPointInsideSurfaceLocked(int32_t x, int32_t y);
|
bool isPointInsideSurfaceLocked(int32_t x, int32_t y);
|
||||||
@ -907,6 +1066,7 @@ private:
|
|||||||
FIELD_ABS_Y = 4,
|
FIELD_ABS_Y = 4,
|
||||||
FIELD_ABS_PRESSURE = 8,
|
FIELD_ABS_PRESSURE = 8,
|
||||||
FIELD_ABS_TOOL_WIDTH = 16,
|
FIELD_ABS_TOOL_WIDTH = 16,
|
||||||
|
FIELD_BUTTONS = 32,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t fields;
|
uint32_t fields;
|
||||||
@ -917,8 +1077,13 @@ private:
|
|||||||
int32_t absPressure;
|
int32_t absPressure;
|
||||||
int32_t absToolWidth;
|
int32_t absToolWidth;
|
||||||
|
|
||||||
|
uint32_t buttonDown;
|
||||||
|
uint32_t buttonUp;
|
||||||
|
|
||||||
inline void clear() {
|
inline void clear() {
|
||||||
fields = 0;
|
fields = 0;
|
||||||
|
buttonDown = 0;
|
||||||
|
buttonUp = 0;
|
||||||
}
|
}
|
||||||
} mAccumulator;
|
} mAccumulator;
|
||||||
|
|
||||||
@ -927,6 +1092,7 @@ private:
|
|||||||
int32_t mY;
|
int32_t mY;
|
||||||
int32_t mPressure;
|
int32_t mPressure;
|
||||||
int32_t mToolWidth;
|
int32_t mToolWidth;
|
||||||
|
uint32_t mButtonState;
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
|
|
||||||
@ -978,12 +1144,20 @@ private:
|
|||||||
}
|
}
|
||||||
} pointers[MAX_POINTERS + 1]; // + 1 to remove the need for extra range checks
|
} pointers[MAX_POINTERS + 1]; // + 1 to remove the need for extra range checks
|
||||||
|
|
||||||
|
// Bitfield of buttons that went down or up.
|
||||||
|
uint32_t buttonDown;
|
||||||
|
uint32_t buttonUp;
|
||||||
|
|
||||||
inline void clear() {
|
inline void clear() {
|
||||||
pointerCount = 0;
|
pointerCount = 0;
|
||||||
pointers[0].clear();
|
pointers[0].clear();
|
||||||
|
buttonDown = 0;
|
||||||
|
buttonUp = 0;
|
||||||
}
|
}
|
||||||
} mAccumulator;
|
} mAccumulator;
|
||||||
|
|
||||||
|
uint32_t mButtonState;
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
|
|
||||||
void sync(nsecs_t when);
|
void sync(nsecs_t when);
|
||||||
|
@ -2460,11 +2460,21 @@ void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper* mapper) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecified_ReturnsTouchPad) {
|
TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNotACursor_ReturnsPointer) {
|
||||||
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
|
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
|
||||||
prepareAxes(POSITION);
|
prepareAxes(POSITION);
|
||||||
addMapperAndConfigure(mapper);
|
addMapperAndConfigure(mapper);
|
||||||
|
|
||||||
|
ASSERT_EQ(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, mapper->getSources());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndIsACursor_ReturnsTouchPad) {
|
||||||
|
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
|
||||||
|
mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_X);
|
||||||
|
mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_Y);
|
||||||
|
prepareAxes(POSITION);
|
||||||
|
addMapperAndConfigure(mapper);
|
||||||
|
|
||||||
ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources());
|
ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user