diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/binder/MemoryHeapBase.cpp | 4 | ||||
-rw-r--r-- | libs/binder/MemoryHeapPmem.cpp | 12 | ||||
-rw-r--r-- | libs/gui/SurfaceTexture.cpp | 12 | ||||
-rw-r--r-- | libs/surfaceflinger_client/ISurfaceComposerClient.cpp | 2 | ||||
-rw-r--r-- | libs/ui/Android.mk | 7 | ||||
-rw-r--r-- | libs/ui/Input.cpp | 345 | ||||
-rw-r--r-- | libs/ui/InputTransport.cpp | 3 | ||||
-rw-r--r-- | libs/ui/KeyLayoutMap.cpp | 70 | ||||
-rw-r--r-- | libs/ui/Keyboard.cpp | 24 | ||||
-rw-r--r-- | libs/ui/tests/Android.mk | 7 | ||||
-rw-r--r-- | libs/ui/tests/InputChannel_test.cpp | 18 | ||||
-rw-r--r-- | libs/ui/tests/InputEvent_test.cpp | 582 | ||||
-rw-r--r-- | libs/ui/tests/InputPublisherAndConsumer_test.cpp | 96 | ||||
-rw-r--r-- | libs/utils/RefBase.cpp | 189 | ||||
-rw-r--r-- | libs/utils/SystemClock.cpp | 8 | ||||
-rw-r--r-- | libs/utils/Threads.cpp | 29 |
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, ®); 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; } |