Report gui::DisplayInfo to clients with window info changes
InputFlinger needs to know specifications about displays such as
orientation and projection from SurfaceFlinger to support the
MotionEvent#getRaw API, which returns coordinates in logical display
space at the moment.
Since dispatcher gets window information from SF, we need to send the
display information that affects input dispatching at the same time as
updating window information to ensure those two pieces of information
remain in sync.
Instead of sending display information along with each window, we
attempt to reduce the amount of information sent through binder by
sending DisplayInfo separately to WindowInfos. The newly added
DisplayInfo struct should only be used by InputFlinger to support raw
coordinates for now, with the goal of removing it altogether in the
future.
Bug: 179274888
Test: atest libgui_test inputflinger_tests
Test: manual, ensure input works
Change-Id: I87429ca4ced5f105f49a117c676cba29f8a5c4da
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 59cb419..84f5a18 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -54,6 +54,7 @@
using android::base::HwTimeoutMultiplier;
using android::base::Result;
using android::base::StringPrintf;
+using android::gui::DisplayInfo;
using android::gui::FocusRequest;
using android::gui::TouchOcclusionMode;
using android::gui::WindowInfo;
@@ -2444,9 +2445,15 @@
inputTarget.inputChannel = inputChannel;
inputTarget.flags = targetFlags;
inputTarget.globalScaleFactor = windowInfo->globalScaleFactor;
- inputTarget.displayOrientation = windowInfo->displayOrientation;
- inputTarget.displaySize =
- int2(windowHandle->getInfo()->displayWidth, windowHandle->getInfo()->displayHeight);
+ const auto& displayInfoIt = mDisplayInfos.find(windowInfo->displayId);
+ if (displayInfoIt != mDisplayInfos.end()) {
+ const auto& displayInfo = displayInfoIt->second;
+ inputTarget.displayOrientation = displayInfo.transform.getOrientation();
+ inputTarget.displaySize = int2(displayInfo.logicalWidth, displayInfo.logicalHeight);
+ } else {
+ ALOGI_IF(isPerWindowInputRotationEnabled(),
+ "DisplayInfo not found for window on display: %d", windowInfo->displayId);
+ }
inputTargets.push_back(inputTarget);
it = inputTargets.end() - 1;
}
@@ -4484,6 +4491,7 @@
void InputDispatcher::setInputWindows(
const std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>>& handlesPerDisplay) {
+ // TODO(b/198444055): Remove setInputWindows from InputDispatcher.
{ // acquire lock
std::scoped_lock _l(mLock);
for (const auto& [displayId, handles] : handlesPerDisplay) {
@@ -5013,9 +5021,17 @@
}
if (!mWindowHandlesByDisplay.empty()) {
- for (auto& it : mWindowHandlesByDisplay) {
- const std::vector<sp<WindowInfoHandle>> windowHandles = it.second;
- dump += StringPrintf(INDENT "Display: %" PRId32 "\n", it.first);
+ for (const auto& [displayId, windowHandles] : mWindowHandlesByDisplay) {
+ dump += StringPrintf(INDENT "Display: %" PRId32 "\n", displayId);
+ if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) {
+ const auto& displayInfo = it->second;
+ dump += StringPrintf(INDENT2 "logicalSize=%dx%d\n", displayInfo.logicalWidth,
+ displayInfo.logicalHeight);
+ displayInfo.transform.dump(dump, "transform", INDENT4);
+ } else {
+ dump += INDENT2 "No DisplayInfo found!\n";
+ }
+
if (!windowHandles.empty()) {
dump += INDENT2 "Windows:\n";
for (size_t i = 0; i < windowHandles.size(); i++) {
@@ -5047,13 +5063,12 @@
windowInfo->inputFeatures.string().c_str());
dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64
"ms, trustedOverlay=%s, hasToken=%s, "
- "touchOcclusionMode=%s, displayOrientation=%d\n",
+ "touchOcclusionMode=%s\n",
windowInfo->ownerPid, windowInfo->ownerUid,
millis(windowInfo->dispatchingTimeout),
toString(windowInfo->trustedOverlay),
toString(windowInfo->token != nullptr),
- toString(windowInfo->touchOcclusionMode).c_str(),
- windowInfo->displayOrientation);
+ toString(windowInfo->touchOcclusionMode).c_str());
windowInfo->transform.dump(dump, "transform", INDENT4);
}
} else {
@@ -6099,16 +6114,29 @@
mLooper->wake();
}
-void InputDispatcher::onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos) {
+void InputDispatcher::onWindowInfosChanged(const std::vector<WindowInfo>& windowInfos,
+ const std::vector<DisplayInfo>& displayInfos) {
// The listener sends the windows as a flattened array. Separate the windows by display for
// more convenient parsing.
std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>> handlesPerDisplay;
-
for (const auto& info : windowInfos) {
handlesPerDisplay.emplace(info.displayId, std::vector<sp<WindowInfoHandle>>());
handlesPerDisplay[info.displayId].push_back(new WindowInfoHandle(info));
}
- setInputWindows(handlesPerDisplay);
+
+ { // acquire lock
+ std::scoped_lock _l(mLock);
+ mDisplayInfos.clear();
+ for (const auto& displayInfo : displayInfos) {
+ mDisplayInfos.emplace(displayInfo.displayId, displayInfo);
+ }
+
+ for (const auto& [displayId, handles] : handlesPerDisplay) {
+ setInputWindowsLocked(handles, displayId);
+ }
+ }
+ // Wake up poll loop since it may need to make new input dispatching choices.
+ mLooper->wake();
}
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 6df333a..afe4366 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -143,7 +143,8 @@
void displayRemoved(int32_t displayId) override;
- void onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos) override;
+ void onWindowInfosChanged(const std::vector<gui::WindowInfo>&,
+ const std::vector<gui::DisplayInfo>&) override;
private:
enum class DropReason {
@@ -337,8 +338,10 @@
float mMaximumObscuringOpacityForTouch GUARDED_BY(mLock);
android::os::BlockUntrustedTouchesMode mBlockUntrustedTouchesMode GUARDED_BY(mLock);
- std::unordered_map<int32_t, std::vector<sp<android::gui::WindowInfoHandle>>>
+ std::unordered_map<int32_t /*displayId*/, std::vector<sp<android::gui::WindowInfoHandle>>>
mWindowHandlesByDisplay GUARDED_BY(mLock);
+ std::unordered_map<int32_t /*displayId*/, android::gui::DisplayInfo> mDisplayInfos
+ GUARDED_BY(mLock);
void setInputWindowsLocked(
const std::vector<sp<android::gui::WindowInfoHandle>>& inputWindowHandles,
int32_t displayId) REQUIRES(mLock);
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 802a17d..fd93b2d 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -139,6 +139,34 @@
return mCompositionDisplay->getRenderSurface()->getPageFlipCount();
}
+std::pair<gui::DisplayInfo, ui::Transform> DisplayDevice::getInputInfo() const {
+ gui::DisplayInfo info;
+ info.displayId = getLayerStack().id;
+
+ // The physical orientation is set when the orientation of the display panel is
+ // different than the default orientation of the device. Other services like
+ // InputFlinger do not know about this, so we do not need to expose the physical
+ // orientation of the panel outside of SurfaceFlinger.
+ const ui::Rotation inversePhysicalOrientation = ui::ROTATION_0 - mPhysicalOrientation;
+ auto width = getWidth();
+ auto height = getHeight();
+ if (inversePhysicalOrientation == ui::ROTATION_90 ||
+ inversePhysicalOrientation == ui::ROTATION_270) {
+ std::swap(width, height);
+ }
+ const ui::Transform undoPhysicalOrientation(ui::Transform::toRotationFlags(
+ inversePhysicalOrientation),
+ width, height);
+ const auto& displayTransform = undoPhysicalOrientation * getTransform();
+ // Send the inverse display transform to input so it can convert display coordinates to
+ // logical display.
+ info.transform = displayTransform.inverse();
+
+ info.logicalWidth = getLayerStackSpaceRect().width();
+ info.logicalHeight = getLayerStackSpaceRect().height();
+ return {info, displayTransform};
+}
+
// ----------------------------------------------------------------------------
void DisplayDevice::setPowerMode(hal::PowerMode mode) {
mPowerMode = mode;
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 43a6bd5..7762054 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -167,6 +167,10 @@
return mDeviceProductInfo;
}
+ // Get the DisplayInfo that will be sent to InputFlinger, and the display transform that should
+ // be applied to all the input windows on the display.
+ std::pair<gui::DisplayInfo, ui::Transform> getInputInfo() const;
+
/* ------------------------------------------------------------------------
* Display power mode management.
*/
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 804cf9a..2376b83 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2131,7 +2131,7 @@
if (traceFlags & SurfaceTracing::TRACE_INPUT) {
WindowInfo info;
if (useDrawing) {
- info = fillInputInfo(nullptr);
+ info = fillInputInfo(ui::Transform());
} else {
info = state.inputInfo;
}
@@ -2265,7 +2265,7 @@
}
}
-WindowInfo Layer::fillInputInfo(const DisplayDevice* display) {
+WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform) {
if (!hasInputInfo()) {
mDrawingState.inputInfo.name = getName();
mDrawingState.inputInfo.ownerUid = mOwnerUid;
@@ -2279,35 +2279,6 @@
info.id = sequence;
info.displayId = getLayerStack().id;
- // Transform that maps from LayerStack space to display space, e.g. rotated to non-rotated.
- // Used when InputFlinger operates in display space.
- ui::Transform displayTransform;
- if (display) {
- // The physical orientation is set when the orientation of the display panel is different
- // than the default orientation of the device. Other services like InputFlinger do not know
- // about this, so we do not need to expose the physical orientation of the panel outside of
- // SurfaceFlinger.
- const ui::Rotation inversePhysicalOrientation =
- ui::ROTATION_0 - display->getPhysicalOrientation();
- auto width = display->getWidth();
- auto height = display->getHeight();
- if (inversePhysicalOrientation == ui::ROTATION_90 ||
- inversePhysicalOrientation == ui::ROTATION_270) {
- std::swap(width, height);
- }
- const ui::Transform undoPhysicalOrientation(ui::Transform::toRotationFlags(
- inversePhysicalOrientation),
- width, height);
- displayTransform = undoPhysicalOrientation * display->getTransform();
-
- // Send the inverse of the display orientation so that input can transform points back to
- // the rotated display space.
- const ui::Rotation inverseOrientation = ui::ROTATION_0 - display->getOrientation();
- info.displayOrientation = ui::Transform::toRotationFlags(inverseOrientation);
-
- info.displayWidth = width;
- info.displayHeight = height;
- }
fillInputFrameInfo(info, displayTransform);
// For compatibility reasons we let layers which can receive input
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 4200be4..3c3c7d0 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -851,7 +851,7 @@
bool getPremultipledAlpha() const;
void setInputInfo(const gui::WindowInfo& info);
- gui::WindowInfo fillInputInfo(const DisplayDevice*);
+ gui::WindowInfo fillInputInfo(const ui::Transform& displayTransform);
/**
* Returns whether this layer has an explicitly set input-info.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 21b889e..12389d1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -169,6 +169,7 @@
using android::hardware::power::Boost;
using base::StringAppendF;
+using gui::DisplayInfo;
using gui::IWindowInfosListener;
using gui::WindowInfo;
using ui::ColorMode;
@@ -3053,6 +3054,16 @@
void SurfaceFlinger::notifyWindowInfos() {
std::vector<WindowInfo> windowInfos;
+ std::vector<DisplayInfo> displayInfos;
+ std::unordered_map<const DisplayDevice*, const ui::Transform> displayTransforms;
+
+ if (enablePerWindowInputRotation()) {
+ for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+ const auto& [info, transform] = display->getInputInfo();
+ displayInfos.emplace_back(info);
+ displayTransforms.emplace(display.get(), transform);
+ }
+ }
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
if (!layer->needsInputInfo()) return;
@@ -3064,9 +3075,11 @@
// When calculating the screen bounds we ignore the transparent region since it may
// result in an unwanted offset.
- windowInfos.push_back(layer->fillInputInfo(display));
+ const auto it = displayTransforms.find(display);
+ windowInfos.push_back(
+ layer->fillInputInfo(it != displayTransforms.end() ? it->second : ui::Transform()));
});
- mWindowInfosListenerInvoker->windowInfosChanged(windowInfos,
+ mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
mInputWindowCommands.syncInputWindows);
}
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
index dc2aa58..b93d127 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -21,6 +21,7 @@
namespace android {
+using gui::DisplayInfo;
using gui::IWindowInfosListener;
using gui::WindowInfo;
@@ -67,6 +68,7 @@
}
void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos,
+ const std::vector<DisplayInfo>& displayInfos,
bool shouldSync) {
std::unordered_set<sp<IWindowInfosListener>, ISurfaceComposer::SpHash<IWindowInfosListener>>
windowInfosListeners;
@@ -81,7 +83,7 @@
mCallbacksPending = windowInfosListeners.size();
for (const auto& listener : windowInfosListeners) {
- listener->onWindowInfosChanged(windowInfos,
+ listener->onWindowInfosChanged(windowInfos, displayInfos,
shouldSync ? mWindowInfosReportedListener : nullptr);
}
}
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
index 5e5796f..ecd797a 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.h
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.h
@@ -33,7 +33,8 @@
void addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
- void windowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos, bool shouldSync);
+ void windowInfosChanged(const std::vector<gui::WindowInfo>&,
+ const std::vector<gui::DisplayInfo>&, bool shouldSync);
protected:
void binderDied(const wp<IBinder>& who) override;
diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
index de116f2..0069111 100644
--- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp
+++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
@@ -22,6 +22,7 @@
namespace android {
using Transaction = SurfaceComposerClient::Transaction;
+using gui::DisplayInfo;
using gui::WindowInfo;
class WindowInfosListenerTest : public ::testing::Test {
@@ -40,7 +41,8 @@
struct SyncWindowInfosListener : public gui::WindowInfosListener {
public:
- void onWindowInfosChanged(const std::vector<WindowInfo>& windowInfos) override {
+ void onWindowInfosChanged(const std::vector<WindowInfo>& windowInfos,
+ const std::vector<DisplayInfo>&) override {
windowInfosPromise.set_value(windowInfos);
}