Merge "Report gui::DisplayInfo to clients with window info changes"
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 326da3a..2d1f5a1 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -65,11 +65,13 @@
     host_supported: true,
     srcs: [
         ":guiconstants_aidl",
+        "android/gui/DisplayInfo.aidl",
         "android/gui/FocusRequest.aidl",
         "android/gui/InputApplicationInfo.aidl",
         "android/gui/IWindowInfosListener.aidl",
         "android/gui/IWindowInfosReportedListener.aidl",
         "android/gui/WindowInfo.aidl",
+        "DisplayInfo.cpp",
         "WindowInfo.cpp",
     ],
 
@@ -90,7 +92,7 @@
     ],
 
     aidl: {
-        export_aidl_headers: true
+        export_aidl_headers: true,
     },
 
     include_dirs: [
@@ -135,8 +137,8 @@
     ],
 
     aidl: {
-        export_aidl_headers: true
-    }
+        export_aidl_headers: true,
+    },
 }
 
 cc_library_shared {
diff --git a/libs/gui/DisplayInfo.cpp b/libs/gui/DisplayInfo.cpp
new file mode 100644
index 0000000..52d9540
--- /dev/null
+++ b/libs/gui/DisplayInfo.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "DisplayInfo"
+
+#include <binder/Parcel.h>
+#include <gui/DisplayInfo.h>
+#include <private/gui/ParcelUtils.h>
+
+#include <log/log.h>
+
+namespace android::gui {
+
+// --- DisplayInfo ---
+
+status_t DisplayInfo::readFromParcel(const android::Parcel* parcel) {
+    if (parcel == nullptr) {
+        ALOGE("%s: Null parcel", __func__);
+        return BAD_VALUE;
+    }
+
+    float dsdx, dtdx, tx, dtdy, dsdy, ty;
+    SAFE_PARCEL(parcel->readInt32, &displayId);
+    SAFE_PARCEL(parcel->readInt32, &logicalWidth);
+    SAFE_PARCEL(parcel->readInt32, &logicalHeight);
+    SAFE_PARCEL(parcel->readFloat, &dsdx);
+    SAFE_PARCEL(parcel->readFloat, &dtdx);
+    SAFE_PARCEL(parcel->readFloat, &tx);
+    SAFE_PARCEL(parcel->readFloat, &dtdy);
+    SAFE_PARCEL(parcel->readFloat, &dsdy);
+    SAFE_PARCEL(parcel->readFloat, &ty);
+
+    transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1});
+
+    return OK;
+}
+
+status_t DisplayInfo::writeToParcel(android::Parcel* parcel) const {
+    if (parcel == nullptr) {
+        ALOGE("%s: Null parcel", __func__);
+        return BAD_VALUE;
+    }
+
+    SAFE_PARCEL(parcel->writeInt32, displayId);
+    SAFE_PARCEL(parcel->writeInt32, logicalWidth);
+    SAFE_PARCEL(parcel->writeInt32, logicalHeight);
+    SAFE_PARCEL(parcel->writeFloat, transform.dsdx());
+    SAFE_PARCEL(parcel->writeFloat, transform.dtdx());
+    SAFE_PARCEL(parcel->writeFloat, transform.tx());
+    SAFE_PARCEL(parcel->writeFloat, transform.dtdy());
+    SAFE_PARCEL(parcel->writeFloat, transform.dsdy());
+    SAFE_PARCEL(parcel->writeFloat, transform.ty());
+
+    return OK;
+}
+
+} // namespace android::gui
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index b2ef7aa..5f3a726 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -54,12 +54,11 @@
             info.frameLeft == frameLeft && info.frameTop == frameTop &&
             info.frameRight == frameRight && info.frameBottom == frameBottom &&
             info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor &&
