Merge "SF: process ComposerHalVsync for the active display" into sc-v2-dev
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 871edfc..d678281 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1371,10 +1371,12 @@
         return kSecondaryDexAccessReadOk;
     } else {
         if (errno == ENOENT) {
-            LOG(INFO) << "Secondary dex does not exist: " <<  dex_path;
+            async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG,
+                    "Secondary dex does not exist: %s", dex_path.c_str());
             return kSecondaryDexAccessDoesNotExist;
         } else {
-            PLOG(ERROR) << "Could not access secondary dex " << dex_path;
+            async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                    "Could not access secondary dex: %s (%d)", dex_path.c_str(), errno);
             return errno == EACCES
                 ? kSecondaryDexAccessPermissionError
                 : kSecondaryDexAccessIOError;
diff --git a/include/input/Input.h b/include/input/Input.h
index d88dcfe..cd110e8 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -577,6 +577,8 @@
 
     void setCursorPosition(float x, float y);
 
+    uint32_t getDisplayOrientation() const { return mDisplayOrientation; }
+
     int2 getDisplaySize() const { return {mDisplayWidth, mDisplayHeight}; }
 
     static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); }
@@ -753,8 +755,8 @@
                     int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState,
                     MotionClassification classification, const ui::Transform& transform,
                     float xPrecision, float yPrecision, float rawXCursorPosition,
-                    float rawYCursorPosition, int32_t displayWidth, int32_t displayHeight,
-                    nsecs_t downTime, nsecs_t eventTime, size_t pointerCount,
+                    float rawYCursorPosition, uint32_t displayOrientation, int32_t displayWidth,
+                    int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount,
                     const PointerProperties* pointerProperties, const PointerCoords* pointerCoords);
 
     void copyFrom(const MotionEvent* other, bool keepHistory);
@@ -812,6 +814,7 @@
     float mYPrecision;
     float mRawXCursorPosition;
     float mRawYCursorPosition;
+    uint32_t mDisplayOrientation;
     int32_t mDisplayWidth;
     int32_t mDisplayHeight;
     nsecs_t mDownTime;
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 360dfbf..a790b56 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -136,10 +136,10 @@
             float yPrecision;
             float xCursorPosition;
             float yCursorPosition;
+            uint32_t displayOrientation;
             int32_t displayWidth;
             int32_t displayHeight;
             uint32_t pointerCount;
