diff options
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/gui/Android.mk | 11 | ||||
| -rw-r--r-- | libs/gui/IGraphicBufferAlloc.cpp (renamed from libs/surfaceflinger_client/IGraphicBufferAlloc.cpp) | 0 | ||||
| -rw-r--r-- | libs/gui/ISurface.cpp (renamed from libs/surfaceflinger_client/ISurface.cpp) | 0 | ||||
| -rw-r--r-- | libs/gui/ISurfaceComposer.cpp (renamed from libs/surfaceflinger_client/ISurfaceComposer.cpp) | 0 | ||||
| -rw-r--r-- | libs/gui/ISurfaceComposerClient.cpp (renamed from libs/surfaceflinger_client/ISurfaceComposerClient.cpp) | 0 | ||||
| -rw-r--r-- | libs/gui/ISurfaceTexture.cpp | 7 | ||||
| -rw-r--r-- | libs/gui/LayerState.cpp (renamed from libs/surfaceflinger_client/LayerState.cpp) | 0 | ||||
| -rw-r--r-- | libs/gui/SharedBufferStack.cpp (renamed from libs/surfaceflinger_client/SharedBufferStack.cpp) | 0 | ||||
| -rw-r--r-- | libs/gui/Surface.cpp (renamed from libs/surfaceflinger_client/Surface.cpp) | 15 | ||||
| -rw-r--r-- | libs/gui/SurfaceComposerClient.cpp (renamed from libs/surfaceflinger_client/SurfaceComposerClient.cpp) | 0 | ||||
| -rw-r--r-- | libs/gui/SurfaceTexture.cpp | 75 | ||||
| -rw-r--r-- | libs/gui/SurfaceTextureClient.cpp | 34 | ||||
| -rw-r--r-- | libs/gui/tests/Android.mk | 2 | ||||
| -rw-r--r-- | libs/gui/tests/SurfaceTextureClient_test.cpp | 147 | ||||
| -rw-r--r-- | libs/gui/tests/Surface_test.cpp (renamed from libs/surfaceflinger_client/tests/Surface_test.cpp) | 0 | ||||
| -rw-r--r-- | libs/surfaceflinger_client/Android.mk | 17 | ||||
| -rw-r--r-- | libs/surfaceflinger_client/tests/Android.mk | 53 | ||||
| -rw-r--r-- | libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk | 17 | ||||
| -rw-r--r-- | libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp | 284 | ||||
| -rw-r--r-- | libs/ui/Input.cpp | 237 | ||||
| -rw-r--r-- | libs/ui/InputTransport.cpp | 4 | ||||
| -rw-r--r-- | libs/utils/AssetManager.cpp | 2 | ||||
| -rw-r--r-- | libs/utils/Looper.cpp | 19 | ||||
| -rw-r--r-- | libs/utils/Timers.cpp | 18 |
24 files changed, 541 insertions, 401 deletions
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk index d1a6af1dc1..58bb0d31f4 100644 --- a/libs/gui/Android.mk +++ b/libs/gui/Android.mk @@ -10,7 +10,15 @@ LOCAL_SRC_FILES:= \ SensorEventQueue.cpp \ SensorManager.cpp \ SurfaceTexture.cpp \ - SurfaceTextureClient.cpp + SurfaceTextureClient.cpp \ + ISurfaceComposer.cpp \ + ISurface.cpp \ + ISurfaceComposerClient.cpp \ + IGraphicBufferAlloc.cpp \ + LayerState.cpp \ + SharedBufferStack.cpp \ + Surface.cpp \ + SurfaceComposerClient.cpp \ LOCAL_SHARED_LIBRARIES := \ libcutils \ @@ -21,7 +29,6 @@ LOCAL_SHARED_LIBRARIES := \ libui \ libEGL \ libGLESv2 \ - libsurfaceflinger_client LOCAL_MODULE:= libgui diff --git a/libs/surfaceflinger_client/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp index e05da725c4..e05da725c4 100644 --- a/libs/surfaceflinger_client/IGraphicBufferAlloc.cpp +++ b/libs/gui/IGraphicBufferAlloc.cpp diff --git a/libs/surfaceflinger_client/ISurface.cpp b/libs/gui/ISurface.cpp index 23b90af311..23b90af311 100644 --- a/libs/surfaceflinger_client/ISurface.cpp +++ b/libs/gui/ISurface.cpp diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 8951c3f045..8951c3f045 100644 --- a/libs/surfaceflinger_client/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp diff --git a/libs/surfaceflinger_client/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp index 7730eb1fa9..7730eb1fa9 100644 --- a/libs/surfaceflinger_client/ISurfaceComposerClient.cpp +++ b/libs/gui/ISurfaceComposerClient.cpp diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp index d661fd5791..bc14ad5514 100644 --- a/libs/gui/ISurfaceTexture.cpp +++ b/libs/gui/ISurfaceTexture.cpp @@ -88,10 +88,11 @@ public: return result; } - virtual status_t queueBuffer(int buf) { + virtual status_t queueBuffer(int buf, int64_t timestamp) { Parcel data, reply; data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); data.writeInt32(buf); + data.writeInt64(timestamp); remote()->transact(QUEUE_BUFFER, data, &reply); status_t result = reply.readInt32(); return result; @@ -174,7 +175,8 @@ status_t BnSurfaceTexture::onTransact( case QUEUE_BUFFER: { CHECK_INTERFACE(ISurfaceTexture, data, reply); int buf = data.readInt32(); - status_t result = queueBuffer(buf); + int64_t timestamp = data.readInt64(); + status_t result = queueBuffer(buf, timestamp); reply->writeInt32(result); return NO_ERROR; } break; @@ -196,7 +198,6 @@ status_t BnSurfaceTexture::onTransact( return NO_ERROR; } break; case SET_TRANSFORM: { - Rect reg; CHECK_INTERFACE(ISurfaceTexture, data, reply); uint32_t transform = data.readInt32(); status_t result = setTransform(transform); diff --git a/libs/surfaceflinger_client/LayerState.cpp b/libs/gui/LayerState.cpp index 01c4c7ebfe..01c4c7ebfe 100644 --- a/libs/surfaceflinger_client/LayerState.cpp +++ b/libs/gui/LayerState.cpp diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/gui/SharedBufferStack.cpp index 7505d530e0..7505d530e0 100644 --- a/libs/surfaceflinger_client/SharedBufferStack.cpp +++ b/libs/gui/SharedBufferStack.cpp diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/gui/Surface.cpp index 21d509a6a8..0dfbf01aa4 100644 --- a/libs/surfaceflinger_client/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -753,6 +753,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: res = dispatch_set_buffers_transform( args ); break; + case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: + res = dispatch_set_buffers_timestamp( args ); + break; default: res = NAME_NOT_FOUND; break; @@ -792,6 +795,11 @@ int Surface::dispatch_set_buffers_transform(va_list args) { return setBuffersTransform(transform); } +int Surface::dispatch_set_buffers_timestamp(va_list args) { + int64_t timestamp = va_arg(args, int64_t); + return setBuffersTimestamp(timestamp); +} + void Surface::setUsage(uint32_t reqUsage) { Mutex::Autolock _l(mSurfaceLock); @@ -910,6 +918,13 @@ int Surface::setBuffersTransform(int transform) return NO_ERROR; } +int Surface::setBuffersTimestamp(int64_t timestamp) +{ + // Surface doesn't really have anything meaningful to do with timestamps + // so they'll just be dropped here. + return NO_ERROR; +} + // ---------------------------------------------------------------------------- int Surface::getConnectedApi() const diff --git a/libs/surfaceflinger_client/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index d3367246a1..d3367246a1 100644 --- a/libs/surfaceflinger_client/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index 5c6d71b150..f4e2a67616 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -76,9 +76,19 @@ static float mtxRot270[16] = { static void mtxMul(float out[16], const float a[16], const float b[16]); SurfaceTexture::SurfaceTexture(GLuint tex) : - mBufferCount(MIN_BUFFER_SLOTS), mCurrentTexture(INVALID_BUFFER_SLOT), - mCurrentTransform(0), mLastQueued(INVALID_BUFFER_SLOT), - mLastQueuedTransform(0), mNextTransform(0), mTexName(tex) { + mDefaultWidth(1), + mDefaultHeight(1), + mPixelFormat(PIXEL_FORMAT_RGBA_8888), + mUseDefaultSize(true), + mBufferCount(MIN_BUFFER_SLOTS), + mCurrentTexture(INVALID_BUFFER_SLOT), + mCurrentTransform(0), + mCurrentTimestamp(0), + mLastQueued(INVALID_BUFFER_SLOT), + mLastQueuedTransform(0), + mLastQueuedTimestamp(0), + mNextTransform(0), + mTexName(tex) { LOGV("SurfaceTexture::SurfaceTexture"); for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { mSlots[i].mEglImage = EGL_NO_IMAGE_KHR; @@ -109,6 +119,16 @@ status_t SurfaceTexture::setBufferCount(int bufferCount) { return OK; } +status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h) +{ + Mutex::Autolock lock(mMutex); + if ((w != mDefaultWidth) || (h != mDefaultHeight)) { + mDefaultWidth = w; + mDefaultHeight = h; + } + return OK; +} + sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { LOGV("SurfaceTexture::requestBuffer"); @@ -118,12 +138,34 @@ sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf, mBufferCount, buf); return 0; } + if ((w && !h) || (!w & h)) { + LOGE("requestBuffer: invalid size: w=%u, h=%u: %d", w, h, buf); + return 0; + } + + const bool useDefaultSize = !w && !h; + if (useDefaultSize) { + // use the default size + w = mDefaultWidth; + h = mDefaultHeight; + } + + const bool updateFormat = (format != 0); + if (!updateFormat) { + // keep the current (or default) format + format = mPixelFormat; + } + usage |= GraphicBuffer::USAGE_HW_TEXTURE; sp<GraphicBuffer> graphicBuffer( mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage)); if (graphicBuffer == 0) { LOGE("requestBuffer: SurfaceComposer::createGraphicBuffer failed"); } else { + mUseDefaultSize = useDefaultSize; + if (updateFormat) { + mPixelFormat = format; + } mSlots[buf].mGraphicBuffer = graphicBuffer; if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) { eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage); @@ -149,11 +191,22 @@ status_t SurfaceTexture::dequeueBuffer(int *buf) { if (found == INVALID_BUFFER_SLOT) { return -EBUSY; } + *buf = found; + + const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer); + if (buffer == NULL) { + return ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; + } + if ((mUseDefaultSize) && + ((uint32_t(buffer->width) != mDefaultWidth) || + (uint32_t(buffer->height) != mDefaultHeight))) { + return ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; + } return OK; } -status_t SurfaceTexture::queueBuffer(int buf) { +status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) { LOGV("SurfaceTexture::queueBuffer"); Mutex::Autolock lock(mMutex); if (buf < 0 || mBufferCount <= buf) { @@ -172,6 +225,7 @@ status_t SurfaceTexture::queueBuffer(int buf) { mLastQueued = buf; mLastQueuedCrop = mNextCrop; mLastQueuedTransform = mNextTransform; + mLastQueuedTimestamp = timestamp; if (mFrameAvailableListener != 0) { mFrameAvailableListener->onFrameAvailable(); } @@ -246,12 +300,13 @@ status_t SurfaceTexture::updateTexImage() { mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer; mCurrentCrop = mLastQueuedCrop; mCurrentTransform = mLastQueuedTransform; + mCurrentTimestamp = mLastQueuedTimestamp; } return OK; } void SurfaceTexture::getTransformMatrix(float mtx[16]) { - LOGV("SurfaceTexture::updateTexImage"); + LOGV("SurfaceTexture::getTransformMatrix"); Mutex::Autolock lock(mMutex); float xform[16]; @@ -304,10 +359,10 @@ void SurfaceTexture::getTransformMatrix(float mtx[16]) { } else { tx = 0.0f; } - if (mCurrentCrop.right < buf->getWidth()) { + if (mCurrentCrop.right < int32_t(buf->getWidth())) { xshrink++; } - if (mCurrentCrop.bottom < buf->getHeight()) { + if (mCurrentCrop.bottom < int32_t(buf->getHeight())) { ty = (float(buf->getHeight() - mCurrentCrop.bottom) + 1.0f) / float(buf->getHeight()); yshrink++; @@ -342,6 +397,12 @@ void SurfaceTexture::getTransformMatrix(float mtx[16]) { mtxMul(mtx, mtxFlipV, mtxBeforeFlipV); } +nsecs_t SurfaceTexture::getTimestamp() { + LOGV("SurfaceTexture::getTimestamp"); + Mutex::Autolock lock(mMutex); + return mCurrentTimestamp; +} + void SurfaceTexture::setFrameAvailableListener( const sp<FrameAvailableListener>& l) { LOGV("SurfaceTexture::setFrameAvailableListener"); diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp index 7f1d9cbf22..29fc4d3edc 100644 --- a/libs/gui/SurfaceTextureClient.cpp +++ b/libs/gui/SurfaceTextureClient.cpp @@ -25,8 +25,9 @@ namespace android { SurfaceTextureClient::SurfaceTextureClient( const sp<ISurfaceTexture>& surfaceTexture): - mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(1), - mReqHeight(1), mReqFormat(DEFAULT_FORMAT), mReqUsage(0), mMutex() { + mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0), + mReqHeight(0), mReqFormat(DEFAULT_FORMAT), mReqUsage(0), + mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mMutex() { // Initialize the ANativeWindow function pointers. ANativeWindow::setSwapInterval = setSwapInterval; ANativeWindow::dequeueBuffer = dequeueBuffer; @@ -99,7 +100,8 @@ int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) { return err; } sp<GraphicBuffer>& gbuf(mSlots[buf]); - if (gbuf == 0 || gbuf->getWidth() != mReqWidth || + if (err == ISurfaceTexture::BUFFER_NEEDS_REALLOCATION || + gbuf == 0 || gbuf->getWidth() != mReqWidth || gbuf->getHeight() != mReqHeight || uint32_t(gbuf->getPixelFormat()) != mReqFormat || (gbuf->getUsage() & mReqUsage) != mReqUsage) { @@ -135,9 +137,17 @@ int SurfaceTextureClient::lockBuffer(android_native_buffer_t* buffer) { int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) { LOGV("SurfaceTextureClient::queueBuffer"); Mutex::Autolock lock(mMutex); + int64_t timestamp; + if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { + timestamp = systemTime(SYSTEM_TIME_MONOTONIC); + LOGV("SurfaceTextureClient::queueBuffer making up timestamp: %.2f ms", + timestamp / 1000000.f); + } else { + timestamp = mTimestamp; + } for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { if (mSlots[i]->handle == buffer->handle) { - return mSurfaceTexture->queueBuffer(i); + return mSurfaceTexture->queueBuffer(i, timestamp); } } LOGE("queueBuffer: unknown buffer queued"); @@ -196,6 +206,9 @@ int SurfaceTextureClient::perform(int operation, va_list args) case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: res = dispatchSetBuffersTransform(args); break; + case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: + res = dispatchSetBuffersTimestamp(args); + break; default: res = NAME_NOT_FOUND; break; @@ -240,6 +253,11 @@ int SurfaceTextureClient::dispatchSetBuffersTransform(va_list args) { return setBuffersTransform(transform); } +int SurfaceTextureClient::dispatchSetBuffersTimestamp(va_list args) { + int64_t timestamp = va_arg(args, int64_t); + return setBuffersTimestamp(timestamp); +} + int SurfaceTextureClient::connect(int api) { LOGV("SurfaceTextureClient::connect"); // XXX: Implement this! @@ -323,6 +341,14 @@ int SurfaceTextureClient::setBuffersTransform(int transform) return err; } +int SurfaceTextureClient::setBuffersTimestamp(int64_t timestamp) +{ + LOGV("SurfaceTextureClient::setBuffersTimestamp"); + Mutex::Autolock lock(mMutex); + mTimestamp = timestamp; + return NO_ERROR; +} + void SurfaceTextureClient::freeAllBuffers() { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { mSlots[i] = 0; diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk index 7516299446..ecd0995115 100644 --- a/libs/gui/tests/Android.mk +++ b/libs/gui/tests/Android.mk @@ -9,6 +9,7 @@ LOCAL_MODULE := SurfaceTexture_test LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := \ + Surface_test.cpp \ SurfaceTextureClient_test.cpp \ SurfaceTexture_test.cpp \ @@ -20,7 +21,6 @@ LOCAL_SHARED_LIBRARIES := \ libcutils \ libgui \ libstlport \ - libsurfaceflinger_client \ libui \ libutils \ diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index 94b05bc2d3..348171dcf3 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -100,4 +100,151 @@ TEST_F(SurfaceTextureClientTest, EglCreateWindowSurfaceFails) { eglTerminate(dpy); } +TEST_F(SurfaceTextureClientTest, BufferGeometryInvalidSizesFail) { + sp<ANativeWindow> anw(mSTC); + + EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(), -1, 0, 0)); + EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(), 0, -1, 0)); + EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, -1)); + EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(), -1, -1, 0)); + EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(), 0, 8, 0)); + EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(), 8, 0, 0)); +} + +TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) { + sp<ANativeWindow> anw(mSTC); + android_native_buffer_t* buf; + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(1, buf->width); + EXPECT_EQ(1, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); +} + +TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) { + sp<ANativeWindow> anw(mSTC); + android_native_buffer_t* buf; + EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, PIXEL_FORMAT_RGB_565)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(16, buf->width); + EXPECT_EQ(8, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); +} + +TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) { + sp<ANativeWindow> anw(mSTC); + android_native_buffer_t* buf; + EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, PIXEL_FORMAT_RGB_565)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(1, buf->width); + EXPECT_EQ(1, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); +} + +TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) { + sp<ANativeWindow> anw(mSTC); + android_native_buffer_t* buf; + EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(16, buf->width); + EXPECT_EQ(8, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); +} + +TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) { + sp<ANativeWindow> anw(mSTC); + android_native_buffer_t* buf; + EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(16, buf->width); + EXPECT_EQ(8, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); + EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, 0)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(1, buf->width); + EXPECT_EQ(1, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); +} + +TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) { + sp<ANativeWindow> anw(mSTC); + android_native_buffer_t* buf; + EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, PIXEL_FORMAT_RGB_565)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(1, buf->width); + EXPECT_EQ(1, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); + EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(16, buf->width); + EXPECT_EQ(8, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); +} + +TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSize) { + sp<ANativeWindow> anw(mSTC); + sp<SurfaceTexture> st(mST); + android_native_buffer_t* buf; + EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf)); + EXPECT_EQ(16, buf->width); + EXPECT_EQ(8, buf->height); + EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf)); +} + +TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeAfterDequeue) { + sp<ANativeWindow> anw(mSTC); + sp<SurfaceTexture> st(mST); + android_native_buffer_t* buf[2]; + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0])); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1])); + EXPECT_NE(buf[0], buf[1]); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0])); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[1])); + EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0])); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1])); + EXPECT_NE(buf[0], buf[1]); + EXPECT_EQ(16, buf[0]->width); + EXPECT_EQ(16, buf[1]->width); + EXPECT_EQ(8, buf[0]->height); + EXPECT_EQ(8, buf[1]->height); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0])); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[1])); +} + +TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) { + sp<ANativeWindow> anw(mSTC); + sp<SurfaceTexture> st(mST); + android_native_buffer_t* buf[2]; + EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0])); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1])); + EXPECT_NE(buf[0], buf[1]); + EXPECT_EQ(16, buf[0]->width); + EXPECT_EQ(16, buf[1]->width); + EXPECT_EQ(8, buf[0]->height); + EXPECT_EQ(8, buf[1]->height); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0])); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[1])); + EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 12, 24, 0)); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0])); + ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1])); + EXPECT_NE(buf[0], buf[1]); + EXPECT_EQ(12, buf[0]->width); + EXPECT_EQ(12, buf[1]->width); + EXPECT_EQ(24, buf[0]->height); + EXPECT_EQ(24, buf[1]->height); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0])); + ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[1])); +} + } diff --git a/libs/surfaceflinger_client/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index fd07479a05..fd07479a05 100644 --- a/libs/surfaceflinger_client/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp diff --git a/libs/surfaceflinger_client/Android.mk b/libs/surfaceflinger_client/Android.mk index 4a0faf06a1..267e3edf44 100644 --- a/libs/surfaceflinger_client/Android.mk +++ b/libs/surfaceflinger_client/Android.mk @@ -1,22 +1,9 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES:= \ - ISurfaceComposer.cpp \ - ISurface.cpp \ - ISurfaceComposerClient.cpp \ - IGraphicBufferAlloc.cpp \ - LayerState.cpp \ - SharedBufferStack.cpp \ - Surface.cpp \ - SurfaceComposerClient.cpp +LOCAL_SRC_FILES:= -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libbinder \ - libhardware \ - libui +LOCAL_SHARED_LIBRARIES := LOCAL_MODULE:= libsurfaceflinger_client diff --git a/libs/surfaceflinger_client/tests/Android.mk b/libs/surfaceflinger_client/tests/Android.mk deleted file mode 100644 index 212b8e7591..0000000000 --- a/libs/surfaceflinger_client/tests/Android.mk +++ /dev/null @@ -1,53 +0,0 @@ -# Build the unit tests. -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -ifneq ($(TARGET_SIMULATOR),true) - -# Build the unit tests. -test_src_files := \ - Surface_test.cpp \ - -shared_libraries := \ - libcutils \ - libutils \ - libbinder \ - libsurfaceflinger_client \ - libstlport \ - -static_libraries := \ - libgtest \ - libgtest_main \ - -c_includes := \ - bionic \ - bionic/libstdc++/include \ - external/gtest/include \ - external/stlport/stlport \ - -module_tags := tests - -$(foreach file,$(test_src_files), \ - $(eval include $(CLEAR_VARS)) \ - $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ - $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ - $(eval LOCAL_C_INCLUDES := $(c_includes)) \ - $(eval LOCAL_SRC_FILES := $(file)) \ - $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ - $(eval LOCAL_MODULE_TAGS := $(module_tags)) \ - $(eval include $(BUILD_EXECUTABLE)) \ -) - -# Build the manual test programs. -include $(call all-subdir-makefiles) - -endif - -# Include subdirectory makefiles -# ============================================================ - -# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework -# team really wants is to build the stuff defined by this makefile. -ifeq (,$(ONE_SHOT_MAKEFILE)) -include $(call first-makefiles-under,$(LOCAL_PATH)) -endif diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk b/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk deleted file mode 100644 index d3dfe04285..0000000000 --- a/libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk +++ /dev/null @@ -1,17 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - SharedBufferStackTest.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libutils \ - libui \ - libsurfaceflinger_client - -LOCAL_MODULE:= test-sharedbufferstack - -LOCAL_MODULE_TAGS := tests - -include $(BUILD_EXECUTABLE) diff --git a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp b/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp deleted file mode 100644 index 7ef59269ba..0000000000 --- a/libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#undef NDEBUG - -#include <assert.h> -#include <cutils/memory.h> -#include <cutils/log.h> -#include <utils/Errors.h> -#include <private/surfaceflinger/SharedBufferStack.h> - -using namespace android; - -void log(const char* prefix, int *b, size_t num); -void test0(SharedBufferServer& s, SharedBufferClient& c, size_t num, int* list); - -// ---------------------------------------------------------------------------- - -int main(int argc, char** argv) -{ - SharedClient client; - sp<SharedBufferServer> ps(new SharedBufferServer(&client, 0, 4, 0)); - SharedBufferServer& s(*ps); - SharedBufferClient c(&client, 0, 4, 0); - - printf("basic test 0\n"); - int list0[4] = {0, 1, 2, 3}; - test0(s, c, 4, list0); - - printf("basic test 1\n"); - int list1[4] = {2, 1, 0, 3}; - test0(s, c, 4, list1); - - int b = c.dequeue(); - c.lock(b); - c.queue(b); - s.retireAndLock(); - - printf("basic test 2\n"); - int list2[4] = {1, 2, 3, 0}; - test0(s, c, 4, list2); - - - printf("resize test\n"); - class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback { - SharedBufferServer& s; - virtual status_t operator()(int bufferCount) const { - return s.resize(bufferCount); - } - public: - SetBufferCountIPC(SharedBufferServer& s) : s(s) { } - } resize(s); - - c.setBufferCount(6, resize); - int list3[6] = {3, 2, 1, 4, 5, 0}; - test0(s, c, 6, list3); - - c.setBufferCount(4, resize); - int list4[4] = {1, 2, 3, 0}; - test0(s, c, 4, list4); - - return 0; -} - -void log(const char* prefix, int *b, size_t num) -{ - printf("%s: ", prefix); - for (size_t i=0 ; i<num ; i++) { - printf("%d ", b[i]); - } - printf("\n"); -} - -// ---------------------------------------------------------------------------- - -void test0( - SharedBufferServer& s, - SharedBufferClient& c, - size_t num, - int* list) -{ - status_t err; - int b[num], u[num], r[num]; - - for (size_t i=0 ; i<num ; i++) { - b[i] = c.dequeue(); - assert(b[i]==list[i]); - } - log("DQ", b, num); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.lock(b[i]); - assert(err==0); - } - log("LK", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.queue(b[i]); - assert(err==0); - } - log(" Q", b, num-1); - - - for (size_t i=0 ; i<num-1 ; i++) { - r[i] = s.retireAndLock(); - assert(r[i]==list[i]); - err = s.unlock(r[i]); - assert(err == 0); - } - log("RT", r, num-1); - - err = c.lock(b[num-1]); - assert(err == 0); - log("LK", b+num-1, 1); - - err = c.queue(b[num-1]); - assert(err == 0); - log(" Q", b+num-1, 1); - - r[num-1] = s.retireAndLock(); - assert(r[num-1]==list[num-1]); - err = s.unlock(r[num-1]); - assert(err == 0); - log("RT", r+num-1, 1); - - // ------------------------------------ - printf("\n"); - - for (size_t i=0 ; i<num ; i++) { - b[i] = c.dequeue(); - assert(b[i]==list[i]); - } - log("DQ", b, num); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.lock(b[i]); - assert(err==0); - } - log("LK", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - u[i] = b[num-2-i]; - } - u[num-1] = b[num-1]; - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.queue(u[i]); - assert(err==0); - } - log(" Q", u, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - r[i] = s.retireAndLock(); - assert(r[i]==u[i]); - err = s.unlock(r[i]); - assert(err == 0); - } - log("RT", r, num-1); - - err = c.lock(b[num-1]); - assert(err == 0); - log("LK", b+num-1, 1); - - err = c.queue(b[num-1]); - assert(err == 0); - log(" Q", b+num-1, 1); - - r[num-1] = s.retireAndLock(); - assert(r[num-1]==list[num-1]); - err = s.unlock(r[num-1]); - assert(err == 0); - log("RT", r+num-1, 1); - - // ------------------------------------ - printf("\n"); - - for (size_t i=0 ; i<num ; i++) { - b[i] = c.dequeue(); - assert(b[i]==u[i]); - } - log("DQ", b, num); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.lock(b[i]); - assert(err==0); - } - log("LK", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.queue(b[i]); - assert(err==0); - } - log(" Q", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - r[i] = s.retireAndLock(); - assert(r[i]==u[i]); - err = s.unlock(r[i]); - assert(err == 0); - } - log("RT", r, num-1); - - err = c.lock(u[num-1]); - assert(err == 0); - log("LK", u+num-1, 1); - - err = c.queue(u[num-1]); - assert(err == 0); - log(" Q", u+num-1, 1); - - r[num-1] = s.retireAndLock(); - assert(r[num-1]==u[num-1]); - err = s.unlock(r[num-1]); - assert(err == 0); - log("RT", r+num-1, 1); - - // ------------------------------------ - printf("\n"); - - b[0] = c.dequeue(); - assert(b[0]==u[0]); - log("DQ", b, 1); - - c.undoDequeue(b[0]); - assert(err == 0); - log("UDQ", b, 1); - - // ------------------------------------ - printf("\n"); - - for (size_t i=0 ; i<num ; i++) { - b[i] = c.dequeue(); - assert(b[i]==u[i]); - } - log("DQ", b, num); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.lock(b[i]); - assert(err==0); - } - log("LK", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - err = c.queue(b[i]); - assert(err==0); - } - log(" Q", b, num-1); - - for (size_t i=0 ; i<num-1 ; i++) { - r[i] = s.retireAndLock(); - assert(r[i]==u[i]); - err = s.unlock(r[i]); - assert(err == 0); - } - log("RT", r, num-1); - - err = c.lock(u[num-1]); - assert(err == 0); - log("LK", u+num-1, 1); - - err = c.queue(u[num-1]); - assert(err == 0); - log(" Q", u+num-1, 1); - - r[num-1] = s.retireAndLock(); - assert(r[num-1]==u[num-1]); - err = s.unlock(r[num-1]); - assert(err == 0); - log("RT", r+num-1, 1); - printf("\n"); -} diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp index e2e698ef7b..bbe579ea83 100644 --- a/libs/ui/Input.cpp +++ b/libs/ui/Input.cpp @@ -7,8 +7,12 @@ //#define LOG_NDEBUG 0 +// Log debug messages about keymap probing. #define DEBUG_PROBE 0 +// Log debug messages about velocity tracking. +#define DEBUG_VELOCITY 0 + #include <stdlib.h> #include <unistd.h> #include <ctype.h> @@ -329,6 +333,27 @@ void PointerCoords::tooManyAxes(int axis) { "cannot contain more than %d axis values.", axis, int(MAX_AXES)); } +bool PointerCoords::operator==(const PointerCoords& other) const { + if (bits != other.bits) { + return false; + } + uint32_t count = __builtin_popcountll(bits); + for (uint32_t i = 0; i < count; i++) { + if (values[i] != other.values[i]) { + return false; + } + } + return true; +} + +void PointerCoords::copyFrom(const PointerCoords& other) { + bits = other.bits; + uint32_t count = __builtin_popcountll(bits); + for (uint32_t i = 0; i < count; i++) { + values[i] = other.values[i]; + } +} + // --- MotionEvent --- @@ -444,6 +469,16 @@ float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, return value; } +ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const { + size_t pointerCount = mPointerIds.size(); + for (size_t i = 0; i < pointerCount; i++) { + if (mPointerIds.itemAt(i) == pointerId) { + return i; + } + } + return -1; +} + void MotionEvent::offsetLocation(float xOffset, float yOffset) { mXOffset += xOffset; mYOffset += yOffset; @@ -634,6 +669,208 @@ bool MotionEvent::isTouchEvent(int32_t source, int32_t action) { } +// --- VelocityTracker --- + +VelocityTracker::VelocityTracker() { + clear(); +} + +void VelocityTracker::clear() { + mIndex = 0; + mMovements[0].idBits.clear(); + mActivePointerId = -1; +} + +void VelocityTracker::clearPointers(BitSet32 idBits) { + BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value); + mMovements[mIndex].idBits = remainingIdBits; + + if (mActivePointerId >= 0 && idBits.hasBit(mActivePointerId)) { + mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1; + } +} + +void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) { + if (++mIndex == HISTORY_SIZE) { + mIndex = 0; + } + + while (idBits.count() > MAX_POINTERS) { + idBits.clearBit(idBits.lastMarkedBit()); + } + + Movement& movement = mMovements[mIndex]; + movement.eventTime = eventTime; + movement.idBits = idBits; + uint32_t count = idBits.count(); + for (uint32_t i = 0; i < count; i++) { + movement.positions[i] = positions[i]; + } + + if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) { + mActivePointerId = count != 0 ? idBits.firstMarkedBit() : -1; + } + +#if DEBUG_VELOCITY + LOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d", + eventTime, idBits.value, mActivePointerId); + for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) { + uint32_t id = iterBits.firstMarkedBit(); + uint32_t index = idBits.getIndexOfBit(id); + iterBits.clearBit(id); + float vx, vy; + bool available = getVelocity(id, &vx, &vy); + if (available) { + LOGD(" %d: position (%0.3f, %0.3f), vx=%0.3f, vy=%0.3f, speed=%0.3f", + id, positions[index].x, positions[index].y, vx, vy, sqrtf(vx * vx + vy * vy)); + } else { + LOG_ASSERT(vx == 0 && vy == 0); + LOGD(" %d: position (%0.3f, %0.3f), velocity not available", + id, positions[index].x, positions[index].y); + } + } +#endif +} + +void VelocityTracker::addMovement(const MotionEvent* event) { + int32_t actionMasked = event->getActionMasked(); + + switch (actionMasked) { + case AMOTION_EVENT_ACTION_DOWN: + // Clear all pointers on down before adding the new movement. + clear(); + break; + case AMOTION_EVENT_ACTION_POINTER_DOWN: { + // Start a new movement trace for a pointer that just went down. + // We do this on down instead of on up because the client may want to query the + // final velocity for a pointer that just went up. + BitSet32 downIdBits; + downIdBits.markBit(event->getActionIndex()); + clearPointers(downIdBits); + break; + } + case AMOTION_EVENT_ACTION_OUTSIDE: + case AMOTION_EVENT_ACTION_CANCEL: + case AMOTION_EVENT_ACTION_SCROLL: + case AMOTION_EVENT_ACTION_UP: + case AMOTION_EVENT_ACTION_POINTER_UP: + // Ignore these actions because they do not convey any new information about + // pointer movement. We also want to preserve the last known velocity of the pointers. + // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position + // of the pointers that went up. ACTION_POINTER_UP does include the new position of + // pointers that remained down but we will also receive an ACTION_MOVE with this + // information if any of them actually moved. Since we don't know how many pointers + // will be going up at once it makes sense to just wait for the following ACTION_MOVE + // before adding the movement. + return; + } + + size_t pointerCount = event->getPointerCount(); + if (pointerCount > MAX_POINTERS) { + pointerCount = MAX_POINTERS; + } + + BitSet32 idBits; + for (size_t i = 0; i < pointerCount; i++) { + idBits.markBit(event->getPointerId(i)); + } + + nsecs_t eventTime; + Position positions[pointerCount]; + + size_t historySize = event->getHistorySize(); + for (size_t h = 0; h < historySize; h++) { + eventTime = event->getHistoricalEventTime(h); + for (size_t i = 0; i < pointerCount; i++) { + positions[i].x = event->getHistoricalX(i, h); + positions[i].y = event->getHistoricalY(i, h); + } + addMovement(eventTime, idBits, positions); + } + + eventTime = event->getEventTime(); + for (size_t i = 0; i < pointerCount; i++) { + positions[i].x = event->getX(i); + positions[i].y = event->getY(i); + } + addMovement(eventTime, idBits, positions); +} + +bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const { + const Movement& newestMovement = mMovements[mIndex]; + if (newestMovement.idBits.hasBit(id)) { + // Find the oldest sample that contains the pointer and that is not older than MAX_AGE. + nsecs_t minTime = newestMovement.eventTime - MAX_AGE; + uint32_t oldestIndex = mIndex; + uint32_t numTouches = 1; + do { + uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1; + const Movement& nextOldestMovement = mMovements[nextOldestIndex]; + if (!nextOldestMovement.idBits.hasBit(id) + || nextOldestMovement.eventTime < minTime) { + break; + } + oldestIndex = nextOldestIndex; + } while (++numTouches < HISTORY_SIZE); + + // Calculate an exponentially weighted moving average of the velocity estimate + // at different points in time measured relative to the oldest sample. + // This is essentially an IIR filter. Newer samples are weighted more heavily + // than older samples. Samples at equal time points are weighted more or less + // equally. + // + // One tricky problem is that the sample data may be poorly conditioned. + // Sometimes samples arrive very close together in time which can cause us to + // overestimate the velocity at that time point. Most samples might be measured + // 16ms apart but some consecutive samples could be only 0.5sm apart because + // the hardware or driver reports them irregularly or in bursts. + float accumVx = 0; + float accumVy = 0; + uint32_t index = oldestIndex; + uint32_t samplesUsed = 0; + const Movement& oldestMovement = mMovements[oldestIndex]; + const Position& oldestPosition = + oldestMovement.positions[oldestMovement.idBits.getIndexOfBit(id)]; + nsecs_t lastDuration = 0; + while (numTouches-- > 1) { + if (++index == HISTORY_SIZE) { + index = 0; + } + const Movement& movement = mMovements[index]; + nsecs_t duration = movement.eventTime - oldestMovement.eventTime; + + // If the duration between samples is small, we may significantly overestimate + // the velocity. Consequently, we impose a minimum duration constraint on the + // samples that we include in the calculation. + if (duration >= MIN_DURATION) { + const Position& position = movement.positions[movement.idBits.getIndexOfBit(id)]; + float scale = 1000000000.0f / duration; // one over time delta in seconds + float vx = (position.x - oldestPosition.x) * scale; + float vy = (position.y - oldestPosition.y) * scale; + + accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration); + accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration); + + lastDuration = duration; + samplesUsed += 1; + } + } + + // Make sure we used at least one sample. + if (samplesUsed != 0) { + *outVx = accumVx; + *outVy = accumVy; + return true; + } + } + + // No data available for this pointer. + *outVx = 0; + *outVy = 0; + return false; +} + + // --- InputDeviceInfo --- InputDeviceInfo::InputDeviceInfo() { diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp index 5c57a76f40..9d1b8b94ec 100644 --- a/libs/ui/InputTransport.cpp +++ b/libs/ui/InputTransport.cpp @@ -406,7 +406,7 @@ status_t InputPublisher::publishMotionEvent( for (size_t i = 0; i < pointerCount; i++) { mSharedMessage->motion.pointerIds[i] = pointerIds[i]; - mSharedMessage->motion.sampleData[0].coords[i] = pointerCoords[i]; + mSharedMessage->motion.sampleData[0].coords[i].copyFrom(pointerCoords[i]); } // Cache essential information about the motion event to ensure that a malicious consumer @@ -475,7 +475,7 @@ status_t InputPublisher::appendMotionSample( mMotionEventSampleDataTail->eventTime = eventTime; for (size_t i = 0; i < mMotionEventPointerCount; i++) { - mMotionEventSampleDataTail->coords[i] = pointerCoords[i]; + mMotionEventSampleDataTail->coords[i].copyFrom(pointerCoords[i]); } mMotionEventSampleDataTail = newTail; diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index e09e755861..6e57d93d8b 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -36,6 +36,7 @@ #include <dirent.h> #include <errno.h> #include <assert.h> +#include <strings.h> using namespace android; @@ -1764,4 +1765,3 @@ int AssetManager::ZipSet::getIndex(const String8& zip) const return mZipPath.size()-1; } - diff --git a/libs/utils/Looper.cpp b/libs/utils/Looper.cpp index 18f858b4b6..d5dd126065 100644 --- a/libs/utils/Looper.cpp +++ b/libs/utils/Looper.cpp @@ -218,14 +218,10 @@ int Looper::pollInner(int timeoutMillis) { // Adjust the timeout based on when the next message is due. if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - if (mNextMessageUptime <= now) { - timeoutMillis = 0; - } else { - uint64_t delay = (mNextMessageUptime - now + 999999LL) / 1000000LL; - if (delay < INT_MAX - && (timeoutMillis < 0 || int(delay) < timeoutMillis)) { - timeoutMillis = int(delay); - } + int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime); + if (messageTimeoutMillis >= 0 + && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) { + timeoutMillis = messageTimeoutMillis; } #if DEBUG_POLL_AND_WAKE LOGD("%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d", @@ -444,12 +440,11 @@ int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outDat return result; } - nsecs_t timeoutNanos = endTime - systemTime(SYSTEM_TIME_MONOTONIC); - if (timeoutNanos <= 0) { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + timeoutMillis = toMillisecondTimeoutDelay(now, endTime); + if (timeoutMillis == 0) { return ALOOPER_POLL_TIMEOUT; } - - timeoutMillis = int(nanoseconds_to_milliseconds(timeoutNanos + 999999LL)); } } } diff --git a/libs/utils/Timers.cpp b/libs/utils/Timers.cpp index 784f035dc0..64a29f5877 100644 --- a/libs/utils/Timers.cpp +++ b/libs/utils/Timers.cpp @@ -26,6 +26,7 @@ #include <sys/time.h> #include <time.h> #include <errno.h> +#include <limits.h> #ifdef HAVE_WIN32_THREADS #include <windows.h> @@ -53,6 +54,23 @@ nsecs_t systemTime(int clock) #endif } +int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime) +{ + int timeoutDelayMillis; + if (timeoutTime > referenceTime) { + uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime); + if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) { + timeoutDelayMillis = -1; + } else { + timeoutDelayMillis = (timeoutDelay + 999999LL) / 1000000LL; + } + } else { + timeoutDelayMillis = 0; + } + return timeoutDelayMillis; +} + + /* * =========================================================================== * DurationTimer |