-            info.transform == transform && info.displayOrientation == displayOrientation &&
-            info.displayWidth == displayWidth && info.displayHeight == displayHeight &&
-            info.touchableRegion.hasSameRects(touchableRegion) && info.visible == visible &&
-            info.trustedOverlay == trustedOverlay && info.focusable == focusable &&
-            info.touchOcclusionMode == touchOcclusionMode && info.hasWallpaper == hasWallpaper &&
-            info.paused == paused && info.ownerPid == ownerPid && info.ownerUid == ownerUid &&
+            info.transform == transform && info.touchableRegion.hasSameRects(touchableRegion) &&
+            info.visible == visible && info.trustedOverlay == trustedOverlay &&
+            info.focusable == focusable && info.touchOcclusionMode == touchOcclusionMode &&
+            info.hasWallpaper == hasWallpaper && info.paused == paused &&
+            info.ownerPid == ownerPid && info.ownerUid == ownerUid &&
             info.packageName == packageName && info.inputFeatures == inputFeatures &&
             info.displayId == displayId && info.portalToDisplayId == portalToDisplayId &&
             info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop &&
@@ -97,9 +96,6 @@
         parcel->writeFloat(transform.dtdy()) ?:
         parcel->writeFloat(transform.dsdy()) ?:
         parcel->writeFloat(transform.ty()) ?:
-        parcel->writeUint32(displayOrientation) ?:
-        parcel->writeInt32(displayWidth) ?:
-        parcel->writeInt32(displayHeight) ?:
         parcel->writeBool(visible) ?:
         parcel->writeBool(focusable) ?:
         parcel->writeBool(hasWallpaper) ?:
@@ -155,9 +151,6 @@
         parcel->readFloat(&dtdy) ?:
         parcel->readFloat(&dsdy) ?:
         parcel->readFloat(&ty) ?:
-        parcel->readUint32(&displayOrientation) ?:
-        parcel->readInt32(&displayWidth) ?:
-        parcel->readInt32(&displayHeight) ?:
         parcel->readBool(&visible) ?:
         parcel->readBool(&focusable) ?:
         parcel->readBool(&hasWallpaper) ?:
diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp
index c00a438..c32b9ab 100644
--- a/libs/gui/WindowInfosListenerReporter.cpp
+++ b/libs/gui/WindowInfosListenerReporter.cpp
@@ -19,6 +19,7 @@
 
 namespace android {
 
+using gui::DisplayInfo;
 using gui::IWindowInfosReportedListener;
 using gui::WindowInfo;
 using gui::WindowInfosListener;
@@ -65,7 +66,7 @@
 }
 
 binder::Status WindowInfosListenerReporter::onWindowInfosChanged(
-        const std::vector<WindowInfo>& windowInfos,
+        const std::vector<WindowInfo>& windowInfos, const std::vector<DisplayInfo>& displayInfos,
         const sp<IWindowInfosReportedListener>& windowInfosReportedListener) {
     std::unordered_set<sp<WindowInfosListener>, ISurfaceComposer::SpHash<WindowInfosListener>>
             windowInfosListeners;
@@ -78,7 +79,7 @@
     }
 
     for (auto listener : windowInfosListeners) {
-        listener->onWindowInfosChanged(windowInfos);
+        listener->onWindowInfosChanged(windowInfos, displayInfos);
     }
 
     if (windowInfosReportedListener) {
diff --git a/libs/gui/android/gui/DisplayInfo.aidl b/libs/gui/android/gui/DisplayInfo.aidl
new file mode 100644
index 0000000..30c0885
--- /dev/null
+++ b/libs/gui/android/gui/DisplayInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gui;
+
+parcelable DisplayInfo cpp_header "gui/DisplayInfo.h";
diff --git a/libs/gui/android/gui/IWindowInfosListener.aidl b/libs/gui/android/gui/IWindowInfosListener.aidl
index d4553ca..a5b2762 100644
--- a/libs/gui/android/gui/IWindowInfosListener.aidl
+++ b/libs/gui/android/gui/IWindowInfosListener.aidl
@@ -16,11 +16,12 @@
 
 package android.gui;
 
+import android.gui.DisplayInfo;
 import android.gui.IWindowInfosReportedListener;
 import android.gui.WindowInfo;
 
 /** @hide */
 oneway interface IWindowInfosListener
 {
-    void onWindowInfosChanged(in WindowInfo[] windowInfos, in @nullable IWindowInfosReportedListener windowInfosReportedListener);
+    void onWindowInfosChanged(in WindowInfo[] windowInfos, in DisplayInfo[] displayInfos, in @nullable IWindowInfosReportedListener windowInfosReportedListener);
 }
diff --git a/libs/gui/include/gui/DisplayInfo.h b/libs/gui/include/gui/DisplayInfo.h
new file mode 100644
index 0000000..74f33a2
--- /dev/null
+++ b/libs/gui/include/gui/DisplayInfo.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <gui/constants.h>
+#include <ui/Transform.h>
+
+namespace android::gui {
+
+/*
+ * Describes information about a display that can have windows in it.
+ *
+ * This should only be used by InputFlinger to support raw coordinates in logical display space.
+ */
+struct DisplayInfo : public Parcelable {
+    int32_t displayId = ADISPLAY_ID_NONE;
+
+    // Logical display dimensions.
+    int32_t logicalWidth = 0;
+    int32_t logicalHeight = 0;
+
+    // The display transform. This takes display coordinates to logical display coordinates.
+    ui::Transform transform;
+
+    status_t writeToParcel(android::Parcel*) const override;
+
+    status_t readFromParcel(const android::Parcel*) override;
+};
+
+} // namespace android::gui
\ No newline at end of file
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index 2d36e3b..54a372c 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -181,13 +181,6 @@
     // Transform applied to individual windows.
     ui::Transform transform;
 
-    // Display orientation as ui::Transform::RotationFlags. Used for compatibility raw coordinates.
-    uint32_t displayOrientation = ui::Transform::ROT_0;
-
-    // Display size in its natural rotation. Used to rotate raw coordinates for compatibility.
-    int32_t displayWidth = 0;
-    int32_t displayHeight = 0;
-
     /*
      * This is filled in by the WM relative to the frame and then translated
      * to absolute coordinates by SurfaceFlinger once the frame is computed.
diff --git a/libs/gui/include/gui/WindowInfosListener.h b/libs/gui/include/gui/WindowInfosListener.h
index 8a70b9b..a18a498 100644
--- a/libs/gui/include/gui/WindowInfosListener.h
+++ b/libs/gui/include/gui/WindowInfosListener.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <gui/DisplayInfo.h>
 #include <gui/WindowInfo.h>
 #include <utils/RefBase.h>
 
@@ -23,6 +24,7 @@
 
 class WindowInfosListener : public virtual RefBase {
 public:
-    virtual void onWindowInfosChanged(const std::vector<WindowInfo>& /*windowInfos*/) = 0;
+    virtual void onWindowInfosChanged(const std::vector<WindowInfo>&,
+                                      const std::vector<DisplayInfo>&) = 0;
 };
 } // namespace android::gui
\ No newline at end of file
diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h
index 7cb96e0..157a804 100644
--- a/libs/gui/include/gui/WindowInfosListenerReporter.h
+++ b/libs/gui/include/gui/WindowInfosListenerReporter.h
@@ -21,7 +21,6 @@
 #include <binder/IBinder.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/WindowInfosListener.h>
-#include <utils/Mutex.h>
 #include <unordered_set>
 
 namespace android {
@@ -30,7 +29,8 @@
 class WindowInfosListenerReporter : public gui::BnWindowInfosListener {
 public:
     static sp<WindowInfosListenerReporter> getInstance();
-    binder::Status onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos,
+    binder::Status onWindowInfosChanged(const std::vector<gui::WindowInfo>&,
+                                        const std::vector<gui::DisplayInfo>&,
                                         const sp<gui::IWindowInfosReportedListener>&) override;
 
     status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener,
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 3d26c3d..6dd1073 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -27,6 +27,7 @@
         "BufferQueue_test.cpp",
         "CpuConsumer_test.cpp",
         "EndToEndNativeInputTest.cpp",
+        "DisplayInfo_test.cpp",
         "DisplayedContentSampling_test.cpp",
         "FillBuffer.cpp",
         "GLTest.cpp",
@@ -62,7 +63,7 @@
         "libinput",
         "libui",
         "libutils",
-        "libnativewindow"
+        "libnativewindow",
     ],
 
     header_libs: ["libsurfaceflinger_headers"],
@@ -117,7 +118,7 @@
         "libgui",
         "libui",
         "libutils",
-        "libbufferhubqueue",  // TODO(b/70046255): Remove these once BufferHub is integrated into libgui.
+        "libbufferhubqueue", // TODO(b/70046255): Remove these once BufferHub is integrated into libgui.
         "libpdx_default_transport",
     ],
 