-            uint32_t empty3;
             /**
              * The "pointers" field must be the last field of the struct InputMessage.
              * When we send the struct InputMessage across the socket, we are not
@@ -355,8 +355,9 @@
                                 int32_t metaState, int32_t buttonState,
                                 MotionClassification classification, const ui::Transform& transform,
                                 float xPrecision, float yPrecision, float xCursorPosition,
-                                float yCursorPosition, int32_t displayWidth, int32_t displayHeight,
-                                nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
+                                float yCursorPosition, uint32_t displayOrientation,
+                                int32_t displayWidth, int32_t displayHeight, nsecs_t downTime,
+                                nsecs_t eventTime, uint32_t pointerCount,
                                 const PointerProperties* pointerProperties,
                                 const PointerCoords* pointerCoords);
 
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index 51ddc50..b0c631a 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -164,6 +164,9 @@
     // Transform applied to individual windows.
     ui::Transform transform;
 
+    // Display orientation. 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;
diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp
index 09c02ca..58f3981 100644
--- a/libs/gui/tests/WindowInfo_test.cpp
+++ b/libs/gui/tests/WindowInfo_test.cpp
@@ -59,6 +59,7 @@
     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;
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 906e3e5..2860aa3 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -66,14 +66,11 @@
     return result;
 }
 
-// Rotates the given point to the transform's orientation. If the display width and height are
+// Rotates the given point to the specified orientation. If the display width and height are
 // provided, the point is rotated in the screen space. Otherwise, the point is rotated about the
 // origin. This helper is used to avoid the extra overhead of creating new Transforms.
-vec2 rotatePoint(const ui::Transform& transform, float x, float y, int32_t displayWidth = 0,
+vec2 rotatePoint(uint32_t orientation, float x, float y, int32_t displayWidth = 0,
                  int32_t displayHeight = 0) {
-    // 0x7 encapsulates all 3 rotations (see ui::Transform::RotationFlags)
-    static const int ALL_ROTATIONS_MASK = 0x7;
-    const uint32_t orientation = (transform.getOrientation() & ALL_ROTATIONS_MASK);
     if (orientation == ui::Transform::ROT_0) {
         return {x, y};
     }
@@ -425,9 +422,9 @@
                              int32_t buttonState, MotionClassification classification,
                              const ui::Transform& transform, float xPrecision, float yPrecision,
                              float rawXCursorPosition, float rawYCursorPosition,
-                             int32_t displayWidth, int32_t displayHeight, nsecs_t downTime,
-                             nsecs_t eventTime, size_t pointerCount,
-                             const PointerProperties* pointerProperties,
+                             uint32_t displayOrientation, int32_t displayWidth,
+                             int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime,
+                             size_t pointerCount, const PointerProperties* pointerProperties,
                              const PointerCoords* pointerCoords) {
     InputEvent::initialize(id, deviceId, source, displayId, hmac);
     mAction = action;
@@ -442,6 +439,7 @@
     mYPrecision = yPrecision;
     mRawXCursorPosition = rawXCursorPosition;
     mRawYCursorPosition = rawYCursorPosition;
+    mDisplayOrientation = displayOrientation;
     mDisplayWidth = displayWidth;
     mDisplayHeight = displayHeight;
     mDownTime = downTime;
@@ -467,6 +465,7 @@
     mYPrecision = other->mYPrecision;
     mRawXCursorPosition = other->mRawXCursorPosition;
     mRawYCursorPosition = other->mRawYCursorPosition;
+    mDisplayOrientation = other->mDisplayOrientation;
     mDisplayWidth = other->mDisplayWidth;
     mDisplayHeight = other->mDisplayHeight;
     mDownTime = other->mDownTime;
@@ -535,8 +534,8 @@
         // For compatibility, convert raw coordinates into "oriented screen space". Once app
         // developers are educated about getRaw, we can consider removing this.
         const vec2 xy = shouldDisregardWindowTranslation(mSource)
-                ? rotatePoint(mTransform, coords->getX(), coords->getY())
-                : rotatePoint(mTransform, coords->getX(), coords->getY(), mDisplayWidth,
+                ? rotatePoint(mDisplayOrientation, coords->getX(), coords->getY())
+                : rotatePoint(mDisplayOrientation, coords->getX(), coords->getY(), mDisplayWidth,
                               mDisplayHeight);
         static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
         return xy[axis];
@@ -545,9 +544,9 @@
     if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) {
         // For compatibility, since we convert raw coordinates into "oriented screen space", we
         // need to convert the relative axes into the same orientation for consistency.
-        const vec2 relativeXy =
-                rotatePoint(mTransform, coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
-                            coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y));
+        const vec2 relativeXy = rotatePoint(mDisplayOrientation,
+                                            coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
+                                            coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y));
         return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y;
     }
 
@@ -698,6 +697,7 @@
     mYPrecision = parcel->readFloat();
     mRawXCursorPosition = parcel->readFloat();
     mRawYCursorPosition = parcel->readFloat();
+    mDisplayOrientation = parcel->readUint32();
     mDisplayWidth = parcel->readInt32();
     mDisplayHeight = parcel->readInt32();
     mDownTime = parcel->readInt64();
@@ -759,6 +759,7 @@
     parcel->writeFloat(mYPrecision);
     parcel->writeFloat(mRawXCursorPosition);
     parcel->writeFloat(mRawYCursorPosition);
+    parcel->writeUint32(mDisplayOrientation);
     parcel->writeInt32(mDisplayWidth);
     parcel->writeInt32(mDisplayHeight);
     parcel->writeInt64(mDownTime);
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index d6c1161..ea8b9a7 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -242,9 +242,11 @@
             msg->body.motion.xCursorPosition = body.motion.xCursorPosition;
             // float yCursorPosition
             msg->body.motion.yCursorPosition = body.motion.yCursorPosition;
-            // int32_t displayW
+            // uint32_t displayOrientation
+            msg->body.motion.displayOrientation = body.motion.displayOrientation;
+            // int32_t displayWidth
             msg->body.motion.displayWidth = body.motion.displayWidth;
-            // int32_t displayH
+            // int32_t displayHeight
             msg->body.motion.displayHeight = body.motion.displayHeight;
             // uint32_t pointerCount
             msg->body.motion.pointerCount = body.motion.pointerCount;
@@ -533,9 +535,10 @@
         std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, int32_t flags,
         int32_t edgeFlags, int32_t metaState, int32_t buttonState,
         MotionClassification classification, const ui::Transform& transform, float xPrecision,
-        float yPrecision, float xCursorPosition, float yCursorPosition, int32_t displayWidth,
-        int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
-        const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) {
+        float yPrecision, float xCursorPosition, float yCursorPosition, uint32_t displayOrientation,
+        int32_t displayWidth, int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime,
+        uint32_t pointerCount, const PointerProperties* pointerProperties,
+        const PointerCoords* pointerCoords) {
     if (ATRACE_ENABLED()) {
         std::string message = StringPrintf(
                 "publishMotionEvent(inputChannel=%s, action=%" PRId32 ")",
@@ -593,6 +596,7 @@
     msg.body.motion.yPrecision = yPrecision;
     msg.body.motion.xCursorPosition = xCursorPosition;
     msg.body.motion.yCursorPosition = yCursorPosition;
+    msg.body.motion.displayOrientation = displayOrientation;
     msg.body.motion.displayWidth = displayWidth;
     msg.body.motion.displayHeight = displayHeight;
     msg.body.motion.downTime = downTime;
@@ -1361,9 +1365,9 @@
                       msg->body.motion.buttonState, msg->body.motion.classification, transform,
                       msg->body.motion.xPrecision, msg->body.motion.yPrecision,
                       msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition,
-                      msg->body.motion.displayWidth, msg->body.motion.displayHeight,
-                      msg->body.motion.downTime, msg->body.motion.eventTime, pointerCount,
-                      pointerProperties, pointerCoords);
+                      msg->body.motion.displayOrientation, msg->body.motion.displayWidth,
+                      msg->body.motion.displayHeight, msg->body.motion.downTime,
+                      msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords);
 }
 
 void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) {
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index f1a26ec..a2fa319 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -272,8 +272,9 @@
                       AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
                       MotionClassification::NONE, mTransform, 2.0f, 2.1f,
                       AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                      INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_DOWN_TIME,
-                      ARBITRARY_EVENT_TIME, 2, pointerProperties, pointerCoords);
+                      ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
+                      ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2, pointerProperties,
+                      pointerCoords);
 
     pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110);
     pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111);
@@ -593,8 +594,9 @@
                      AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
                      MotionClassification::NONE, identityTransform, 0 /*xPrecision*/,
                      0 /*yPrecision*/, 3 + RADIUS /*xCursorPosition*/, 2 /*yCursorPosition*/,
