summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/gui/Android.mk11
-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.cpp7
-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.cpp75
-rw-r--r--libs/gui/SurfaceTextureClient.cpp34
-rw-r--r--libs/gui/tests/Android.mk2
-rw-r--r--libs/gui/tests/SurfaceTextureClient_test.cpp147
-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.mk17
-rw-r--r--libs/surfaceflinger_client/tests/Android.mk53
-rw-r--r--libs/surfaceflinger_client/tests/SharedBufferStack/Android.mk17
-rw-r--r--libs/surfaceflinger_client/tests/SharedBufferStack/SharedBufferStackTest.cpp284
-rw-r--r--libs/ui/Input.cpp237
-rw-r--r--libs/ui/InputTransport.cpp4
-rw-r--r--libs/utils/AssetManager.cpp2
-rw-r--r--libs/utils/Looper.cpp19
-rw-r--r--libs/utils/Timers.cpp18
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