Snap for 12385180 from 322fb3b70d8151b984ed98b1909b9e0bd59e7601 to 24Q4-release
Change-Id: I082f60ec03cd648696bbca0095ec4cacddcff69c
diff --git a/include/input/Resampler.h b/include/input/Resampler.h
index 2892137..67d92bd 100644
--- a/include/input/Resampler.h
+++ b/include/input/Resampler.h
@@ -35,9 +35,9 @@
virtual ~Resampler() = default;
/**
- * Tries to resample motionEvent at resampleTime. The provided resampleTime must be greater than
+ * Tries to resample motionEvent at frameTime. The provided frameTime must be greater than
* the latest sample time of motionEvent. It is not guaranteed that resampling occurs at
- * resampleTime. Interpolation may occur is futureSample is available. Otherwise, motionEvent
+ * frameTime. Interpolation may occur is futureSample is available. Otherwise, motionEvent
* may be resampled by another method, or not resampled at all. Furthermore, it is the
* implementer's responsibility to guarantee the following:
* - If resampling occurs, a single additional sample should be added to motionEvent. That is,
@@ -45,15 +45,14 @@
* samples by the end of the resampling. No other field of motionEvent should be modified.
* - If resampling does not occur, then motionEvent must not be modified in any way.
*/
- virtual void resampleMotionEvent(std::chrono::nanoseconds resampleTime,
- MotionEvent& motionEvent,
+ virtual void resampleMotionEvent(std::chrono::nanoseconds frameTime, MotionEvent& motionEvent,
const InputMessage* futureSample) = 0;
};
class LegacyResampler final : public Resampler {
public:
/**
- * Tries to resample `motionEvent` at `resampleTime` by adding a resampled sample at the end of
+ * Tries to resample `motionEvent` at `frameTime` by adding a resampled sample at the end of
* `motionEvent` with eventTime equal to `resampleTime` and pointer coordinates determined by
* linear interpolation or linear extrapolation. An earlier `resampleTime` will be used if
* extrapolation takes place and `resampleTime` is too far in the future. If `futureSample` is
@@ -61,7 +60,7 @@
* data, LegacyResampler will extrapolate. Otherwise, no resampling takes place and
* `motionEvent` is unmodified.
*/
- void resampleMotionEvent(std::chrono::nanoseconds resampleTime, MotionEvent& motionEvent,
+ void resampleMotionEvent(std::chrono::nanoseconds frameTime, MotionEvent& motionEvent,
const InputMessage* futureSample) override;
private:
diff --git a/libs/binder/tests/binderCacheUnitTest.cpp b/libs/binder/tests/binderCacheUnitTest.cpp
index 92dab19..482d197 100644
--- a/libs/binder/tests/binderCacheUnitTest.cpp
+++ b/libs/binder/tests/binderCacheUnitTest.cpp
@@ -137,9 +137,9 @@
ASSERT_EQ(binder1, result);
// Kill the server, this should remove from cache.
- foo.killServer(binder1);
pid_t pid;
ASSERT_EQ(OK, binder1->getDebugPid(&pid));
+ foo.killServer(binder1);
system(("kill -9 " + std::to_string(pid)).c_str());
sp<IBinder> binder2 = sp<BBinder>::make();
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 94998e5..c65eafa 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -1266,6 +1266,11 @@
mTransactionHangCallback = std::move(callback);
}
+void BLASTBufferQueue::setApplyToken(sp<IBinder> applyToken) {
+ std::lock_guard _lock{mMutex};
+ mApplyToken = std::move(applyToken);
+}
+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader(
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 868dbd0..ba58a15 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -143,7 +143,7 @@
* indicates the reason for the hang.
*/
void setTransactionHangCallback(std::function<void(const std::string&)> callback);
-
+ void setApplyToken(sp<IBinder>);
virtual ~BLASTBufferQueue();
void onFirstRef() override;
@@ -272,7 +272,7 @@
// Queues up transactions using this token in SurfaceFlinger. This prevents queued up
// transactions from other parts of the client from blocking this transaction.
- const sp<IBinder> mApplyToken GUARDED_BY(mMutex) = sp<BBinder>::make();
+ sp<IBinder> mApplyToken GUARDED_BY(mMutex) = sp<BBinder>::make();
// Guards access to mDequeueTimestamps since we cannot hold to mMutex in onFrameDequeued or
// we will deadlock.
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index eb2a61d..53f4a36 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -186,6 +186,10 @@
mBlastBufferQueueAdapter->mergeWithNextTransaction(merge, frameNumber);
}
+ void setApplyToken(sp<IBinder> applyToken) {
+ mBlastBufferQueueAdapter->setApplyToken(std::move(applyToken));
+ }
+
private:
sp<TestBLASTBufferQueue> mBlastBufferQueueAdapter;
};
@@ -511,6 +515,69 @@
adapter.waitForCallbacks();
}
+class WaitForCommittedCallback {
+public:
+ WaitForCommittedCallback() = default;
+ ~WaitForCommittedCallback() = default;
+
+ void wait() {
+ std::unique_lock lock(mMutex);
+ cv.wait(lock, [this] { return mCallbackReceived; });
+ }
+
+ void notify() {
+ std::unique_lock lock(mMutex);
+ mCallbackReceived = true;
+ cv.notify_one();
+ mCallbackReceivedTimeStamp = std::chrono::system_clock::now();
+ }
+ auto getCallback() {
+ return [this](void* /* unused context */, nsecs_t /* latchTime */,
+ const sp<Fence>& /* presentFence */,
+ const std::vector<SurfaceControlStats>& /* stats */) { notify(); };
+ }
+ std::chrono::time_point<std::chrono::system_clock> mCallbackReceivedTimeStamp;
+
+private:
+ std::mutex mMutex;
+ std::condition_variable cv;
+ bool mCallbackReceived = false;
+};
+
+TEST_F(BLASTBufferQueueTest, setApplyToken) {
+ sp<IBinder> applyToken = sp<BBinder>::make();
+ WaitForCommittedCallback firstTransaction;
+ WaitForCommittedCallback secondTransaction;
+ {
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ adapter.setApplyToken(applyToken);
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+
+ Transaction t;
+ t.addTransactionCommittedCallback(firstTransaction.getCallback(), nullptr);
+ adapter.mergeWithNextTransaction(&t, 1);
+ queueBuffer(igbProducer, 127, 127, 127,
+ /*presentTimeDelay*/ std::chrono::nanoseconds(500ms).count());
+ }
+ {
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ adapter.setApplyToken(applyToken);
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+
+ Transaction t;
+ t.addTransactionCommittedCallback(secondTransaction.getCallback(), nullptr);
+ adapter.mergeWithNextTransaction(&t, 1);
+ queueBuffer(igbProducer, 127, 127, 127, /*presentTimeDelay*/ 0);
+ }
+
+ firstTransaction.wait();
+ secondTransaction.wait();
+ EXPECT_GT(secondTransaction.mCallbackReceivedTimeStamp,
+ firstTransaction.mCallbackReceivedTimeStamp);
+}
+
TEST_F(BLASTBufferQueueTest, SetCrop_Item) {
uint8_t r = 255;
uint8_t g = 0;
diff --git a/libs/input/Resampler.cpp b/libs/input/Resampler.cpp
index c663649..b535ff4 100644
--- a/libs/input/Resampler.cpp
+++ b/libs/input/Resampler.cpp
@@ -241,13 +241,15 @@
motionEvent.getId());
}
-void LegacyResampler::resampleMotionEvent(nanoseconds resampleTime, MotionEvent& motionEvent,
+void LegacyResampler::resampleMotionEvent(nanoseconds frameTime, MotionEvent& motionEvent,
const InputMessage* futureSample) {
if (mPreviousDeviceId && *mPreviousDeviceId != motionEvent.getDeviceId()) {
mLatestSamples.clear();
}
mPreviousDeviceId = motionEvent.getDeviceId();
+ const nanoseconds resampleTime = frameTime - RESAMPLE_LATENCY;
+
updateLatestSamples(motionEvent);
const std::optional<Sample> sample = (futureSample != nullptr)
diff --git a/libs/input/tests/Resampler_test.cpp b/libs/input/tests/Resampler_test.cpp
index 7ae9a28..26dee39 100644
--- a/libs/input/tests/Resampler_test.cpp
+++ b/libs/input/tests/Resampler_test.cpp
@@ -120,6 +120,47 @@
} // namespace
+/**
+ * The testing setup assumes an input rate of 200 Hz and a display rate of 60 Hz. This implies that
+ * input events are received every 5 milliseconds, while the display consumes batched events every
+ * ~16 milliseconds. The resampler's RESAMPLE_LATENCY constant determines the resample time, which
+ * is calculated as frameTime - RESAMPLE_LATENCY. resampleTime specifies the time used for
+ * resampling. For example, if the desired frame time consumption is ~16 milliseconds, the resample
+ * time would be ~11 milliseconds. Consequenly, the last added sample to the motion event has an
+ * event time of ~11 milliseconds. Note that there are specific scenarios where resampleMotionEvent
+ * is not called with a multiple of ~16 milliseconds. These cases are primarily for data addition
+ * or to test other functionalities of the resampler.
+ *
+ * Coordinates are calculated using linear interpolation (lerp) based on the last two available
+ * samples. Linear interpolation is defined as (a + alpha*(b - a)). Let t_b and t_a be the
+ * timestamps of samples a and b, respectively. The interpolation factor alpha is calculated as
+ * (resampleTime - t_a) / (t_b - t_a). The value of alpha determines whether the resampled
+ * coordinates are interpolated or extrapolated. If alpha falls within the semi-closed interval [0,
+ * 1), the coordinates are interpolated. If alpha is greater than or equal to 1, the coordinates are
+ * extrapolated.
+ *
+ * The timeline below depics an interpolation scenario
+ * -----------------------------------|---------|---------|---------|----------
+ * 10ms 11ms 15ms 16ms
+ * MOVE | MOVE |
+ * resampleTime frameTime
+ * Based on the timeline alpha is (11 - 10)/(15 - 10) = 1/5. Thus, coordinates are interpolated.
+ *
+ * The following timeline portrays an extrapolation scenario
+ * -------------------------|---------|---------|-------------------|----------
+ * 5ms 10ms 11ms 16ms
+ * MOVE MOVE | |
+ * resampleTime frameTime
+ * Likewise, alpha = (11 - 5)/(10 - 5) = 6/5. Hence, coordinates are extrapolated.
+ *
+ * If a motion event was resampled, the tests will check that the following conditions are satisfied
+ * to guarantee resampling correctness:
+ * - The motion event metadata must not change.
+ * - The number of samples in the motion event must only increment by 1.
+ * - The resampled values must be at the end of motion event coordinates.
+ * - The rasamples values must be near the hand calculations.
+ * - The resampled time must be the most recent one in motion event.
+ */
class ResamplerTest : public testing::Test {
protected:
ResamplerTest() : mResampler(std::make_unique<LegacyResampler>()) {}
@@ -225,7 +266,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample);
+ mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
EXPECT_EQ(motionEvent.getTouchMajor(0), TOUCH_MAJOR_VALUE);
@@ -243,7 +284,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(11ms, motionEvent, /*futureSample=*/nullptr);
+ mResampler->resampleMotionEvent(16ms, motionEvent, /*futureSample=*/nullptr);
assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
}
@@ -270,23 +311,6 @@
assertMotionEventIsNotResampled(originalMotionEvent, motionFromSecondDevice);
}
-// Increments of 16 ms for display refresh rate
-// Increments of 6 ms for input frequency
-// Resampling latency is known to be 5 ms
-// Therefore, first resampling time will be 11 ms
-
-/**
- * Timeline
- * ----+----------------------+---------+---------+---------+----------
- * 0ms 10ms 11ms 15ms 16ms
- * DOWN MOVE | MSG |
- * resample frame
- * Resampling occurs at 11ms. It is possible to interpolate because there is a sample available
- * after the resample time. It is assumed that the InputMessage frequency is 100Hz, and the frame
- * frequency is 60Hz. This means the time between InputMessage samples is 10ms, and the time between
- * frames is ~16ms. Resample time is frameTime - RESAMPLE_LATENCY. The resampled sample must be the
- * last one in the batch to consume.
- */
TEST_F(ResamplerTest, SinglePointerSingleSampleInterpolation) {
MotionEvent motionEvent =
InputStream{{InputSample{10ms,
@@ -297,7 +321,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample);
+ mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
{Pointer{.id = 0,
@@ -338,18 +362,13 @@
const MotionEvent originalMotionEvent = secondMotionEvent;
- mResampler->resampleMotionEvent(11ms, secondMotionEvent, nullptr);
+ mResampler->resampleMotionEvent(16ms, secondMotionEvent, nullptr);
assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, secondMotionEvent,
{Pointer{.id = 0,
.x = 2.2f,
.y = 4.4f,
.isResampled = true}});
- // Integrity of the whole motionEvent
- // History size should increment by 1
- // Check if the resampled value is the last one
- // Check if the resampleTime is correct
- // Check if the PointerCoords are consistent with the other computations
}
TEST_F(ResamplerTest, SinglePointerMultipleSampleInterpolation) {
@@ -364,7 +383,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample);
+ mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
{Pointer{.id = 0,
@@ -382,7 +401,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(11ms, motionEvent, nullptr);
+ mResampler->resampleMotionEvent(16ms, motionEvent, nullptr);
assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
{Pointer{.id = 0,
@@ -400,7 +419,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(11ms, motionEvent, nullptr);
+ mResampler->resampleMotionEvent(16ms, motionEvent, nullptr);
assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
}
@@ -414,7 +433,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(27ms, motionEvent, nullptr);
+ mResampler->resampleMotionEvent(32ms, motionEvent, nullptr);
assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
}
@@ -428,7 +447,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(43ms, motionEvent, nullptr);
+ mResampler->resampleMotionEvent(48ms, motionEvent, nullptr);
assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
{Pointer{.id = 0,
@@ -451,7 +470,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample);
+ mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
{Pointer{.x = 2.2f, .y = 2.2f, .isResampled = true},
@@ -475,7 +494,7 @@
const MotionEvent originalMotionEvent = secondMotionEvent;
- mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr);
+ mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr);
assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, secondMotionEvent,
{Pointer{.x = 3.4f, .y = 3.4f, .isResampled = true},
@@ -498,7 +517,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample);
+ mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
{Pointer{.x = 3.4f, .y = 3.4f, .isResampled = true},
@@ -517,7 +536,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(11ms, motionEvent, /*futureSample=*/nullptr);
+ mResampler->resampleMotionEvent(16ms, motionEvent, /*futureSample=*/nullptr);
assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
{Pointer{.x = 3.4f, .y = 3.4f, .isResampled = true},
@@ -539,7 +558,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample);
+ mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
{Pointer{.x = 1.4f, .y = 1.4f, .isResampled = true},
@@ -560,7 +579,7 @@
const MotionEvent originalSecondMotionEvent = secondMotionEvent;
- mResampler->resampleMotionEvent(27ms, secondMotionEvent, &secondFutureSample);
+ mResampler->resampleMotionEvent(32ms, secondMotionEvent, &secondFutureSample);
assertMotionEventIsResampledAndCoordsNear(originalSecondMotionEvent, secondMotionEvent,
{Pointer{.x = 3.8f, .y = 3.8f, .isResampled = true},
@@ -586,7 +605,7 @@
const MotionEvent secondOriginalMotionEvent = secondMotionEvent;
- mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr);
+ mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr);
assertMotionEventIsNotResampled(secondOriginalMotionEvent, secondMotionEvent);
}
@@ -606,7 +625,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample);
+ mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
}
@@ -629,7 +648,7 @@
const MotionEvent secondOriginalMotionEvent = secondMotionEvent;
- mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr);
+ mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr);
assertMotionEventIsResampledAndCoordsNear(secondOriginalMotionEvent, secondMotionEvent,
{Pointer{.x = 3.4f, .y = 3.4f, .isResampled = true},
@@ -650,7 +669,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample);
+ mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
}
@@ -672,7 +691,7 @@
const MotionEvent secondOriginalMotionEvent = secondMotionEvent;
- mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr);
+ mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr);
assertMotionEventIsNotResampled(secondOriginalMotionEvent, secondMotionEvent);
}
@@ -691,7 +710,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample);
+ mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
}
@@ -713,7 +732,7 @@
const MotionEvent secondOriginalMotionEvent = secondMotionEvent;
- mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr);
+ mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr);
assertMotionEventIsNotResampled(secondOriginalMotionEvent, secondMotionEvent);
}
@@ -746,7 +765,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample);
+ mResampler->resampleMotionEvent(16ms, motionEvent, &futureSample);
assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
}
@@ -782,7 +801,7 @@
const MotionEvent secondOriginalMotionEvent = secondMotionEvent;
- mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr);
+ mResampler->resampleMotionEvent(16ms, secondMotionEvent, /*futureSample=*/nullptr);
assertMotionEventIsNotResampled(secondOriginalMotionEvent, secondMotionEvent);
}
@@ -815,7 +834,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(11ms, motionEvent, /*futureSample=*/nullptr);
+ mResampler->resampleMotionEvent(16ms, motionEvent, /*futureSample=*/nullptr);
assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
}
@@ -847,7 +866,7 @@
const MotionEvent originalMotionEvent = motionEvent;
- mResampler->resampleMotionEvent(11ms, motionEvent, /*futureSample=*/nullptr);
+ mResampler->resampleMotionEvent(16ms, motionEvent, /*futureSample=*/nullptr);
assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
}
diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp
index 397feda..006d507 100644
--- a/services/inputflinger/PointerChoreographer.cpp
+++ b/services/inputflinger/PointerChoreographer.cpp
@@ -407,7 +407,8 @@
// TODO(b/315815559): Do not fade and reset the icon if the hover exit will be followed
// immediately by a DOWN event.
pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
- pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED);
+ pc.updatePointerIcon(mShowTouchesEnabled ? PointerIconStyle::TYPE_SPOT_HOVER
+ : PointerIconStyle::TYPE_NOT_SPECIFIED);
} else if (canUnfadeOnDisplay(args.displayId)) {
pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
}
@@ -792,6 +793,13 @@
if (isFromSource(sources, AINPUT_SOURCE_STYLUS)) {
auto it = mStylusPointersByDevice.find(deviceId);
if (it != mStylusPointersByDevice.end()) {
+ if (mShowTouchesEnabled) {
+ // If an app doesn't override the icon for the hovering stylus, show the hover icon.
+ auto* style = std::get_if<PointerIconStyle>(&icon);
+ if (style != nullptr && *style == PointerIconStyle::TYPE_NOT_SPECIFIED) {
+ *style = PointerIconStyle::TYPE_SPOT_HOVER;
+ }
+ }
setIconForController(icon, *it->second);
return true;
}
diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h
index e34ed0f..8f3d9ca 100644
--- a/services/inputflinger/include/PointerControllerInterface.h
+++ b/services/inputflinger/include/PointerControllerInterface.h
@@ -72,10 +72,6 @@
/* Dumps the state of the pointer controller. */
virtual std::string dump() = 0;
- /* Gets the bounds of the region that the pointer can traverse.
- * Returns true if the bounds are available. */
- virtual std::optional<FloatRect> getBounds() const = 0;
-
/* Move the pointer. */
virtual void move(float deltaX, float deltaY) = 0;
diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
index c8e7790..dd46bbc 100644
--- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
+++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
@@ -20,14 +20,19 @@
#include <sstream>
#include <android-base/stringprintf.h>
+#include <com_android_input_flags.h>
#include <input/PrintTools.h>
#include <linux/input-event-codes.h>
#include <log/log_main.h>
+namespace input_flags = com::android::input::flags;
+
namespace android {
namespace {
+static constexpr uint32_t SOURCE = AINPUT_SOURCE_TOUCHPAD;
+
int32_t actionWithIndex(int32_t action, int32_t index) {
return action | (index << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
}
@@ -43,6 +48,12 @@
return i;
}
+void addRawMotionRange(InputDeviceInfo& deviceInfo, int32_t androidAxis,
+ RawAbsoluteAxisInfo& evdevAxis) {
+ deviceInfo.addMotionRange(androidAxis, SOURCE, evdevAxis.minValue, evdevAxis.maxValue,
+ evdevAxis.flat, evdevAxis.fuzz, evdevAxis.resolution);
+}
+
} // namespace
CapturedTouchpadEventConverter::CapturedTouchpadEventConverter(
@@ -108,8 +119,15 @@
}
void CapturedTouchpadEventConverter::populateMotionRanges(InputDeviceInfo& info) const {
- tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_X, ABS_MT_POSITION_X);
- tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_Y, ABS_MT_POSITION_Y);
+ if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
+ tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_X,
+ AMOTION_EVENT_AXIS_RELATIVE_X, ABS_MT_POSITION_X);
+ tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_Y,
+ AMOTION_EVENT_AXIS_RELATIVE_Y, ABS_MT_POSITION_Y);
+ } else {
+ tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_X, ABS_MT_POSITION_X);
+ tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_Y, ABS_MT_POSITION_Y);
+ }
tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MAJOR, ABS_MT_TOUCH_MAJOR);
tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MINOR, ABS_MT_TOUCH_MINOR);
tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOOL_MAJOR, ABS_MT_WIDTH_MAJOR);
@@ -135,8 +153,23 @@
int32_t evdevAxis) const {
std::optional<RawAbsoluteAxisInfo> info = mDeviceContext.getAbsoluteAxisInfo(evdevAxis);
if (info) {
- deviceInfo.addMotionRange(androidAxis, SOURCE, info->minValue, info->maxValue, info->flat,
- info->fuzz, info->resolution);
+ addRawMotionRange(/*byref*/ deviceInfo, androidAxis, *info);
+ }
+}
+
+void CapturedTouchpadEventConverter::tryAddRawMotionRangeWithRelative(InputDeviceInfo& deviceInfo,
+ int32_t androidAxis,
+ int32_t androidRelativeAxis,
+ int32_t evdevAxis) const {
+ std::optional<RawAbsoluteAxisInfo> axisInfo = mDeviceContext.getAbsoluteAxisInfo(evdevAxis);
+ if (axisInfo) {
+ addRawMotionRange(/*byref*/ deviceInfo, androidAxis, *axisInfo);
+
+ // The largest movement we could possibly report on a relative axis is from the minimum to
+ // the maximum (or vice versa) of the absolute axis.
+ float range = axisInfo->maxValue - axisInfo->minValue;
+ deviceInfo.addMotionRange(androidRelativeAxis, SOURCE, -range, range, axisInfo->flat,
+ axisInfo->fuzz, axisInfo->resolution);
}
}
@@ -163,7 +196,7 @@
std::list<NotifyArgs> out;
std::vector<PointerCoords> coords;
std::vector<PointerProperties> properties;
- std::map<size_t, size_t> coordsIndexForSlotNumber;
+ std::map<size_t /*slotNumber*/, size_t /*coordsIndex*/> coordsIndexForSlotNumber;
// For all the touches that were already down, send a MOVE event with their updated coordinates.
// A convention of the MotionEvent API is that pointer coordinates in UP events match the
@@ -175,11 +208,19 @@
// to stay perfectly still between frames, and if it does the worst that can happen is
// an extra MOVE event, so it's not worth the overhead of checking for changes.
coordsIndexForSlotNumber[slotNumber] = coords.size();
- coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber)));
+ coords.push_back(makePointerCoordsForSlot(slotNumber));
properties.push_back({.id = pointerId, .toolType = ToolType::FINGER});
}
out.push_back(
makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, coords, properties));
+ if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
+ // For any further events we send from this sync, the pointers won't have moved relative
+ // to the positions we just reported in this MOVE event, so zero out the relative axes.
+ for (PointerCoords& pointer : coords) {
+ pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0);
+ pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0);
+ }
+ }
}
std::vector<size_t> upSlots, downSlots;
@@ -234,6 +275,9 @@
/*flags=*/cancel ? AMOTION_EVENT_FLAG_CANCELED : 0));
freePointerIdForSlot(slotNumber);
+ if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
+ mPreviousCoordsForSlotNumber.erase(slotNumber);
+ }
coords.erase(coords.begin() + indexToRemove);
properties.erase(properties.begin() + indexToRemove);
// Now that we've removed some coords and properties, we might have to update the slot
@@ -254,7 +298,7 @@
: actionWithIndex(AMOTION_EVENT_ACTION_POINTER_DOWN, coordsIndex);
coordsIndexForSlotNumber[slotNumber] = coordsIndex;
- coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber)));
+ coords.push_back(makePointerCoordsForSlot(slotNumber));
properties.push_back(
{.id = allocatePointerIdToSlot(slotNumber), .toolType = ToolType::FINGER});
@@ -286,12 +330,22 @@
AMOTION_EVENT_INVALID_CURSOR_POSITION, mDownTime, /*videoFrames=*/{});
}
-PointerCoords CapturedTouchpadEventConverter::makePointerCoordsForSlot(
- const MultiTouchMotionAccumulator::Slot& slot) const {
+PointerCoords CapturedTouchpadEventConverter::makePointerCoordsForSlot(size_t slotNumber) {
+ const MultiTouchMotionAccumulator::Slot& slot = mMotionAccumulator.getSlot(slotNumber);
PointerCoords coords;
coords.clear();
coords.setAxisValue(AMOTION_EVENT_AXIS_X, slot.getX());
coords.setAxisValue(AMOTION_EVENT_AXIS_Y, slot.getY());
+ if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
+ if (auto it = mPreviousCoordsForSlotNumber.find(slotNumber);
+ it != mPreviousCoordsForSlotNumber.end()) {
+ auto [oldX, oldY] = it->second;
+ coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, slot.getX() - oldX);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, slot.getY() - oldY);
+ }
+ mPreviousCoordsForSlotNumber[slotNumber] = std::make_pair(slot.getX(), slot.getY());
+ }
+
coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, slot.getTouchMajor());
coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, slot.getTouchMinor());
coords.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, slot.getToolMajor());
diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h
index 9b6df7a..d6c0708 100644
--- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h
+++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h
@@ -21,6 +21,7 @@
#include <map>
#include <set>
#include <string>
+#include <utility>
#include <vector>
#include <android/input.h>
@@ -49,12 +50,14 @@
private:
void tryAddRawMotionRange(InputDeviceInfo& deviceInfo, int32_t androidAxis,
int32_t evdevAxis) const;
+ void tryAddRawMotionRangeWithRelative(InputDeviceInfo& deviceInfo, int32_t androidAxis,
+ int32_t androidRelativeAxis, int32_t evdevAxis) const;
[[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime);
[[nodiscard]] NotifyMotionArgs makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action,
const std::vector<PointerCoords>& coords,
const std::vector<PointerProperties>& properties,
int32_t actionButton = 0, int32_t flags = 0);
- PointerCoords makePointerCoordsForSlot(const MultiTouchMotionAccumulator::Slot& slot) const;
+ PointerCoords makePointerCoordsForSlot(size_t slotNumber);
int32_t allocatePointerIdToSlot(size_t slotNumber);
void freePointerIdForSlot(size_t slotNumber);
@@ -76,8 +79,7 @@
std::bitset<MAX_POINTER_ID + 1> mPointerIdsInUse;
std::map<size_t, int32_t> mPointerIdForSlotNumber;
-
- static constexpr uint32_t SOURCE = AINPUT_SOURCE_TOUCHPAD;
+ std::map<size_t, std::pair<float, float>> mPreviousCoordsForSlotNumber;
};
} // namespace android
diff --git a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
index f20c43c..353011a 100644
--- a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
+++ b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
@@ -20,6 +20,7 @@
#include <memory>
#include <EventHub.h>
+#include <com_android_input_flags.h>
#include <gtest/gtest.h>
#include <linux/input-event-codes.h>
#include <linux/input.h>
@@ -32,6 +33,8 @@
#include "TestEventMatchers.h"
#include "TestInputListener.h"
+namespace input_flags = com::android::input::flags;
+
namespace android {
using testing::AllOf;
@@ -47,6 +50,8 @@
mReader(mFakeEventHub, mFakePolicy, mFakeListener),
mDevice(newDevice()),
mDeviceContext(*mDevice, EVENTHUB_ID) {
+ input_flags::include_relative_axis_values_for_captured_touchpads(true);
+
const size_t slotCount = 8;
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_SLOT, 0, slotCount - 1, 0, 0, 0);
mAccumulator.configure(mDeviceContext, slotCount, /*usingSlotsProtocol=*/true);
@@ -126,7 +131,7 @@
TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populatedCorrectly) {
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, 0, 4000, 0, 0, 45);
- mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, 0, 2500, 0, 0, 40);
+ mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, -500, 2000, 0, 0, 40);
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MAJOR, 0, 1100, 0, 0, 35);
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MINOR, 0, 1000, 0, 0, 30);
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, 0, 900, 0, 0, 25);
@@ -150,8 +155,8 @@
const InputDeviceInfo::MotionRange* posY =
info.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHPAD);
ASSERT_NE(nullptr, posY);
- EXPECT_NEAR(0, posY->min, EPSILON);
- EXPECT_NEAR(2500, posY->max, EPSILON);
+ EXPECT_NEAR(-500, posY->min, EPSILON);
+ EXPECT_NEAR(2000, posY->max, EPSILON);
EXPECT_NEAR(40, posY->resolution, EPSILON);
const InputDeviceInfo::MotionRange* touchMajor =
@@ -182,8 +187,22 @@
EXPECT_NEAR(800, toolMinor->max, EPSILON);
EXPECT_NEAR(20, toolMinor->resolution, EPSILON);
- // ...except orientation and pressure, which get scaled, and size, which is generated from other
- // values.
+ // ...except for the relative motion axes, derived from the corresponding absolute ones:
+ const InputDeviceInfo::MotionRange* relX =
+ info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, AINPUT_SOURCE_TOUCHPAD);
+ ASSERT_NE(nullptr, relX);
+ EXPECT_NEAR(-4000, relX->min, EPSILON);
+ EXPECT_NEAR(4000, relX->max, EPSILON);
+ EXPECT_NEAR(45, relX->resolution, EPSILON);
+
+ const InputDeviceInfo::MotionRange* relY =
+ info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, AINPUT_SOURCE_TOUCHPAD);
+ ASSERT_NE(nullptr, relY);
+ EXPECT_NEAR(-2500, relY->min, EPSILON);
+ EXPECT_NEAR(2500, relY->max, EPSILON);
+ EXPECT_NEAR(40, relY->resolution, EPSILON);
+
+ // ...orientation and pressure, which get scaled:
const InputDeviceInfo::MotionRange* orientation =
info.getMotionRange(AMOTION_EVENT_AXIS_ORIENTATION, AINPUT_SOURCE_TOUCHPAD);
ASSERT_NE(nullptr, orientation);
@@ -198,6 +217,7 @@
EXPECT_NEAR(1, pressure->max, EPSILON);
EXPECT_NEAR(0, pressure->resolution, EPSILON);
+ // ... and size, which is generated from other values.
const InputDeviceInfo::MotionRange* size =
info.getMotionRange(AMOTION_EVENT_AXIS_SIZE, AINPUT_SOURCE_TOUCHPAD);
ASSERT_NE(nullptr, size);
@@ -219,7 +239,9 @@
// present, since it's generated from axes that aren't provided by this device).
EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHPAD));
EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHPAD));
- EXPECT_EQ(2u, info.getMotionRanges().size());
+ EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, AINPUT_SOURCE_TOUCHPAD));
+ EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, AINPUT_SOURCE_TOUCHPAD));
+ EXPECT_EQ(4u, info.getMotionRanges().size());
}
TEST_F(CapturedTouchpadEventConverterTest, OneFinger_motionReportedCorrectly) {
@@ -235,14 +257,16 @@
EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
- WithCoords(50, 100), WithToolType(ToolType::FINGER)));
+ WithCoords(50, 100), WithRelativeMotion(0, 0),
+ WithToolType(ToolType::FINGER)));
processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);
processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 99);
EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
- WithCoords(52, 99), WithToolType(ToolType::FINGER)));
+ WithCoords(52, 99), WithRelativeMotion(2, -1),
+ WithToolType(ToolType::FINGER)));
processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
processAxis(conv, EV_KEY, BTN_TOUCH, 0);
@@ -255,8 +279,9 @@
VariantWith<NotifyMotionArgs>(
WithMotionAction(AMOTION_EVENT_ACTION_UP))));
EXPECT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(52, 99), WithPointerCount(1u),
- WithToolType(ToolType::FINGER)))));
+ Each(VariantWith<NotifyMotionArgs>(
+ AllOf(WithCoords(52, 99), WithRelativeMotion(0, 0), WithPointerCount(1u),
+ WithToolType(ToolType::FINGER)))));
}
TEST_F(CapturedTouchpadEventConverterTest, OneFinger_touchDimensionsPassedThrough) {
@@ -507,13 +532,13 @@
EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
- WithCoords(51, 100)));
+ WithCoords(51, 100), WithRelativeMotion(0, 0)));
processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);
EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
- WithCoords(52, 100)));
+ WithCoords(52, 100), WithRelativeMotion(1, 0)));
}
TEST_F(CapturedTouchpadEventConverterTest, FingerArrivingAfterPalm_onlyFingerReported) {
@@ -553,7 +578,7 @@
EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
- WithCoords(98, 148)));
+ WithCoords(98, 148), WithRelativeMotion(-2, -2)));
}
TEST_F(CapturedTouchpadEventConverterTest, FingerAndFingerTurningIntoPalm_partiallyCancelled) {
@@ -660,7 +685,8 @@
EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
- WithCoords(50, 100), WithToolType(ToolType::FINGER)));
+ WithCoords(50, 100), WithRelativeMotion(0, 0),
+ WithToolType(ToolType::FINGER)));
processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);
@@ -678,13 +704,16 @@
ElementsAre(VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
WithPointerCount(1u), WithCoords(52, 99),
+ WithRelativeMotion(2, -1),
WithToolType(ToolType::FINGER))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(
AMOTION_EVENT_ACTION_POINTER_DOWN |
1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
WithPointerCount(2u), WithPointerCoords(0, 52, 99),
+ WithPointerRelativeMotion(0, 0, 0),
WithPointerCoords(1, 250, 200),
+ WithPointerRelativeMotion(1, 0, 0),
WithPointerToolType(0, ToolType::FINGER),
WithPointerToolType(1, ToolType::FINGER)))));
@@ -700,14 +729,17 @@
std::list<NotifyArgs> args = processSync(conv);
EXPECT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
- WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
- VariantWith<NotifyMotionArgs>(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_UP |
- 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT))));
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
+ WithPointerRelativeMotion(1, 5, 2))),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(
+ AMOTION_EVENT_ACTION_POINTER_UP |
+ 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ WithPointerRelativeMotion(1, 0, 0)))));
EXPECT_THAT(args,
Each(VariantWith<NotifyMotionArgs>(
AllOf(WithPointerCount(2u), WithPointerCoords(0, 52, 99),
- WithPointerCoords(1, 255, 202),
+ WithPointerRelativeMotion(0, 0, 0), WithPointerCoords(1, 255, 202),
WithPointerToolType(1, ToolType::FINGER),
WithPointerToolType(0, ToolType::FINGER)))));
@@ -723,9 +755,69 @@
WithMotionAction(AMOTION_EVENT_ACTION_UP))));
EXPECT_THAT(args,
Each(VariantWith<NotifyMotionArgs>(AllOf(WithPointerCount(1u), WithCoords(255, 202),
+ WithRelativeMotion(0, 0),
WithToolType(ToolType::FINGER)))));
}
+TEST_F(CapturedTouchpadEventConverterTest, RelativeMotionAxesClearedForNewFingerInSlot) {
+ CapturedTouchpadEventConverter conv = createConverter();
+ // Put down one finger.
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
+
+ processAxis(conv, EV_KEY, BTN_TOUCH, 1);
+ processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);
+
+ EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
+ WithCoords(50, 100), WithRelativeMotion(0, 0)));
+
+ // Move it in negative X and Y directions.
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 47);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 97);
+
+ EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(47, 97),
+ WithRelativeMotion(-3, -3)));
+
+ // Lift it.
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
+ processAxis(conv, EV_KEY, BTN_TOUCH, 0);
+ processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);
+
+ std::list<NotifyArgs> args = processSync(conv);
+ EXPECT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
+ VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_UP))));
+ EXPECT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(47, 97),
+ WithRelativeMotion(0, 0),
+ WithPointerCount(1u)))));
+
+ // Put down another finger using the same slot. Relative axis values should be cleared.
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 2);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 60);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 60);
+
+ processAxis(conv, EV_KEY, BTN_TOUCH, 1);
+ processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);
+
+ EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
+ WithCoords(60, 60), WithRelativeMotion(0, 0)));
+
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 64);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 58);
+
+ EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
+ WithCoords(64, 58), WithRelativeMotion(4, -2)));
+}
+
// Pointer IDs max out at 31, and so must be reused once a touch is lifted to avoid running out.
TEST_F(CapturedTouchpadEventConverterTest, PointerIdsReusedAfterLift) {
CapturedTouchpadEventConverter conv = createConverter();
diff --git a/services/inputflinger/tests/FakePointerController.cpp b/services/inputflinger/tests/FakePointerController.cpp
index d0998ba..887a939 100644
--- a/services/inputflinger/tests/FakePointerController.cpp
+++ b/services/inputflinger/tests/FakePointerController.cpp
@@ -148,12 +148,6 @@
return mIsPointerShown;
}
-std::optional<FloatRect> FakePointerController::getBounds() const {
- if (!mEnabled) return std::nullopt;
-
- return mHaveBounds ? std::make_optional<FloatRect>(mMinX, mMinY, mMaxX, mMaxY) : std::nullopt;
-}
-
void FakePointerController::move(float deltaX, float deltaY) {
if (!mEnabled) return;
diff --git a/services/inputflinger/tests/FakePointerController.h b/services/inputflinger/tests/FakePointerController.h
index 2c76c62..9b773a7 100644
--- a/services/inputflinger/tests/FakePointerController.h
+++ b/services/inputflinger/tests/FakePointerController.h
@@ -65,7 +65,6 @@
private:
std::string dump() override { return ""; }
- std::optional<FloatRect> getBounds() const override;
void move(float deltaX, float deltaY) override;
void unfade(Transition) override;
void setPresentation(Presentation) override {}
diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp
index 18222dd..411c7ba 100644
--- a/services/inputflinger/tests/PointerChoreographer_test.cpp
+++ b/services/inputflinger/tests/PointerChoreographer_test.cpp
@@ -978,6 +978,36 @@
assertPointerControllerRemoved(pc);
}
+/**
+ * When both "show touches" and "stylus hover icons" are enabled, if the app doesn't specify an
+ * icon for the hovering stylus, fall back to using the spot hover icon.
+ */
+TEST_F(PointerChoreographerTest, ShowTouchesOverridesUnspecifiedStylusIcon) {
+ mChoreographer.setShowTouchesEnabled(true);
+ mChoreographer.setStylusPointerIconEnabled(true);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
+ DISPLAY_ID)}});
+
+ mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
+ AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ auto pc = assertPointerControllerCreated(ControllerType::STYLUS);
+
+ mChoreographer.setPointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED, DISPLAY_ID, DEVICE_ID);
+ pc->assertPointerIconSet(PointerIconStyle::TYPE_SPOT_HOVER);
+
+ mChoreographer.setPointerIcon(PointerIconStyle::TYPE_ARROW, DISPLAY_ID, DEVICE_ID);
+ pc->assertPointerIconSet(PointerIconStyle::TYPE_ARROW);
+
+ mChoreographer.setPointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED, DISPLAY_ID, DEVICE_ID);
+ pc->assertPointerIconSet(PointerIconStyle::TYPE_SPOT_HOVER);
+}
+
using StylusFixtureParam =
std::tuple</*name*/ std::string_view, /*source*/ uint32_t, ControllerType>;
diff --git a/services/inputflinger/tests/TestEventMatchers.h b/services/inputflinger/tests/TestEventMatchers.h
index cfedc6e..6fa3365 100644
--- a/services/inputflinger/tests/TestEventMatchers.h
+++ b/services/inputflinger/tests/TestEventMatchers.h
@@ -615,7 +615,12 @@
explicit WithPointerIdMatcher(size_t index, int32_t pointerId)
: mIndex(index), mPointerId(pointerId) {}
- bool MatchAndExplain(const NotifyMotionArgs& args, std::ostream*) const {
+ bool MatchAndExplain(const NotifyMotionArgs& args, std::ostream* os) const {
+ if (mIndex >= args.pointerCoords.size()) {
+ *os << "Pointer index " << mIndex << " is out of bounds";
+ return false;
+ }
+
return args.pointerProperties[mIndex].id == mPointerId;
}
@@ -646,12 +651,51 @@
return (isnan(x) ? isnan(argX) : x == argX) && (isnan(y) ? isnan(argY) : y == argY);
}
-MATCHER_P2(WithRelativeMotion, x, y, "InputEvent with specified relative motion") {
- const auto argX = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
- const auto argY = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
- *result_listener << "expected relative motion (" << x << ", " << y << "), but got (" << argX
- << ", " << argY << ")";
- return argX == x && argY == y;
+/// Relative motion matcher
+class WithRelativeMotionMatcher {
+public:
+ using is_gtest_matcher = void;
+ explicit WithRelativeMotionMatcher(size_t pointerIndex, float relX, float relY)
+ : mPointerIndex(pointerIndex), mRelX(relX), mRelY(relY) {}
+
+ bool MatchAndExplain(const NotifyMotionArgs& event, std::ostream* os) const {
+ if (mPointerIndex >= event.pointerCoords.size()) {
+ *os << "Pointer index " << mPointerIndex << " is out of bounds";
+ return false;
+ }
+
+ const PointerCoords& coords = event.pointerCoords[mPointerIndex];
+ bool matches = mRelX == coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X) &&
+ mRelY == coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
+ if (!matches) {
+ *os << "expected relative motion (" << mRelX << ", " << mRelY << ") at pointer index "
+ << mPointerIndex << ", but got ("
+ << coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X) << ", "
+ << coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y) << ")";
+ }
+ return matches;
+ }
+
+ void DescribeTo(std::ostream* os) const {
+ *os << "with relative motion (" << mRelX << ", " << mRelY << ") at pointer index "
+ << mPointerIndex;
+ }
+
+ void DescribeNegationTo(std::ostream* os) const { *os << "wrong relative motion"; }
+
+private:
+ const size_t mPointerIndex;
+ const float mRelX;
+ const float mRelY;
+};
+
+inline WithRelativeMotionMatcher WithRelativeMotion(float relX, float relY) {
+ return WithRelativeMotionMatcher(0, relX, relY);
+}
+
+inline WithRelativeMotionMatcher WithPointerRelativeMotion(size_t pointerIndex, float relX,
+ float relY) {
+ return WithRelativeMotionMatcher(pointerIndex, relX, relY);
}
MATCHER_P3(WithGestureOffset, dx, dy, epsilon,
@@ -758,10 +802,14 @@
return argToolType == toolType;
}
-MATCHER_P2(WithPointerToolType, pointer, toolType,
+MATCHER_P2(WithPointerToolType, pointerIndex, toolType,
"InputEvent with specified tool type for pointer") {
- const auto argToolType = arg.pointerProperties[pointer].toolType;
- *result_listener << "expected pointer " << pointer << " to have tool type "
+ if (std::cmp_greater_equal(pointerIndex, arg.getPointerCount())) {
+ *result_listener << "Pointer index " << pointerIndex << " is out of bounds";
+ return false;
+ }
+ const auto argToolType = arg.pointerProperties[pointerIndex].toolType;
+ *result_listener << "expected pointer " << pointerIndex << " to have tool type "
<< ftl::enum_string(toolType) << ", but got " << ftl::enum_string(argToolType);
return argToolType == toolType;
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index be00079..5e13154 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -38,7 +38,6 @@
#include <FrameTimeline/FrameTimeline.h>
#include <scheduler/interface/ICompositor.h>
-#include <algorithm>
#include <cinttypes>
#include <cstdint>
#include <functional>
@@ -46,16 +45,15 @@
#include <numeric>
#include <common/FlagManager.h>
-#include "../Layer.h"
#include "EventThread.h"
#include "FrameRateOverrideMappings.h"
#include "FrontEnd/LayerHandle.h"
+#include "Layer.h"
#include "OneShotTimer.h"
#include "RefreshRateStats.h"
#include "SurfaceFlingerFactory.h"
#include "SurfaceFlingerProperties.h"
#include "TimeStats/TimeStats.h"
-#include "VSyncTracker.h"
#include "VsyncConfiguration.h"
#include "VsyncController.h"
#include "VsyncSchedule.h"
@@ -361,10 +359,8 @@
if (cycle == Cycle::Render) {
mRenderEventThread = std::move(eventThread);
- mRenderEventConnection = mRenderEventThread->createEventConnection();
} else {
mLastCompositeEventThread = std::move(eventThread);
- mLastCompositeEventConnection = mLastCompositeEventThread->createEventConnection();
}
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 1367ec3..c88b563 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -145,10 +145,6 @@
Cycle, EventRegistrationFlags eventRegistration = {},
const sp<IBinder>& layerHandle = nullptr) EXCLUDES(mChoreographerLock);
- const sp<EventThreadConnection>& getEventConnection(Cycle cycle) const {
- return cycle == Cycle::Render ? mRenderEventConnection : mLastCompositeEventConnection;
- }
-
enum class Hotplug { Connected, Disconnected };
void dispatchHotplug(PhysicalDisplayId, Hotplug);
@@ -467,10 +463,7 @@
void onExpectedPresentTimePosted(TimePoint expectedPresentTime) override EXCLUDES(mDisplayLock);
std::unique_ptr<EventThread> mRenderEventThread;
- sp<EventThreadConnection> mRenderEventConnection;
-
std::unique_ptr<EventThread> mLastCompositeEventThread;
- sp<EventThreadConnection> mLastCompositeEventConnection;
std::atomic<nsecs_t> mLastResyncTime = 0;
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index fa31643..9b10c94 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -64,17 +64,6 @@
void DisplayTransactionTest::injectMockScheduler(PhysicalDisplayId displayId) {
LOG_ALWAYS_FATAL_IF(mFlinger.scheduler());
-
- EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*mEventThread, createEventConnection(_, _))
- .WillOnce(Return(
- sp<EventThreadConnection>::make(mEventThread, mock::EventThread::kCallingUid)));
-
- EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*mSFEventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(mSFEventThread,
- mock::EventThread::kCallingUid)));
-
mFlinger.setupScheduler(std::make_unique<mock::VsyncController>(),
std::make_shared<mock::VSyncTracker>(),
std::unique_ptr<EventThread>(mEventThread),
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 45ca7e2..ac09cbc 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -124,7 +124,7 @@
// createConnection call to scheduler makes a createEventConnection call to EventThread. Make
// sure that call gets executed and returns an EventThread::Connection object.
- EXPECT_CALL(*mEventThread, createEventConnection(_, _))
+ EXPECT_CALL(*mEventThread, createEventConnection(_))
.WillRepeatedly(Return(mEventThreadConnection));
mScheduler->setEventThread(Cycle::Render, std::move(eventThread));
@@ -797,7 +797,7 @@
const auto mockConnection1 = sp<MockEventThreadConnection>::make(mEventThread);
const auto mockConnection2 = sp<MockEventThreadConnection>::make(mEventThread);
- EXPECT_CALL(*mEventThread, createEventConnection(_, _))
+ EXPECT_CALL(*mEventThread, createEventConnection(_))
.WillOnce(Return(mockConnection1))
.WillOnce(Return(mockConnection2));
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index 4b0a7c3..8699621 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -187,16 +187,6 @@
mAppEventThread = eventThread.get();
auto sfEventThread = std::make_unique<mock::EventThread>();
- EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
- mock::EventThread::kCallingUid)));
-
- EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
- mock::EventThread::kCallingUid)));
-
auto vsyncController = std::make_unique<mock::VsyncController>();
auto vsyncTracker = std::make_shared<mock::VSyncTracker>();
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index df16b2e..d92f891 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -74,10 +74,8 @@
void setEventThread(Cycle cycle, std::unique_ptr<EventThread> eventThreadPtr) {
if (cycle == Cycle::Render) {
mRenderEventThread = std::move(eventThreadPtr);
- mRenderEventConnection = mRenderEventThread->createEventConnection();
} else {
mLastCompositeEventThread = std::move(eventThreadPtr);
- mLastCompositeEventConnection = mLastCompositeEventThread->createEventConnection();
}
}
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 725354b..347a396 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -16,7 +16,6 @@
#pragma once
-#include <algorithm>
#include <chrono>
#include <memory>
#include <variant>
@@ -44,7 +43,6 @@
#include "Layer.h"
#include "NativeWindowSurface.h"
#include "RenderArea.h"
-#include "Scheduler/MessageQueue.h"
#include "Scheduler/RefreshRateSelector.h"
#include "SurfaceFlinger.h"
#include "TestableScheduler.h"
@@ -60,7 +58,6 @@
#include "Scheduler/VSyncTracker.h"
#include "Scheduler/VsyncController.h"
-#include "mock/MockVSyncDispatch.h"
#include "mock/MockVSyncTracker.h"
#include "mock/MockVsyncController.h"
@@ -88,9 +85,7 @@
public:
~Factory() = default;
- std::unique_ptr<HWComposer> createHWComposer(const std::string&) override {
- return nullptr;
- }
+ std::unique_ptr<HWComposer> createHWComposer(const std::string&) override { return nullptr; }
std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
Fps /*currentRefreshRate*/) override {
@@ -276,17 +271,6 @@
auto eventThread = makeMock<mock::EventThread>(options.useNiceMock);
auto sfEventThread = makeMock<mock::EventThread>(options.useNiceMock);
-
- EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
- mock::EventThread::kCallingUid)));
-
- EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
- mock::EventThread::kCallingUid)));
-
auto vsyncController = makeMock<mock::VsyncController>(options.useNiceMock);
auto vsyncTracker = makeSharedMock<mock::VSyncTracker>(options.useNiceMock);
@@ -502,7 +486,7 @@
}
auto getDisplayNativePrimaries(const sp<IBinder>& displayToken,
- ui::DisplayPrimaries &primaries) {
+ ui::DisplayPrimaries& primaries) {
return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
}
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 8dd1a34..7398cbe 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -24,21 +24,11 @@
class EventThread : public android::EventThread {
public:
- static constexpr auto kCallingUid = static_cast<uid_t>(0);
-
EventThread();
~EventThread() override;
- // TODO(b/302035909): workaround otherwise gtest complains about
- // error: no viable conversion from
- // 'tuple<android::ftl::Flags<android::gui::ISurfaceComposer::EventRegistration> &&>' to 'const
- // tuple<android::ftl::Flags<android::gui::ISurfaceComposer::EventRegistration>>'
- sp<EventThreadConnection> createEventConnection(EventRegistrationFlags flags) const override {
- return createEventConnection(false, flags);
- }
- MOCK_METHOD(sp<EventThreadConnection>, createEventConnection, (bool, EventRegistrationFlags),
- (const));
-
+ MOCK_METHOD(sp<EventThreadConnection>, createEventConnection, (EventRegistrationFlags),
+ (const, override));
MOCK_METHOD(void, enableSyntheticVsync, (bool), (override));
MOCK_METHOD(void, onHotplugReceived, (PhysicalDisplayId, bool), (override));
MOCK_METHOD(void, onHotplugConnectionError, (int32_t), (override));