-                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, 0 /*eventTime*/,
-                     pointerCount, pointerProperties, pointerCoords);
+                     ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
+                     0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties,
+                     pointerCoords);
     float originalRawX = 0 + 3;
     float originalRawY = -RADIUS + 2;
 
@@ -636,7 +638,8 @@
 }
 
 MotionEvent createTouchDownEvent(float x, float y, float dx, float dy,
-                                 const ui::Transform& transform) {
+                                 const ui::Transform& transform,
+                                 uint32_t displayOrientation = ui::Transform::ROT_0) {
     std::vector<PointerProperties> pointerProperties;
     pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER});
     std::vector<PointerCoords> pointerCoords;
@@ -652,7 +655,8 @@
                      /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE,
                      /* buttonState */ 0, MotionClassification::NONE, transform,
                      /* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, /* displayWidth */ 400,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, displayOrientation,
+                     /* displayWidth */ 400,
                      /* displayHeight */ 800, eventTime, eventTime, pointerCoords.size(),
                      pointerProperties.data(), pointerCoords.data());
     return event;
@@ -663,7 +667,7 @@
     ui::Transform identity;
     ui::Transform xform(ui::Transform::ROT_90, 800, 400);
     xform.set(xform.tx() + 20, xform.ty() + 40);
-    MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
+    MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90);
     ASSERT_EQ(700, event.getRawX(0));
     ASSERT_EQ(60, event.getRawY(0));
     ASSERT_NE(event.getRawX(0), event.getX(0));
@@ -703,7 +707,7 @@
         // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
         ui::Transform xform(ui::Transform::ROT_90, 800, 400);
         xform.set(xform.tx() + 20, xform.ty() + 40);
-        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
+        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90);
         event.setSource(source);
 
         // Since this event comes from a non-pointer source, it should include rotation but not
@@ -736,7 +740,7 @@
         // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
         ui::Transform xform(ui::Transform::ROT_90, 800, 400);
         xform.set(xform.tx() + 20, xform.ty() + 40);
-        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
+        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90);
         ASSERT_EQ(700, event.getRawX(0));
         ASSERT_EQ(60, event.getRawY(0));
         ASSERT_NE(event.getRawX(0), event.getX(0));
@@ -750,7 +754,7 @@
         // Same as above, but check rotate-180.
         ui::Transform xform(ui::Transform::ROT_180, 400, 800);
         xform.set(xform.tx() + 20, xform.ty() + 40);
-        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
+        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_180);
         ASSERT_EQ(340, event.getRawX(0));
         ASSERT_EQ(700, event.getRawY(0));
         // Relative values should be rotated but not translated.
