Merge changes from topic "AIDL_DisplayCapability"
* changes:
Add to_string(DisplayCapability)
Switch from HIDL DisplayCapability to AIDL
diff --git a/include/input/Input.h b/include/input/Input.h
index e1cacac..ddff144 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -382,7 +382,6 @@
// window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR
// axes, however the window scaling will not.
void scale(float globalScale, float windowXScale, float windowYScale);
- void applyOffset(float xOffset, float yOffset);
void transform(const ui::Transform& transform);
@@ -572,7 +571,7 @@
inline float getYOffset() const { return mTransform.ty(); }
- inline ui::Transform getTransform() const { return mTransform; }
+ inline const ui::Transform& getTransform() const { return mTransform; }
int getSurfaceRotation() const;
@@ -590,7 +589,7 @@
void setCursorPosition(float x, float y);
- ui::Transform getRawTransform() const { return mRawTransform; }
+ inline const ui::Transform& getRawTransform() const { return mRawTransform; }
static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); }
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index e5dcdea..ec3587b 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -66,6 +66,7 @@
host_supported: true,
srcs: [
":guiconstants_aidl",
+ ":inputconstants_aidl",
"android/gui/DisplayInfo.aidl",
"android/gui/FocusRequest.aidl",
"android/gui/InputApplicationInfo.aidl",
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index e92be01..8d356aa 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -47,6 +47,10 @@
return inputFeatures.test(Feature::SPY);
}
+bool WindowInfo::interceptsStylus() const {
+ return inputFeatures.test(Feature::INTERCEPTS_STYLUS);
+}
+
bool WindowInfo::overlaps(const WindowInfo* other) const {
return frameLeft < other->frameRight && frameRight > other->frameLeft &&
frameTop < other->frameBottom && frameBottom > other->frameTop;
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index 808afe4..2bfaec8 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -17,6 +17,7 @@
#pragma once
#include <android/gui/TouchOcclusionMode.h>
+#include <android/os/IInputConstants.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <ftl/Flags.h>
@@ -131,13 +132,23 @@
ftl_last = FIRST_SYSTEM_WINDOW + 15
};
+ // This is a conversion of os::IInputConstants::InputFeature to an enum backed by an unsigned
+ // type. This indicates that they are flags, so it can be used with ftl/enum.h.
enum class Feature : uint32_t {
- DISABLE_TOUCH_PAD_GESTURES = 1u << 0,
- NO_INPUT_CHANNEL = 1u << 1,
- DISABLE_USER_ACTIVITY = 1u << 2,
- DROP_INPUT = 1u << 3,
- DROP_INPUT_IF_OBSCURED = 1u << 4,
- SPY = 1u << 5,
+ // clang-format off
+ NO_INPUT_CHANNEL =
+ static_cast<uint32_t>(os::IInputConstants::InputFeature::NO_INPUT_CHANNEL),
+ DISABLE_USER_ACTIVITY =
+ static_cast<uint32_t>(os::IInputConstants::InputFeature::DISABLE_USER_ACTIVITY),
+ DROP_INPUT =
+ static_cast<uint32_t>(os::IInputConstants::InputFeature::DROP_INPUT),
+ DROP_INPUT_IF_OBSCURED =
+ static_cast<uint32_t>(os::IInputConstants::InputFeature::DROP_INPUT_IF_OBSCURED),
+ SPY =
+ static_cast<uint32_t>(os::IInputConstants::InputFeature::SPY),
+ INTERCEPTS_STYLUS =
+ static_cast<uint32_t>(os::IInputConstants::InputFeature::INTERCEPTS_STYLUS),
+ // clang-format on
};
/* These values are filled in by the WM and passed through SurfaceFlinger
@@ -218,6 +229,8 @@
bool isSpy() const;
+ bool interceptsStylus() const;
+
bool overlaps(const WindowInfo* other) const;
bool operator==(const WindowInfo& inputChannel) const;
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index f0b97a7..84dba84 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -344,11 +344,6 @@
scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_Y, windowYScale);
}
-void PointerCoords::applyOffset(float xOffset, float yOffset) {
- setAxisValue(AMOTION_EVENT_AXIS_X, getX() + xOffset);
- setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset);
-}
-
#ifdef __linux__
status_t PointerCoords::readFromParcel(Parcel* parcel) {
bits = parcel->readInt64();
diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl
index 474a1e4..63bf23d 100644
--- a/libs/input/android/os/IInputConstants.aidl
+++ b/libs/input/android/os/IInputConstants.aidl
@@ -53,4 +53,53 @@
* set of flags, including in input/Input.h and in android/input.h.
*/
const int INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800;
+
+ @Backing(type="int")
+ enum InputFeature {
+ /**
+ * Does not construct an input channel for this window. The channel will therefore
+ * be incapable of receiving input.
+ */
+ NO_INPUT_CHANNEL = 0x00000002,
+
+ /**
+ * When this window has focus, does not call user activity for all input events so
+ * the application will have to do it itself. Should only be used by
+ * the keyguard and phone app.
+ *
+ * Should only be used by the keyguard and phone app.
+ */
+ DISABLE_USER_ACTIVITY = 0x00000004,
+
+ /**
+ * Internal flag used to indicate that input should be dropped on this window.
+ */
+ DROP_INPUT = 0x00000008,
+
+ /**
+ * Internal flag used to indicate that input should be dropped on this window if this window
+ * is obscured.
+ */
+ DROP_INPUT_IF_OBSCURED = 0x00000010,
+
+ /**
+ * An input spy window. This window will receive all pointer events within its touchable
+ * area, but will will not stop events from being sent to other windows below it in z-order.
+ * An input event will be dispatched to all spy windows above the top non-spy window at the
+ * event's coordinates.
+ */
+ SPY = 0x00000020,
+
+ /**
+ * When used with the window flag {@link #FLAG_NOT_TOUCHABLE}, this window will continue
+ * to receive events from a stylus device within its touchable region. All other pointer
+ * events, such as from a mouse or touchscreen, will be dispatched to the windows behind it.
+ *
+ * This input feature has no effect when the window flag {@link #FLAG_NOT_TOUCHABLE} is
+ * not set.
+ *
+ * The window must be a trusted overlay to use this input feature.
+ */
+ INTERCEPTS_STYLUS = 0x00000040,
+ }
}
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 936ecf9..8046bbe 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -214,7 +214,7 @@
int32_t edgeFlags, float xPrecision, float yPrecision,
float xCursorPosition, float yCursorPosition, nsecs_t downTime,
uint32_t pointerCount, const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords, float xOffset, float yOffset)
+ const PointerCoords* pointerCoords)
: EventEntry(id, Type::MOTION, eventTime, policyFlags),
deviceId(deviceId),
source(source),
@@ -235,9 +235,6 @@
for (uint32_t i = 0; i < pointerCount; i++) {
this->pointerProperties[i].copyFrom(pointerProperties[i]);
this->pointerCoords[i].copyFrom(pointerCoords[i]);
- if (xOffset || yOffset) {
- this->pointerCoords[i].applyOffset(xOffset, yOffset);
- }
}
}
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 477781a..0f79296 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -184,8 +184,7 @@
int32_t metaState, int32_t buttonState, MotionClassification classification,
int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition,
float yCursorPosition, nsecs_t downTime, uint32_t pointerCount,
- const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
- float xOffset, float yOffset);
+ const PointerProperties* pointerProperties, const PointerCoords* pointerCoords);
std::string getDescription() const override;
~MotionEntry() override;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 6ff2450..ff2e4a0 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -378,7 +378,7 @@
motionEntry.yPrecision, motionEntry.xCursorPosition,
motionEntry.yCursorPosition, motionEntry.downTime,
motionEntry.pointerCount, motionEntry.pointerProperties,
- pointerCoords.data(), 0 /* xOffset */, 0 /* yOffset */);
+ pointerCoords.data());
if (motionEntry.injectionState) {
combinedMotionEntry->injectionState = motionEntry.injectionState;
@@ -506,12 +506,6 @@
return true;
}
-vec2 transformWithoutTranslation(const ui::Transform& transform, float x, float y) {
- const vec2 transformedXy = transform.transform(x, y);
- const vec2 transformedOrigin = transform.transform(0, 0);
- return transformedXy - transformedOrigin;
-}
-
// Returns true if the event type passed as argument represents a user activity.
bool isUserActivityEvent(const EventEntry& eventEntry) {
switch (eventEntry.type) {
@@ -530,12 +524,14 @@
}
// Returns true if the given window can accept pointer events at the given display location.
-bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32_t x, int32_t y) {
+bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, int32_t x, int32_t y,
+ bool isStylus) {
if (windowInfo.displayId != displayId || !windowInfo.visible) {
return false;
}
const auto flags = windowInfo.flags;
- if (flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) {
+ const bool windowCanInterceptTouch = isStylus && windowInfo.interceptsStylus();
+ if (flags.test(WindowInfo::Flag::NOT_TOUCHABLE) && !windowCanInterceptTouch) {
return false;
}
const bool isModalWindow = !flags.test(WindowInfo::Flag::NOT_FOCUSABLE) &&
@@ -546,6 +542,12 @@
return true;
}
+bool isPointerFromStylus(const MotionEntry& entry, int32_t pointerIndex) {
+ return isFromSource(entry.source, AINPUT_SOURCE_STYLUS) &&
+ (entry.pointerProperties[pointerIndex].toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS ||
+ entry.pointerProperties[pointerIndex].toolType == AMOTION_EVENT_TOOL_TYPE_ERASER);
+}
+
} // namespace
// --- InputDispatcher ---
@@ -939,8 +941,10 @@
motionEntry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
int32_t y = static_cast<int32_t>(
motionEntry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
+
+ const bool isStylus = isPointerFromStylus(motionEntry, 0 /*pointerIndex*/);
sp<WindowInfoHandle> touchedWindowHandle =
- findTouchedWindowAtLocked(displayId, x, y, nullptr);
+ findTouchedWindowAtLocked(displayId, x, y, nullptr, isStylus);
if (touchedWindowHandle != nullptr &&
touchedWindowHandle->getApplicationToken() !=
mAwaitedFocusedApplication->getApplicationToken()) {
@@ -1045,6 +1049,7 @@
sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x,
int32_t y, TouchState* touchState,
+ bool isStylus,
bool addOutsideTargets,
bool ignoreDragWindow) {
if (addOutsideTargets && touchState == nullptr) {
@@ -1058,7 +1063,7 @@
}
const WindowInfo& info = *windowHandle->getInfo();
- if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y)) {
+ if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y, isStylus)) {
return windowHandle;
}
@@ -1070,16 +1075,15 @@
return nullptr;
}
-std::vector<sp<WindowInfoHandle>> InputDispatcher::findTouchedSpyWindowsAtLocked(int32_t displayId,
- int32_t x,
- int32_t y) const {
+std::vector<sp<WindowInfoHandle>> InputDispatcher::findTouchedSpyWindowsAtLocked(
+ int32_t displayId, int32_t x, int32_t y, bool isStylus) const {
// Traverse windows from front to back and gather the touched spy windows.
std::vector<sp<WindowInfoHandle>> spyWindows;
const auto& windowHandles = getWindowHandlesLocked(displayId);
for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
const WindowInfo& info = *windowHandle->getInfo();
- if (!windowAcceptsTouchAt(info, displayId, x, y)) {
+ if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus)) {
continue;
}
if (!info.isSpy()) {
@@ -2062,8 +2066,9 @@
y = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y));
}
const bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN;
+ const bool isStylus = isPointerFromStylus(entry, pointerIndex);
newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState,
- isDown /*addOutsideTargets*/);
+ isStylus, isDown /*addOutsideTargets*/);
// Handle the case where we did not find a window.
if (newTouchedWindowHandle == nullptr) {
@@ -2100,7 +2105,7 @@
}
std::vector<sp<WindowInfoHandle>> newTouchedWindows =
- findTouchedSpyWindowsAtLocked(displayId, x, y);
+ findTouchedSpyWindowsAtLocked(displayId, x, y, isStylus);
if (newTouchedWindowHandle != nullptr) {
// Process the foreground window first so that it is the first to receive the event.
newTouchedWindows.insert(newTouchedWindows.begin(), newTouchedWindowHandle);
@@ -2213,9 +2218,11 @@
const int32_t x = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
const int32_t y = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
+ const bool isStylus = isPointerFromStylus(entry, 0 /*pointerIndex*/);
sp<WindowInfoHandle> oldTouchedWindowHandle =
tempTouchState.getFirstForegroundWindowHandle();
- newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState);
+ newTouchedWindowHandle =
+ findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, isStylus);
// Drop touch events if requested by input feature
if (newTouchedWindowHandle != nullptr &&
@@ -2477,8 +2484,12 @@
}
void InputDispatcher::finishDragAndDrop(int32_t displayId, float x, float y) {
+ // Prevent stylus interceptor windows from affecting drag and drop behavior for now, until we
+ // have an explicit reason to support it.
+ constexpr bool isStylus = false;
+
const sp<WindowInfoHandle> dropWindow =
- findTouchedWindowAtLocked(displayId, x, y, nullptr /*touchState*/,
+ findTouchedWindowAtLocked(displayId, x, y, nullptr /*touchState*/, isStylus,
false /*addOutsideTargets*/, true /*ignoreDragWindow*/);
if (dropWindow) {
vec2 local = dropWindow->getInfo()->transform.transform(x, y);
@@ -2511,8 +2522,12 @@
return;
}
+ // Prevent stylus interceptor windows from affecting drag and drop behavior for now, until
+ // we have an explicit reason to support it.
+ constexpr bool isStylus = false;
+
const sp<WindowInfoHandle> hoverWindowHandle =
- findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/,
+ findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/, isStylus,
false /*addOutsideTargets*/, true /*ignoreDragWindow*/);
// enqueue drag exit if needed.
if (hoverWindowHandle != mDragState->dragHoverWindowHandle &&
@@ -3815,7 +3830,7 @@
originalMotionEntry.xCursorPosition,
originalMotionEntry.yCursorPosition,
originalMotionEntry.downTime, splitPointerCount,
- splitPointerProperties, splitPointerCoords, 0, 0);
+ splitPointerProperties, splitPointerCoords);
if (originalMotionEntry.injectionState) {
splitMotionEntry->injectionState = originalMotionEntry.injectionState;
@@ -4041,7 +4056,7 @@
args->xPrecision, args->yPrecision,
args->xCursorPosition, args->yCursorPosition,
args->downTime, args->pointerCount,
- args->pointerProperties, args->pointerCoords, 0, 0);
+ args->pointerProperties, args->pointerCoords);
if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID &&
IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER &&
@@ -4271,10 +4286,8 @@
motionEvent.getRawXCursorPosition(),
motionEvent.getRawYCursorPosition(),
motionEvent.getDownTime(), uint32_t(pointerCount),
- pointerProperties, samplePointerCoords,
- motionEvent.getXOffset(),
- motionEvent.getYOffset());
- transformMotionEntryForInjectionLocked(*injectedEntry);
+ pointerProperties, samplePointerCoords);
+ transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform());
injectedEntries.push(std::move(injectedEntry));
for (size_t i = motionEvent.getHistorySize(); i > 0; i--) {
sampleEventTimes += 1;
@@ -4293,9 +4306,9 @@
motionEvent.getRawYCursorPosition(),
motionEvent.getDownTime(),
uint32_t(pointerCount), pointerProperties,
- samplePointerCoords, motionEvent.getXOffset(),
- motionEvent.getYOffset());
- transformMotionEntryForInjectionLocked(*nextInjectedEntry);
+ samplePointerCoords);
+ transformMotionEntryForInjectionLocked(*nextInjectedEntry,
+ motionEvent.getTransform());
injectedEntries.push(std::move(nextInjectedEntry));
}
break;
@@ -4459,35 +4472,28 @@
}
}
-void InputDispatcher::transformMotionEntryForInjectionLocked(MotionEntry& entry) const {
- const bool isRelativeMouseEvent = isFromSource(entry.source, AINPUT_SOURCE_MOUSE_RELATIVE);
- if (!isRelativeMouseEvent && !isFromSource(entry.source, AINPUT_SOURCE_CLASS_POINTER)) {
- return;
- }
-
+void InputDispatcher::transformMotionEntryForInjectionLocked(
+ MotionEntry& entry, const ui::Transform& injectedTransform) const {
// Input injection works in the logical display coordinate space, but the input pipeline works
// display space, so we need to transform the injected events accordingly.
const auto it = mDisplayInfos.find(entry.displayId);
if (it == mDisplayInfos.end()) return;
- const auto& transformToDisplay = it->second.transform.inverse();
+ const auto& transformToDisplay = it->second.transform.inverse() * injectedTransform;
for (uint32_t i = 0; i < entry.pointerCount; i++) {
PointerCoords& pc = entry.pointerCoords[i];
- const auto xy = isRelativeMouseEvent
- ? transformWithoutTranslation(transformToDisplay, pc.getX(), pc.getY())
- : transformToDisplay.transform(pc.getXYValue());
- pc.setAxisValue(AMOTION_EVENT_AXIS_X, xy.x);
- pc.setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y);
+ // Make a copy of the injected coords. We cannot change them in place because some of them
+ // are interdependent (for example, X coordinate might depend on the Y coordinate).
+ PointerCoords injectedCoords = entry.pointerCoords[i];
- // Axes with relative values never represent points on a screen, so they should never have
- // translation applied. If a device does not report relative values, these values are always
- // 0, and will remain unaffected by the following operation.
- const auto rel =
- transformWithoutTranslation(transformToDisplay,
- pc.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
- pc.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y));
- pc.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, rel.x);
- pc.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, rel.y);
+ BitSet64 bits(injectedCoords.bits);
+ while (!bits.isEmpty()) {
+ const auto axis = static_cast<int32_t>(bits.clearFirstMarkedBit());
+ const float value =
+ MotionEvent::calculateTransformedAxisValue(axis, entry.source,
+ transformToDisplay, injectedCoords);
+ pc.setAxisValue(axis, value);
+ }
}
}
@@ -4685,15 +4691,27 @@
ALOGD("setInputWindows displayId=%" PRId32 " %s", displayId, windowList.c_str());
}
- // Ensure all tokens are null if the window has feature NO_INPUT_CHANNEL
+ // Check preconditions for new input windows
for (const sp<WindowInfoHandle>& window : windowInfoHandles) {
- const bool noInputWindow =
- window->getInfo()->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL);
+ const WindowInfo& info = *window->getInfo();
+
+ // Ensure all tokens are null if the window has feature NO_INPUT_CHANNEL
+ const bool noInputWindow = info.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL);
if (noInputWindow && window->getToken() != nullptr) {
ALOGE("%s has feature NO_INPUT_WINDOW, but a non-null token. Clearing",
window->getName().c_str());
window->releaseChannel();
}
+
+ // Ensure all spy windows are trusted overlays
+ LOG_ALWAYS_FATAL_IF(info.isSpy() && !info.trustedOverlay,
+ "%s has feature SPY, but is not a trusted overlay.",
+ window->getName().c_str());
+
+ // Ensure all stylus interceptors are trusted overlays
+ LOG_ALWAYS_FATAL_IF(info.interceptsStylus() && !info.trustedOverlay,
+ "%s has feature INTERCEPTS_STYLUS, but is not a trusted overlay.",
+ window->getName().c_str());
}
// Copy old handles for release if they are no longer present.
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index fb9c81b..ee50ec5 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -234,16 +234,12 @@
// to transfer focus to a new application.
std::shared_ptr<EventEntry> mNextUnblockedEvent GUARDED_BY(mLock);
- sp<android::gui::WindowInfoHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x,
- int32_t y, TouchState* touchState,
- bool addOutsideTargets = false,
- bool ignoreDragWindow = false)
- REQUIRES(mLock);
+ sp<android::gui::WindowInfoHandle> findTouchedWindowAtLocked(
+ int32_t displayId, int32_t x, int32_t y, TouchState* touchState, bool isStylus = false,
+ bool addOutsideTargets = false, bool ignoreDragWindow = false) REQUIRES(mLock);
- std::vector<sp<android::gui::WindowInfoHandle>> findTouchedSpyWindowsAtLocked(int32_t displayId,
- int32_t x,
- int32_t y) const
- REQUIRES(mLock);
+ std::vector<sp<android::gui::WindowInfoHandle>> findTouchedSpyWindowsAtLocked(
+ int32_t displayId, int32_t x, int32_t y, bool isStylus) const REQUIRES(mLock);
sp<Connection> getConnectionLocked(const sp<IBinder>& inputConnectionToken) const
REQUIRES(mLock);
@@ -287,7 +283,9 @@
bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
void setInjectionResult(EventEntry& entry,
android::os::InputEventInjectionResult injectionResult);
- void transformMotionEntryForInjectionLocked(MotionEntry&) const REQUIRES(mLock);
+ void transformMotionEntryForInjectionLocked(MotionEntry&,
+ const ui::Transform& injectedTransform) const
+ REQUIRES(mLock);
std::condition_variable mInjectionSyncFinished;
void incrementPendingForegroundDispatches(EventEntry& entry);
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index 3bb0bc9..ad3c615 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -296,8 +296,7 @@
memento.yPrecision, memento.xCursorPosition,
memento.yCursorPosition, memento.downTime,
memento.pointerCount, memento.pointerProperties,
- memento.pointerCoords, 0 /*xOffset*/,
- 0 /*yOffset*/));
+ memento.pointerCoords));
}
}
return events;
@@ -349,8 +348,7 @@
AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
memento.yPrecision, memento.xCursorPosition,
memento.yCursorPosition, memento.downTime,
- pointerCount, pointerProperties, pointerCoords,
- 0 /*xOffset*/, 0 /*yOffset*/));
+ pointerCount, pointerProperties, pointerCoords));
}
memento.firstNewPointerIdx = INVALID_POINTER_INDEX;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index ba70929..0814bc2 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -1003,6 +1003,7 @@
mInfo.ownerPid = INJECTOR_PID;
mInfo.ownerUid = INJECTOR_UID;
mInfo.displayId = displayId;
+ mInfo.trustedOverlay = false;
}
sp<FakeWindowHandle> clone(
@@ -1054,7 +1055,9 @@
void setFlags(Flags<WindowInfo::Flag> flags) { mInfo.flags = flags; }
- void setInputFeatures(WindowInfo::Feature features) { mInfo.inputFeatures = features; }
+ void setInputFeatures(Flags<WindowInfo::Feature> features) { mInfo.inputFeatures = features; }
+
+ void setTrustedOverlay(bool trustedOverlay) { mInfo.trustedOverlay = trustedOverlay; }
void setWindowTransform(float dsdx, float dtdx, float dtdy, float dsdy) {
mInfo.transform.set(dsdx, dtdx, dtdy, dsdy);
@@ -2183,6 +2186,33 @@
secondWindow->assertNoEvents();
}
+// Ensure that when a MotionEvent that has a custom transform is injected, the post-transformed
+// event should be treated as being in the logical display space.
+TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisplaySpace) {
+ auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
+
+ const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0};
+ ui::Transform injectedEventTransform;
+ injectedEventTransform.set(matrix);
+ const vec2 expectedPoint{75, 55}; // The injected point in the logical display space.
+ const vec2 untransformedPoint = injectedEventTransform.inverse().transform(expectedPoint);
+
+ MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(untransformedPoint.x)
+ .y(untransformedPoint.y))
+ .build();
+ event.transform(matrix);
+
+ injectMotionEvent(mDispatcher, event, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT);
+
+ firstWindow->consumeMotionDown();
+ secondWindow->assertNoEvents();
+}
+
TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) {
auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
@@ -6297,6 +6327,7 @@
sp<FakeWindowHandle> spy =
new FakeWindowHandle(application, mDispatcher, name.c_str(), ADISPLAY_ID_DEFAULT);
spy->setInputFeatures(WindowInfo::Feature::SPY);
+ spy->setTrustedOverlay(true);
spy->addFlags(flags);
return spy;
}
@@ -6315,6 +6346,16 @@
};
/**
+ * Adding a spy window that is not a trusted overlay causes Dispatcher to abort.
+ */
+TEST_F(InputDispatcherSpyWindowTest, UntrustedSpy_AbortsDispatcher) {
+ auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ spy->setTrustedOverlay(false);
+ ASSERT_DEATH(mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}}),
+ ".* not a trusted overlay");
+}
+
+/**
* Input injection into a display with a spy window but no foreground windows should succeed.
*/
TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) {
@@ -6474,28 +6515,6 @@
}
/**
- * When configured to block untrusted touches, events will not be dispatched to windows below a spy
- * window if it is not a trusted overly.
- */
-TEST_F(InputDispatcherSpyWindowTest, BlockUntrustedTouches) {
- mDispatcher->setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode::BLOCK);
-
- auto window = createForeground();
- auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
- window->setOwnerInfo(111, 111);
- spy->setOwnerInfo(222, 222);
- spy->setTouchOcclusionMode(TouchOcclusionMode::BLOCK_UNTRUSTED);
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
-
- // Inject an event outside the spy window's frame and touchable region.
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- spy->consumeMotionDown();
- window->assertNoEvents();
-}
-
-/**
* A spy window can pilfer pointers. When this happens, touch gestures that are currently sent to
* any other windows - including other spy windows - will also be cancelled.
*/
@@ -6600,4 +6619,97 @@
spyRight->consumeMotionDown();
}
+class InputDispatcherStylusInterceptorTest : public InputDispatcherTest {
+public:
+ std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupStylusOverlayScenario() {
+ std::shared_ptr<FakeApplicationHandle> overlayApplication =
+ std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> overlay =
+ new FakeWindowHandle(overlayApplication, mDispatcher, "Stylus interceptor window",
+ ADISPLAY_ID_DEFAULT);
+ overlay->setFocusable(false);
+ overlay->setOwnerInfo(111, 111);
+ overlay->setFlags(WindowInfo::Flag::NOT_TOUCHABLE | WindowInfo::Flag::SPLIT_TOUCH);
+ overlay->setInputFeatures(WindowInfo::Feature::INTERCEPTS_STYLUS);
+ overlay->setTrustedOverlay(true);
+
+ std::shared_ptr<FakeApplicationHandle> application =
+ std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Application window",
+ ADISPLAY_ID_DEFAULT);
+ window->setFocusable(true);
+ window->setOwnerInfo(222, 222);
+ window->setFlags(WindowInfo::Flag::SPLIT_TOUCH);
+
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}});
+ setFocusedWindow(window);
+ window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
+ return {std::move(overlay), std::move(window)};
+ }
+
+ void sendFingerEvent(int32_t action) {
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
+ ADISPLAY_ID_DEFAULT, {PointF{20, 20}});
+ mDispatcher->notifyMotion(&motionArgs);
+ }
+
+ void sendStylusEvent(int32_t action) {
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
+ ADISPLAY_ID_DEFAULT, {PointF{30, 40}});
+ motionArgs.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+ mDispatcher->notifyMotion(&motionArgs);
+ }
+};
+
+TEST_F(InputDispatcherStylusInterceptorTest, UntrustedOverlay_AbortsDispatcher) {
+ auto [overlay, window] = setupStylusOverlayScenario();
+ overlay->setTrustedOverlay(false);
+ // Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort.
+ ASSERT_DEATH(mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}),
+ ".* not a trusted overlay");
+}
+
+TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) {
+ auto [overlay, window] = setupStylusOverlayScenario();
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}});
+
+ sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
+ overlay->consumeMotionDown();
+ sendStylusEvent(AMOTION_EVENT_ACTION_UP);
+ overlay->consumeMotionUp();
+
+ sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
+ window->consumeMotionDown();
+ sendFingerEvent(AMOTION_EVENT_ACTION_UP);
+ window->consumeMotionUp();
+
+ overlay->assertNoEvents();
+ window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) {
+ auto [overlay, window] = setupStylusOverlayScenario();
+ overlay->setInputFeatures(overlay->getInfo()->inputFeatures | WindowInfo::Feature::SPY);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}});
+
+ sendStylusEvent(AMOTION_EVENT_ACTION_DOWN);
+ overlay->consumeMotionDown();
+ window->consumeMotionDown();
+ sendStylusEvent(AMOTION_EVENT_ACTION_UP);
+ overlay->consumeMotionUp();
+ window->consumeMotionUp();
+
+ sendFingerEvent(AMOTION_EVENT_ACTION_DOWN);
+ window->consumeMotionDown();
+ sendFingerEvent(AMOTION_EVENT_ACTION_UP);
+ window->consumeMotionUp();
+
+ overlay->assertNoEvents();
+ window->assertNoEvents();
+}
+
} // namespace android::inputdispatcher