Unrotate inputwindows into rotation display grew-up in
This way inputflinger internally works within one coordinate
space at all times and only transforms coordinates for dispatch
to targets
This is behind a flag:
adb shell setprop persist.debug.per_window_input_rotation 1
Bug: 179274888
Test: phone should work as before
Change-Id: I503f9beea9863193801aa6422a416382374e48c8
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 237aaff..8ef7c90 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -25,6 +25,7 @@
#include "Layer.h"
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android/native_window.h>
#include <binder/IPCThreadState.h>
@@ -2480,7 +2481,7 @@
if (traceFlags & SurfaceTracing::TRACE_INPUT) {
InputWindowInfo info;
if (useDrawing) {
- info = fillInputInfo();
+ info = fillInputInfo({nullptr});
} else {
info = state.inputInfo;
}
@@ -2501,7 +2502,7 @@
return mRemovedFromCurrentState;
}
-void Layer::fillInputFrameInfo(InputWindowInfo& info) {
+void Layer::fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhysicalDisplay) {
// Transform layer size to screen space and inset it by surface insets.
// If this is a portal window, set the touchableRegion to the layerBounds.
Rect layerBounds = info.portalToDisplayId == ADISPLAY_ID_NONE
@@ -2521,9 +2522,13 @@
return;
}
- ui::Transform t = getTransform();
+ ui::Transform layerToDisplay = getTransform();
+ // Transform that takes window coordinates to unrotated display coordinates
+ ui::Transform t = toPhysicalDisplay * layerToDisplay;
int32_t xSurfaceInset = info.surfaceInset;
int32_t ySurfaceInset = info.surfaceInset;
+ // Bring screenBounds into unrotated space
+ Rect screenBounds = toPhysicalDisplay.transform(Rect{mScreenBounds});
const float xScale = t.getScaleX();
const float yScale = t.getScaleY();
@@ -2581,7 +2586,6 @@
// We need to send the layer bounds cropped to the screenbounds since the layer can be cropped.
// The frame should be the area the user sees on screen since it's used for occlusion
// detection.
- Rect screenBounds = Rect{mScreenBounds};
transformedLayerBounds.intersect(screenBounds, &transformedLayerBounds);
info.frameLeft = transformedLayerBounds.left;
info.frameTop = transformedLayerBounds.top;
@@ -2593,7 +2597,7 @@
info.touchableRegion = inputTransform.transform(info.touchableRegion);
}
-InputWindowInfo Layer::fillInputInfo() {
+InputWindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) {
if (!hasInputInfo()) {
mDrawingState.inputInfo.name = getName();
mDrawingState.inputInfo.ownerUid = mOwnerUid;
@@ -2610,7 +2614,13 @@
info.displayId = getLayerStack();
}
- fillInputFrameInfo(info);
+ // Transform that goes from "logical(rotated)" display to physical/unrotated display.
+ // This is for when inputflinger operates in physical display-space.
+ ui::Transform toPhysicalDisplay;
+ if (display) {
+ toPhysicalDisplay = display->getTransform();
+ }
+ fillInputFrameInfo(info, toPhysicalDisplay);
// For compatibility reasons we let layers which can receive input
// receive input before they have actually submitted a buffer. Because
@@ -2626,12 +2636,14 @@
auto cropLayer = mDrawingState.touchableRegionCrop.promote();
if (info.replaceTouchableRegionWithCrop) {
if (cropLayer == nullptr) {
- info.touchableRegion = Region(Rect{mScreenBounds});
+ info.touchableRegion = Region(toPhysicalDisplay.transform(Rect{mScreenBounds}));
} else {
- info.touchableRegion = Region(Rect{cropLayer->mScreenBounds});
+ info.touchableRegion =
+ Region(toPhysicalDisplay.transform(Rect{cropLayer->mScreenBounds}));
}
} else if (cropLayer != nullptr) {
- info.touchableRegion = info.touchableRegion.intersect(Rect{cropLayer->mScreenBounds});
+ info.touchableRegion = info.touchableRegion.intersect(
+ toPhysicalDisplay.transform(Rect{cropLayer->mScreenBounds}));
}
// If the layer is a clone, we need to crop the input region to cloned root to prevent
@@ -2639,7 +2651,7 @@
if (isClone()) {
sp<Layer> clonedRoot = getClonedRoot();
if (clonedRoot != nullptr) {
- Rect rect(clonedRoot->mScreenBounds);
+ Rect rect = toPhysicalDisplay.transform(Rect{clonedRoot->mScreenBounds});
info.touchableRegion = info.touchableRegion.intersect(rect);
}
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 687f473..1461756 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -913,7 +913,7 @@
bool getPremultipledAlpha() const;
void setInputInfo(const InputWindowInfo& info);
- InputWindowInfo fillInputInfo();
+ InputWindowInfo fillInputInfo(const sp<DisplayDevice>& display);
/**
* Returns whether this layer has an explicitly set input-info.
*/
@@ -1193,7 +1193,7 @@
sp<Layer> getRootLayer();
// Fills in the frame and transform info for the InputWindowInfo
- void fillInputFrameInfo(InputWindowInfo& info);
+ void fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhysicalDisplay);
// Cached properties computed from drawing state
// Effective transform taking into account parent transforms and any parent scaling, which is
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7fada82..e9438e9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2906,15 +2906,32 @@
mInputWindowCommands.clear();
}
+bool enablePerWindowInputRotation() {
+ static bool value =
+ android::base::GetBoolProperty("persist.debug.per_window_input_rotation", false);
+ return value;
+}
+
void SurfaceFlinger::updateInputWindowInfo() {
std::vector<InputWindowInfo> inputInfos;
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
- if (layer->needsInputInfo()) {
- // When calculating the screen bounds we ignore the transparent region since it may
- // result in an unwanted offset.
- inputInfos.push_back(layer->fillInputInfo());
+ if (!layer->needsInputInfo()) return;
+ sp<DisplayDevice> display;
+ if (enablePerWindowInputRotation()) {
+ for (const auto& pair : ON_MAIN_THREAD(mDisplays)) {
+ const auto& displayDevice = pair.second;
+ if (!displayDevice->getCompositionDisplay()
+ ->belongsInOutput(layer->getLayerStack(),
+ layer->getPrimaryDisplayOnly())) {
+ continue;
+ }
+ display = displayDevice;
+ }
}
+ // When calculating the screen bounds we ignore the transparent region since it may
+ // result in an unwanted offset.
+ inputInfos.push_back(layer->fillInputInfo(display));
});
mInputFlinger->setInputWindows(inputInfos,