@@ -762,13 +766,25 @@
         // Same as above, but check rotate-270.
         ui::Transform xform(ui::Transform::ROT_270, 800, 400);
         xform.set(xform.tx() + 20, xform.ty() + 40);
-        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
+        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_270);
         ASSERT_EQ(100, event.getRawX(0));
         ASSERT_EQ(340, event.getRawY(0));
         // Relative values should be rotated but not translated.
         ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
         ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
     }
+
+    {
+        // Finally, check that raw isn't effected by transform
+        ui::Transform xform(ui::Transform::ROT_270, 800, 400);
+        xform.set(xform.tx() + 20, xform.ty() + 40);
+        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90);
+        ASSERT_EQ(700, event.getRawX(0));
+        ASSERT_EQ(60, event.getRawY(0));
+        // Relative values should be rotated but not translated.
+        ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
+        ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
+    }
 }
 
 TEST_F(MotionEventTest, Initialize_SetsClassification) {
@@ -794,9 +810,9 @@
                          DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
                          AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, classification,
                          identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                         AMOTION_EVENT_INVALID_CURSOR_POSITION, INVALID_DISPLAY_SIZE,
-                         INVALID_DISPLAY_SIZE, 0 /*downTime*/, 0 /*eventTime*/, pointerCount,
-                         pointerProperties, pointerCoords);
+                         AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+                         INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/,
+                         0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
         ASSERT_EQ(classification, event.getClassification());
     }
 }
@@ -816,9 +832,9 @@
     event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID,
                      INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE,
                      AMETA_NONE, 0, MotionClassification::NONE, identityTransform, 0, 0,
-                     280 /*xCursorPosition*/, 540 /*yCursorPosition*/, INVALID_DISPLAY_SIZE,
-                     INVALID_DISPLAY_SIZE, 0 /*downTime*/, 0 /*eventTime*/, pointerCount,
-                     pointerProperties, pointerCoords);
+                     280 /*xCursorPosition*/, 540 /*yCursorPosition*/, ui::Transform::ROT_0,
+                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, 0 /*eventTime*/,
+                     pointerCount, pointerProperties, pointerCoords);
     event.offsetLocation(20, 60);
     ASSERT_EQ(280, event.getRawXCursorPosition());
     ASSERT_EQ(540, event.getRawYCursorPosition());
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index d0c337c..5d1f2c3 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -163,6 +163,7 @@
     constexpr float yPrecision = 0.5;
     constexpr float xCursorPosition = 1.3;
     constexpr float yCursorPosition = 50.6;
+    constexpr uint32_t displayOrientation = ui::Transform::ROT_0;
     constexpr int32_t displayWidth = 1000;
     constexpr int32_t displayHeight = 2000;
     constexpr nsecs_t downTime = 3;
@@ -193,9 +194,9 @@
     status = mPublisher->publishMotionEvent(seq, eventId, deviceId, source, displayId, hmac, action,
                                             actionButton, flags, edgeFlags, metaState, buttonState,
                                             classification, transform, xPrecision, yPrecision,
-                                            xCursorPosition, yCursorPosition, displayWidth,
-                                            displayHeight, downTime, eventTime, pointerCount,
-                                            pointerProperties, pointerCoords);
+                                            xCursorPosition, yCursorPosition, displayOrientation,
+                                            displayWidth, displayHeight, downTime, eventTime,
+                                            pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(OK, status)
             << "publisher publishMotionEvent should return OK";
 
@@ -232,6 +233,7 @@
     EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition());
     EXPECT_EQ(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition());
     EXPECT_EQ(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition());
+    EXPECT_EQ(displayOrientation, motionEvent->getDisplayOrientation());
     EXPECT_EQ(displayWidth, motionEvent->getDisplaySize().x);
     EXPECT_EQ(displayHeight, motionEvent->getDisplaySize().y);
     EXPECT_EQ(downTime, motionEvent->getDownTime());
@@ -461,8 +463,9 @@
     status = mPublisher->publishMotionEvent(0, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
                                             0, 0, 0, MotionClassification::NONE, identityTransform,
                                             0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                            AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 0, 0,
-                                            pointerCount, pointerProperties, pointerCoords);
+                                            AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                            ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount,
+                                            pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
 }
@@ -477,8 +480,9 @@
     status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
                                             0, 0, 0, MotionClassification::NONE, identityTransform,
                                             0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                            AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 0, 0,
-                                            pointerCount, pointerProperties, pointerCoords);
+                                            AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                            ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount,
+                                            pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
 }
@@ -498,8 +502,9 @@
     status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
                                             0, 0, 0, MotionClassification::NONE, identityTransform,
                                             0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                            AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 0, 0,
