Merge "Revert "libvulkan: Implement EXT_swapchain_maintenance1""
diff --git a/include/audiomanager/AudioManager.h b/include/audiomanager/AudioManager.h
index 6794fbf..43048db 100644
--- a/include/audiomanager/AudioManager.h
+++ b/include/audiomanager/AudioManager.h
@@ -40,9 +40,17 @@
PLAYER_UPDATE_DEVICE_ID = 5,
PLAYER_UPDATE_PORT_ID = 6,
PLAYER_UPDATE_MUTED = 7,
+ PLAYER_UPDATE_FORMAT = 8,
} player_state_t;
static constexpr char
+ kExtraPlayerEventSpatializedKey[] = "android.media.extra.PLAYER_EVENT_SPATIALIZED";
+static constexpr char
+ kExtraPlayerEventSampleRateKey[] = "android.media.extra.PLAYER_EVENT_SAMPLE_RATE";
+static constexpr char
+ kExtraPlayerEventChannelMaskKey[] = "android.media.extra.PLAYER_EVENT_CHANNEL_MASK";
+
+static constexpr char
kExtraPlayerEventMuteKey[] = "android.media.extra.PLAYER_EVENT_MUTE";
enum {
PLAYER_MUTE_MASTER = (1 << 0),
diff --git a/include/input/Input.h b/include/input/Input.h
index 015efdd..1a35196 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -203,6 +203,13 @@
*/
vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy);
+/*
+ * Transform an angle on the x-y plane. An angle of 0 radians corresponds to "north" or
+ * pointing upwards in the negative Y direction, a positive angle points towards the right, and a
+ * negative angle points towards the left.
+ */
+float transformAngle(const ui::Transform& transform, float angleRadians);
+
const char* inputEventTypeToString(int32_t type);
std::string inputEventSourceToString(int32_t source);
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index ee081c4..44ff62b 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1475,7 +1475,7 @@
#ifdef BINDER_WITH_KERNEL_IPC
flat_binder_object obj;
obj.hdr.type = BINDER_TYPE_FD;
- obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
+ obj.flags = 0;
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
obj.handle = fd;
obj.cookie = takeOwnership ? 1 : 0;
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 9e8ebf3..d893cb9 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -46,25 +46,6 @@
namespace {
-float transformAngle(const ui::Transform& transform, float angleRadians) {
- // Construct and transform a vector oriented at the specified clockwise angle from vertical.
- // Coordinate system: down is increasing Y, right is increasing X.
- float x = sinf(angleRadians);
- float y = -cosf(angleRadians);
- vec2 transformedPoint = transform.transform(x, y);
-
- // Determine how the origin is transformed by the matrix so that we
- // can transform orientation vectors.
- const vec2 origin = transform.transform(0, 0);
-
- transformedPoint.x -= origin.x;
- transformedPoint.y -= origin.y;
-
- // Derive the transformed vector's clockwise angle from vertical.
- // The return value of atan2f is in range [-pi, pi] which conforms to the orientation API.
- return atan2f(transformedPoint.x, -transformedPoint.y);
-}
-
bool shouldDisregardTransformation(uint32_t source) {
// Do not apply any transformations to axes from joysticks, touchpads, or relative mice.
return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK) ||
@@ -172,6 +153,25 @@
return transformedXy - transformedOrigin;
}
+float transformAngle(const ui::Transform& transform, float angleRadians) {
+ // Construct and transform a vector oriented at the specified clockwise angle from vertical.
+ // Coordinate system: down is increasing Y, right is increasing X.
+ float x = sinf(angleRadians);
+ float y = -cosf(angleRadians);
+ vec2 transformedPoint = transform.transform(x, y);
+
+ // Determine how the origin is transformed by the matrix so that we
+ // can transform orientation vectors.
+ const vec2 origin = transform.transform(0, 0);
+
+ transformedPoint.x -= origin.x;
+ transformedPoint.y -= origin.y;
+
+ // Derive the transformed vector's clockwise angle from vertical.
+ // The return value of atan2f is in range [-pi, pi] which conforms to the orientation API.
+ return atan2f(transformedPoint.x, -transformedPoint.y);
+}
+
const char* inputEventTypeToString(int32_t type) {
switch (type) {
case AINPUT_EVENT_TYPE_KEY: {
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index bbafbff..cf927db 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -617,15 +617,27 @@
static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::R_8) ==
AHARDWAREBUFFER_FORMAT_R8_UNORM,
"HAL and AHardwareBuffer pixel format don't match");
+ static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::R_16_UINT) ==
+ AHARDWAREBUFFER_FORMAT_R16_UINT,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::RG_1616_UINT) ==
+ AHARDWAREBUFFER_FORMAT_R16G16_UINT,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::RGBA_10101010) ==
+ AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
switch (format) {
case AHARDWAREBUFFER_FORMAT_R8_UNORM:
+ case AHARDWAREBUFFER_FORMAT_R16_UINT:
+ case AHARDWAREBUFFER_FORMAT_R16G16_UINT:
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
+ case AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM:
case AHARDWAREBUFFER_FORMAT_BLOB:
case AHARDWAREBUFFER_FORMAT_D16_UNORM:
case AHARDWAREBUFFER_FORMAT_D24_UNORM:
@@ -677,6 +689,7 @@
return 1;
case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
case AHARDWAREBUFFER_FORMAT_D16_UNORM:
+ case AHARDWAREBUFFER_FORMAT_R16_UINT:
return 2;
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
case AHARDWAREBUFFER_FORMAT_D24_UNORM:
@@ -686,8 +699,10 @@
case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
+ case AHARDWAREBUFFER_FORMAT_R16G16_UINT:
return 4;
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
+ case AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM:
return 8;
default:
return 0;
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index c35507b..b2e8bea 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -173,6 +173,27 @@
* OpenGL ES: GR_GL_R8
*/
AHARDWAREBUFFER_FORMAT_R8_UNORM = 0x38,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_R16_UINT
+ * OpenGL ES: GR_GL_R16UI
+ */
+ AHARDWAREBUFFER_FORMAT_R16_UINT = 0x39,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_R16G16_UINT
+ * OpenGL ES: GR_GL_RG16UI
+ */
+ AHARDWAREBUFFER_FORMAT_R16G16_UINT = 0x3a,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16
+ * OpenGL ES: N/A
+ */
+ AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM = 0x3b,
};
/**
diff --git a/libs/ui/include/ui/PixelFormat.h b/libs/ui/include/ui/PixelFormat.h
index f422ce4..cf5c2e8 100644
--- a/libs/ui/include/ui/PixelFormat.h
+++ b/libs/ui/include/ui/PixelFormat.h
@@ -53,16 +53,19 @@
// real pixel formats supported for rendering -----------------------------
- PIXEL_FORMAT_RGBA_8888 = HAL_PIXEL_FORMAT_RGBA_8888, // 4x8-bit RGBA
- PIXEL_FORMAT_RGBX_8888 = HAL_PIXEL_FORMAT_RGBX_8888, // 4x8-bit RGB0
- PIXEL_FORMAT_RGB_888 = HAL_PIXEL_FORMAT_RGB_888, // 3x8-bit RGB
- PIXEL_FORMAT_RGB_565 = HAL_PIXEL_FORMAT_RGB_565, // 16-bit RGB
- PIXEL_FORMAT_BGRA_8888 = HAL_PIXEL_FORMAT_BGRA_8888, // 4x8-bit BGRA
- PIXEL_FORMAT_RGBA_5551 = 6, // 16-bit ARGB
- PIXEL_FORMAT_RGBA_4444 = 7, // 16-bit ARGB
- PIXEL_FORMAT_RGBA_FP16 = HAL_PIXEL_FORMAT_RGBA_FP16, // 64-bit RGBA
- PIXEL_FORMAT_RGBA_1010102 = HAL_PIXEL_FORMAT_RGBA_1010102, // 32-bit RGBA
- PIXEL_FORMAT_R_8 = 0x38,
+ PIXEL_FORMAT_RGBA_8888 = HAL_PIXEL_FORMAT_RGBA_8888, // 4x8-bit RGBA
+ PIXEL_FORMAT_RGBX_8888 = HAL_PIXEL_FORMAT_RGBX_8888, // 4x8-bit RGB0
+ PIXEL_FORMAT_RGB_888 = HAL_PIXEL_FORMAT_RGB_888, // 3x8-bit RGB
+ PIXEL_FORMAT_RGB_565 = HAL_PIXEL_FORMAT_RGB_565, // 16-bit RGB
+ PIXEL_FORMAT_BGRA_8888 = HAL_PIXEL_FORMAT_BGRA_8888, // 4x8-bit BGRA
+ PIXEL_FORMAT_RGBA_5551 = 6, // 16-bit ARGB
+ PIXEL_FORMAT_RGBA_4444 = 7, // 16-bit ARGB
+ PIXEL_FORMAT_RGBA_FP16 = HAL_PIXEL_FORMAT_RGBA_FP16, // 64-bit RGBA
+ PIXEL_FORMAT_RGBA_1010102 = HAL_PIXEL_FORMAT_RGBA_1010102, // 32-bit RGBA
+ PIXEL_FORMAT_R_8 = 0x38,
+ PIXEL_FORMAT_R_16_UINT = 0x39,
+ PIXEL_FORMAT_RG_1616_UINT = 0x3a,
+ PIXEL_FORMAT_RGBA_10101010 = 0x3b,
};
typedef int32_t PixelFormat;
diff --git a/opengl/TEST_MAPPING b/opengl/TEST_MAPPING
index d391dce..7c50a94 100644
--- a/opengl/TEST_MAPPING
+++ b/opengl/TEST_MAPPING
@@ -2,6 +2,9 @@
"presubmit": [
{
"name": "CtsGpuToolsHostTestCases"
+ },
+ {
+ "name": "EGL_test"
}
]
}
diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp
index 51c9376..d96a895 100644
--- a/opengl/tests/EGLTest/Android.bp
+++ b/opengl/tests/EGLTest/Android.bp
@@ -1,4 +1,3 @@
-
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
@@ -11,6 +10,7 @@
cc_test {
name: "EGL_test",
+ test_suites: ["general-tests"],
srcs: [
"egl_cache_test.cpp",
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index bbd786d..cbe4ef9 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -343,6 +343,11 @@
}
TEST_F(EGLTest, EGLDisplayP31010102) {
+ // This test has been failing since:
+ // libEGL: When driver doesn't understand P3, map sRGB-encoded P3 to sRGB
+ // https://android-review.git.corp.google.com/c/platform/frameworks/native/+/793504
+ GTEST_SKIP() << "Skipping broken test. See b/120714942 and b/117104367";
+
EGLint numConfigs;
EGLConfig config;
EGLBoolean success;
@@ -866,6 +871,12 @@
EGLConfig config;
EGLBoolean success;
+ if (!hasWideColorDisplay) {
+ // skip this test if device does not have wide-color display
+ RecordProperty("hasWideColorDisplay", false);
+ return;
+ }
+
const EGLint attrs[] = {
// clang-format off
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
@@ -951,6 +962,12 @@
TEST_F(EGLTest, EGLCreateWindowTwoColorspaces) {
EGLConfig config;
+ if (!hasWideColorDisplay) {
+ // skip this test if device does not have wide-color display
+ RecordProperty("hasWideColorDisplay", false);
+ return;
+ }
+
ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
struct MockConsumer : public BnConsumerListener {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 4aac377..906bb1b 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2060,6 +2060,12 @@
if (touchedWindow.windowHandle->getInfo()->supportsSplitTouch()) {
continue;
}
+ if (touchedWindow.windowHandle->getInfo()->inputConfig.test(
+ gui::WindowInfo::InputConfig::IS_WALLPAPER)) {
+ // Wallpaper window should not affect whether or not touch is split
+ continue;
+ }
+
// Eventually, touchedWindow will contain the deviceId of each pointer that's currently
// being sent there. For now, use deviceId from touch state.
if (entry.deviceId == touchState.deviceId && !touchedWindow.pointerIds.isEmpty()) {
@@ -2223,6 +2229,32 @@
tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds,
entry.eventTime);
+
+ // If this is the pointer going down and the touched window has a wallpaper
+ // then also add the touched wallpaper windows so they are locked in for the duration
+ // of the touch gesture.
+ // We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper
+ // engine only supports touch events. We would need to add a mechanism similar
+ // to View.onGenericMotionEvent to enable wallpapers to handle these events.
+ if (maskedAction == AMOTION_EVENT_ACTION_DOWN ||
+ maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) {
+ if (targetFlags.test(InputTarget::Flags::FOREGROUND) &&
+ windowHandle->getInfo()->inputConfig.test(
+ gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
+ sp<WindowInfoHandle> wallpaper = findWallpaperWindowBelow(windowHandle);
+ if (wallpaper != nullptr) {
+ ftl::Flags<InputTarget::Flags> wallpaperFlags =
+ InputTarget::Flags::WINDOW_IS_OBSCURED |
+ InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED |
+ InputTarget::Flags::DISPATCH_AS_IS;
+ if (isSplit) {
+ wallpaperFlags |= InputTarget::Flags::SPLIT;
+ }
+ tempTouchState.addOrUpdateWindow(wallpaper, wallpaperFlags, pointerIds,
+ entry.eventTime);
+ }
+ }
+ }
}
// If any existing window is pilfering pointers from newly added window, remove it
@@ -2307,6 +2339,10 @@
pointerIds.markBit(entry.pointerProperties[0].id);
tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds,
entry.eventTime);
+
+ // Check if the wallpaper window should deliver the corresponding event.
+ slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle,
+ tempTouchState, pointerIds);
}
}
@@ -2413,38 +2449,6 @@
}
}
- // If this is the first pointer going down and the touched window has a wallpaper
- // then also add the touched wallpaper windows so they are locked in for the duration
- // of the touch gesture.
- // We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper
- // engine only supports touch events. We would need to add a mechanism similar
- // to View.onGenericMotionEvent to enable wallpapers to handle these events.
- if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
- sp<WindowInfoHandle> foregroundWindowHandle =
- tempTouchState.getFirstForegroundWindowHandle();
- if (foregroundWindowHandle &&
- foregroundWindowHandle->getInfo()->inputConfig.test(
- WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
- const std::vector<sp<WindowInfoHandle>>& windowHandles =
- getWindowHandlesLocked(displayId);
- for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
- const WindowInfo* info = windowHandle->getInfo();
- if (info->displayId == displayId &&
- windowHandle->getInfo()->inputConfig.test(
- WindowInfo::InputConfig::IS_WALLPAPER)) {
- BitSet32 pointerIds;
- pointerIds.markBit(entry.pointerProperties[0].id);
- tempTouchState.addOrUpdateWindow(windowHandle,
- InputTarget::Flags::WINDOW_IS_OBSCURED |
- InputTarget::Flags::
- WINDOW_IS_PARTIALLY_OBSCURED |
- InputTarget::Flags::DISPATCH_AS_IS,
- pointerIds, entry.eventTime);
- }
- }
- }
- }
-
// Success! Output targets.
touchedWindows = tempTouchState.windows;
outInjectionResult = InputEventInjectionResult::SUCCEEDED;
@@ -3726,7 +3730,8 @@
}
void InputDispatcher::synthesizePointerDownEventsForConnectionLocked(
- const nsecs_t downTime, const sp<Connection>& connection) {
+ const nsecs_t downTime, const sp<Connection>& connection,
+ ftl::Flags<InputTarget::Flags> targetFlags) {
if (connection->status == Connection::Status::BROKEN) {
return;
}
@@ -3752,7 +3757,7 @@
target.globalScaleFactor = windowInfo->globalScaleFactor;
}
target.inputChannel = connection->inputChannel;
- target.flags = InputTarget::Flags::DISPATCH_AS_IS;
+ target.flags = targetFlags;
const bool wasEmpty = connection->outboundQueue.empty();
for (std::unique_ptr<EventEntry>& downEventEntry : downEvents) {
@@ -3787,6 +3792,16 @@
}
}
+void InputDispatcher::synthesizeCancelationEventsForWindowLocked(
+ const sp<WindowInfoHandle>& windowHandle, const CancelationOptions& options) {
+ if (windowHandle != nullptr) {
+ sp<Connection> wallpaperConnection = getConnectionLocked(windowHandle->getToken());
+ if (wallpaperConnection != nullptr) {
+ synthesizeCancelationEventsForConnectionLocked(wallpaperConnection, options);
+ }
+ }
+}
+
std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent(
const MotionEntry& originalMotionEntry, BitSet32 pointerIds, nsecs_t splitDownTime) {
ALOG_ASSERT(pointerIds.value != 0);
@@ -4847,14 +4862,7 @@
touchedWindow.windowHandle->getInfo()->inputConfig.test(
gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
sp<WindowInfoHandle> wallpaper = state.getWallpaperWindow();
- if (wallpaper != nullptr) {
- sp<Connection> wallpaperConnection =
- getConnectionLocked(wallpaper->getToken());
- if (wallpaperConnection != nullptr) {
- synthesizeCancelationEventsForConnectionLocked(wallpaperConnection,
- options);
- }
- }
+ synthesizeCancelationEventsForWindowLocked(wallpaper, options);
}
}
state.windows.erase(state.windows.begin() + i);
@@ -5155,6 +5163,7 @@
// Erase old window.
ftl::Flags<InputTarget::Flags> oldTargetFlags = touchedWindow->targetFlags;
BitSet32 pointerIds = touchedWindow->pointerIds;
+ sp<WindowInfoHandle> fromWindowHandle = touchedWindow->windowHandle;
state->removeWindowByToken(fromToken);
// Add new window.
@@ -5187,7 +5196,12 @@
options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
"transferring touch focus from this window to another window");
synthesizeCancelationEventsForConnectionLocked(fromConnection, options);
- synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, toConnection);
+ synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, toConnection,
+ newTargetFlags);
+
+ // Check if the wallpaper window should deliver the corresponding event.
+ transferWallpaperTouch(oldTargetFlags, newTargetFlags, fromWindowHandle, toWindowHandle,
+ *state, pointerIds);
}
} // release lock
@@ -6465,4 +6479,100 @@
mMonitorDispatchingTimeout = timeout;
}
+void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags,
+ const sp<WindowInfoHandle>& oldWindowHandle,
+ const sp<WindowInfoHandle>& newWindowHandle,
+ TouchState& state, const BitSet32& pointerIds) {
+ const bool oldHasWallpaper = oldWindowHandle->getInfo()->inputConfig.test(
+ gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER);
+ const bool newHasWallpaper = targetFlags.test(InputTarget::Flags::FOREGROUND) &&
+ newWindowHandle->getInfo()->inputConfig.test(
+ gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER);
+ const sp<WindowInfoHandle> oldWallpaper =
+ oldHasWallpaper ? state.getWallpaperWindow() : nullptr;
+ const sp<WindowInfoHandle> newWallpaper =
+ newHasWallpaper ? findWallpaperWindowBelow(newWindowHandle) : nullptr;
+ if (oldWallpaper == newWallpaper) {
+ return;
+ }
+
+ if (oldWallpaper != nullptr) {
+ state.addOrUpdateWindow(oldWallpaper, InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT,
+ BitSet32(0));
+ }
+
+ if (newWallpaper != nullptr) {
+ state.addOrUpdateWindow(newWallpaper,
+ InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER |
+ InputTarget::Flags::WINDOW_IS_OBSCURED |
+ InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED,
+ pointerIds);
+ }
+}
+
+void InputDispatcher::transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldTargetFlags,
+ ftl::Flags<InputTarget::Flags> newTargetFlags,
+ const sp<WindowInfoHandle> fromWindowHandle,
+ const sp<WindowInfoHandle> toWindowHandle,
+ TouchState& state, const BitSet32& pointerIds) {
+ const bool oldHasWallpaper = oldTargetFlags.test(InputTarget::Flags::FOREGROUND) &&
+ fromWindowHandle->getInfo()->inputConfig.test(
+ gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER);
+ const bool newHasWallpaper = newTargetFlags.test(InputTarget::Flags::FOREGROUND) &&
+ toWindowHandle->getInfo()->inputConfig.test(
+ gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER);
+
+ const sp<WindowInfoHandle> oldWallpaper =
+ oldHasWallpaper ? state.getWallpaperWindow() : nullptr;
+ const sp<WindowInfoHandle> newWallpaper =
+ newHasWallpaper ? findWallpaperWindowBelow(toWindowHandle) : nullptr;
+ if (oldWallpaper == newWallpaper) {
+ return;
+ }
+
+ if (oldWallpaper != nullptr) {
+ CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
+ "transferring touch focus to another window");
+ state.removeWindowByToken(oldWallpaper->getToken());
+ synthesizeCancelationEventsForWindowLocked(oldWallpaper, options);
+ }
+
+ if (newWallpaper != nullptr) {
+ nsecs_t downTimeInTarget = now();
+ ftl::Flags<InputTarget::Flags> wallpaperFlags =
+ oldTargetFlags & (InputTarget::Flags::SPLIT | InputTarget::Flags::DISPATCH_AS_IS);
+ wallpaperFlags |= InputTarget::Flags::WINDOW_IS_OBSCURED |
+ InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED;
+ state.addOrUpdateWindow(newWallpaper, wallpaperFlags, pointerIds, downTimeInTarget);
+ sp<Connection> wallpaperConnection = getConnectionLocked(newWallpaper->getToken());
+ if (wallpaperConnection != nullptr) {
+ sp<Connection> toConnection = getConnectionLocked(toWindowHandle->getToken());
+ toConnection->inputState.mergePointerStateTo(wallpaperConnection->inputState);
+ synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, wallpaperConnection,
+ wallpaperFlags);
+ }
+ }
+}
+
+sp<WindowInfoHandle> InputDispatcher::findWallpaperWindowBelow(
+ const sp<WindowInfoHandle>& windowHandle) const {
+ const std::vector<sp<WindowInfoHandle>>& windowHandles =
+ getWindowHandlesLocked(windowHandle->getInfo()->displayId);
+ bool foundWindow = false;
+ for (const sp<WindowInfoHandle>& otherHandle : windowHandles) {
+ if (!foundWindow && otherHandle != windowHandle) {
+ continue;
+ }
+ if (windowHandle == otherHandle) {
+ foundWindow = true;
+ continue;
+ }
+
+ if (otherHandle->getInfo()->inputConfig.test(WindowInfo::InputConfig::IS_WALLPAPER)) {
+ return otherHandle;
+ }
+ }
+ return nullptr;
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 5efb39e..a32ebd3 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -628,9 +628,14 @@
REQUIRES(mLock);
void synthesizePointerDownEventsForConnectionLocked(const nsecs_t downTime,
- const sp<Connection>& connection)
+ const sp<Connection>& connection,
+ ftl::Flags<InputTarget::Flags> targetFlags)
REQUIRES(mLock);
+ void synthesizeCancelationEventsForWindowLocked(
+ const sp<android::gui::WindowInfoHandle>& windowHandle,
+ const CancelationOptions& options) REQUIRES(mLock);
+
// Splitting motion events across windows. When splitting motion event for a target,
// splitDownTime refers to the time of first 'down' event on that particular target
std::unique_ptr<MotionEntry> splitMotionEvent(const MotionEntry& originalMotionEntry,
@@ -691,6 +696,19 @@
bool recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);
sp<InputReporterInterface> mReporter;
+
+ void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags,
+ const sp<android::gui::WindowInfoHandle>& oldWindowHandle,
+ const sp<android::gui::WindowInfoHandle>& newWindowHandle,
+ TouchState& state, const BitSet32& pointerIds) REQUIRES(mLock);
+ void transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldTargetFlags,
+ ftl::Flags<InputTarget::Flags> newTargetFlags,
+ const sp<android::gui::WindowInfoHandle> fromWindowHandle,
+ const sp<android::gui::WindowInfoHandle> toWindowHandle,
+ TouchState& state, const BitSet32& pointerIds) REQUIRES(mLock);
+
+ sp<android::gui::WindowInfoHandle> findWallpaperWindowBelow(
+ const sp<android::gui::WindowInfoHandle>& windowHandle) const REQUIRES(mLock);
};
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 160f9eb..9a7af40 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -51,9 +51,8 @@
return base::StringPrintf("%dx%d", size.width, size.height);
}
-static bool isPointInRect(const Rect& rect, int32_t x, int32_t y) {
- // Consider all four sides as "inclusive".
- return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
+static bool isPointInRect(const Rect& rect, vec2 p) {
+ return p.x >= rect.left && p.x < rect.right && p.y >= rect.top && p.y < rect.bottom;
}
template <typename T>
@@ -81,29 +80,12 @@
return value >= 8 ? value - 16 : value;
}
-static std::tuple<ui::Size /*displayBounds*/, Rect /*physicalFrame*/> getNaturalDisplayInfo(
- const DisplayViewport& viewport, ui::Rotation naturalOrientation) {
+static ui::Size getNaturalDisplaySize(const DisplayViewport& viewport) {
ui::Size rotatedDisplaySize{viewport.deviceWidth, viewport.deviceHeight};
- if (naturalOrientation == ui::ROTATION_90 || naturalOrientation == ui::ROTATION_270) {
+ if (viewport.orientation == ui::ROTATION_90 || viewport.orientation == ui::ROTATION_270) {
std::swap(rotatedDisplaySize.width, rotatedDisplaySize.height);
}
-
- ui::Transform rotate(ui::Transform::toRotationFlags(naturalOrientation),
- rotatedDisplaySize.width, rotatedDisplaySize.height);
-
- Rect physicalFrame{viewport.physicalLeft, viewport.physicalTop, viewport.physicalRight,
- viewport.physicalBottom};
- physicalFrame = rotate.transform(physicalFrame);
-
- LOG_ALWAYS_FATAL_IF(!physicalFrame.isValid());
- if (physicalFrame.isEmpty()) {
- ALOGE("Viewport is not set properly: %s", viewport.toString().c_str());
- physicalFrame.right =
- physicalFrame.left + (physicalFrame.width() == 0 ? 1 : physicalFrame.width());
- physicalFrame.bottom =
- physicalFrame.top + (physicalFrame.height() == 0 ? 1 : physicalFrame.height());
- }
- return {rotatedDisplaySize, physicalFrame};
+ return rotatedDisplaySize;
}
// --- RawPointerData ---
@@ -197,18 +179,6 @@
if (mCursorScrollAccumulator.haveRelativeHWheel()) {
info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
}
- if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::BOX) {
- const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
- const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
- info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat, x.fuzz,
- x.resolution);
- info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat, y.fuzz,
- y.resolution);
- info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat, x.fuzz,
- x.resolution);
- info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat, y.fuzz,
- y.resolution);
- }
info->setButtonUnderPad(mParameters.hasButtonUnderPad);
info->setSupportsUsi(mParameters.supportsUsi);
}
@@ -224,10 +194,10 @@
dumpDisplay(dump);
dump += StringPrintf(INDENT3 "Translation and Scaling Factors:\n");
- dump += StringPrintf(INDENT4 "XScale: %0.3f\n", mXScale);
- dump += StringPrintf(INDENT4 "YScale: %0.3f\n", mYScale);
- dump += StringPrintf(INDENT4 "XPrecision: %0.3f\n", mXPrecision);
- dump += StringPrintf(INDENT4 "YPrecision: %0.3f\n", mYPrecision);
+ mRawToDisplay.dump(dump, "RawToDisplay Transform:", INDENT4);
+ mRawRotation.dump(dump, "RawRotation Transform:", INDENT4);
+ dump += StringPrintf(INDENT4 "OrientedXPrecision: %0.3f\n", mOrientedXPrecision);
+ dump += StringPrintf(INDENT4 "OrientedYPrecision: %0.3f\n", mOrientedYPrecision);
dump += StringPrintf(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale);
dump += StringPrintf(INDENT4 "PressureScale: %0.3f\n", mPressureScale);
dump += StringPrintf(INDENT4 "SizeScale: %0.3f\n", mSizeScale);
@@ -687,10 +657,10 @@
void TouchInputMapper::initializeOrientedRanges() {
// Configure X and Y factors.
- mXScale = float(mDisplayBounds.width) / mRawPointerAxes.getRawWidth();
- mYScale = float(mDisplayBounds.height) / mRawPointerAxes.getRawHeight();
- mXPrecision = 1.0f / mXScale;
- mYPrecision = 1.0f / mYScale;
+ const float orientedScaleX = mRawToDisplay.getScaleX();
+ const float orientedScaleY = mRawToDisplay.getScaleY();
+ mOrientedXPrecision = 1.0f / orientedScaleX;
+ mOrientedYPrecision = 1.0f / orientedScaleY;
mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X;
mOrientedRanges.x.source = mSource;
@@ -700,7 +670,7 @@
// Scale factor for terms that are not oriented in a particular axis.
// If the pixels are square then xScale == yScale otherwise we fake it
// by choosing an average.
- mGeometricScale = avg(mXScale, mYScale);
+ mGeometricScale = avg(orientedScaleX, orientedScaleY);
initializeSizeRanges();
@@ -817,44 +787,74 @@
// Compute oriented precision, scales and ranges.
// Note that the maximum value reported is an inclusive maximum value so it is one
// unit less than the total width or height of the display.
+ // TODO(b/20508709): Calculate the oriented ranges using the input device's raw frame.
switch (mInputDeviceOrientation) {
case ui::ROTATION_90:
case ui::ROTATION_270:
- mOrientedXPrecision = mYPrecision;
- mOrientedYPrecision = mXPrecision;
-
mOrientedRanges.x.min = 0;
mOrientedRanges.x.max = mDisplayBounds.height - 1;
mOrientedRanges.x.flat = 0;
mOrientedRanges.x.fuzz = 0;
- mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale;
+ mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mRawToDisplay.getScaleY();
mOrientedRanges.y.min = 0;
mOrientedRanges.y.max = mDisplayBounds.width - 1;
mOrientedRanges.y.flat = 0;
mOrientedRanges.y.fuzz = 0;
- mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale;
+ mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mRawToDisplay.getScaleX();
break;
default:
- mOrientedXPrecision = mXPrecision;
- mOrientedYPrecision = mYPrecision;
-
mOrientedRanges.x.min = 0;
mOrientedRanges.x.max = mDisplayBounds.width - 1;
mOrientedRanges.x.flat = 0;
mOrientedRanges.x.fuzz = 0;
- mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale;
+ mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mRawToDisplay.getScaleX();
mOrientedRanges.y.min = 0;
mOrientedRanges.y.max = mDisplayBounds.height - 1;
mOrientedRanges.y.flat = 0;
mOrientedRanges.y.fuzz = 0;
- mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale;
+ mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mRawToDisplay.getScaleY();
break;
}
}
+void TouchInputMapper::computeInputTransforms() {
+ const ui::Size rawSize{mRawPointerAxes.getRawWidth(), mRawPointerAxes.getRawHeight()};
+
+ ui::Size rotatedRawSize = rawSize;
+ if (mInputDeviceOrientation == ui::ROTATION_270 || mInputDeviceOrientation == ui::ROTATION_90) {
+ std::swap(rotatedRawSize.width, rotatedRawSize.height);
+ }
+ const auto rotationFlags = ui::Transform::toRotationFlags(-mInputDeviceOrientation);
+ mRawRotation = ui::Transform{rotationFlags};
+
+ // Step 1: Undo the raw offset so that the raw coordinate space now starts at (0, 0).
+ ui::Transform undoRawOffset;
+ undoRawOffset.set(-mRawPointerAxes.x.minValue, -mRawPointerAxes.y.minValue);
+
+ // Step 2: Rotate the raw coordinates to the expected orientation.
+ ui::Transform rotate;
+ // When rotating raw coordinates, the raw size will be used as an offset.
+ // Account for the extra unit added to the raw range when the raw size was calculated.
+ rotate.set(rotationFlags, rotatedRawSize.width - 1, rotatedRawSize.height - 1);
+
+ // Step 3: Scale the raw coordinates to the display space.
+ ui::Transform scaleToDisplay;
+ const float xScale = static_cast<float>(mDisplayBounds.width) / rotatedRawSize.width;
+ const float yScale = static_cast<float>(mDisplayBounds.height) / rotatedRawSize.height;
+ scaleToDisplay.set(xScale, 0, 0, yScale);
+
+ mRawToDisplay = (scaleToDisplay * (rotate * undoRawOffset));
+
+ // Calculate the transform that takes raw coordinates to the rotated display space.
+ ui::Transform displayToRotatedDisplay;
+ displayToRotatedDisplay.set(ui::Transform::toRotationFlags(-mViewport.orientation),
+ mViewport.deviceWidth, mViewport.deviceHeight);
+ mRawToRotatedDisplay = displayToRotatedDisplay * mRawToDisplay;
+}
+
void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) {
const DeviceMode oldDeviceMode = mDeviceMode;
@@ -926,14 +926,9 @@
if (mDeviceMode == DeviceMode::DIRECT || mDeviceMode == DeviceMode::POINTER) {
const auto oldDisplayBounds = mDisplayBounds;
- // Apply the inverse of the input device orientation so that the input device is
- // configured in the same orientation as the viewport. The input device orientation will
- // be re-applied by mInputDeviceOrientation.
- const ui::Rotation naturalDeviceOrientation =
- mViewport.orientation - mParameters.orientation;
-
- std::tie(mDisplayBounds, mPhysicalFrameInDisplay) =
- getNaturalDisplayInfo(mViewport, naturalDeviceOrientation);
+ mDisplayBounds = getNaturalDisplaySize(mViewport);
+ mPhysicalFrameInRotatedDisplay = {mViewport.physicalLeft, mViewport.physicalTop,
+ mViewport.physicalRight, mViewport.physicalBottom};
// InputReader works in the un-rotated display coordinate space, so we don't need to do
// anything if the device is already orientation-aware. If the device is not
@@ -950,10 +945,14 @@
// Apply the input device orientation for the device.
mInputDeviceOrientation = mInputDeviceOrientation + mParameters.orientation;
+ computeInputTransforms();
} else {
mDisplayBounds = rawSize;
- mPhysicalFrameInDisplay = Rect{mDisplayBounds};
+ mPhysicalFrameInRotatedDisplay = Rect{mDisplayBounds};
mInputDeviceOrientation = ui::ROTATION_0;
+ mRawToDisplay.reset();
+ mRawToDisplay.set(-mRawPointerAxes.x.minValue, -mRawPointerAxes.y.minValue);
+ mRawToRotatedDisplay = mRawToDisplay;
}
}
@@ -1036,7 +1035,8 @@
void TouchInputMapper::dumpDisplay(std::string& dump) {
dump += StringPrintf(INDENT3 "%s\n", mViewport.toString().c_str());
dump += StringPrintf(INDENT3 "DisplayBounds: %s\n", toString(mDisplayBounds).c_str());
- dump += StringPrintf(INDENT3 "PhysicalFrame: %s\n", toString(mPhysicalFrameInDisplay).c_str());
+ dump += StringPrintf(INDENT3 "PhysicalFrameInRotatedDisplay: %s\n",
+ toString(mPhysicalFrameInRotatedDisplay).c_str());
dump += StringPrintf(INDENT3 "InputDeviceOrientation: %d\n", mInputDeviceOrientation);
}
@@ -1197,19 +1197,6 @@
if (in.tryGetProperty("touch.distance.scale", distanceScale)) {
out.distanceScale = distanceScale;
}
-
- out.coverageCalibration = Calibration::CoverageCalibration::DEFAULT;
- std::string coverageCalibrationString;
- if (in.tryGetProperty("touch.coverage.calibration", coverageCalibrationString)) {
- if (coverageCalibrationString == "none") {
- out.coverageCalibration = Calibration::CoverageCalibration::NONE;
- } else if (coverageCalibrationString == "box") {
- out.coverageCalibration = Calibration::CoverageCalibration::BOX;
- } else if (coverageCalibrationString != "default") {
- ALOGW("Invalid value for touch.coverage.calibration: '%s'",
- coverageCalibrationString.c_str());
- }
- }
}
void TouchInputMapper::resolveCalibration() {
@@ -1248,11 +1235,6 @@
} else {
mCalibration.distanceCalibration = Calibration::DistanceCalibration::NONE;
}
-
- // Coverage
- if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::DEFAULT) {
- mCalibration.coverageCalibration = Calibration::CoverageCalibration::NONE;
- }
}
void TouchInputMapper::dumpCalibration(std::string& dump) {
@@ -1323,17 +1305,6 @@
if (mCalibration.distanceScale) {
dump += StringPrintf(INDENT4 "touch.distance.scale: %0.3f\n", *mCalibration.distanceScale);
}
-
- switch (mCalibration.coverageCalibration) {
- case Calibration::CoverageCalibration::NONE:
- dump += INDENT4 "touch.coverage.calibration: none\n";
- break;
- case Calibration::CoverageCalibration::BOX:
- dump += INDENT4 "touch.coverage.calibration: box\n";
- break;
- default:
- ALOG_ASSERT(false);
- }
}
void TouchInputMapper::dumpAffineTransformation(std::string& dump) {
@@ -2290,20 +2261,20 @@
if (mHaveTilt) {
float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale;
float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale;
- orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle));
+ orientation = transformAngle(mRawRotation, atan2f(-sinf(tiltXAngle), sinf(tiltYAngle)));
tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle));
} else {
tilt = 0;
switch (mCalibration.orientationCalibration) {
case Calibration::OrientationCalibration::INTERPOLATED:
- orientation = in.orientation * mOrientationScale;
+ orientation = transformAngle(mRawRotation, in.orientation * mOrientationScale);
break;
case Calibration::OrientationCalibration::VECTOR: {
int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4);
int32_t c2 = signExtendNybble(in.orientation & 0x0f);
if (c1 != 0 || c2 != 0) {
- orientation = atan2f(c1, c2) * 0.5f;
+ orientation = transformAngle(mRawRotation, atan2f(c1, c2) * 0.5f);
float confidence = hypotf(c1, c2);
float scale = 1.0f + confidence / 16.0f;
touchMajor *= scale;
@@ -2330,76 +2301,16 @@
distance = 0;
}
- // Coverage
- int32_t rawLeft, rawTop, rawRight, rawBottom;
- switch (mCalibration.coverageCalibration) {
- case Calibration::CoverageCalibration::BOX:
- rawLeft = (in.toolMinor & 0xffff0000) >> 16;
- rawRight = in.toolMinor & 0x0000ffff;
- rawBottom = in.toolMajor & 0x0000ffff;
- rawTop = (in.toolMajor & 0xffff0000) >> 16;
- break;
- default:
- rawLeft = rawTop = rawRight = rawBottom = 0;
- break;
- }
-
- // Adjust X,Y coords for device calibration
- // TODO: Adjust coverage coords?
- float xTransformed = in.x, yTransformed = in.y;
- mAffineTransform.applyTo(xTransformed, yTransformed);
- rotateAndScale(xTransformed, yTransformed);
-
- // Adjust X, Y, and coverage coords for input device orientation.
- float left, top, right, bottom;
-
- switch (mInputDeviceOrientation) {
- case ui::ROTATION_90:
- left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale;
- right = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale;
- bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale;
- top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale;
- orientation -= M_PI_2;
- if (mOrientedRanges.orientation && orientation < mOrientedRanges.orientation->min) {
- orientation +=
- (mOrientedRanges.orientation->max - mOrientedRanges.orientation->min);
- }
- break;
- case ui::ROTATION_180:
- left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale;
- right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale;
- bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale;
- top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale;
- orientation -= M_PI;
- if (mOrientedRanges.orientation && orientation < mOrientedRanges.orientation->min) {
- orientation +=
- (mOrientedRanges.orientation->max - mOrientedRanges.orientation->min);
- }
- break;
- case ui::ROTATION_270:
- left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale;
- right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale;
- bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale;
- top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale;
- orientation += M_PI_2;
- if (mOrientedRanges.orientation && orientation > mOrientedRanges.orientation->max) {
- orientation -=
- (mOrientedRanges.orientation->max - mOrientedRanges.orientation->min);
- }
- break;
- default:
- left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale;
- right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale;
- bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale;
- top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale;
- break;
- }
+ // Adjust X,Y coords for device calibration and convert to the natural display coordinates.
+ vec2 transformed = {in.x, in.y};
+ mAffineTransform.applyTo(transformed.x /*byRef*/, transformed.y /*byRef*/);
+ transformed = mRawToDisplay.transform(transformed);
// Write output coords.
PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i];
out.clear();
- out.setAxisValue(AMOTION_EVENT_AXIS_X, xTransformed);
- out.setAxisValue(AMOTION_EVENT_AXIS_Y, yTransformed);
+ out.setAxisValue(AMOTION_EVENT_AXIS_X, transformed.x);
+ out.setAxisValue(AMOTION_EVENT_AXIS_Y, transformed.y);
out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size);
out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor);
@@ -2407,23 +2318,16 @@
out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation);
out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt);
out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance);
- if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::BOX) {
- out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left);
- out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top);
- out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right);
- out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom);
- } else {
- out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor);
- out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor);
- }
+ out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor);
+ out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor);
// Write output relative fields 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);
+ float dx = transformed.x - p.getAxisValue(AMOTION_EVENT_AXIS_X);
+ float dy = transformed.y - p.getAxisValue(AMOTION_EVENT_AXIS_Y);
out.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, dx);
out.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, dy);
}
@@ -3796,48 +3700,10 @@
return out;
}
-// Transform input device coordinates to display panel coordinates.
-void TouchInputMapper::rotateAndScale(float& x, float& y) const {
- const float xScaled = float(x - mRawPointerAxes.x.minValue) * mXScale;
- const float yScaled = float(y - mRawPointerAxes.y.minValue) * mYScale;
-
- const float xScaledMax = float(mRawPointerAxes.x.maxValue - x) * mXScale;
- const float yScaledMax = float(mRawPointerAxes.y.maxValue - y) * mYScale;
-
- // Rotate to display coordinate.
- // 0 - no swap and reverse.
- // 90 - swap x/y and reverse y.
- // 180 - reverse x, y.
- // 270 - swap x/y and reverse x.
- switch (mInputDeviceOrientation) {
- case ui::ROTATION_0:
- x = xScaled;
- y = yScaled;
- break;
- case ui::ROTATION_90:
- y = xScaledMax;
- x = yScaled;
- break;
- case ui::ROTATION_180:
- x = xScaledMax;
- y = yScaledMax;
- break;
- case ui::ROTATION_270:
- y = xScaled;
- x = yScaledMax;
- break;
- default:
- assert(false);
- }
-}
-
bool TouchInputMapper::isPointInsidePhysicalFrame(int32_t x, int32_t y) const {
- const float xScaled = (x - mRawPointerAxes.x.minValue) * mXScale;
- const float yScaled = (y - mRawPointerAxes.y.minValue) * mYScale;
-
return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue &&
y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue &&
- isPointInRect(mPhysicalFrameInDisplay, xScaled, yScaled);
+ isPointInRect(mPhysicalFrameInRotatedDisplay, mRawToRotatedDisplay.transform(x, y));
}
const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) {
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 50a7ea3..6e35b46 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -291,14 +291,6 @@
DistanceCalibration distanceCalibration;
std::optional<float> distanceScale;
- enum class CoverageCalibration {
- DEFAULT,
- NONE,
- BOX,
- };
-
- CoverageCalibration coverageCalibration;
-
inline void applySizeScaleAndBias(float& outSize) const {
if (sizeScale) {
outSize *= *sizeScale;
@@ -410,21 +402,26 @@
// Always starts at (0, 0).
ui::Size mDisplayBounds{ui::kInvalidSize};
- // The physical frame is the rectangle in the natural display's coordinate space that maps to
+ // The physical frame is the rectangle in the rotated display's coordinate space that maps to
// the logical display frame.
- Rect mPhysicalFrameInDisplay{Rect::INVALID_RECT};
+ Rect mPhysicalFrameInRotatedDisplay{Rect::INVALID_RECT};
// The orientation of the input device relative to that of the display panel. It specifies
// the rotation of the input device coordinates required to produce the display panel
// orientation, so it will depend on whether the device is orientation aware.
ui::Rotation mInputDeviceOrientation;
- // Translation and scaling factors, orientation-independent.
- float mXScale;
- float mXPrecision;
+ // The transform that maps the input device's raw coordinate space to the un-rotated display's
+ // coordinate space. InputReader generates events in the un-rotated display's coordinate space.
+ ui::Transform mRawToDisplay;
- float mYScale;
- float mYPrecision;
+ // The transform that maps the input device's raw coordinate space to the rotated display's
+ // coordinate space. This used to perform hit-testing of raw events with the physical frame in
+ // the rotated coordinate space. See mPhysicalFrameInRotatedDisplay.
+ ui::Transform mRawToRotatedDisplay;
+
+ // The transform used for non-planar raw axes, such as orientation and tilt.
+ ui::Transform mRawRotation;
float mGeometricScale;
@@ -813,7 +810,7 @@
static void assignPointerIds(const RawState& last, RawState& current);
- void rotateAndScale(float& x, float& y) const;
+ void computeInputTransforms();
void configureDeviceType();
};
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index d2ff097..864aaea 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -64,6 +64,8 @@
AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
static constexpr int32_t POINTER_3_DOWN =
AMOTION_EVENT_ACTION_POINTER_DOWN | (3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+static constexpr int32_t POINTER_0_UP =
+ AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
static constexpr int32_t POINTER_1_UP =
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
@@ -83,6 +85,9 @@
static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms;
+static constexpr int expectedWallpaperFlags =
+ AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+
struct PointF {
float x;
float y;
@@ -1738,8 +1743,6 @@
sp<FakeWindowHandle> wallpaperWindow =
sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
wallpaperWindow->setIsWallpaper(true);
- constexpr int expectedWallpaperFlags =
- AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -1782,8 +1785,6 @@
sp<FakeWindowHandle> wallpaperWindow =
sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
wallpaperWindow->setIsWallpaper(true);
- constexpr int expectedWallpaperFlags =
- AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -1813,24 +1814,27 @@
foregroundWindow->consumeMotionCancel();
}
+class ShouldSplitTouchFixture : public InputDispatcherTest,
+ public ::testing::WithParamInterface<bool> {};
+INSTANTIATE_TEST_SUITE_P(InputDispatcherTest, ShouldSplitTouchFixture,
+ ::testing::Values(true, false));
/**
* A single window that receives touch (on top), and a wallpaper window underneath it.
* The top window gets a multitouch gesture.
* Ensure that wallpaper gets the same gesture.
*/
-TEST_F(InputDispatcherTest, WallpaperWindow_ReceivesMultiTouch) {
+TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
- window->setDupTouchToWallpaper(true);
+ sp<FakeWindowHandle> foregroundWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
+ foregroundWindow->setDupTouchToWallpaper(true);
+ foregroundWindow->setPreventSplitting(GetParam());
sp<FakeWindowHandle> wallpaperWindow =
sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
wallpaperWindow->setIsWallpaper(true);
- constexpr int expectedWallpaperFlags =
- AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, wallpaperWindow}}});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}});
// Touch down on top window
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -1839,7 +1843,7 @@
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
// Both top window and its wallpaper should receive the touch down
- window->consumeMotionDown();
+ foregroundWindow->consumeMotionDown();
wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
// Second finger down on the top window
@@ -1858,11 +1862,34 @@
InputEventInjectionSync::WAIT_FOR_RESULT))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- window->consumeMotionPointerDown(1 /* pointerIndex */);
+ foregroundWindow->consumeMotionPointerDown(1 /* pointerIndex */);
wallpaperWindow->consumeMotionPointerDown(1 /* pointerIndex */, ADISPLAY_ID_DEFAULT,
expectedWallpaperFlags);
- window->assertNoEvents();
- wallpaperWindow->assertNoEvents();
+
+ const MotionEvent secondFingerUpEvent =
+ MotionEventBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(100)
+ .y(100))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(150)
+ .y(150))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ foregroundWindow->consumeMotionPointerUp(0);
+ wallpaperWindow->consumeMotionPointerUp(0, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {100, 100}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ foregroundWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+ wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
}
/**
@@ -1889,8 +1916,6 @@
sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
wallpaperWindow->setFrame(Rect(0, 0, 400, 200));
wallpaperWindow->setIsWallpaper(true);
- constexpr int expectedWallpaperFlags =
- AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
mDispatcher->setInputWindows(
{{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow, wallpaperWindow}}});
@@ -1955,62 +1980,49 @@
wallpaperWindow->assertNoEvents();
}
-TEST_F(InputDispatcherTest, WallpaperWindowReceivesMultiTouch) {
+/**
+ * Two windows: a window on the left with dup touch to wallpaper and window on the right without it.
+ * The touch slips to the right window. so left window and wallpaper should receive ACTION_CANCEL
+ * The right window should receive ACTION_DOWN.
+ */
+TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
- window->setDupTouchToWallpaper(true);
+ sp<FakeWindowHandle> leftWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
+ leftWindow->setFrame(Rect(0, 0, 200, 200));
+ leftWindow->setDupTouchToWallpaper(true);
+ leftWindow->setSlippery(true);
+
+ sp<FakeWindowHandle> rightWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
+ rightWindow->setFrame(Rect(200, 0, 400, 200));
sp<FakeWindowHandle> wallpaperWindow =
sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
wallpaperWindow->setIsWallpaper(true);
- constexpr int expectedWallpaperFlags =
- AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
- wallpaperWindow->setPreventSplitting(true);
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, wallpaperWindow}}});
+ mDispatcher->setInputWindows(
+ {{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow, wallpaperWindow}}});
+ // Touch down on left window
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
- {50, 50}))
+ {100, 100}))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+ // Both foreground window and its wallpaper should receive the touch down
+ leftWindow->consumeMotionDown();
wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
- const MotionEvent secondFingerDownEvent =
- MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
- .displayId(ADISPLAY_ID_DEFAULT)
- .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
- .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
- .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10))
- .build();
+ // Move to right window, the left window should receive cancel.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
- InputEventInjectionSync::WAIT_FOR_RESULT))
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {201, 100}))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- window->consumeMotionPointerDown(1);
- wallpaperWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
-
- const MotionEvent secondFingerUpEvent =
- MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
- .displayId(ADISPLAY_ID_DEFAULT)
- .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
- .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
- .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10))
- .build();
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
- InputEventInjectionSync::WAIT_FOR_RESULT))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- window->consumeMotionPointerUp(1);
- wallpaperWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
-
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50}))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- window->consumeMotionUp(ADISPLAY_ID_DEFAULT);
- wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+ leftWindow->consumeMotionCancel();
+ rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
}
/**
@@ -2858,21 +2870,26 @@
sp<FakeWindowHandle> firstWindow =
sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
ADISPLAY_ID_DEFAULT);
+ firstWindow->setDupTouchToWallpaper(true);
sp<FakeWindowHandle> secondWindow =
sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
ADISPLAY_ID_DEFAULT);
-
+ sp<FakeWindowHandle> wallpaper =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
+ wallpaper->setIsWallpaper(true);
// Add the windows to the dispatcher
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow, wallpaper}}});
// Send down to the first window
NotifyMotionArgs downMotionArgs =
generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
ADISPLAY_ID_DEFAULT);
mDispatcher->notifyMotion(&downMotionArgs);
+
// Only the first window should get the down event
firstWindow->consumeMotionDown();
secondWindow->assertNoEvents();
+ wallpaper->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
// Transfer touch to the second window
TransferFunction f = GetParam();
@@ -2881,6 +2898,7 @@
// The first window gets cancel and the second gets down
firstWindow->consumeMotionCancel();
secondWindow->consumeMotionDown();
+ wallpaper->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
// Send up event to the second window
NotifyMotionArgs upMotionArgs =
@@ -2890,6 +2908,7 @@
// The first window gets no events and the second gets up
firstWindow->assertNoEvents();
secondWindow->consumeMotionUp();
+ wallpaper->assertNoEvents();
}
/**
@@ -3013,6 +3032,65 @@
secondWindow->consumeMotionUp();
}
+TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+ // Create a couple of windows
+ sp<FakeWindowHandle> firstWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
+ ADISPLAY_ID_DEFAULT);
+ firstWindow->setDupTouchToWallpaper(true);
+ sp<FakeWindowHandle> secondWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
+ ADISPLAY_ID_DEFAULT);
+ secondWindow->setDupTouchToWallpaper(true);
+
+ sp<FakeWindowHandle> wallpaper1 =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper1", ADISPLAY_ID_DEFAULT);
+ wallpaper1->setIsWallpaper(true);
+
+ sp<FakeWindowHandle> wallpaper2 =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper2", ADISPLAY_ID_DEFAULT);
+ wallpaper2->setIsWallpaper(true);
+ // Add the windows to the dispatcher
+ mDispatcher->setInputWindows(
+ {{ADISPLAY_ID_DEFAULT, {firstWindow, wallpaper1, secondWindow, wallpaper2}}});
+
+ // Send down to the first window
+ NotifyMotionArgs downMotionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&downMotionArgs);
+
+ // Only the first window should get the down event
+ firstWindow->consumeMotionDown();
+ secondWindow->assertNoEvents();
+ wallpaper1->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+ wallpaper2->assertNoEvents();
+
+ // Transfer touch focus to the second window
+ TransferFunction f = GetParam();
+ bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
+ ASSERT_TRUE(success);
+
+ // The first window gets cancel and the second gets down
+ firstWindow->consumeMotionCancel();
+ secondWindow->consumeMotionDown();
+ wallpaper1->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+ wallpaper2->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+
+ // Send up event to the second window
+ NotifyMotionArgs upMotionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&upMotionArgs);
+ // The first window gets no events and the second gets up
+ firstWindow->assertNoEvents();
+ secondWindow->consumeMotionUp();
+ wallpaper1->assertNoEvents();
+ wallpaper2->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+}
+
// For the cases of single pointer touch and two pointers non-split touch, the api's
// 'transferTouch' and 'transferTouchFocus' are equivalent in behaviour. They only differ
// for the case where there are multiple pointers split across several windows.
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index ef2080f..96d27b8 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -5553,7 +5553,7 @@
// Rotation 90.
clearViewports();
prepareDisplay(ui::ROTATION_90);
- processDown(mapper, toRawX(75), RAW_Y_MAX - toRawY(50) + RAW_Y_MIN);
+ processDown(mapper, toRotatedRawX(75), RAW_Y_MAX - toRotatedRawY(50) + RAW_Y_MIN);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
@@ -5581,7 +5581,7 @@
// Rotation 270.
clearViewports();
prepareDisplay(ui::ROTATION_270);
- processDown(mapper, RAW_X_MAX - toRawX(75) + RAW_X_MIN, toRawY(50));
+ processDown(mapper, RAW_X_MAX - toRotatedRawX(75) + RAW_X_MIN, toRotatedRawY(50));
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
@@ -5718,7 +5718,7 @@
// Orientation 90, Rotation 90.
clearViewports();
prepareDisplay(ui::ROTATION_90);
- processDown(mapper, toRotatedRawX(50), toRotatedRawY(75));
+ processDown(mapper, toRawX(50), toRawY(75));
processSync(mapper);
EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
@@ -5746,8 +5746,7 @@
// Orientation 90, Rotation 270.
clearViewports();
prepareDisplay(ui::ROTATION_270);
- processDown(mapper, RAW_X_MAX - toRotatedRawX(50) + RAW_X_MIN,
- RAW_Y_MAX - toRotatedRawY(75) + RAW_Y_MIN);
+ processDown(mapper, RAW_X_MAX - toRawX(50) + RAW_X_MIN, RAW_Y_MAX - toRawY(75) + RAW_Y_MIN);
processSync(mapper);
EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
@@ -5759,6 +5758,61 @@
EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
}
+TEST_F(SingleTouchInputMapperTest, Process_IgnoresTouchesOutsidePhysicalFrame) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareButtons();
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.orientationAware", "1");
+ prepareDisplay(ui::ROTATION_0);
+ auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+
+ // Set a physical frame in the display viewport.
+ auto viewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL);
+ viewport->physicalLeft = 20;
+ viewport->physicalTop = 600;
+ viewport->physicalRight = 30;
+ viewport->physicalBottom = 610;
+ mFakePolicy->updateViewport(*viewport);
+ configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+ // Start the touch.
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_TOUCH, 1);
+ processSync(mapper);
+
+ // Expect all input starting outside the physical frame to be ignored.
+ const std::array<Point, 6> outsidePoints = {
+ {{0, 0}, {19, 605}, {31, 605}, {25, 599}, {25, 611}, {DISPLAY_WIDTH, DISPLAY_HEIGHT}}};
+ for (const auto& p : outsidePoints) {
+ processMove(mapper, toRawX(p.x), toRawY(p.y));
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+ }
+
+ // Move the touch into the physical frame.
+ processMove(mapper, toRawX(25), toRawY(605));
+ processSync(mapper);
+ NotifyMotionArgs args;
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
+ EXPECT_NEAR(25, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(605, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+
+ // Once the touch down is reported, continue reporting input, even if it is outside the frame.
+ for (const auto& p : outsidePoints) {
+ processMove(mapper, toRawX(p.x), toRawY(p.y));
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+ EXPECT_NEAR(p.x, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(p.y, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+ }
+
+ processUp(mapper);
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(
+ mFakeListener->assertNotifyMotionWasCalled(WithMotionAction(AMOTION_EVENT_ACTION_UP)));
+}
+
TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(ui::ROTATION_0);
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
index 4f5842a..14d08f8 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
@@ -61,7 +61,7 @@
std::chrono::nanoseconds(800us).count();
// The lowest Render Frame Rate that will ever be selected
- static constexpr Fps kMinSupportedFrameRate = 20_Hz;
+ static constexpr Fps kMinSupportedFrameRate = 1_Hz;
class Policy {
static constexpr int kAllowGroupSwitchingDefault = false;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b930477..3dd86aa 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -440,6 +440,9 @@
property_get("debug.sf.treat_170m_as_sRGB", value, "0");
mTreat170mAsSrgb = atoi(value);
+ mIgnoreHwcPhysicalDisplayOrientation =
+ base::GetBoolProperty("debug.sf.ignore_hwc_physical_display_orientation"s, false);
+
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
// comes online to attempt to read the property. The property is
@@ -2442,7 +2445,8 @@
if (!id) {
return ui::ROTATION_0;
}
- if (getHwComposer().getComposer()->isSupported(
+ if (!mIgnoreHwcPhysicalDisplayOrientation &&
+ getHwComposer().getComposer()->isSupported(
Hwc2::Composer::OptionalFeature::PhysicalDisplayOrientation)) {
switch (getHwComposer().getPhysicalDisplayOrientation(*id)) {
case Hwc2::AidlTransform::ROT_90:
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7bb0514..23ac19e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -311,6 +311,11 @@
// on this behavior to increase contrast for some media sources.
bool mTreat170mAsSrgb = false;
+ // Allows to ignore physical orientation provided through hwc API in favour of
+ // 'ro.surface_flinger.primary_display_orientation'.
+ // TODO(b/246793311): Clean up a temporary property
+ bool mIgnoreHwcPhysicalDisplayOrientation = false;
+
protected:
// We're reference counted, never destroy SurfaceFlinger directly
virtual ~SurfaceFlinger();
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index a3b3c4c..79d02dd 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -141,6 +141,12 @@
RefreshRateSelectorTest();
~RefreshRateSelectorTest();
+ // Represents the number of refresh rates possible
+ // from 1_Hz to 90_hz, including fractional rates.
+ static constexpr size_t kTotalRefreshRates120 = 120;
+ // Represents the number of refresh rates possible
+ // from 1_Hz to 120_hz, including fractional rates.
+ static constexpr size_t kTotalRefreshRates216 = 216;
static constexpr DisplayModeId kModeId60{0};
static constexpr DisplayModeId kModeId90{1};
static constexpr DisplayModeId kModeId72{2};
@@ -1129,7 +1135,12 @@
return {{90_Hz, kMode90}, {60_Hz, kMode60}, {45_Hz, kMode90}, {30_Hz, kMode30}};
}
}();
- ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+
+ if (GetParam() == Config::FrameRateOverride::Enabled) {
+ ASSERT_EQ(kTotalRefreshRates120, refreshRates.size());
+ } else {
+ ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+ }
for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].frameRateMode)
@@ -1155,10 +1166,18 @@
case Config::FrameRateOverride::AppOverride:
return {{30_Hz, kMode30}, {60_Hz, kMode60}, {90_Hz, kMode90}};
case Config::FrameRateOverride::Enabled:
- return {{30_Hz, kMode30}, {45_Hz, kMode90}, {60_Hz, kMode60}, {90_Hz, kMode90}};
+ return {{1_Hz, kMode30},
+ {1.011_Hz, kMode90},
+ {1.016_Hz, kMode60},
+ {1.022_Hz, kMode90}};
}
}();
- ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+
+ if (GetParam() == Config::FrameRateOverride::Enabled) {
+ ASSERT_EQ(kTotalRefreshRates120, refreshRates.size());
+ } else {
+ ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+ }
for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].frameRateMode)
@@ -1250,7 +1269,12 @@
{30_Hz, kMode60}, {22.5_Hz, kMode90}, {20_Hz, kMode60}};
}
}();
- ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+
+ if (GetParam() == Config::FrameRateOverride::Enabled) {
+ ASSERT_EQ(kTotalRefreshRates120, refreshRates.size());
+ } else {
+ ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+ }
for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].frameRateMode)
@@ -1264,7 +1288,11 @@
selector.getRankedRefreshRatesAsPair({}, {.powerOnImminent = true});
EXPECT_TRUE(signals.powerOnImminent);
- ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+ if (GetParam() == Config::FrameRateOverride::Enabled) {
+ ASSERT_EQ(kTotalRefreshRates120, refreshRates.size());
+ } else {
+ ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+ }
for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].frameRateMode)
@@ -1284,7 +1312,11 @@
selector.getRankedRefreshRatesAsPair(layers, {.powerOnImminent = true});
EXPECT_TRUE(signals.powerOnImminent);
- ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+ if (GetParam() == Config::FrameRateOverride::Enabled) {
+ ASSERT_EQ(kTotalRefreshRates120, refreshRates.size());
+ } else {
+ ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+ }
for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].frameRateMode)
@@ -1309,7 +1341,12 @@
{30_Hz, kMode60}, {22.5_Hz, kMode90}, {20_Hz, kMode60}};
}
}();
- ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+
+ if (GetParam() == Config::FrameRateOverride::Enabled) {
+ ASSERT_EQ(kTotalRefreshRates120, refreshRates.size());
+ } else {
+ ASSERT_EQ(expectedRefreshRates.size(), refreshRates.size());
+ }
for (size_t i = 0; i < expectedRefreshRates.size(); ++i) {
EXPECT_EQ(expectedRefreshRates[i], refreshRates[i].frameRateMode)
@@ -1562,7 +1599,11 @@
}();
auto actualRanking = selector.getRankedFrameRates(layers, {}).ranking;
- ASSERT_EQ(expectedRanking.size(), actualRanking.size());
+ if (GetParam() == Config::FrameRateOverride::Enabled) {
+ ASSERT_EQ(kTotalRefreshRates216, actualRanking.size());
+ } else {
+ ASSERT_EQ(expectedRanking.size(), actualRanking.size());
+ }
for (size_t i = 0; i < expectedRanking.size(); ++i) {
EXPECT_EQ(expectedRanking[i], actualRanking[i].frameRateMode)
@@ -1604,7 +1645,11 @@
}();
actualRanking = selector.getRankedFrameRates(layers, {}).ranking;
- ASSERT_EQ(expectedRanking.size(), actualRanking.size());
+ if (GetParam() == Config::FrameRateOverride::Enabled) {
+ ASSERT_EQ(kTotalRefreshRates216, actualRanking.size());
+ } else {
+ ASSERT_EQ(expectedRanking.size(), actualRanking.size());
+ }
for (size_t i = 0; i < expectedRanking.size(); ++i) {
EXPECT_EQ(expectedRanking[i], actualRanking[i].frameRateMode)
@@ -1644,7 +1689,11 @@
}();
actualRanking = selector.getRankedFrameRates(layers, {}).ranking;
- ASSERT_EQ(expectedRanking.size(), actualRanking.size());
+ if (GetParam() == Config::FrameRateOverride::Enabled) {
+ ASSERT_EQ(kTotalRefreshRates216, actualRanking.size());
+ } else {
+ ASSERT_EQ(expectedRanking.size(), actualRanking.size());
+ }
for (size_t i = 0; i < expectedRanking.size(); ++i) {
EXPECT_EQ(expectedRanking[i], actualRanking[i].frameRateMode)
@@ -1687,7 +1736,11 @@
}();
actualRanking = selector.getRankedFrameRates(layers, {}).ranking;
- ASSERT_EQ(expectedRanking.size(), actualRanking.size());
+ if (GetParam() == Config::FrameRateOverride::Enabled) {
+ ASSERT_EQ(kTotalRefreshRates216, actualRanking.size());
+ } else {
+ ASSERT_EQ(expectedRanking.size(), actualRanking.size());
+ }
for (size_t i = 0; i < expectedRanking.size(); ++i) {
EXPECT_EQ(expectedRanking[i], actualRanking[i].frameRateMode)
@@ -2317,7 +2370,8 @@
}
// b/190578904
-TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withCloseRefreshRates) {
+TEST_P(RefreshRateSelectorTest,
+ getBestFrameRateMode_withCloseRefreshRates_LayerVoteType_Heuristic) {
if (g_noSlowTests) {
GTEST_SKIP();
}
@@ -2346,8 +2400,101 @@
for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
const auto refreshRate = Fps::fromValue(static_cast<float>(fps));
testRefreshRate(refreshRate, LayerVoteType::Heuristic);
+ }
+}
+TEST_P(RefreshRateSelectorTest,
+ getBestFrameRateMode_withCloseRefreshRates_LayerVoteType_ExplicitDefault) {
+ if (g_noSlowTests) {
+ GTEST_SKIP();
+ }
+
+ const int kMinRefreshRate = RefreshRateSelector::kMinSupportedFrameRate.getIntValue();
+ constexpr int kMaxRefreshRate = 240;
+
+ DisplayModes displayModes;
+ for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
+ const DisplayModeId modeId(fps);
+ displayModes.try_emplace(modeId,
+ createDisplayMode(modeId,
+ Fps::fromValue(static_cast<float>(fps))));
+ }
+
+ const auto selector = createSelector(std::move(displayModes), DisplayModeId(kMinRefreshRate));
+
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+ const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) {
+ layers[0].desiredRefreshRate = fps;
+ layers[0].vote = vote;
+ EXPECT_EQ(fps.getIntValue(), selector.getBestFrameRateMode(layers)->getFps().getIntValue())
+ << "Failed for " << ftl::enum_string(vote);
+ };
+
+ for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
+ const auto refreshRate = Fps::fromValue(static_cast<float>(fps));
testRefreshRate(refreshRate, LayerVoteType::ExplicitDefault);
+ }
+}
+TEST_P(RefreshRateSelectorTest,
+ getBestFrameRateMode_withCloseRefreshRates_LayerVoteType_ExplicitExactOrMultiple) {
+ if (g_noSlowTests) {
+ GTEST_SKIP();
+ }
+
+ const int kMinRefreshRate = RefreshRateSelector::kMinSupportedFrameRate.getIntValue();
+ constexpr int kMaxRefreshRate = 240;
+
+ DisplayModes displayModes;
+ for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
+ const DisplayModeId modeId(fps);
+ displayModes.try_emplace(modeId,
+ createDisplayMode(modeId,
+ Fps::fromValue(static_cast<float>(fps))));
+ }
+
+ const auto selector = createSelector(std::move(displayModes), DisplayModeId(kMinRefreshRate));
+
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+ const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) {
+ layers[0].desiredRefreshRate = fps;
+ layers[0].vote = vote;
+ EXPECT_EQ(fps.getIntValue(), selector.getBestFrameRateMode(layers)->getFps().getIntValue())
+ << "Failed for " << ftl::enum_string(vote);
+ };
+
+ for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
+ const auto refreshRate = Fps::fromValue(static_cast<float>(fps));
testRefreshRate(refreshRate, LayerVoteType::ExplicitExactOrMultiple);
+ }
+}
+TEST_P(RefreshRateSelectorTest,
+ getBestFrameRateMode_withCloseRefreshRates_LayerVoteType_ExplicitExact) {
+ if (g_noSlowTests) {
+ GTEST_SKIP();
+ }
+
+ const int kMinRefreshRate = RefreshRateSelector::kMinSupportedFrameRate.getIntValue();
+ constexpr int kMaxRefreshRate = 240;
+
+ DisplayModes displayModes;
+ for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
+ const DisplayModeId modeId(fps);
+ displayModes.try_emplace(modeId,
+ createDisplayMode(modeId,
+ Fps::fromValue(static_cast<float>(fps))));
+ }
+
+ const auto selector = createSelector(std::move(displayModes), DisplayModeId(kMinRefreshRate));
+
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+ const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) {
+ layers[0].desiredRefreshRate = fps;
+ layers[0].vote = vote;
+ EXPECT_EQ(fps.getIntValue(), selector.getBestFrameRateMode(layers)->getFps().getIntValue())
+ << "Failed for " << ftl::enum_string(vote);
+ };
+
+ for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
+ const auto refreshRate = Fps::fromValue(static_cast<float>(fps));
testRefreshRate(refreshRate, LayerVoteType::ExplicitExact);
}
}
@@ -2807,13 +2954,18 @@
{90_Hz, 90_Hz},
{120_Hz, 120_Hz}};
case Config::FrameRateOverride::Enabled:
- return {{30_Hz, 30_Hz}, {36_Hz, 72_Hz}, {40_Hz, 120_Hz}, {45_Hz, 90_Hz},
- {60_Hz, 60_Hz}, {72_Hz, 72_Hz}, {90_Hz, 90_Hz}, {120_Hz, 120_Hz}};
+ return {{1_Hz, 30_Hz}, {1.008_Hz, 120_Hz}, {1.011_Hz, 90_Hz},
+ {1.014_Hz, 72_Hz}, {1.016_Hz, 60_Hz}, {1.022_Hz, 90_Hz},
+ {1.0256_Hz, 120_Hz}, {1.028_Hz, 72_Hz}};
}
}();
const auto& primaryRefreshRates = selector.getPrimaryFrameRates();
- ASSERT_EQ(expected.size(), primaryRefreshRates.size());
+ if (GetParam() == Config::FrameRateOverride::Enabled) {
+ ASSERT_EQ(kTotalRefreshRates216, primaryRefreshRates.size());
+ } else {
+ ASSERT_EQ(expected.size(), primaryRefreshRates.size());
+ }
for (size_t i = 0; i < expected.size(); i++) {
const auto [expectedRenderRate, expectedRefreshRate] = expected[i];
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 1bf7abb..b03200e 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -511,6 +511,10 @@
case VK_FORMAT_R8_UNORM:
native_format = android::PIXEL_FORMAT_R_8;
break;
+ // TODO: Do we need to query for VK_EXT_rgba10x6_formats here?
+ case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
+ native_format = android::PIXEL_FORMAT_RGBA_10101010;
+ break;
default:
ALOGV("unsupported swapchain format %d", format);
break;
@@ -858,6 +862,22 @@
}
}
+ // TODO query VK_EXT_rgba10x6_formats support
+ desc.format = AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM;
+ if (AHardwareBuffer_isSupported(&desc)) {
+ all_formats.emplace_back(
+ VkSurfaceFormatKHR{VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
+ VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
+ if (colorspace_ext) {
+ all_formats.emplace_back(
+ VkSurfaceFormatKHR{VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
+ VK_COLOR_SPACE_PASS_THROUGH_EXT});
+ all_formats.emplace_back(
+ VkSurfaceFormatKHR{VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16,
+ VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
+ }
+ }
+
// NOTE: Any new formats that are added must be coordinated across different
// Android users. This includes the ANGLE team (a layered implementation of
// OpenGL-ES).
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index da6b00a..0284192 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -731,7 +731,7 @@
visitor->Visit("vulkanMemoryModelAvailabilityVisibilityChains", &features->vulkanMemoryModelAvailabilityVisibilityChains) &&
visitor->Visit("shaderOutputViewportIndex", &features->shaderOutputViewportIndex) &&
visitor->Visit("shaderOutputLayer", &features->shaderOutputLayer) &&
- visitor->Visit("shaderOutputLayer", &features->shaderOutputLayer);
+ visitor->Visit("subgroupBroadcastDynamicId", &features->subgroupBroadcastDynamicId);
}
template <typename Visitor>