@@ -146,5 +147,5 @@
         "liblog",
         "libui",
         "libutils",
-    ]
+    ],
 }
diff --git a/libs/gui/tests/DisplayInfo_test.cpp b/libs/gui/tests/DisplayInfo_test.cpp
new file mode 100644
index 0000000..df3329c
--- /dev/null
+++ b/libs/gui/tests/DisplayInfo_test.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <binder/Parcel.h>
+
+#include <gui/DisplayInfo.h>
+
+namespace android {
+
+using gui::DisplayInfo;
+
+namespace test {
+
+TEST(DisplayInfo, Parcelling) {
+    DisplayInfo info;
+    info.displayId = 42;
+    info.logicalWidth = 99;
+    info.logicalHeight = 78;
+    info.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1});
+
+    Parcel p;
+    info.writeToParcel(&p);
+    p.setDataPosition(0);
+
+    DisplayInfo info2;
+    info2.readFromParcel(&p);
+    ASSERT_EQ(info.displayId, info2.displayId);
+    ASSERT_EQ(info.logicalWidth, info2.logicalWidth);
+    ASSERT_EQ(info.logicalHeight, info2.logicalHeight);
+    ASSERT_EQ(info.transform, info2.transform);
+}
+
+} // namespace test
+} // namespace android
diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp
index a4f436c..dcdf76f 100644
--- a/libs/gui/tests/WindowInfo_test.cpp
+++ b/libs/gui/tests/WindowInfo_test.cpp
@@ -60,9 +60,6 @@
     i.globalScaleFactor = 0.3;
     i.alpha = 0.7;
     i.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1});
-    i.displayOrientation = ui::Transform::ROT_0;
-    i.displayWidth = 1000;
-    i.displayHeight = 2000;
     i.visible = false;
     i.focusable = false;
     i.hasWallpaper = false;
@@ -100,8 +97,6 @@
     ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor);
     ASSERT_EQ(i.alpha, i2.alpha);
     ASSERT_EQ(i.transform, i2.transform);
-    ASSERT_EQ(i.displayWidth, i2.displayWidth);
-    ASSERT_EQ(i.displayHeight, i2.displayHeight);
     ASSERT_EQ(i.visible, i2.visible);
     ASSERT_EQ(i.focusable, i2.focusable);
     ASSERT_EQ(i.hasWallpaper, i2.hasWallpaper);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index a9cca8d..da3e237 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -55,6 +55,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;
@@ -2523,9 +2524,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;
     }
@@ -4579,6 +4586,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) {
@@ -5111,9 +5119,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++) {
@@ -5145,13 +5161,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 {
@@ -6197,16 +6212,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();
 }
 
 bool InputDispatcher::shouldDropInput(
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 0db076f..4f6d0d2 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 2f8a90f..3397118 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 9de578f..4a731bd 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 f070d87..ef6f115 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2132,7 +2132,7 @@
     if (traceFlags & SurfaceTracing::TRACE_INPUT) {
         WindowInfo info;
         if (useDrawing) {
-            info = fillInputInfo(nullptr);
+            info = fillInputInfo(ui::Transform());
         } else {
             info = state.inputInfo;
         }
@@ -2266,7 +2266,7 @@
     }
 }
 
-WindowInfo Layer::fillInputInfo(const DisplayDevice* display) {
+WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform) {
     if (!hasInputInfo()) {
         mDrawingState.inputInfo.name = getName();
         mDrawingState.inputInfo.ownerUid = mOwnerUid;
@@ -2280,35 +2280,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 34b5cdc..5a881a3 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;
@@ -3059,6 +3060,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;
@@ -3070,9 +3081,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);
         }