-                                            pointerCount, pointerProperties, pointerCoords);
+                                            AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                            ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount,
+                                            pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
 }
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 5861d55..59fed1f 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -74,10 +74,10 @@
   CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 124);
   CHECK_OFFSET(InputMessage::Body::Motion, xCursorPosition, 128);
   CHECK_OFFSET(InputMessage::Body::Motion, yCursorPosition, 132);
-  CHECK_OFFSET(InputMessage::Body::Motion, displayWidth, 136);
-  CHECK_OFFSET(InputMessage::Body::Motion, displayHeight, 140);
-  CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 144);
-  CHECK_OFFSET(InputMessage::Body::Motion, empty3, 148);
+  CHECK_OFFSET(InputMessage::Body::Motion, displayOrientation, 136);
+  CHECK_OFFSET(InputMessage::Body::Motion, displayWidth, 140);
+  CHECK_OFFSET(InputMessage::Body::Motion, displayHeight, 144);
+  CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 148);
   CHECK_OFFSET(InputMessage::Body::Motion, pointers, 152);
 
   CHECK_OFFSET(InputMessage::Body::Focus, eventId, 0);
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 8ae7dcc..13e2b02 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -184,9 +184,9 @@
                          AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
                          MotionClassification::NONE, identityTransform, 0 /*xPrecision*/,
                          0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                         AMOTION_EVENT_INVALID_CURSOR_POSITION, INVALID_DISPLAY_SIZE,
-                         INVALID_DISPLAY_SIZE, 0 /*downTime*/, entry.eventTime.count(),
-                         pointerCount, properties, coords);
+                         AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+                         INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/,
+                         entry.eventTime.count(), pointerCount, properties, coords);
 
         events.emplace_back(event);
     }
diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp
index a0c9c17..b29c9a4 100644
--- a/libs/input/tests/VerifiedInputEvent_test.cpp
+++ b/libs/input/tests/VerifiedInputEvent_test.cpp
@@ -47,9 +47,9 @@
                      INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags,
                      AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
                      MotionClassification::NONE, transform, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/,
-                     280 /*xCursorPosition*/, 540 /*yCursorPosition*/, INVALID_DISPLAY_SIZE,
-                     INVALID_DISPLAY_SIZE, 100 /*downTime*/, 200 /*eventTime*/, pointerCount,
-                     pointerProperties, pointerCoords);
+                     280 /*xCursorPosition*/, 540 /*yCursorPosition*/, ui::Transform::ROT_0,
+                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 100 /*downTime*/,
+                     200 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
     return event;
 }
 
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index 4ad6e94..7c5bee9 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -81,7 +81,7 @@
     // Kawase is an approximation of Gaussian, but it behaves differently from it.
     // A radius transformation is required for approximating them, and also to introduce
     // non-integer steps, necessary to smoothly interpolate large radii.
-    float tmpRadius = (float)blurRadius / 6.0f;
+    float tmpRadius = (float)blurRadius / 2.0f;
     float numberOfPasses = std::min(kMaxPasses, (uint32_t)ceil(tmpRadius));
     float radiusByPasses = tmpRadius / (float)numberOfPasses;
 
diff --git a/libs/renderengine/skia/filters/BlurFilter.h b/libs/renderengine/skia/filters/BlurFilter.h
index a8e6dd7..7110018 100644
--- a/libs/renderengine/skia/filters/BlurFilter.h
+++ b/libs/renderengine/skia/filters/BlurFilter.h
@@ -42,7 +42,7 @@
     static constexpr uint32_t kMaxPasses = 4;
     // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited
     // image, up to this radius.
-    static constexpr float kMaxCrossFadeRadius = 30.0f;
+    static constexpr float kMaxCrossFadeRadius = 10.0f;
 
     explicit BlurFilter();
     virtual ~BlurFilter(){};
diff --git a/libs/vibrator/ExternalVibrationUtils.cpp b/libs/vibrator/ExternalVibrationUtils.cpp
index 749c568..980b08b 100644
--- a/libs/vibrator/ExternalVibrationUtils.cpp
+++ b/libs/vibrator/ExternalVibrationUtils.cpp
@@ -56,6 +56,36 @@
     }
 }
 
