summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/binder/MemoryHeapBase.cpp4
-rw-r--r--libs/binder/MemoryHeapPmem.cpp12
-rw-r--r--libs/gui/SurfaceTexture.cpp12
-rw-r--r--libs/surfaceflinger_client/ISurfaceComposerClient.cpp2
-rw-r--r--libs/ui/Android.mk7
-rw-r--r--libs/ui/Input.cpp345
-rw-r--r--libs/ui/InputTransport.cpp3
-rw-r--r--libs/ui/KeyLayoutMap.cpp70
-rw-r--r--libs/ui/Keyboard.cpp24
-rw-r--r--libs/ui/tests/Android.mk7
-rw-r--r--libs/ui/tests/InputChannel_test.cpp18
-rw-r--r--libs/ui/tests/InputEvent_test.cpp582
-rw-r--r--libs/ui/tests/InputPublisherAndConsumer_test.cpp96
-rw-r--r--libs/utils/RefBase.cpp189
-rw-r--r--libs/utils/SystemClock.cpp8
-rw-r--r--libs/utils/Threads.cpp29
16 files changed, 1258 insertions, 150 deletions
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index 624f7eb..9f501e2 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -31,7 +31,7 @@
#include <binder/MemoryHeapBase.h>
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
#include <linux/android_pmem.h>
#endif
@@ -108,7 +108,7 @@ status_t MemoryHeapBase::mapfd(int fd, size_t size, uint32_t offset)
{
if (size == 0) {
// try to figure out the size automatically
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
// first try the PMEM ioctl
pmem_region reg;
int err = ioctl(fd, PMEM_GET_TOTAL_SIZE, &reg);
diff --git a/libs/binder/MemoryHeapPmem.cpp b/libs/binder/MemoryHeapPmem.cpp
index 16e92f9..03322ea 100644
--- a/libs/binder/MemoryHeapPmem.cpp
+++ b/libs/binder/MemoryHeapPmem.cpp
@@ -30,7 +30,7 @@
#include <binder/MemoryHeapPmem.h>
#include <binder/MemoryHeapBase.h>
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
#include <linux/android_pmem.h>
#endif
@@ -72,7 +72,7 @@ SubRegionMemory::SubRegionMemory(const sp<MemoryHeapPmem>& heap,
memset(start_ptr, 0xda, size);
#endif
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
if (size > 0) {
const size_t pagesize = getpagesize();
size = (size + pagesize-1) & ~(pagesize-1);
@@ -107,7 +107,7 @@ void SubRegionMemory::revoke()
// which means MemoryHeapPmem::revoke() wouldn't have been able to
// promote() it.
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
if (mSize != 0) {
const sp<MemoryHeapPmem>& heap(getHeap());
int our_fd = heap->heapID();
@@ -130,7 +130,7 @@ MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
: MemoryHeapBase()
{
char const * const device = pmemHeap->getDevice();
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
if (device) {
int fd = open(device, O_RDWR | (flags & NO_CACHING ? O_SYNC : 0));
LOGE_IF(fd<0, "couldn't open %s (%s)", device, strerror(errno));
@@ -187,7 +187,7 @@ sp<MemoryHeapPmem::MemoryPmem> MemoryHeapPmem::createMemory(
status_t MemoryHeapPmem::slap()
{
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
size_t size = getSize();
const size_t pagesize = getpagesize();
size = (size + pagesize-1) & ~(pagesize-1);
@@ -205,7 +205,7 @@ status_t MemoryHeapPmem::slap()
status_t MemoryHeapPmem::unslap()
{
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
size_t size = getSize();
const size_t pagesize = getpagesize();
size = (size + pagesize-1) & ~(pagesize-1);
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index d6cc8ce..223cf09 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -220,11 +220,19 @@ status_t SurfaceTexture::updateTexImage() {
mSlots[mLastQueued].mEglImage = image;
mSlots[mLastQueued].mEglDisplay = dpy;
}
+
+ GLint error;
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ LOGE("GL error cleared before updating SurfaceTexture: %#04x", error);
+ }
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
- GLint error = glGetError();
- if (error != GL_NO_ERROR) {
+ bool failed = false;
+ while ((error = glGetError()) != GL_NO_ERROR) {
LOGE("error binding external texture image %p (slot %d): %#04x",
image, mLastQueued, error);
+ failed = true;
+ }
+ if (failed) {
return -EINVAL;
}
diff --git a/libs/surfaceflinger_client/ISurfaceComposerClient.cpp b/libs/surfaceflinger_client/ISurfaceComposerClient.cpp
index 2cc1f8e..7730eb1 100644
--- a/libs/surfaceflinger_client/ISurfaceComposerClient.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposerClient.cpp
@@ -157,7 +157,7 @@ status_t BnSurfaceComposerClient::onTransact(
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
const int self_pid = getpid();
- if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS)) {
+ if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) {
// we're called from a different process, do the real check
if (!checkCallingPermission(
String16("android.permission.ACCESS_SURFACE_FLINGER")))
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 0d55f08..f9990bb 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -60,7 +60,12 @@ LOCAL_SHARED_LIBRARIES := \
libEGL \
libpixelflinger \
libhardware \
- libhardware_legacy
+ libhardware_legacy \
+ libskia \
+ libbinder
+
+LOCAL_C_INCLUDES := \
+ external/skia/include/core
LOCAL_MODULE:= libui
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index b8d59e6..a80320e 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -15,6 +15,16 @@
#include <ui/Input.h>
+#include <math.h>
+
+#ifdef HAVE_ANDROID_OS
+#include <binder/Parcel.h>
+
+#include "SkPoint.h"
+#include "SkMatrix.h"
+#include "SkScalar.h"
+#endif
+
namespace android {
static const char* CONFIGURATION_FILE_DIR[] = {
@@ -237,6 +247,89 @@ void KeyEvent::initialize(const KeyEvent& from) {
mEventTime = from.mEventTime;
}
+
+// --- PointerCoords ---
+
+float PointerCoords::getAxisValue(int32_t axis) const {
+ if (axis < 0 || axis > 63) {
+ return 0;
+ }
+
+ uint64_t axisBit = 1LL << axis;
+ if (!(bits & axisBit)) {
+ return 0;
+ }
+ uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
+ return values[index];
+}
+
+status_t PointerCoords::setAxisValue(int32_t axis, float value) {
+ if (axis < 0 || axis > 63) {
+ return NAME_NOT_FOUND;
+ }
+
+ uint64_t axisBit = 1LL << axis;
+ uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
+ if (!(bits & axisBit)) {
+ uint32_t count = __builtin_popcountll(bits);
+ if (count >= MAX_AXES) {
+ tooManyAxes(axis);
+ return NO_MEMORY;
+ }
+ bits |= axisBit;
+ for (uint32_t i = count; i > index; i--) {
+ values[i] = values[i - 1];
+ }
+ }
+ values[index] = value;
+ return OK;
+}
+
+float* PointerCoords::editAxisValue(int32_t axis) {
+ if (axis < 0 || axis > 63) {
+ return NULL;
+ }
+
+ uint64_t axisBit = 1LL << axis;
+ if (!(bits & axisBit)) {
+ return NULL;
+ }
+ uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
+ return &values[index];
+}
+
+#ifdef HAVE_ANDROID_OS
+status_t PointerCoords::readFromParcel(Parcel* parcel) {
+ bits = parcel->readInt64();
+
+ uint32_t count = __builtin_popcountll(bits);
+ if (count > MAX_AXES) {
+ return BAD_VALUE;
+ }
+
+ for (uint32_t i = 0; i < count; i++) {
+ values[i] = parcel->readInt32();
+ }
+ return OK;
+}
+
+status_t PointerCoords::writeToParcel(Parcel* parcel) const {
+ parcel->writeInt64(bits);
+
+ uint32_t count = __builtin_popcountll(bits);
+ for (uint32_t i = 0; i < count; i++) {
+ parcel->writeInt32(values[i]);
+ }
+ return OK;
+}
+#endif
+
+void PointerCoords::tooManyAxes(int axis) {
+ LOGW("Could not set value for axis %d because the PointerCoords structure is full and "
+ "cannot contain more than %d axis values.", axis, int(MAX_AXES));
+}
+
+
// --- MotionEvent ---
void MotionEvent::initialize(
@@ -272,6 +365,33 @@ void MotionEvent::initialize(
addSample(eventTime, pointerCoords);
}
+void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
+ InputEvent::initialize(other->mDeviceId, other->mSource);
+ mAction = other->mAction;
+ mFlags = other->mFlags;
+ mEdgeFlags = other->mEdgeFlags;
+ mMetaState = other->mMetaState;
+ mXOffset = other->mXOffset;
+ mYOffset = other->mYOffset;
+ mXPrecision = other->mXPrecision;
+ mYPrecision = other->mYPrecision;
+ mDownTime = other->mDownTime;
+ mPointerIds = other->mPointerIds;
+
+ if (keepHistory) {
+ mSampleEventTimes = other->mSampleEventTimes;
+ mSamplePointerCoords = other->mSamplePointerCoords;
+ } else {
+ mSampleEventTimes.clear();
+ mSampleEventTimes.push(other->getEventTime());
+ mSamplePointerCoords.clear();
+ size_t pointerCount = other->getPointerCount();
+ size_t historySize = other->getHistorySize();
+ mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array()
+ + (historySize * pointerCount), pointerCount);
+ }
+}
+
void MotionEvent::addSample(
int64_t eventTime,
const PointerCoords* pointerCoords) {
@@ -279,11 +399,224 @@ void MotionEvent::addSample(
mSamplePointerCoords.appendArray(pointerCoords, getPointerCount());
}
+const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
+ return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
+}
+
+float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const {
+ return getRawPointerCoords(pointerIndex)->getAxisValue(axis);
+}
+
+float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const {
+ float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis);
+ switch (axis) {
+ case AMOTION_EVENT_AXIS_X:
+ value += mXOffset;
+ break;
+ case AMOTION_EVENT_AXIS_Y:
+ value += mYOffset;
+ break;
+ }
+ return value;
+}
+
+const PointerCoords* MotionEvent::getHistoricalRawPointerCoords(
+ size_t pointerIndex, size_t historicalIndex) const {
+ return &mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex];
+}
+
+float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
+ size_t historicalIndex) const {
+ return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
+}
+
+float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
+ size_t historicalIndex) const {
+ float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
+ switch (axis) {
+ case AMOTION_EVENT_AXIS_X:
+ value += mXOffset;
+ break;
+ case AMOTION_EVENT_AXIS_Y:
+ value += mYOffset;
+ break;
+ }
+ return value;
+}
+
void MotionEvent::offsetLocation(float xOffset, float yOffset) {
mXOffset += xOffset;
mYOffset += yOffset;
}
+static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) {
+ float* value = c.editAxisValue(axis);
+ if (value) {
+ *value *= scaleFactor;
+ }
+}
+
+void MotionEvent::scale(float scaleFactor) {
+ mXOffset *= scaleFactor;
+ mYOffset *= scaleFactor;
+ mXPrecision *= scaleFactor;
+ mYPrecision *= scaleFactor;
+
+ size_t numSamples = mSamplePointerCoords.size();
+ for (size_t i = 0; i < numSamples; i++) {
+ PointerCoords& c = mSamplePointerCoords.editItemAt(i);
+ // No need to scale pressure or size since they are normalized.
+ // No need to scale orientation since it is meaningless to do so.
+ scaleAxisValue(c, AMOTION_EVENT_AXIS_X, scaleFactor);
+ scaleAxisValue(c, AMOTION_EVENT_AXIS_Y, scaleFactor);
+ scaleAxisValue(c, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor);
+ scaleAxisValue(c, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor);
+ scaleAxisValue(c, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor);
+ scaleAxisValue(c, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor);
+ }
+}
+
+#ifdef HAVE_ANDROID_OS
+static inline float transformAngle(const SkMatrix* matrix, float angleRadians) {
+ // Construct and transform a vector oriented at the specified clockwise angle from vertical.
+ // Coordinate system: down is increasing Y, right is increasing X.
+ SkPoint vector;
+ vector.fX = SkFloatToScalar(sinf(angleRadians));
+ vector.fY = SkFloatToScalar(-cosf(angleRadians));
+ matrix->mapVectors(& vector, 1);
+
+ // Derive the transformed vector's clockwise angle from vertical.
+ float result = atan2f(SkScalarToFloat(vector.fX), SkScalarToFloat(-vector.fY));
+ if (result < - M_PI_2) {
+ result += M_PI;
+ } else if (result > M_PI_2) {
+ result -= M_PI;
+ }
+ return result;
+}
+
+void MotionEvent::transform(const SkMatrix* matrix) {
+ float oldXOffset = mXOffset;
+ float oldYOffset = mYOffset;
+
+ // The tricky part of this implementation is to preserve the value of
+ // rawX and rawY. So we apply the transformation to the first point
+ // then derive an appropriate new X/Y offset that will preserve rawX and rawY.
+ SkPoint point;
+ float rawX = getRawX(0);
+ float rawY = getRawY(0);
+ matrix->mapXY(SkFloatToScalar(rawX + oldXOffset), SkFloatToScalar(rawY + oldYOffset),
+ & point);
+ float newX = SkScalarToFloat(point.fX);
+ float newY = SkScalarToFloat(point.fY);
+ float newXOffset = newX - rawX;
+ float newYOffset = newY - rawY;
+
+ mXOffset = newXOffset;
+ mYOffset = newYOffset;
+
+ // Apply the transformation to all samples.
+ size_t numSamples = mSamplePointerCoords.size();
+ for (size_t i = 0; i < numSamples; i++) {
+ PointerCoords& c = mSamplePointerCoords.editItemAt(i);
+ float* xPtr = c.editAxisValue(AMOTION_EVENT_AXIS_X);
+ float* yPtr = c.editAxisValue(AMOTION_EVENT_AXIS_Y);
+ if (xPtr && yPtr) {
+ float x = *xPtr + oldXOffset;
+ float y = *yPtr + oldYOffset;
+ matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), & point);
+ *xPtr = SkScalarToFloat(point.fX) - newXOffset;
+ *yPtr = SkScalarToFloat(point.fY) - newYOffset;
+ }
+
+ float* orientationPtr = c.editAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
+ if (orientationPtr) {
+ *orientationPtr = transformAngle(matrix, *orientationPtr);
+ }
+ }
+}
+
+status_t MotionEvent::readFromParcel(Parcel* parcel) {
+ size_t pointerCount = parcel->readInt32();
+ size_t sampleCount = parcel->readInt32();
+ if (pointerCount == 0 || pointerCount > MAX_POINTERS || sampleCount == 0) {
+ return BAD_VALUE;
+ }
+
+ mDeviceId = parcel->readInt32();
+ mSource = parcel->readInt32();
+ mAction = parcel->readInt32();
+ mFlags = parcel->readInt32();
+ mEdgeFlags = parcel->readInt32();
+ mMetaState = parcel->readInt32();
+ mXOffset = parcel->readFloat();
+ mYOffset = parcel->readFloat();
+ mXPrecision = parcel->readFloat();
+ mYPrecision = parcel->readFloat();
+ mDownTime = parcel->readInt64();
+
+ mPointerIds.clear();
+ mPointerIds.setCapacity(pointerCount);
+ mSampleEventTimes.clear();
+ mSampleEventTimes.setCapacity(sampleCount);
+ mSamplePointerCoords.clear();
+ mSamplePointerCoords.setCapacity(sampleCount * pointerCount);
+
+ for (size_t i = 0; i < pointerCount; i++) {
+ mPointerIds.push(parcel->readInt32());
+ }
+
+ while (sampleCount-- > 0) {
+ mSampleEventTimes.push(parcel->readInt64());
+ for (size_t i = 0; i < pointerCount; i++) {
+ mSamplePointerCoords.push();
+ status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel);
+ if (status) {
+ return status;
+ }
+ }
+ }
+ return OK;
+}
+
+status_t MotionEvent::writeToParcel(Parcel* parcel) const {
+ size_t pointerCount = mPointerIds.size();
+ size_t sampleCount = mSampleEventTimes.size();
+
+ parcel->writeInt32(pointerCount);
+ parcel->writeInt32(sampleCount);
+
+ parcel->writeInt32(mDeviceId);
+ parcel->writeInt32(mSource);
+ parcel->writeInt32(mAction);
+ parcel->writeInt32(mFlags);
+ parcel->writeInt32(mEdgeFlags);
+ parcel->writeInt32(mMetaState);
+ parcel->writeFloat(mXOffset);
+ parcel->writeFloat(mYOffset);
+ parcel->writeFloat(mXPrecision);
+ parcel->writeFloat(mYPrecision);
+ parcel->writeInt64(mDownTime);
+
+ for (size_t i = 0; i < pointerCount; i++) {
+ parcel->writeInt32(mPointerIds.itemAt(i));
+ }
+
+ const PointerCoords* pc = mSamplePointerCoords.array();
+ for (size_t h = 0; h < sampleCount; h++) {
+ parcel->writeInt64(mSampleEventTimes.itemAt(h));
+ for (size_t i = 0; i < pointerCount; i++) {
+ status_t status = (pc++)->writeToParcel(parcel);
+ if (status) {
+ return status;
+ }
+ }
+ }
+ return OK;
+}
+#endif
+
+
// --- InputDeviceInfo ---
InputDeviceInfo::InputDeviceInfo() {
@@ -307,8 +640,8 @@ void InputDeviceInfo::initialize(int32_t id, const String8& name) {
mMotionRanges.clear();
}
-const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(int32_t rangeType) const {
- ssize_t index = mMotionRanges.indexOfKey(rangeType);
+const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(int32_t axis) const {
+ ssize_t index = mMotionRanges.indexOfKey(axis);
return index >= 0 ? & mMotionRanges.valueAt(index) : NULL;
}
@@ -316,14 +649,14 @@ void InputDeviceInfo::addSource(uint32_t source) {
mSources |= source;
}
-void InputDeviceInfo::addMotionRange(int32_t rangeType, float min, float max,
+void InputDeviceInfo::addMotionRange(int32_t axis, float min, float max,
float flat, float fuzz) {
MotionRange range = { min, max, flat, fuzz };
- addMotionRange(rangeType, range);
+ addMotionRange(axis, range);
}
-void InputDeviceInfo::addMotionRange(int32_t rangeType, const MotionRange& range) {
- mMotionRanges.add(rangeType, range);
+void InputDeviceInfo::addMotionRange(int32_t axis, const MotionRange& range) {
+ mMotionRanges.add(axis, range);
}
} // namespace android
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 83d9556..5c57a76 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -412,7 +412,8 @@ status_t InputPublisher::publishMotionEvent(
// Cache essential information about the motion event to ensure that a malicious consumer
// cannot confuse the publisher by modifying the contents of the shared memory buffer while
// it is being updated.
- if (action == AMOTION_EVENT_ACTION_MOVE) {
+ if (action == AMOTION_EVENT_ACTION_MOVE
+ || action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
mMotionEventPointerCount = pointerCount;
mMotionEventSampleDataStride = InputMessage::sampleDataStride(pointerCount);
mMotionEventSampleDataTail = InputMessage::sampleDataPtrIncrement(
diff --git a/libs/ui/KeyLayoutMap.cpp b/libs/ui/KeyLayoutMap.cpp
index 56bc26f..2ed0e66 100644
--- a/libs/ui/KeyLayoutMap.cpp
+++ b/libs/ui/KeyLayoutMap.cpp
@@ -82,11 +82,11 @@ status_t KeyLayoutMap::load(const String8& filename, KeyLayoutMap** outMap) {
return status;
}
-status_t KeyLayoutMap::map(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const {
+status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const {
ssize_t index = mKeys.indexOfKey(scanCode);
if (index < 0) {
#if DEBUG_MAPPING
- LOGD("map: scanCode=%d ~ Failed.", scanCode);
+ LOGD("mapKey: scanCode=%d ~ Failed.", scanCode);
#endif
*keyCode = AKEYCODE_UNKNOWN;
*flags = 0;
@@ -98,12 +98,12 @@ status_t KeyLayoutMap::map(int32_t scanCode, int32_t* keyCode, uint32_t* flags)
*flags = k.flags;
#if DEBUG_MAPPING
- LOGD("map: scanCode=%d ~ Result keyCode=%d, flags=0x%08x.", scanCode, *keyCode, *flags);
+ LOGD("mapKey: scanCode=%d ~ Result keyCode=%d, flags=0x%08x.", scanCode, *keyCode, *flags);
#endif
return NO_ERROR;
}
-status_t KeyLayoutMap::findScanCodes(int32_t keyCode, Vector<int32_t>* outScanCodes) const {
+status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const {
const size_t N = mKeys.size();
for (size_t i=0; i<N; i++) {
if (mKeys.valueAt(i).keyCode == keyCode) {
@@ -113,6 +113,25 @@ status_t KeyLayoutMap::findScanCodes(int32_t keyCode, Vector<int32_t>* outScanCo
return NO_ERROR;
}
+status_t KeyLayoutMap::mapAxis(int32_t scanCode, int32_t* axis) const {
+ ssize_t index = mAxes.indexOfKey(scanCode);
+ if (index < 0) {
+#if DEBUG_MAPPING
+ LOGD("mapAxis: scanCode=%d ~ Failed.", scanCode);
+#endif
+ *axis = -1;
+ return NAME_NOT_FOUND;
+ }
+
+ *axis = mAxes.valueAt(index);
+
+#if DEBUG_MAPPING
+ LOGD("mapAxis: scanCode=%d ~ Result axis=%d.", scanCode, *axis);
+#endif
+ return NO_ERROR;
+}
+
+
// --- KeyLayoutMap::Parser ---
KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
@@ -137,6 +156,10 @@ status_t KeyLayoutMap::Parser::parse() {
mTokenizer->skipDelimiters(WHITESPACE);
status_t status = parseKey();
if (status) return status;
+ } else if (keywordToken == "axis") {
+ mTokenizer->skipDelimiters(WHITESPACE);
+ status_t status = parseAxis();
+ if (status) return status;
} else {
LOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
keywordToken.string());
@@ -162,12 +185,12 @@ status_t KeyLayoutMap::Parser::parseKey() {
char* end;
int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
if (*end) {
- LOGE("%s: Expected scan code number, got '%s'.", mTokenizer->getLocation().string(),
+ LOGE("%s: Expected key scan code number, got '%s'.", mTokenizer->getLocation().string(),
scanCodeToken.string());
return BAD_VALUE;
}
if (mMap->mKeys.indexOfKey(scanCode) >= 0) {
- LOGE("%s: Duplicate entry for scan code '%s'.", mTokenizer->getLocation().string(),
+ LOGE("%s: Duplicate entry for key scan code '%s'.", mTokenizer->getLocation().string(),
scanCodeToken.string());
return BAD_VALUE;
}
@@ -189,12 +212,12 @@ status_t KeyLayoutMap::Parser::parseKey() {
String8 flagToken = mTokenizer->nextToken(WHITESPACE);
uint32_t flag = getKeyFlagByLabel(flagToken.string());
if (!flag) {
- LOGE("%s: Expected flag label, got '%s'.", mTokenizer->getLocation().string(),
+ LOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(),
flagToken.string());
return BAD_VALUE;
}
if (flags & flag) {
- LOGE("%s: Duplicate flag '%s'.", mTokenizer->getLocation().string(),
+ LOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(),
flagToken.string());
return BAD_VALUE;
}
@@ -211,4 +234,35 @@ status_t KeyLayoutMap::Parser::parseKey() {
return NO_ERROR;
}
+status_t KeyLayoutMap::Parser::parseAxis() {
+ String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
+ char* end;
+ int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
+ if (*end) {
+ LOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(),
+ scanCodeToken.string());
+ return BAD_VALUE;
+ }
+ if (mMap->mAxes.indexOfKey(scanCode) >= 0) {
+ LOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(),
+ scanCodeToken.string());
+ return BAD_VALUE;
+ }
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+ String8 axisToken = mTokenizer->nextToken(WHITESPACE);
+ int32_t axis = getAxisByLabel(axisToken.string());
+ if (axis < 0) {
+ LOGE("%s: Expected axis label, got '%s'.", mTokenizer->getLocation().string(),
+ axisToken.string());
+ return BAD_VALUE;
+ }
+
+#if DEBUG_PARSER
+ LOGD("Parsed axis: scanCode=%d, axis=%d.", scanCode, axis);
+#endif
+ mMap->mAxes.add(scanCode, axis);
+ return NO_ERROR;
+}
+
};
diff --git a/libs/ui/Keyboard.cpp b/libs/ui/Keyboard.cpp
index 6faa600..8b6300a 100644
--- a/libs/ui/Keyboard.cpp
+++ b/libs/ui/Keyboard.cpp
@@ -217,7 +217,7 @@ status_t getKeyCharacterMapFile(int32_t deviceId, String8& outKeyCharacterMapFil
return NAME_NOT_FOUND;
}
-static int lookupLabel(const char* literal, const KeycodeLabel *list) {
+static int lookupValueByLabel(const char* literal, const KeycodeLabel *list) {
while (list->literal) {
if (strcmp(literal, list->literal) == 0) {
return list->value;
@@ -227,12 +227,30 @@ static int lookupLabel(const char* literal, const KeycodeLabel *list) {
return list->value;
}
+static const char* lookupLabelByValue(int value, const KeycodeLabel *list) {
+ while (list->literal) {
+ if (list->value == value) {
+ return list->literal;
+ }
+ list++;
+ }
+ return NULL;
+}
+
int32_t getKeyCodeByLabel(const char* label) {
- return int32_t(lookupLabel(label, KEYCODES));
+ return int32_t(lookupValueByLabel(label, KEYCODES));
}
uint32_t getKeyFlagByLabel(const char* label) {
- return uint32_t(lookupLabel(label, FLAGS));
+ return uint32_t(lookupValueByLabel(label, FLAGS));
+}
+
+int32_t getAxisByLabel(const char* label) {
+ return int32_t(lookupValueByLabel(label, AXES));
+}
+
+const char* getAxisLabel(int32_t axisId) {
+ return lookupLabelByValue(axisId, AXES);
}
static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) {
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
index 580d73c..e231971 100644
--- a/libs/ui/tests/Android.mk
+++ b/libs/ui/tests/Android.mk
@@ -7,6 +7,7 @@ ifneq ($(TARGET_SIMULATOR),true)
# Build the unit tests.
test_src_files := \
InputChannel_test.cpp \
+ InputEvent_test.cpp \
InputPublisherAndConsumer_test.cpp
shared_libraries := \
@@ -18,7 +19,8 @@ shared_libraries := \
libhardware \
libhardware_legacy \
libui \
- libstlport
+ libstlport \
+ libskia
static_libraries := \
libgtest \
@@ -28,7 +30,8 @@ c_includes := \
bionic \
bionic/libstdc++/include \
external/gtest/include \
- external/stlport/stlport
+ external/stlport/stlport \
+ external/skia/include/core
module_tags := eng tests
diff --git a/libs/ui/tests/InputChannel_test.cpp b/libs/ui/tests/InputChannel_test.cpp
index 6cec1c0..eff22ee 100644
--- a/libs/ui/tests/InputChannel_test.cpp
+++ b/libs/ui/tests/InputChannel_test.cpp
@@ -1,6 +1,18 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#include <ui/InputTransport.h>
#include <utils/Timers.h>
diff --git a/libs/ui/tests/InputEvent_test.cpp b/libs/ui/tests/InputEvent_test.cpp
new file mode 100644
index 0000000..b77489e
--- /dev/null
+++ b/libs/ui/tests/InputEvent_test.cpp
@@ -0,0 +1,582 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ui/Input.h>
+#include <gtest/gtest.h>
+#include <binder/Parcel.h>
+
+#include <math.h>
+#include <SkMatrix.h>
+
+namespace android {
+
+class BaseTest : public testing::Test {
+protected:
+ virtual void SetUp() { }
+ virtual void TearDown() { }
+};
+
+// --- PointerCoordsTest ---
+
+class PointerCoordsTest : public BaseTest {
+};
+
+TEST_F(PointerCoordsTest, ClearSetsBitsToZero) {
+ PointerCoords coords;
+ coords.clear();
+
+ ASSERT_EQ(0ULL, coords.bits);
+}
+
+TEST_F(PointerCoordsTest, AxisValues) {
+ float* valuePtr;
+ PointerCoords coords;
+ coords.clear();
+
+ // Check invariants when no axes are present.
+ ASSERT_EQ(0, coords.getAxisValue(0))
+ << "getAxisValue should return zero because axis is not present";
+ ASSERT_EQ(0, coords.getAxisValue(1))
+ << "getAxisValue should return zero because axis is not present";
+
+ ASSERT_EQ(NULL, coords.editAxisValue(0))
+ << "editAxisValue should return null because axis is not present";
+
+ // Set first axis.
+ ASSERT_EQ(OK, coords.setAxisValue(1, 5));
+ ASSERT_EQ(0x00000002ULL, coords.bits);
+ ASSERT_EQ(5, coords.values[0]);
+
+ ASSERT_EQ(0, coords.getAxisValue(0))
+ << "getAxisValue should return zero because axis is not present";
+ ASSERT_EQ(5, coords.getAxisValue(1))
+ << "getAxisValue should return value of axis";
+
+ // Set an axis with a higher id than all others. (appending value at the end)
+ ASSERT_EQ(OK, coords.setAxisValue(3, 2));
+ ASSERT_EQ(0x0000000aULL, coords.bits);
+ ASSERT_EQ(5, coords.values[0]);
+ ASSERT_EQ(2, coords.values[1]);
+
+ ASSERT_EQ(0, coords.getAxisValue(0))
+ << "getAxisValue should return zero because axis is not present";
+ ASSERT_EQ(5, coords.getAxisValue(1))
+ << "getAxisValue should return value of axis";
+ ASSERT_EQ(0, coords.getAxisValue(2))
+ << "getAxisValue should return zero because axis is not present";
+ ASSERT_EQ(2, coords.getAxisValue(3))
+ << "getAxisValue should return value of axis";
+
+ // Set an axis with an id lower than all others. (prepending value at beginning)
+ ASSERT_EQ(OK, coords.setAxisValue(0, 4));
+ ASSERT_EQ(0x0000000bULL, coords.bits);
+ ASSERT_EQ(4, coords.values[0]);
+ ASSERT_EQ(5, coords.values[1]);
+ ASSERT_EQ(2, coords.values[2]);
+
+ ASSERT_EQ(4, coords.getAxisValue(0))
+ << "getAxisValue should return value of axis";
+ ASSERT_EQ(5, coords.getAxisValue(1))
+ << "getAxisValue should return value of axis";
+ ASSERT_EQ(0, coords.getAxisValue(2))
+ << "getAxisValue should return zero because axis is not present";
+ ASSERT_EQ(2, coords.getAxisValue(3))
+ << "getAxisValue should return value of axis";
+
+ // Edit an existing axis value in place.
+ valuePtr = coords.editAxisValue(1);
+ ASSERT_EQ(5, *valuePtr)
+ << "editAxisValue should return pointer to axis value";
+
+ *valuePtr = 7;
+ ASSERT_EQ(7, coords.getAxisValue(1))
+ << "getAxisValue should return value of axis";
+
+ // Set an axis with an id between the others. (inserting value in the middle)
+ ASSERT_EQ(OK, coords.setAxisValue(2, 1));
+ ASSERT_EQ(0x0000000fULL, coords.bits);
+ ASSERT_EQ(4, coords.values[0]);
+ ASSERT_EQ(7, coords.values[1]);
+ ASSERT_EQ(1, coords.values[2]);
+ ASSERT_EQ(2, coords.values[3]);
+
+ ASSERT_EQ(4, coords.getAxisValue(0))
+ << "getAxisValue should return value of axis";
+ ASSERT_EQ(7, coords.getAxisValue(1))
+ << "getAxisValue should return value of axis";
+ ASSERT_EQ(1, coords.getAxisValue(2))
+ << "getAxisValue should return value of axis";
+ ASSERT_EQ(2, coords.getAxisValue(3))
+ << "getAxisValue should return value of axis";
+
+ // Set an existing axis value in place.
+ ASSERT_EQ(OK, coords.setAxisValue(1, 6));
+ ASSERT_EQ(0x0000000fULL, coords.bits);
+ ASSERT_EQ(4, coords.values[0]);
+ ASSERT_EQ(6, coords.values[1]);
+ ASSERT_EQ(1, coords.values[2]);
+ ASSERT_EQ(2, coords.values[3]);
+
+ ASSERT_EQ(4, coords.getAxisValue(0))
+ << "getAxisValue should return value of axis";
+ ASSERT_EQ(6, coords.getAxisValue(1))
+ << "getAxisValue should return value of axis";
+ ASSERT_EQ(1, coords.getAxisValue(2))
+ << "getAxisValue should return value of axis";
+ ASSERT_EQ(2, coords.getAxisValue(3))
+ << "getAxisValue should return value of axis";
+
+ // Set maximum number of axes.
+ for (size_t axis = 4; axis < PointerCoords::MAX_AXES; axis++) {
+ ASSERT_EQ(OK, coords.setAxisValue(axis, axis));
+ }
+ ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcountll(coords.bits));
+
+ // Try to set one more axis beyond maximum number.
+ // Ensure bits are unchanged.
+ ASSERT_EQ(NO_MEMORY, coords.setAxisValue(PointerCoords::MAX_AXES, 100));
+ ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcountll(coords.bits));
+}
+
+TEST_F(PointerCoordsTest, Parcel) {
+ Parcel parcel;
+
+ PointerCoords inCoords;
+ inCoords.clear();
+ PointerCoords outCoords;
+
+ // Round trip with empty coords.
+ inCoords.writeToParcel(&parcel);
+ parcel.setDataPosition(0);
+ outCoords.readFromParcel(&parcel);
+
+ ASSERT_EQ(0ULL, outCoords.bits);
+
+ // Round trip with some values.
+ parcel.freeData();
+ inCoords.setAxisValue(2, 5);
+ inCoords.setAxisValue(5, 8);
+
+ inCoords.writeToParcel(&parcel);
+ parcel.setDataPosition(0);
+ outCoords.readFromParcel(&parcel);
+
+ ASSERT_EQ(outCoords.bits, inCoords.bits);
+ ASSERT_EQ(outCoords.values[0], inCoords.values[0]);
+ ASSERT_EQ(outCoords.values[1], inCoords.values[1]);
+}
+
+
+// --- KeyEventTest ---
+
+class KeyEventTest : public BaseTest {
+};
+
+TEST_F(KeyEventTest, Properties) {
+ KeyEvent event;
+
+ // Initialize and get properties.
+ const nsecs_t ARBITRARY_DOWN_TIME = 1;
+ const nsecs_t ARBITRARY_EVENT_TIME = 2;
+ event.initialize(2, AINPUT_SOURCE_GAMEPAD, AKEY_EVENT_ACTION_DOWN,
+ AKEY_EVENT_FLAG_FROM_SYSTEM, AKEYCODE_BUTTON_X, 121,
+ AMETA_ALT_ON, 1, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME);
+
+ ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event.getType());
+ ASSERT_EQ(2, event.getDeviceId());
+ ASSERT_EQ(AINPUT_SOURCE_GAMEPAD, event.getSource());
+ ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, event.getAction());
+ ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, event.getFlags());
+ ASSERT_EQ(AKEYCODE_BUTTON_X, event.getKeyCode());
+ ASSERT_EQ(121, event.getScanCode());
+ ASSERT_EQ(AMETA_ALT_ON, event.getMetaState());
+ ASSERT_EQ(1, event.getRepeatCount());
+ ASSERT_EQ(ARBITRARY_DOWN_TIME, event.getDownTime());
+ ASSERT_EQ(ARBITRARY_EVENT_TIME, event.getEventTime());
+
+ // Set source.
+ event.setSource(AINPUT_SOURCE_JOYSTICK);
+ ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource());
+}
+
+
+// --- MotionEventTest ---
+
+class MotionEventTest : public BaseTest {
+protected:
+ static const nsecs_t ARBITRARY_DOWN_TIME;
+ static const nsecs_t ARBITRARY_EVENT_TIME;
+ static const float X_OFFSET;
+ static const float Y_OFFSET;
+
+ void initializeEventWithHistory(MotionEvent* event);
+ void assertEqualsEventWithHistory(const MotionEvent* event);
+};
+
+const nsecs_t MotionEventTest::ARBITRARY_DOWN_TIME = 1;
+const nsecs_t MotionEventTest::ARBITRARY_EVENT_TIME = 2;
+const float MotionEventTest::X_OFFSET = 1.0f;
+const float MotionEventTest::Y_OFFSET = 1.1f;
+
+void MotionEventTest::initializeEventWithHistory(MotionEvent* event) {
+ int32_t pointerIds[] = { 1, 2 };
+ PointerCoords pointerCoords[2];
+ pointerCoords[0].clear();
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 10);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 11);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 12);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 13);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 14);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 15);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 16);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 17);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 18);
+ pointerCoords[1].clear();
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 20);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 21);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 22);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 23);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 24);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 25);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
+ event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE,
+ AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
+ AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON,
+ X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
+ ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME,
+ 2, pointerIds, pointerCoords);
+
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 112);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 113);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 114);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 115);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 116);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 117);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 118);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 120);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 121);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 122);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 123);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 124);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 125);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 126);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 127);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 128);
+ event->addSample(ARBITRARY_EVENT_TIME + 1, pointerCoords);
+
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 210);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 211);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 212);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 213);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 214);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 215);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 216);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 217);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 218);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 220);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 221);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 222);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 223);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 224);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 225);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 226);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 227);
+ pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 228);
+ event->addSample(ARBITRARY_EVENT_TIME + 2, pointerCoords);
+}
+
+void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) {
+ // Check properties.
+ ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType());
+ ASSERT_EQ(2, event->getDeviceId());
+ ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, event->getSource());
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event->getAction());
+ ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags());
+ ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags());
+ ASSERT_EQ(AMETA_ALT_ON, event->getMetaState());
+ ASSERT_EQ(X_OFFSET, event->getXOffset());
+ ASSERT_EQ(Y_OFFSET, event->getYOffset());
+ ASSERT_EQ(2.0f, event->getXPrecision());
+ ASSERT_EQ(2.1f, event->getYPrecision());
+ ASSERT_EQ(ARBITRARY_DOWN_TIME, event->getDownTime());
+
+ ASSERT_EQ(2U, event->getPointerCount());
+ ASSERT_EQ(1, event->getPointerId(0));
+ ASSERT_EQ(2, event->getPointerId(1));
+
+ ASSERT_EQ(2U, event->getHistorySize());
+
+ // Check data.
+ ASSERT_EQ(ARBITRARY_EVENT_TIME, event->getHistoricalEventTime(0));
+ ASSERT_EQ(ARBITRARY_EVENT_TIME + 1, event->getHistoricalEventTime(1));
+ ASSERT_EQ(ARBITRARY_EVENT_TIME + 2, event->getEventTime());
+
+ ASSERT_EQ(11, event->getHistoricalRawPointerCoords(0, 0)->
+ getAxisValue(AMOTION_EVENT_AXIS_Y));
+ ASSERT_EQ(21, event->getHistoricalRawPointerCoords(1, 0)->
+ getAxisValue(AMOTION_EVENT_AXIS_Y));
+ ASSERT_EQ(111, event->getHistoricalRawPointerCoords(0, 1)->
+ getAxisValue(AMOTION_EVENT_AXIS_Y));
+ ASSERT_EQ(121, event->getHistoricalRawPointerCoords(1, 1)->
+ getAxisValue(AMOTION_EVENT_AXIS_Y));
+ ASSERT_EQ(211, event->getRawPointerCoords(0)->
+ getAxisValue(AMOTION_EVENT_AXIS_Y));
+ ASSERT_EQ(221, event->getRawPointerCoords(1)->
+ getAxisValue(AMOTION_EVENT_AXIS_Y));
+
+ ASSERT_EQ(11, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0));
+ ASSERT_EQ(21, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0));
+ ASSERT_EQ(111, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1));
+ ASSERT_EQ(121, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1));
+ ASSERT_EQ(211, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0));
+ ASSERT_EQ(221, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1));
+
+ ASSERT_EQ(10, event->getHistoricalRawX(0, 0));
+ ASSERT_EQ(20, event->getHistoricalRawX(1, 0));
+ ASSERT_EQ(110, event->getHistoricalRawX(0, 1));
+ ASSERT_EQ(120, event->getHistoricalRawX(1, 1));
+ ASSERT_EQ(210, event->getRawX(0));
+ ASSERT_EQ(220, event->getRawX(1));
+
+ ASSERT_EQ(11, event->getHistoricalRawY(0, 0));
+ ASSERT_EQ(21, event->getHistoricalRawY(1, 0));
+ ASSERT_EQ(111, event->getHistoricalRawY(0, 1));
+ ASSERT_EQ(121, event->getHistoricalRawY(1, 1));
+ ASSERT_EQ(211, event->getRawY(0));
+ ASSERT_EQ(221, event->getRawY(1));
+
+ ASSERT_EQ(X_OFFSET + 10, event->getHistoricalX(0, 0));
+ ASSERT_EQ(X_OFFSET + 20, event->getHistoricalX(1, 0));
+ ASSERT_EQ(X_OFFSET + 110, event->getHistoricalX(0, 1));
+ ASSERT_EQ(X_OFFSET + 120, event->getHistoricalX(1, 1));
+ ASSERT_EQ(X_OFFSET + 210, event->getX(0));
+ ASSERT_EQ(X_OFFSET + 220, event->getX(1));
+
+ ASSERT_EQ(Y_OFFSET + 11, event->getHistoricalY(0, 0));
+ ASSERT_EQ(Y_OFFSET + 21, event->getHistoricalY(1, 0));
+ ASSERT_EQ(Y_OFFSET + 111, event->getHistoricalY(0, 1));
+ ASSERT_EQ(Y_OFFSET + 121, event->getHistoricalY(1, 1));
+ ASSERT_EQ(Y_OFFSET + 211, event->getY(0));
+ ASSERT_EQ(Y_OFFSET + 221, event->getY(1));
+
+ ASSERT_EQ(12, event->getHistoricalPressure(0, 0));
+ ASSERT_EQ(22, event->getHistoricalPressure(1, 0));
+ ASSERT_EQ(112, event->getHistoricalPressure(0, 1));
+ ASSERT_EQ(122, event->getHistoricalPressure(1, 1));
+ ASSERT_EQ(212, event->getPressure(0));
+ ASSERT_EQ(222, event->getPressure(1));
+
+ ASSERT_EQ(13, event->getHistoricalSize(0, 0));
+ ASSERT_EQ(23, event->getHistoricalSize(1, 0));
+ ASSERT_EQ(113, event->getHistoricalSize(0, 1));
+ ASSERT_EQ(123, event->getHistoricalSize(1, 1));
+ ASSERT_EQ(213, event->getSize(0));
+ ASSERT_EQ(223, event->getSize(1));
+
+ ASSERT_EQ(14, event->getHistoricalTouchMajor(0, 0));
+ ASSERT_EQ(24, event->getHistoricalTouchMajor(1, 0));
+ ASSERT_EQ(114, event->getHistoricalTouchMajor(0, 1));
+ ASSERT_EQ(124, event->getHistoricalTouchMajor(1, 1));
+ ASSERT_EQ(214, event->getTouchMajor(0));
+ ASSERT_EQ(224, event->getTouchMajor(1));
+
+ ASSERT_EQ(15, event->getHistoricalTouchMinor(0, 0));
+ ASSERT_EQ(25, event->getHistoricalTouchMinor(1, 0));
+ ASSERT_EQ(115, event->getHistoricalTouchMinor(0, 1));
+ ASSERT_EQ(125, event->getHistoricalTouchMinor(1, 1));
+ ASSERT_EQ(215, event->getTouchMinor(0));
+ ASSERT_EQ(225, event->getTouchMinor(1));
+
+ ASSERT_EQ(16, event->getHistoricalToolMajor(0, 0));
+ ASSERT_EQ(26, event->getHistoricalToolMajor(1, 0));
+ ASSERT_EQ(116, event->getHistoricalToolMajor(0, 1));
+ ASSERT_EQ(126, event->getHistoricalToolMajor(1, 1));
+ ASSERT_EQ(216, event->getToolMajor(0));
+ ASSERT_EQ(226, event->getToolMajor(1));
+
+ ASSERT_EQ(17, event->getHistoricalToolMinor(0, 0));
+ ASSERT_EQ(27, event->getHistoricalToolMinor(1, 0));
+ ASSERT_EQ(117, event->getHistoricalToolMinor(0, 1));
+ ASSERT_EQ(127, event->getHistoricalToolMinor(1, 1));
+ ASSERT_EQ(217, event->getToolMinor(0));
+ ASSERT_EQ(227, event->getToolMinor(1));
+
+ ASSERT_EQ(18, event->getHistoricalOrientation(0, 0));
+ ASSERT_EQ(28, event->getHistoricalOrientation(1, 0));
+ ASSERT_EQ(118, event->getHistoricalOrientation(0, 1));
+ ASSERT_EQ(128, event->getHistoricalOrientation(1, 1));
+ ASSERT_EQ(218, event->getOrientation(0));
+ ASSERT_EQ(228, event->getOrientation(1));
+}
+
+TEST_F(MotionEventTest, Properties) {
+ MotionEvent event;
+
+ // Initialize, add samples and check properties.
+ initializeEventWithHistory(&event);
+ ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&event));
+
+ // Set source.
+ event.setSource(AINPUT_SOURCE_JOYSTICK);
+ ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource());
+
+ // Set action.
+ event.setAction(AMOTION_EVENT_ACTION_CANCEL);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, event.getAction());
+
+ // Set meta state.
+ event.setMetaState(AMETA_CTRL_ON);
+ ASSERT_EQ(AMETA_CTRL_ON, event.getMetaState());
+}
+
+TEST_F(MotionEventTest, CopyFrom_KeepHistory) {
+ MotionEvent event;
+ initializeEventWithHistory(&event);
+
+ MotionEvent copy;
+ copy.copyFrom(&event, true /*keepHistory*/);
+
+ ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&event));
+}
+
+TEST_F(MotionEventTest, CopyFrom_DoNotKeepHistory) {
+ MotionEvent event;
+ initializeEventWithHistory(&event);
+
+ MotionEvent copy;
+ copy.copyFrom(&event, false /*keepHistory*/);
+
+ ASSERT_EQ(event.getPointerCount(), copy.getPointerCount());
+ ASSERT_EQ(0U, copy.getHistorySize());
+
+ ASSERT_EQ(event.getPointerId(0), copy.getPointerId(0));
+ ASSERT_EQ(event.getPointerId(1), copy.getPointerId(1));
+
+ ASSERT_EQ(event.getEventTime(), copy.getEventTime());
+
+ ASSERT_EQ(event.getX(0), copy.getX(0));
+}
+
+TEST_F(MotionEventTest, OffsetLocation) {
+ MotionEvent event;
+ initializeEventWithHistory(&event);
+
+ event.offsetLocation(5.0f, -2.0f);
+
+ ASSERT_EQ(X_OFFSET + 5.0f, event.getXOffset());
+ ASSERT_EQ(Y_OFFSET - 2.0f, event.getYOffset());
+}
+
+TEST_F(MotionEventTest, Scale) {
+ MotionEvent event;
+ initializeEventWithHistory(&event);
+
+ event.scale(2.0f);
+
+ ASSERT_EQ(X_OFFSET * 2, event.getXOffset());
+ ASSERT_EQ(Y_OFFSET * 2, event.getYOffset());
+
+ ASSERT_EQ(210 * 2, event.getRawX(0));
+ ASSERT_EQ(211 * 2, event.getRawY(0));
+ ASSERT_EQ((X_OFFSET + 210) * 2, event.getX(0));
+ ASSERT_EQ((Y_OFFSET + 211) * 2, event.getY(0));
+ ASSERT_EQ(212, event.getPressure(0));
+ ASSERT_EQ(213, event.getSize(0));
+ ASSERT_EQ(214 * 2, event.getTouchMajor(0));
+ ASSERT_EQ(215 * 2, event.getTouchMinor(0));
+ ASSERT_EQ(216 * 2, event.getToolMajor(0));
+ ASSERT_EQ(217 * 2, event.getToolMinor(0));
+ ASSERT_EQ(218, event.getOrientation(0));
+}
+
+TEST_F(MotionEventTest, Parcel) {
+ Parcel parcel;
+
+ MotionEvent inEvent;
+ initializeEventWithHistory(&inEvent);
+ MotionEvent outEvent;
+
+ // Round trip.
+ inEvent.writeToParcel(&parcel);
+ parcel.setDataPosition(0);
+ outEvent.readFromParcel(&parcel);
+
+ ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&outEvent));
+}
+
+TEST_F(MotionEventTest, Transform) {
+ // Generate some points on a circle.
+ // Each point 'i' is a point on a circle of radius ROTATION centered at (3,2) at an angle
+ // of ARC * i degrees clockwise relative to the Y axis.
+ // The geometrical representation is irrelevant to the test, it's just easy to generate
+ // and check rotation. We set the orientation to the same angle.
+ // Coordinate system: down is increasing Y, right is increasing X.
+ const float PI_180 = float(M_PI / 180);
+ const float RADIUS = 10;
+ const float ARC = 36;
+ const float ROTATION = ARC * 2;
+
+ const size_t pointerCount = 11;
+ int pointerIds[pointerCount];
+ PointerCoords pointerCoords[pointerCount];
+ for (size_t i = 0; i < pointerCount; i++) {
+ float angle = float(i * ARC * PI_180);
+ pointerIds[i] = i;
+ pointerCoords[i].clear();
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, sinf(angle) * RADIUS + 3);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, -cosf(angle) * RADIUS + 2);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle);
+ }
+ MotionEvent event;
+ event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
+ float originalRawX = 0 + 3;
+ float originalRawY = -RADIUS + 2;
+
+ // Check original raw X and Y assumption.
+ ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
+ ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
+
+ // Now translate the motion event so the circle's origin is at (0,0).
+ event.offsetLocation(-3, -2);
+
+ // Offsetting the location should preserve the raw X and Y of the first point.
+ ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
+ ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
+
+ // Apply a rotation about the origin by ROTATION degrees clockwise.
+ SkMatrix matrix;
+ matrix.setRotate(ROTATION);
+ event.transform(&matrix);
+
+ // Check the points.
+ for (size_t i = 0; i < pointerCount; i++) {
+ float angle = float((i * ARC + ROTATION) * PI_180);
+ ASSERT_NEAR(sinf(angle) * RADIUS, event.getX(i), 0.001);
+ ASSERT_NEAR(-cosf(angle) * RADIUS, event.getY(i), 0.001);
+ ASSERT_NEAR(tanf(angle), tanf(event.getOrientation(i)), 0.1);
+ }
+
+ // Applying the transformation should preserve the raw X and Y of the first point.
+ ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
+ ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
+}
+
+} // namespace android
diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
index 903fcaf..6e18a4f 100644
--- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
@@ -1,6 +1,18 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#include <ui/InputTransport.h>
#include <utils/Timers.h>
@@ -159,15 +171,17 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
sampleEventTimes.push(i + 10);
for (size_t j = 0; j < pointerCount; j++) {
samplePointerCoords.push();
- samplePointerCoords.editTop().x = 100 * i + j;
- samplePointerCoords.editTop().y = 200 * i + j;
- samplePointerCoords.editTop().pressure = 0.5 * i + j;
- samplePointerCoords.editTop().size = 0.7 * i + j;
- samplePointerCoords.editTop().touchMajor = 1.5 * i + j;
- samplePointerCoords.editTop().touchMinor = 1.7 * i + j;
- samplePointerCoords.editTop().toolMajor = 2.5 * i + j;
- samplePointerCoords.editTop().toolMinor = 2.7 * i + j;
- samplePointerCoords.editTop().orientation = 3.5 * i + j;
+ PointerCoords& pc = samplePointerCoords.editTop();
+ pc.clear();
+ pc.setAxisValue(AMOTION_EVENT_AXIS_X, 100 * i + j);
+ pc.setAxisValue(AMOTION_EVENT_AXIS_Y, 200 * i + j);
+ pc.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i + j);
+ pc.setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i + j);
+ pc.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i + j);
+ pc.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 1.7 * i + j);
+ pc.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.5 * i + j);
+ pc.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.7 * i + j);
+ pc.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i + j);
}
}
@@ -239,27 +253,27 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
for (size_t i = 0; i < pointerCount; i++) {
SCOPED_TRACE(i);
size_t offset = sampleIndex * pointerCount + i;
- EXPECT_EQ(samplePointerCoords[offset].x,
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X),
motionEvent->getHistoricalRawX(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].y,
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y),
motionEvent->getHistoricalRawY(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].x + xOffset,
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset,
motionEvent->getHistoricalX(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].y + yOffset,
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset,
motionEvent->getHistoricalY(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].pressure,
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
motionEvent->getHistoricalPressure(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].size,
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
motionEvent->getHistoricalSize(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].touchMajor,
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
motionEvent->getHistoricalTouchMajor(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].touchMinor,
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
motionEvent->getHistoricalTouchMinor(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].toolMajor,
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
motionEvent->getHistoricalToolMajor(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].toolMinor,
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
motionEvent->getHistoricalToolMinor(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].orientation,
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
motionEvent->getHistoricalOrientation(i, sampleIndex));
}
}
@@ -269,17 +283,28 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
for (size_t i = 0; i < pointerCount; i++) {
SCOPED_TRACE(i);
size_t offset = lastSampleIndex * pointerCount + i;
- EXPECT_EQ(samplePointerCoords[offset].x, motionEvent->getRawX(i));
- EXPECT_EQ(samplePointerCoords[offset].y, motionEvent->getRawY(i));
- EXPECT_EQ(samplePointerCoords[offset].x + xOffset, motionEvent->getX(i));
- EXPECT_EQ(samplePointerCoords[offset].y + yOffset, motionEvent->getY(i));
- EXPECT_EQ(samplePointerCoords[offset].pressure, motionEvent->getPressure(i));
- EXPECT_EQ(samplePointerCoords[offset].size, motionEvent->getSize(i));
- EXPECT_EQ(samplePointerCoords[offset].touchMajor, motionEvent->getTouchMajor(i));
- EXPECT_EQ(samplePointerCoords[offset].touchMinor, motionEvent->getTouchMinor(i));
- EXPECT_EQ(samplePointerCoords[offset].toolMajor, motionEvent->getToolMajor(i));
- EXPECT_EQ(samplePointerCoords[offset].toolMinor, motionEvent->getToolMinor(i));
- EXPECT_EQ(samplePointerCoords[offset].orientation, motionEvent->getOrientation(i));
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X),
+ motionEvent->getRawX(i));
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y),
+ motionEvent->getRawY(i));
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset,
+ motionEvent->getX(i));
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset,
+ motionEvent->getY(i));
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
+ motionEvent->getPressure(i));
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
+ motionEvent->getSize(i));
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
+ motionEvent->getTouchMajor(i));
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
+ motionEvent->getTouchMinor(i));
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
+ motionEvent->getToolMajor(i));
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
+ motionEvent->getToolMinor(i));
+ EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
+ motionEvent->getOrientation(i));
}
status = mConsumer->sendFinishedSignal(false);
@@ -328,7 +353,8 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenNotReset_ReturnsErr
const size_t pointerCount = 1;
int32_t pointerIds[pointerCount] = { 0 };
- PointerCoords pointerCoords[pointerCount] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
+ PointerCoords pointerCoords[pointerCount];
+ pointerCoords[0].clear();
status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerIds, pointerCoords);
diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp
index 0bd1af4..0fd404d 100644
--- a/libs/utils/RefBase.cpp
+++ b/libs/utils/RefBase.cpp
@@ -20,9 +20,9 @@
#include <utils/Atomic.h>
#include <utils/CallStack.h>
-#include <utils/KeyedVector.h>
#include <utils/Log.h>
#include <utils/threads.h>
+#include <utils/TextOutput.h>
#include <stdlib.h>
#include <stdio.h>
@@ -34,6 +34,7 @@
// compile with refcounting debugging enabled
#define DEBUG_REFS 0
+#define DEBUG_REFS_FATAL_SANITY_CHECKS 0
#define DEBUG_REFS_ENABLED_BY_DEFAULT 1
#define DEBUG_REFS_CALLSTACK_ENABLED 1
@@ -69,8 +70,10 @@ public:
void addStrongRef(const void* /*id*/) { }
void removeStrongRef(const void* /*id*/) { }
+ void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
void addWeakRef(const void* /*id*/) { }
void removeWeakRef(const void* /*id*/) { }
+ void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
void printRefs() const { }
void trackMe(bool, bool) { }
@@ -86,39 +89,73 @@ public:
, mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
, mRetain(false)
{
- //LOGI("NEW weakref_impl %p for RefBase %p", this, base);
}
~weakref_impl()
{
- LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!");
- LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!");
+ bool dumpStack = false;
+ if (!mRetain && mStrongRefs != NULL) {
+ dumpStack = true;
+#if DEBUG_REFS_FATAL_SANITY_CHECKS
+ LOG_ALWAYS_FATAL("Strong references remain!");
+#else
+ LOGE("Strong references remain!");
+#endif
+ }
+
+ if (!mRetain && mWeakRefs != NULL) {
+ dumpStack = true;
+#if DEBUG_REFS_FATAL_SANITY_CHECKS
+ LOG_ALWAYS_FATAL("Weak references remain!");
+#else
+ LOGE("Weak references remain!");
+#endif
+ }
+
+ if (dumpStack) {
+ CallStack stack;
+ stack.update();
+ stack.dump();
+ }
}
- void addStrongRef(const void* id)
- {
+ void addStrongRef(const void* id) {
+ //LOGD_IF(mTrackEnabled,
+ // "addStrongRef: RefBase=%p, id=%p", mBase, id);
addRef(&mStrongRefs, id, mStrong);
}
- void removeStrongRef(const void* id)
- {
- if (!mRetain)
+ void removeStrongRef(const void* id) {
+ //LOGD_IF(mTrackEnabled,
+ // "removeStrongRef: RefBase=%p, id=%p", mBase, id);
+ if (!mRetain) {
removeRef(&mStrongRefs, id);
- else
+ } else {
addRef(&mStrongRefs, id, -mStrong);
+ }
}
- void addWeakRef(const void* id)
- {
+ void renameStrongRefId(const void* old_id, const void* new_id) {
+ //LOGD_IF(mTrackEnabled,
+ // "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",
+ // mBase, old_id, new_id);
+ renameRefsId(mStrongRefs, old_id, new_id);
+ }
+
+ void addWeakRef(const void* id) {
addRef(&mWeakRefs, id, mWeak);
}
- void removeWeakRef(const void* id)
- {
- if (!mRetain)
+ void removeWeakRef(const void* id) {
+ if (!mRetain) {
removeRef(&mWeakRefs, id);
- else
+ } else {
addRef(&mWeakRefs, id, -mWeak);
+ }
+ }
+
+ void renameWeakRefId(const void* old_id, const void* new_id) {
+ renameRefsId(mWeakRefs, old_id, new_id);
}
void trackMe(bool track, bool retain)
@@ -132,8 +169,7 @@ public:
String8 text;
{
- AutoMutex _l(const_cast<weakref_impl*>(this)->mMutex);
-
+ Mutex::Autolock _l(const_cast<weakref_impl*>(this)->mMutex);
char buf[128];
sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
text.append(buf);
@@ -172,6 +208,7 @@ private:
{
if (mTrackEnabled) {
AutoMutex _l(mMutex);
+
ref_entry* ref = new ref_entry;
// Reference count at the time of the snapshot, but before the
// update. Positive value means we increment, negative--we
@@ -181,7 +218,6 @@ private:
#if DEBUG_REFS_CALLSTACK_ENABLED
ref->stack.update(2);
#endif
-
ref->next = *refs;
*refs = ref;
}
@@ -199,13 +235,37 @@ private:
delete ref;
return;
}
-
refs = &ref->next;
ref = *refs;
}
-
- LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!",
- id, mBase, this);
+
+#if DEBUG_REFS_FATAL_SANITY_CHECKS
+ LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p"
+ "(weakref_type %p) that doesn't exist!",
+ id, mBase, this);
+#endif
+
+ LOGE("RefBase: removing id %p on RefBase %p"
+ "(weakref_type %p) that doesn't exist!",
+ id, mBase, this);
+
+ CallStack stack;
+ stack.update();
+ stack.dump();
+ }
+ }
+
+ void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)
+ {
+ if (mTrackEnabled) {
+ AutoMutex _l(mMutex);
+ ref_entry* ref = r;
+ while (ref != NULL) {
+ if (ref->id == old_id) {
+ ref->id = new_id;
+ }
+ ref = ref->next;
+ }
}
}
@@ -235,44 +295,6 @@ private:
// on removeref that match the address ones.
bool mRetain;
-#if 0
- void addRef(KeyedVector<const void*, int32_t>* refs, const void* id)
- {
- AutoMutex _l(mMutex);
- ssize_t i = refs->indexOfKey(id);
- if (i >= 0) {
- ++(refs->editValueAt(i));
- } else {
- i = refs->add(id, 1);
- }
- }
-
- void removeRef(KeyedVector<const void*, int32_t>* refs, const void* id)
- {
- AutoMutex _l(mMutex);
- ssize_t i = refs->indexOfKey(id);
- LOG_ALWAYS_FATAL_IF(i < 0, "RefBase: removing id %p that doesn't exist!", id);
- if (i >= 0) {
- int32_t val = --(refs->editValueAt(i));
- if (val == 0) {
- refs->removeItemsAt(i);
- }
- }
- }
-
- void printRefs(const KeyedVector<const void*, int32_t>& refs)
- {
- const size_t N=refs.size();
- for (size_t i=0; i<N; i++) {
- printf("\tID %p: %d remain\n", refs.keyAt(i), refs.valueAt(i));
- }
- }
-
- mutable Mutex mMutex;
- KeyedVector<const void*, int32_t> mStrongRefs;
- KeyedVector<const void*, int32_t> mWeakRefs;
-#endif
-
#endif
};
@@ -281,7 +303,6 @@ private:
void RefBase::incStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
- refs->addWeakRef(id);
refs->incWeak(id);
refs->addStrongRef(id);
@@ -313,14 +334,12 @@ void RefBase::decStrong(const void* id) const
delete this;
}
}
- refs->removeWeakRef(id);
refs->decWeak(id);
}
void RefBase::forceIncStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
- refs->addWeakRef(id);
refs->incWeak(id);
refs->addStrongRef(id);
@@ -372,7 +391,7 @@ void RefBase::weakref_type::decWeak(const void* id)
if (impl->mStrong == INITIAL_STRONG_VALUE)
delete impl->mBase;
else {
-// LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
+ // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
delete impl;
}
} else {
@@ -432,7 +451,6 @@ bool RefBase::weakref_type::attemptIncStrong(const void* id)
}
}
- impl->addWeakRef(id);
impl->addStrongRef(id);
#if PRINT_REFS
@@ -450,7 +468,7 @@ bool RefBase::weakref_type::attemptIncStrong(const void* id)
bool RefBase::weakref_type::attemptIncWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
-
+
int32_t curCount = impl->mWeak;
LOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
this);
@@ -497,14 +515,11 @@ RefBase::weakref_type* RefBase::getWeakRefs() const
RefBase::RefBase()
: mRefs(new weakref_impl(this))
{
-// LOGV("Creating refs %p with RefBase %p\n", mRefs, this);
}
RefBase::~RefBase()
{
-// LOGV("Destroying RefBase %p (refs %p)\n", this, mRefs);
if (mRefs->mWeak == 0) {
-// LOGV("Freeing refs %p of old RefBase %p\n", mRefs, this);
delete mRefs;
}
}
@@ -530,5 +545,37 @@ bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
void RefBase::onLastWeakRef(const void* /*id*/)
{
}
-
+
+// ---------------------------------------------------------------------------
+
+void RefBase::moveReferences(void* dst, void const* src, size_t n,
+ const ReferenceConverterBase& caster)
+{
+#if DEBUG_REFS
+ const size_t itemSize = caster.getReferenceTypeSize();
+ for (size_t i=0 ; i<n ; i++) {
+ void* d = reinterpret_cast<void *>(intptr_t(dst) + i*itemSize);
+ void const* s = reinterpret_cast<void const*>(intptr_t(src) + i*itemSize);
+ RefBase* ref(reinterpret_cast<RefBase*>(caster.getReferenceBase(d)));
+ ref->mRefs->renameStrongRefId(s, d);
+ ref->mRefs->renameWeakRefId(s, d);
+ }
+#endif
+}
+
+// ---------------------------------------------------------------------------
+
+TextOutput& printStrongPointer(TextOutput& to, const void* val)
+{
+ to << "sp<>(" << val << ")";
+ return to;
+}
+
+TextOutput& printWeakPointer(TextOutput& to, const void* val)
+{
+ to << "wp<>(" << val << ")";
+ return to;
+}
+
+
}; // namespace android
diff --git a/libs/utils/SystemClock.cpp b/libs/utils/SystemClock.cpp
index 2bdc0ce..062e6d7 100644
--- a/libs/utils/SystemClock.cpp
+++ b/libs/utils/SystemClock.cpp
@@ -19,7 +19,7 @@
* System clock functions.
*/
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
#include <linux/ioctl.h>
#include <linux/rtc.h>
#include <utils/Atomic.h>
@@ -50,7 +50,7 @@ int setCurrentTimeMillis(int64_t millis)
return -1;
#else
struct timeval tv;
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
struct timespec ts;
int fd;
int res;
@@ -66,7 +66,7 @@ int setCurrentTimeMillis(int64_t millis)
LOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec);
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
fd = open("/dev/alarm", O_RDWR);
if(fd < 0) {
LOGW("Unable to open alarm driver: %s\n", strerror(errno));
@@ -106,7 +106,7 @@ int64_t uptimeMillis()
*/
int64_t elapsedRealtime()
{
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
static int s_fd = -1;
if (s_fd == -1) {
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index b1bd828..8b5da0e 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -675,6 +675,9 @@ Thread::Thread(bool canCallJava)
mLock("Thread::mLock"),
mStatus(NO_ERROR),
mExitPending(false), mRunning(false)
+#ifdef HAVE_ANDROID_OS
+ , mTid(-1)
+#endif
{
}
@@ -715,6 +718,7 @@ status_t Thread::run(const char* name, int32_t priority, size_t stack)
res = androidCreateRawThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
}
+ // The new thread wakes up at _threadLoop, but immediately blocks on mLock
if (res == false) {
mStatus = UNKNOWN_ERROR; // something happened!
@@ -730,16 +734,24 @@ status_t Thread::run(const char* name, int32_t priority, size_t stack)
// here merely indicates successfully starting the thread and does not
// imply successful termination/execution.
return NO_ERROR;
+
+ // Exiting scope of mLock is a memory barrier and allows new thread to run
}
int Thread::_threadLoop(void* user)
{
Thread* const self = static_cast<Thread*>(user);
+
+ // force a memory barrier before reading any fields, in particular mHoldSelf
+ {
+ Mutex::Autolock _l(self->mLock);
+ }
+
sp<Thread> strong(self->mHoldSelf);
wp<Thread> weak(strong);
self->mHoldSelf.clear();
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
// this is very useful for debugging with gdb
self->mTid = gettid();
#endif
@@ -753,7 +765,7 @@ int Thread::_threadLoop(void* user)
self->mStatus = self->readyToRun();
result = (self->mStatus == NO_ERROR);
- if (result && !self->mExitPending) {
+ if (result && !self->exitPending()) {
// Binder threads (and maybe others) rely on threadLoop
// running at least once after a successful ::readyToRun()
// (unless, of course, the thread has already been asked to exit
@@ -770,18 +782,21 @@ int Thread::_threadLoop(void* user)
result = self->threadLoop();
}
+ // establish a scope for mLock
+ {
+ Mutex::Autolock _l(self->mLock);
if (result == false || self->mExitPending) {
self->mExitPending = true;
- self->mLock.lock();
self->mRunning = false;
// clear thread ID so that requestExitAndWait() does not exit if
// called by a new thread using the same thread ID as this one.
self->mThread = thread_id_t(-1);
+ // note that interested observers blocked in requestExitAndWait are
+ // awoken by broadcast, but blocked on mLock until break exits scope
self->mThreadExitedCondition.broadcast();
- self->mThread = thread_id_t(-1); // thread id could be reused
- self->mLock.unlock();
break;
}
+ }
// Release our strong reference, to let a chance to the thread
// to die a peaceful death.
@@ -795,6 +810,7 @@ int Thread::_threadLoop(void* user)
void Thread::requestExit()
{
+ Mutex::Autolock _l(mLock);
mExitPending = true;
}
@@ -815,6 +831,8 @@ status_t Thread::requestExitAndWait()
while (mRunning == true) {
mThreadExitedCondition.wait(mLock);
}
+ // This next line is probably not needed any more, but is being left for
+ // historical reference. Note that each interested party will clear flag.
mExitPending = false;
return mStatus;
@@ -822,6 +840,7 @@ status_t Thread::requestExitAndWait()
bool Thread::exitPending() const
{
+ Mutex::Autolock _l(mLock);
return mExitPending;
}