diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 79a54c3cfb32d..a510b3076c7ba 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -77,6 +77,7 @@ import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.IRemoteCallback; +import android.os.Looper; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; @@ -2686,6 +2687,26 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { }); } + /** + * Returns {@code true} if the transition and the corresponding transaction should be applied + * on display thread. Currently, this only checks for display rotation change because the order + * of dispatching the new display info will be after requesting the windows to sync drawing. + * That avoids potential flickering of screen overlays (e.g. cutout, rounded corner). Also, + * because the display thread has a higher priority, it is faster to perform the configuration + * changes and window hierarchy traversal. + */ + boolean shouldApplyOnDisplayThread() { + for (int i = mParticipants.size() - 1; i >= 0; --i) { + final DisplayContent dc = mParticipants.valueAt(i).asDisplayContent(); + if (dc == null) continue; + final ChangeInfo changeInfo = mChanges.get(dc); + if (changeInfo != null && changeInfo.mRotation != dc.getRotation()) { + return Looper.myLooper() != mController.mAtm.mWindowManager.mH.getLooper(); + } + } + return false; + } + /** Applies the new configuration for the changed displays. */ void applyDisplayChangeIfNeeded() { for (int i = mParticipants.size() - 1; i >= 0; --i) { diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index a539a4893d4f6..79cb61be5948b 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -588,15 +588,6 @@ class TransitionController { /** Sets the sync method for the display change. */ private void setDisplaySyncMethod(@NonNull TransitionRequestInfo.DisplayChange displayChange, @NonNull Transition displayTransition, @NonNull DisplayContent displayContent) { - final int startRotation = displayChange.getStartRotation(); - final int endRotation = displayChange.getEndRotation(); - if (startRotation != endRotation && (startRotation + endRotation) % 2 == 0) { - // 180 degrees rotation change may not change screen size. So the clients may draw - // some frames before and after the display projection transaction is applied by the - // remote player. That may cause some buffers to show in different rotation. So use - // sync method to pause clients drawing until the projection transaction is applied. - mSyncEngine.setSyncMethod(displayTransition.getSyncId(), BLASTSyncEngine.METHOD_BLAST); - } final Rect startBounds = displayChange.getStartAbsBounds(); final Rect endBounds = displayChange.getEndAbsBounds(); if (startBounds == null || endBounds == null) return; diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index a2f7ba499fdff..31918f478e444 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -321,9 +321,18 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub applyTransaction(wct, -1 /*syncId*/, null /*transition*/, caller); return transition.getToken(); } - transition.start(); transition.mLogger.mStartWCT = wct; - applyTransaction(wct, -1 /*syncId*/, transition, caller); + if (transition.shouldApplyOnDisplayThread()) { + mService.mH.post(() -> { + synchronized (mService.mGlobalLock) { + transition.start(); + applyTransaction(wct, -1 /* syncId */, transition, caller); + } + }); + } else { + transition.start(); + applyTransaction(wct, -1 /* syncId */, transition, caller); + } // Since the transition is already provided, it means WMCore is determining the // "readiness lifecycle" outside the provided transaction, so don't set ready here. return transition.getToken(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 5369b93c95346..bdd178b0b3178 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -2046,6 +2046,7 @@ public class DisplayContentTests extends WindowTestsBase { // Once transition starts, rotation is applied and transition shows DC rotating. testPlayer.startTransition(); + waitUntilHandlersIdle(); assertNotEquals(origRot, dc.getConfiguration().windowConfiguration.getRotation()); assertNotNull(testPlayer.mLastReady); assertTrue(testPlayer.mController.isPlaying());