+void applyHapticScale(float* buffer, size_t length, HapticScale scale) {
+    if (scale == HapticScale::MUTE) {
+        memset(buffer, 0, length * sizeof(float));
+        return;
+    }
+    if (scale == HapticScale::NONE) {
+        return;
+    }
+    float gamma = getHapticScaleGamma(scale);
+    float maxAmplitudeRatio = getHapticMaxAmplitudeRatio(scale);
+    for (size_t i = 0; i < length; i++) {
+        float sign = buffer[i] >= 0 ? 1.0 : -1.0;
+        buffer[i] = powf(fabsf(buffer[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma)
+                * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * sign;
+    }
+}
+
+void clipHapticData(float* buffer, size_t length, float limit) {
+    if (isnan(limit) || limit == 0) {
+        return;
+    }
+    limit = fabsf(limit);
+    for (size_t i = 0; i < length; i++) {
+        float sign = buffer[i] >= 0 ? 1.0 : -1.0;
+        if (fabsf(buffer[i]) > limit) {
+            buffer[i] = limit * sign;
+        }
+    }
+}
+
 } // namespace
 
 bool isValidHapticScale(HapticScale scale) {
@@ -71,21 +101,11 @@
     return false;
 }
 
-void scaleHapticData(float* buffer, size_t length, HapticScale scale) {
-    if (!isValidHapticScale(scale) || scale == HapticScale::NONE) {
-        return;
+void scaleHapticData(float* buffer, size_t length, HapticScale scale, float limit) {
+    if (isValidHapticScale(scale)) {
+        applyHapticScale(buffer, length, scale);
     }
-    if (scale == HapticScale::MUTE) {
-        memset(buffer, 0, length * sizeof(float));
-        return;
-    }
-    float gamma = getHapticScaleGamma(scale);
-    float maxAmplitudeRatio = getHapticMaxAmplitudeRatio(scale);
-    for (size_t i = 0; i < length; i++) {
-        float sign = buffer[i] >= 0 ? 1.0 : -1.0;
-        buffer[i] = powf(fabsf(buffer[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma)
-                * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * sign;
-    }
+    clipHapticData(buffer, length, limit);
 }
 
 } // namespace android::os
diff --git a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h
index 20045d0..84357fc 100644
--- a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h
+++ b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h
@@ -32,7 +32,11 @@
 
 bool isValidHapticScale(HapticScale scale);
 
-void scaleHapticData(float* buffer, size_t length, HapticScale scale);
+/* Scales the haptic data in given buffer using the selected HapticScale and ensuring no absolute
+ * value will be larger than the absolute of given limit.
+ * The limit will be ignored if it is NaN or zero.
+ */
+void scaleHapticData(float* buffer, size_t length, HapticScale scale, float limit);
 
 } // namespace android::os
 
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 55deec4..f77c029 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -237,8 +237,8 @@
                      /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
                      identityTransform, /* xPrecision */ 0,
                      /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, INVALID_DISPLAY_SIZE,
-                     INVALID_DISPLAY_SIZE, currentTime, currentTime,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, currentTime, currentTime,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     return event;
 }
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 881024f..b5ed064 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -296,12 +296,14 @@
 volatile int32_t DispatchEntry::sNextSeqAtomic;
 
 DispatchEntry::DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags,
-                             ui::Transform transform, float globalScaleFactor, int2 displaySize)
+                             ui::Transform transform, float globalScaleFactor,
+                             uint32_t displayOrientation, int2 displaySize)
       : seq(nextSeq()),
         eventEntry(std::move(eventEntry)),
         targetFlags(targetFlags),
         transform(transform),
         globalScaleFactor(globalScaleFactor),
+        displayOrientation(displayOrientation),
         displaySize(displaySize),
         deliveryTime(0),
         resolvedAction(0),
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 89d7659..1b7fcf2 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -215,6 +215,7 @@
     int32_t targetFlags;
     ui::Transform transform;
     float globalScaleFactor;
+    uint32_t displayOrientation;
     int2 displaySize;
     // Both deliveryTime and timeoutTime are only populated when the entry is sent to the app,
     // and will be undefined before that.
@@ -228,7 +229,8 @@
     int32_t resolvedFlags;
 
     DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags,
-                  ui::Transform transform, float globalScaleFactor, int2 displaySize);
+                  ui::Transform transform, float globalScaleFactor, uint32_t displayOrientation,
+                  int2 displaySize);
 
     inline bool hasForegroundTarget() const { return targetFlags & InputTarget::FLAG_FOREGROUND; }
 
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 4835795..9f4108d 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -331,6 +331,7 @@
             // don't depend on the window transform.
             return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, identityTransform,
                                                    1.0f /*globalScaleFactor*/,
+                                                   inputTarget.displayOrientation,
                                                    inputTarget.displaySize);
         }
     }
@@ -339,6 +340,7 @@
         const ui::Transform& transform = inputTarget.getDefaultPointerTransform();
         return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, transform,
                                                inputTarget.globalScaleFactor,
+                                               inputTarget.displayOrientation,
                                                inputTarget.displaySize);
     }
 
