Merge "SF: use cached vsync period"
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index d67ce15..157538e 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -614,7 +614,7 @@
talkWithDriver(false);
}
-int IPCThreadState::setupPolling(int* fd)
+status_t IPCThreadState::setupPolling(int* fd)
{
if (mProcess->mDriverFD < 0) {
return -EBADF;
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 8d51cdc..2bd39a7 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -85,8 +85,8 @@
int64_t clearCallingIdentity();
// Restores PID/UID (not SID)
void restoreCallingIdentity(int64_t token);
-
- int setupPolling(int* fd);
+
+ status_t setupPolling(int* fd);
status_t handlePolledCommands();
void flushCommands();
diff --git a/libs/binder/ndk/include_platform/android/binder_process.h b/libs/binder/ndk/include_platform/android/binder_process.h
index fdefbb4..f408fad 100644
--- a/libs/binder/ndk/include_platform/android/binder_process.h
+++ b/libs/binder/ndk/include_platform/android/binder_process.h
@@ -19,10 +19,15 @@
#include <stdint.h>
#include <sys/cdefs.h>
+#include <android/binder_status.h>
+
__BEGIN_DECLS
/**
* This creates a threadpool for incoming binder transactions if it has not already been created.
+ *
+ * When using this, it is expected that ABinderProcess_setupPolling and
+ * ABinderProcess_handlePolledCommands are not used.
*/
void ABinderProcess_startThreadPool();
/**
@@ -37,4 +42,27 @@
*/
void ABinderProcess_joinThreadPool();
+/**
+ * This gives you an fd to wait on. Whenever data is available on the fd,
+ * ABinderProcess_handlePolledCommands can be called to handle binder queries.
+ * This is expected to be used in a single threaded process which waits on
+ * events from multiple different fds.
+ *
+ * When using this, it is expected ABinderProcess_startThreadPool and
+ * ABinderProcess_joinThreadPool are not used.
+ *
+ * \param fd out param corresponding to the binder domain opened in this
+ * process.
+ * \return STATUS_OK on success
+ */
+__attribute__((weak)) binder_status_t ABinderProcess_setupPolling(int* fd) __INTRODUCED_IN(31);
+
+/**
+ * This will handle all queued binder commands in this process and then return.
+ * It is expected to be called whenever there is data on the fd.
+ *
+ * \return STATUS_OK on success
+ */
+__attribute__((weak)) binder_status_t ABinderProcess_handlePolledCommands() __INTRODUCED_IN(31);
+
__END_DECLS
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 9b5fa26..d435382 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -113,6 +113,8 @@
LIBBINDER_NDK31 { # introduced=31
global:
+ ABinderProcess_handlePolledCommands; # apex
+ ABinderProcess_setupPolling; # apex
AIBinder_getCallingSid; # apex
AIBinder_setRequestingSid; # apex
};
diff --git a/libs/binder/ndk/process.cpp b/libs/binder/ndk/process.cpp
index c89caaf..ac582a4 100644
--- a/libs/binder/ndk/process.cpp
+++ b/libs/binder/ndk/process.cpp
@@ -34,3 +34,11 @@
void ABinderProcess_joinThreadPool() {
IPCThreadState::self()->joinThreadPool();
}
+
+binder_status_t ABinderProcess_setupPolling(int* fd) {
+ return IPCThreadState::self()->setupPolling(fd);
+}
+
+binder_status_t ABinderProcess_handlePolledCommands() {
+ return IPCThreadState::self()->handlePolledCommands();
+}
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index e3fdb4b..9b2fcf0 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -24,6 +24,7 @@
#include <android/binder_process.h>
#include <gtest/gtest.h>
#include <iface/iface.h>
+#include <utils/Looper.h>
// warning: this is assuming that libbinder_ndk is using the same copy
// of libbinder that we are.
@@ -107,19 +108,39 @@
}
};
-int manualService(const char* instance) {
- ABinderProcess_setThreadPoolMaxThreadCount(0);
-
+void manualService(const char* instance) {
// Strong reference to MyFoo kept by service manager.
binder_status_t status = (new MyFoo)->addService(instance);
if (status != STATUS_OK) {
LOG(FATAL) << "Could not register: " << status << " " << instance;
}
+}
+int manualPollingService(const char* instance) {
+ int fd;
+ CHECK(STATUS_OK == ABinderProcess_setupPolling(&fd));
+ manualService(instance);
+ class Handler : public LooperCallback {
+ int handleEvent(int /*fd*/, int /*events*/, void* /*data*/) override {
+ ABinderProcess_handlePolledCommands();
+ return 1; // Continue receiving callbacks.
+ }
+ };
+
+ sp<Looper> looper = Looper::prepare(0 /* opts */);
+ looper->addFd(fd, Looper::POLL_CALLBACK, Looper::EVENT_INPUT, new Handler(), nullptr /*data*/);
+ // normally, would add additional fds
+ while (true) {
+ looper->pollAll(-1 /* timeoutMillis */);
+ }
+ return 1; // should not reach
+}
+int manualThreadPoolService(const char* instance) {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ manualService(instance);
ABinderProcess_joinThreadPool();
-
- return 1; // should not return
+ return 1;
}
// This is too slow
@@ -448,11 +469,11 @@
if (fork() == 0) {
prctl(PR_SET_PDEATHSIG, SIGHUP);
- return manualService(IFoo::kInstanceNameToDieFor);
+ return manualThreadPoolService(IFoo::kInstanceNameToDieFor);
}
if (fork() == 0) {
prctl(PR_SET_PDEATHSIG, SIGHUP);
- return manualService(IFoo::kSomeInstanceName);
+ return manualPollingService(IFoo::kSomeInstanceName);
}
if (fork() == 0) {
prctl(PR_SET_PDEATHSIG, SIGHUP);
diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp
index 74fb019..a27c09f 100644
--- a/opengl/libs/EGL/BlobCache.cpp
+++ b/opengl/libs/EGL/BlobCache.cpp
@@ -78,12 +78,12 @@
return;
}
- std::shared_ptr<Blob> dummyKey(new Blob(key, keySize, false));
- CacheEntry dummyEntry(dummyKey, nullptr);
+ std::shared_ptr<Blob> cacheKey(new Blob(key, keySize, false));
+ CacheEntry cacheEntry(cacheKey, nullptr);
while (true) {
- auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), dummyEntry);
- if (index == mCacheEntries.end() || dummyEntry < *index) {
+ auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), cacheEntry);
+ if (index == mCacheEntries.end() || cacheEntry < *index) {
// Create a new cache entry.
std::shared_ptr<Blob> keyBlob(new Blob(key, keySize, true));
std::shared_ptr<Blob> valueBlob(new Blob(value, valueSize, true));
@@ -138,10 +138,10 @@
keySize, mMaxKeySize);
return 0;
}
- std::shared_ptr<Blob> dummyKey(new Blob(key, keySize, false));
- CacheEntry dummyEntry(dummyKey, nullptr);
- auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), dummyEntry);
- if (index == mCacheEntries.end() || dummyEntry < *index) {
+ std::shared_ptr<Blob> cacheKey(new Blob(key, keySize, false));
+ CacheEntry cacheEntry(cacheKey, nullptr);
+ auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), cacheEntry);
+ if (index == mCacheEntries.end() || cacheEntry < *index) {
ALOGV("get: no cache entry found for key of size %zu", keySize);
return 0;
}
diff --git a/opengl/libs/EGL/FileBlobCache.cpp b/opengl/libs/EGL/FileBlobCache.cpp
index 3284778..751f3be 100644
--- a/opengl/libs/EGL/FileBlobCache.cpp
+++ b/opengl/libs/EGL/FileBlobCache.cpp
@@ -70,7 +70,7 @@
return;
}
- // Sanity check the size before trying to mmap it.
+ // Check the size before trying to mmap it.
size_t fileSize = statBuf.st_size;
if (fileSize > mMaxTotalSize * 2) {
ALOGE("cache file is too large: %#" PRIx64,
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 510226d..bbd786d 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -138,7 +138,7 @@
};
EXPECT_TRUE(eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs));
- struct DummyConsumer : public BnConsumerListener {
+ struct MockConsumer : public BnConsumerListener {
void onFrameAvailable(const BufferItem& /* item */) override {}
void onBuffersReleased() override {}
void onSidebandStreamChanged() override {}
@@ -148,7 +148,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
- consumer->consumerConnect(new DummyConsumer, false);
+ consumer->consumerConnect(new MockConsumer, false);
sp<Surface> mSTC = new Surface(producer);
sp<ANativeWindow> mANW = mSTC;
@@ -258,7 +258,7 @@
EXPECT_EQ(components[2], 8);
EXPECT_EQ(components[3], 8);
- struct DummyConsumer : public BnConsumerListener {
+ struct MockConsumer : public BnConsumerListener {
void onFrameAvailable(const BufferItem& /* item */) override {}
void onBuffersReleased() override {}
void onSidebandStreamChanged() override {}
@@ -268,7 +268,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
- consumer->consumerConnect(new DummyConsumer, false);
+ consumer->consumerConnect(new MockConsumer, false);
sp<Surface> mSTC = new Surface(producer);
sp<ANativeWindow> mANW = mSTC;
EGLint winAttrs[] = {
@@ -306,7 +306,7 @@
get8BitConfig(config);
- struct DummyConsumer : public BnConsumerListener {
+ struct MockConsumer : public BnConsumerListener {
void onFrameAvailable(const BufferItem& /* item */) override {}
void onBuffersReleased() override {}
void onSidebandStreamChanged() override {}
@@ -316,7 +316,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
- consumer->consumerConnect(new DummyConsumer, false);
+ consumer->consumerConnect(new MockConsumer, false);
sp<Surface> mSTC = new Surface(producer);
sp<ANativeWindow> mANW = mSTC;
EGLint winAttrs[] = {
@@ -398,7 +398,7 @@
EXPECT_EQ(components[2], 10);
EXPECT_EQ(components[3], 2);
- struct DummyConsumer : public BnConsumerListener {
+ struct MockConsumer : public BnConsumerListener {
void onFrameAvailable(const BufferItem& /* item */) override {}
void onBuffersReleased() override {}
void onSidebandStreamChanged() override {}
@@ -408,7 +408,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
- consumer->consumerConnect(new DummyConsumer, false);
+ consumer->consumerConnect(new MockConsumer, false);
sp<Surface> mSTC = new Surface(producer);
sp<ANativeWindow> mANW = mSTC;
EGLint winAttrs[] = {
@@ -570,7 +570,7 @@
ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
- struct DummyConsumer : public BnConsumerListener {
+ struct MockConsumer : public BnConsumerListener {
void onFrameAvailable(const BufferItem& /* item */) override {}
void onBuffersReleased() override {}
void onSidebandStreamChanged() override {}
@@ -580,7 +580,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
- consumer->consumerConnect(new DummyConsumer, false);
+ consumer->consumerConnect(new MockConsumer, false);
sp<Surface> mSTC = new Surface(producer);
sp<ANativeWindow> mANW = mSTC;
@@ -622,7 +622,7 @@
ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
- struct DummyConsumer : public BnConsumerListener {
+ struct MockConsumer : public BnConsumerListener {
void onFrameAvailable(const BufferItem& /* item */) override {}
void onBuffersReleased() override {}
void onSidebandStreamChanged() override {}
@@ -632,7 +632,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
- consumer->consumerConnect(new DummyConsumer, false);
+ consumer->consumerConnect(new MockConsumer, false);
sp<Surface> mSTC = new Surface(producer);
sp<ANativeWindow> mANW = mSTC;
std::vector<EGLint> winAttrs;
@@ -705,7 +705,7 @@
EXPECT_GE(components[2], 16);
EXPECT_GE(components[3], 16);
- struct DummyConsumer : public BnConsumerListener {
+ struct MockConsumer : public BnConsumerListener {
void onFrameAvailable(const BufferItem& /* item */) override {}
void onBuffersReleased() override {}
void onSidebandStreamChanged() override {}
@@ -714,7 +714,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
- consumer->consumerConnect(new DummyConsumer, false);
+ consumer->consumerConnect(new MockConsumer, false);
sp<Surface> mSTC = new Surface(producer);
sp<ANativeWindow> mANW = mSTC;
@@ -734,7 +734,7 @@
ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_KHR_no_config_context"));
- struct DummyConsumer : public BnConsumerListener {
+ struct MockConsumer : public BnConsumerListener {
void onFrameAvailable(const BufferItem& /* item */) override {}
void onBuffersReleased() override {}
void onSidebandStreamChanged() override {}
@@ -809,7 +809,7 @@
EXPECT_EQ(components[2], 10);
EXPECT_EQ(components[3], 2);
- struct DummyConsumer : public BnConsumerListener {
+ struct MockConsumer : public BnConsumerListener {
void onFrameAvailable(const BufferItem& /* item */) override {}
void onBuffersReleased() override {}
void onSidebandStreamChanged() override {}
@@ -819,7 +819,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
- consumer->consumerConnect(new DummyConsumer, false);
+ consumer->consumerConnect(new MockConsumer, false);
sp<Surface> mSTC = new Surface(producer);
sp<ANativeWindow> mANW = mSTC;
@@ -835,7 +835,7 @@
ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
- struct DummyConsumer : public BnConsumerListener {
+ struct MockConsumer : public BnConsumerListener {
void onFrameAvailable(const BufferItem& /* item */) override {}
void onBuffersReleased() override {}
void onSidebandStreamChanged() override {}
@@ -845,7 +845,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
- consumer->consumerConnect(new DummyConsumer, false);
+ consumer->consumerConnect(new MockConsumer, false);
sp<Surface> mSTC = new Surface(producer);
sp<ANativeWindow> mANW = mSTC;
@@ -882,7 +882,7 @@
ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
ASSERT_EQ(1, numConfigs);
- struct DummyConsumer : public BnConsumerListener {
+ struct MockConsumer : public BnConsumerListener {
void onFrameAvailable(const BufferItem& /* item */) override {}
void onBuffersReleased() override {}
void onSidebandStreamChanged() override {}
@@ -892,7 +892,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
- consumer->consumerConnect(new DummyConsumer, false);
+ consumer->consumerConnect(new MockConsumer, false);
sp<Surface> mSTC = new Surface(producer);
sp<ANativeWindow> mANW = mSTC;
@@ -913,7 +913,7 @@
ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
- struct DummyConsumer : public BnConsumerListener {
+ struct MockConsumer : public BnConsumerListener {
void onFrameAvailable(const BufferItem& /* item */) override {}
void onBuffersReleased() override {}
void onSidebandStreamChanged() override {}
@@ -923,7 +923,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
- consumer->consumerConnect(new DummyConsumer, false);
+ consumer->consumerConnect(new MockConsumer, false);
sp<Surface> mSTC = new Surface(producer);
sp<ANativeWindow> mANW = mSTC;
@@ -953,7 +953,7 @@
ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
- struct DummyConsumer : public BnConsumerListener {
+ struct MockConsumer : public BnConsumerListener {
void onFrameAvailable(const BufferItem& /* item */) override {}
void onBuffersReleased() override {}
void onSidebandStreamChanged() override {}
@@ -963,7 +963,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
- consumer->consumerConnect(new DummyConsumer, false);
+ consumer->consumerConnect(new MockConsumer, false);
sp<Surface> mSTC = new Surface(producer);
sp<ANativeWindow> mANW = mSTC;
diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen
index 9efd38f..7fd9c3a 100755
--- a/opengl/tools/glgen/gen
+++ b/opengl/tools/glgen/gen
@@ -17,7 +17,7 @@
mkdir out
-# Create dummy Java files for Android APIs that are used by the code we generate.
+# Create stub Java files for Android APIs that are used by the code we generate.
# This allows us to test the generated code without building the rest of Android.
mkdir -p out/javax/microedition/khronos/opengles
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index d1f20c7..9118805 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -82,6 +82,10 @@
} else {
info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f);
info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f);
+ info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, mSource, -1.0f, 1.0f, 0.0f, mXScale,
+ 0.0f);
+ info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale,
+ 0.0f);
}
info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
@@ -341,6 +345,8 @@
} else {
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
+ pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
+ pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
displayId = ADISPLAY_ID_NONE;
}
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 15d5288..afbec99 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -142,12 +142,14 @@
hoveringIdBits.clear();
touchingIdBits.clear();
canceledIdBits.clear();
+ validIdBits.clear();
}
void CookedPointerData::copyFrom(const CookedPointerData& other) {
pointerCount = other.pointerCount;
hoveringIdBits = other.hoveringIdBits;
touchingIdBits = other.touchingIdBits;
+ validIdBits = other.validIdBits;
for (uint32_t i = 0; i < pointerCount; i++) {
pointerProperties[i].copyFrom(other.pointerProperties[i]);
@@ -288,12 +290,14 @@
const PointerProperties& pointerProperties =
mLastCookedState.cookedPointerData.pointerProperties[i];
const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i];
- dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, "
- "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, "
- "toolMinor=%0.3f, "
+ dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, dx=%0.3f, dy=%0.3f, "
+ "pressure=%0.3f, touchMajor=%0.3f, touchMinor=%0.3f, "
+ "toolMajor=%0.3f, toolMinor=%0.3f, "
"orientation=%0.3f, tilt=%0.3f, distance=%0.3f, "
"toolType=%d, isHovering=%s\n",
i, pointerProperties.id, pointerCoords.getX(), pointerCoords.getY(),
+ pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
+ pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y),
pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
@@ -379,6 +383,7 @@
if (!changes ||
(changes &
(InputReaderConfiguration::CHANGE_DISPLAY_INFO |
+ InputReaderConfiguration::CHANGE_POINTER_CAPTURE |
InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT |
InputReaderConfiguration::CHANGE_SHOW_TOUCHES |
InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) {
@@ -562,7 +567,7 @@
* 4. Otherwise, use a non-display viewport.
*/
std::optional<DisplayViewport> TouchInputMapper::findViewport() {
- if (mParameters.hasAssociatedDisplay) {
+ if (mParameters.hasAssociatedDisplay && mDeviceMode != DeviceMode::UNSCALED) {
const std::optional<uint8_t> displayPort = getDeviceContext().getAssociatedDisplayPort();
if (displayPort) {
// Find the viewport that contains the same port
@@ -620,7 +625,7 @@
// Determine device mode.
if (mParameters.deviceType == Parameters::DeviceType::POINTER &&
- mConfig.pointerGesturesEnabled) {
+ mConfig.pointerGesturesEnabled && !mConfig.pointerCapture) {
mSource = AINPUT_SOURCE_MOUSE;
mDeviceMode = DeviceMode::POINTER;
if (hasStylus()) {
@@ -2269,15 +2274,26 @@
out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor);
}
+ // Write output relative fieldis if applicable.
+ uint32_t id = in.id;
+ if (mSource == AINPUT_SOURCE_TOUCHPAD &&
+ mLastCookedState.cookedPointerData.hasPointerCoordsForId(id)) {
+ const PointerCoords& p = mLastCookedState.cookedPointerData.pointerCoordsForId(id);
+ float dx = xTransformed - p.getAxisValue(AMOTION_EVENT_AXIS_X);
+ float dy = yTransformed - p.getAxisValue(AMOTION_EVENT_AXIS_Y);
+ out.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, dx);
+ out.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, dy);
+ }
+
// Write output properties.
PointerProperties& properties = mCurrentCookedState.cookedPointerData.pointerProperties[i];
- uint32_t id = in.id;
properties.clear();
properties.id = id;
properties.toolType = in.toolType;
- // Write id index.
+ // Write id index and mark id as valid.
mCurrentCookedState.cookedPointerData.idToIndex[id] = i;
+ mCurrentCookedState.cookedPointerData.validIdBits.markBit(id);
}
}
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 94486a6..df6581d 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -103,7 +103,7 @@
uint32_t pointerCount;
PointerProperties pointerProperties[MAX_POINTERS];
PointerCoords pointerCoords[MAX_POINTERS];
- BitSet32 hoveringIdBits, touchingIdBits, canceledIdBits;
+ BitSet32 hoveringIdBits, touchingIdBits, canceledIdBits, validIdBits;
uint32_t idToIndex[MAX_POINTER_ID + 1];
CookedPointerData();
@@ -129,6 +129,8 @@
inline bool isTouching(uint32_t pointerIndex) const {
return touchingIdBits.hasBit(pointerProperties[pointerIndex].id);
}
+
+ inline bool hasPointerCoordsForId(uint32_t id) const { return validIdBits.hasBit(id); }
};
class TouchInputMapper : public InputMapper {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 21dd3c7..232045b 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -297,6 +297,8 @@
mConfig.defaultPointerDisplayId = pointerDisplayId;
}
+ float getPointerGestureMovementSpeedRatio() { return mConfig.pointerGestureMovementSpeedRatio; }
+
private:
DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height,
int32_t orientation, const std::string& uniqueId, std::optional<uint8_t> physicalPort,
@@ -7533,4 +7535,207 @@
constexpr int32_t yExpected = (x + 1) - DISPLAY_WIDTH / 4;
processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected);
}
+
+TEST_F(MultiTouchInputMapperTest, Process_TouchpadCapture) {
+ // we need a pointer controller for mouse mode of touchpad (start pointer at 0,0)
+ std::shared_ptr<FakePointerController> fakePointerController =
+ std::make_shared<FakePointerController>();
+ fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
+ fakePointerController->setPosition(0, 0);
+ fakePointerController->setButtonState(0);
+
+ // prepare device and capture
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION | ID | SLOT);
+ mFakeEventHub->addKey(EVENTHUB_ID, BTN_LEFT, 0, AKEYCODE_UNKNOWN, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0);
+ mFakePolicy->setPointerCapture(true);
+ mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+ // captured touchpad should be a touchpad source
+ NotifyDeviceResetArgs resetArgs;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+ ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources());
+
+ // run captured pointer tests - note that this is unscaled, so input listener events should be
+ // identical to what the hardware sends (accounting for any
+ // calibration).
+ // FINGER 0 DOWN
+ processId(mapper, 1);
+ processPosition(mapper, 100 + RAW_X_MIN, 100 + RAW_Y_MIN);
+ processKey(mapper, BTN_TOUCH, 1);
+ processSync(mapper);
+
+ // expect coord[0] to contain initial location of touch 0
+ NotifyMotionArgs args;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
+ ASSERT_EQ(1U, args.pointerCount);
+ ASSERT_EQ(0, args.pointerProperties[0].id);
+ ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, args.source);
+ ASSERT_NO_FATAL_FAILURE(
+ assertPointerCoords(args.pointerCoords[0], 100, 100, 1, 0, 0, 0, 0, 0, 0, 0));
+
+ // FINGER 1 DOWN
+ processSlot(mapper, 1);
+ processId(mapper, 2);
+ processPosition(mapper, 560 + RAW_X_MIN, 154 + RAW_Y_MIN);
+ processSync(mapper);
+
+ // expect coord[0] to contain previous location, coord[1] to contain new touch 1 location
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | 0x0100, args.action);
+ ASSERT_EQ(2U, args.pointerCount);
+ ASSERT_EQ(0, args.pointerProperties[0].id);
+ ASSERT_EQ(1, args.pointerProperties[1].id);
+ ASSERT_NO_FATAL_FAILURE(
+ assertPointerCoords(args.pointerCoords[0], 100, 100, 1, 0, 0, 0, 0, 0, 0, 0));
+ ASSERT_NO_FATAL_FAILURE(
+ assertPointerCoords(args.pointerCoords[1], 560, 154, 1, 0, 0, 0, 0, 0, 0, 0));
+
+ // FINGER 1 MOVE
+ processPosition(mapper, 540 + RAW_X_MIN, 690 + RAW_Y_MIN);
+ processSync(mapper);
+
+ // expect coord[0] to contain previous location, coord[1] to contain new touch 1 location
+ // from move
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+ ASSERT_NO_FATAL_FAILURE(
+ assertPointerCoords(args.pointerCoords[0], 100, 100, 1, 0, 0, 0, 0, 0, 0, 0));
+ ASSERT_NO_FATAL_FAILURE(
+ assertPointerCoords(args.pointerCoords[1], 540, 690, 1, 0, 0, 0, 0, 0, 0, 0));
+
+ // FINGER 0 MOVE
+ processSlot(mapper, 0);
+ processPosition(mapper, 50 + RAW_X_MIN, 800 + RAW_Y_MIN);
+ processSync(mapper);
+
+ // expect coord[0] to contain new touch 0 location, coord[1] to contain previous location
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+ ASSERT_NO_FATAL_FAILURE(
+ assertPointerCoords(args.pointerCoords[0], 50, 800, 1, 0, 0, 0, 0, 0, 0, 0));
+ ASSERT_NO_FATAL_FAILURE(
+ assertPointerCoords(args.pointerCoords[1], 540, 690, 1, 0, 0, 0, 0, 0, 0, 0));
+
+ // BUTTON DOWN
+ processKey(mapper, BTN_LEFT, 1);
+ processSync(mapper);
+
+ // touchinputmapper design sends a move before button press
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, args.action);
+
+ // BUTTON UP
+ processKey(mapper, BTN_LEFT, 0);
+ processSync(mapper);
+
+ // touchinputmapper design sends a move after button release
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, args.action);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+
+ // FINGER 0 UP
+ processId(mapper, -1);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | 0x0000, args.action);
+
+ // FINGER 1 MOVE
+ processSlot(mapper, 1);
+ processPosition(mapper, 320 + RAW_X_MIN, 900 + RAW_Y_MIN);
+ processSync(mapper);
+
+ // expect coord[0] to contain new location of touch 1, and properties[0].id to contain 1
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+ ASSERT_EQ(1U, args.pointerCount);
+ ASSERT_EQ(1, args.pointerProperties[0].id);
+ ASSERT_NO_FATAL_FAILURE(
+ assertPointerCoords(args.pointerCoords[0], 320, 900, 1, 0, 0, 0, 0, 0, 0, 0));
+
+ // FINGER 1 UP
+ processId(mapper, -1);
+ processKey(mapper, BTN_TOUCH, 0);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action);
+
+ // non captured touchpad should be a mouse source
+ mFakePolicy->setPointerCapture(false);
+ configureDevice(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources());
+}
+
+TEST_F(MultiTouchInputMapperTest, Process_UnCapturedTouchpadPointer) {
+ std::shared_ptr<FakePointerController> fakePointerController =
+ std::make_shared<FakePointerController>();
+ fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
+ fakePointerController->setPosition(0, 0);
+ fakePointerController->setButtonState(0);
+
+ // prepare device and capture
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION | ID | SLOT);
+ mFakeEventHub->addKey(EVENTHUB_ID, BTN_LEFT, 0, AKEYCODE_UNKNOWN, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0);
+ mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+ // run uncaptured pointer tests - pushes out generic events
+ // FINGER 0 DOWN
+ processId(mapper, 3);
+ processPosition(mapper, 100, 100);
+ processKey(mapper, BTN_TOUCH, 1);
+ processSync(mapper);
+
+ // start at (100,100), cursor should be at (0,0) * scale
+ NotifyMotionArgs args;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
+ ASSERT_NO_FATAL_FAILURE(
+ assertPointerCoords(args.pointerCoords[0], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+
+ // FINGER 0 MOVE
+ processPosition(mapper, 200, 200);
+ processSync(mapper);
+
+ // compute scaling to help with touch position checking
+ float rawDiagonal = hypotf(RAW_X_MAX - RAW_X_MIN, RAW_Y_MAX - RAW_Y_MIN);
+ float displayDiagonal = hypotf(DISPLAY_WIDTH, DISPLAY_HEIGHT);
+ float scale =
+ mFakePolicy->getPointerGestureMovementSpeedRatio() * displayDiagonal / rawDiagonal;
+
+ // translate from (100,100) -> (200,200), cursor should have changed to (100,100) * scale)
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
+ ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 100 * scale, 100 * scale, 0,
+ 0, 0, 0, 0, 0, 0, 0));
+}
+
+TEST_F(MultiTouchInputMapperTest, WhenCapturedAndNotCaptured_GetSources) {
+ std::shared_ptr<FakePointerController> fakePointerController =
+ std::make_shared<FakePointerController>();
+
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION | ID | SLOT);
+ mFakeEventHub->addKey(EVENTHUB_ID, BTN_LEFT, 0, AKEYCODE_UNKNOWN, 0);
+ mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
+ mFakePolicy->setPointerCapture(false);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+ // uncaptured touchpad should be a pointer device
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources());
+
+ // captured touchpad should be a touchpad device
+ mFakePolicy->setPointerCapture(true);
+ configureDevice(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+ ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources());
+}
+
} // namespace android