@@ -391,6 +393,7 @@
     std::unique_ptr<DispatchEntry> dispatchEntry =
             std::make_unique<DispatchEntry>(std::move(combinedMotionEntry), inputTargetFlags,
                                             firstPointerTransform, inputTarget.globalScaleFactor,
+                                            inputTarget.displayOrientation,
                                             inputTarget.displaySize);
     return dispatchEntry;
 }
@@ -2448,6 +2451,7 @@
         inputTarget.inputChannel = inputChannel;
         inputTarget.flags = targetFlags;
         inputTarget.globalScaleFactor = windowInfo->globalScaleFactor;
+        inputTarget.displayOrientation = windowInfo->displayOrientation;
         inputTarget.displaySize =
                 int2(windowHandle->getInfo()->displayWidth, windowHandle->getInfo()->displayHeight);
         inputTargets.push_back(inputTarget);
@@ -3161,6 +3165,7 @@
                                                      motionEntry.xPrecision, motionEntry.yPrecision,
                                                      motionEntry.xCursorPosition,
                                                      motionEntry.yCursorPosition,
+                                                     dispatchEntry->displayOrientation,
                                                      dispatchEntry->displaySize.x,
                                                      dispatchEntry->displaySize.y,
                                                      motionEntry.downTime, motionEntry.eventTime,
@@ -3873,9 +3878,9 @@
                              args->action, args->actionButton, args->flags, args->edgeFlags,
                              args->metaState, args->buttonState, args->classification, transform,
                              args->xPrecision, args->yPrecision, args->xCursorPosition,
-                             args->yCursorPosition, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
-                             args->downTime, args->eventTime, args->pointerCount,
-                             args->pointerProperties, args->pointerCoords);
+                             args->yCursorPosition, ui::Transform::ROT_0, INVALID_DISPLAY_SIZE,
+                             INVALID_DISPLAY_SIZE, args->downTime, args->eventTime,
+                             args->pointerCount, args->pointerProperties, args->pointerCoords);
 
             policyFlags |= POLICY_FLAG_FILTERED;
             if (!mPolicy->filterInputEvent(&event, policyFlags)) {
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index 9c62b7e..7c463c8 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -101,6 +101,9 @@
     // (ignored for KeyEvents)
     float globalScaleFactor = 1.0f;
 
+    // Current display orientation
+    uint32_t displayOrientation = ui::Transform::ROT_0;
+
     // Display-size in its natural rotation. Used for compatibility transform of raw coordinates.
     int2 displaySize = {INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE};
 
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 6cad839..a568220 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -530,8 +530,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, INVALID_DISPLAY_SIZE,
-                     INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -544,7 +544,8 @@
                              (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+                     ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -556,7 +557,8 @@
                              (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+                     ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -569,7 +571,8 @@
                              (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+                     ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -581,7 +584,8 @@
                              (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+                     ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -592,8 +596,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, INVALID_DISPLAY_SIZE,
-                     INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 0, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -603,8 +607,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, INVALID_DISPLAY_SIZE,
-                     INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -616,8 +620,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, INVALID_DISPLAY_SIZE,
-                     INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -628,8 +632,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, INVALID_DISPLAY_SIZE,
-                     INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -642,8 +646,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, INVALID_DISPLAY_SIZE,
-                     INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 2, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -1264,8 +1268,9 @@
                          mAction, mActionButton, mFlags, /* edgeFlags */ 0, AMETA_NONE,
                          mButtonState, MotionClassification::NONE, identityTransform,
                          /* xPrecision */ 0, /* yPrecision */ 0, mRawXCursorPosition,
-                         mRawYCursorPosition, mDisplayWidth, mDisplayHeight, mEventTime, mEventTime,
-                         mPointers.size(), pointerProperties.data(), pointerCoords.data());
+                         mRawYCursorPosition, mDisplayOrientation, mDisplayWidth, mDisplayHeight,
+                         mEventTime, mEventTime, mPointers.size(), pointerProperties.data(),
+                         pointerCoords.data());
 
         return event;
     }
@@ -1280,6 +1285,7 @@
     int32_t mFlags{0};
     float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
     float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
+    uint32_t mDisplayOrientation{ui::Transform::ROT_0};
     int32_t mDisplayWidth{INVALID_DISPLAY_SIZE};
     int32_t mDisplayHeight{INVALID_DISPLAY_SIZE};
 
@@ -3200,9 +3206,9 @@
                          DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
                          AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE,
                          identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                         AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                         0 /*AMOTION_EVENT_INVALID_DISPLAY_SIZE*/,
-                         0 /*AMOTION_EVENT_INVALID_DISPLAY_SIZE*/, eventTime, eventTime,
+                         AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
+                         0 /*INVALID_DISPLAY_SIZE*/, 0 /*INVALID_DISPLAY_SIZE*/, eventTime,
+                         eventTime,
                          /*pointerCount*/ 1, pointerProperties, pointerCoords);
 
         const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 2976937..93c86d1 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -580,8 +580,8 @@
     layerSettings.geometry.positionTransform = getTransform().asMatrix4();
 
     // skip drawing content if the targetSettings indicate the content will be occluded
-    layerSettings.skipContentDraw =
-            layerSettings.skipContentDraw || !targetSettings.realContentIsVisible;
+    const bool drawContent = targetSettings.realContentIsVisible || targetSettings.clearContent;
+    layerSettings.skipContentDraw = !drawContent;
 
     if (hasColorTransform()) {
         layerSettings.colorTransform = getColorTransform();
@@ -2298,6 +2298,10 @@
     ui::Transform toPhysicalDisplay;
     if (display) {
         toPhysicalDisplay = display->getTransform();
+        // getOrientation() without masking can contain more-significant bits (eg. ROT_INVALID).
+        static constexpr uint32_t ALL_ROTATIONS_MASK =
+                ui::Transform::ROT_90 | ui::Transform::ROT_180 | ui::Transform::ROT_270;
+        info.displayOrientation = toPhysicalDisplay.getOrientation() & ALL_ROTATIONS_MASK;
         info.displayWidth = display->getWidth();
         info.displayHeight = display->getHeight();
     }
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 24789cf..3aaa680 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -796,6 +796,11 @@
     // for symmetry with Vector::remove
     ssize_t removeChild(const sp<Layer>& layer);
     sp<Layer> getParent() const { return mCurrentParent.promote(); }
+
+    // Should be called with the surfaceflinger statelock held
+    bool isAtRoot() const { return mIsAtRoot; }
+    void setIsAtRoot(bool isAtRoot) { mIsAtRoot = isAtRoot; }
+
     bool hasParent() const { return getParent() != nullptr; }
     Rect getScreenBounds(bool reduceTransparentRegion = true) const;
     bool setChildLayer(const sp<Layer>& childLayer, int32_t z);
@@ -1103,6 +1108,8 @@
 
     // A list of regions on this layer that should have blurs.
     const std::vector<BlurRegion> getBlurRegions() const;
+
+    bool mIsAtRoot = false;
 };
 
 std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate);
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index b0d76e6..8704c88 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -200,6 +200,7 @@
 
     mLayer = mClient->getLayerUser(mIBinder);
     mLayer->setFrameRate(Layer::FrameRate(Fps(0.0f), Layer::FrameRateCompatibility::NoVote));
+    mLayer->setIsAtRoot(true);
 
     // setting Layer's Z requires resorting layersSortedByZ
     ssize_t idx = mFlinger.mDrawingState.layersSortedByZ.indexOf(mLayer);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 2c2bdad..5e17828 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1157,6 +1157,12 @@
     }
 
     const auto upcomingModeInfo = MAIN_THREAD_GUARD(display->getUpcomingActiveMode());
+    if (!upcomingModeInfo.mode) {
+        // There is no pending mode change. This can happen if the active
+        // display changed and the mode change happened on a different display.
+        return;
+    }
+
     if (display->getActiveMode()->getSize() != upcomingModeInfo.mode->getSize()) {
         auto& state = mCurrentState.displays.editValueFor(display->getDisplayToken());
         // We need to generate new sequenceId in order to recreate the display (and this
@@ -4156,6 +4162,7 @@
                 : nullptr;
         if (layer->reparent(parentHandle)) {
             if (!hadParent) {
+                layer->setIsAtRoot(false);
                 mCurrentState.layersSortedByZ.remove(layer);
             }
             flags |= eTransactionNeeded | eTraversalNeeded;
@@ -4422,7 +4429,8 @@
     // with the idea that the parent holds a reference and will eventually
     // be cleaned up. However no one cleans up the top-level so we do so
     // here.
-    if (layer->getParent() == nullptr) {
+    if (layer->isAtRoot()) {
+        layer->setIsAtRoot(false);
         mCurrentState.layersSortedByZ.remove(layer);
     }
     markLayerPendingRemovalLocked(layer);
@@ -6900,6 +6908,7 @@
     }
 
     if (parent == nullptr && allowAddRoot) {
+        layer->setIsAtRoot(true);
         mCurrentState.layersSortedByZ.add(layer);
     } else if (parent == nullptr) {
         layer->onRemovedFromCurrentState();