From 9d186163c4c2723921d94cc350799c5e4b5b3eae Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Wed, 15 Mar 2023 22:49:45 +0800 Subject: [PATCH] Validate visibility when finishing transition If the transition info doesn't contain any visible modes, then recover the visible state of surface for the correspond window container. This avoids showing blank screen by an incomplete transition that hides task or display area unexpectedly. Bug: 273206473 Fix: 269732484 Test: Assume a task X has an Activity A. Consecutive steps: Start B: X[A, B] Start A' with FLAG_ACTIVITY_CLEAR_TOP to finish [A, B] Final: X[A'] The surface of Task X and its parent should be visible. Change-Id: Id9de134a2ddc04f7ed7fb2d3c67d7337261c5ba7 --- .../com/android/server/wm/Transition.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 97f48b7d03097..370d304ed324e 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -1012,6 +1012,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { dc.removeImeSurfaceImmediately(); dc.handleCompleteDeferredRemoval(); } + validateVisibility(); mState = STATE_FINISHED; mController.mTransitionTracer.logState(this); @@ -1920,6 +1921,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { change.setLastParent(info.mStartParent.mRemoteToken.toWindowContainerToken()); } change.setMode(info.getTransitMode(target)); + info.mReadyMode = change.getMode(); change.setStartAbsBounds(info.mAbsoluteBounds); change.setFlags(info.getChangeFlags(target)); change.setDisplayId(info.mDisplayId, getDisplayId(target)); @@ -2177,6 +2179,26 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { return mainWin.getAttrs().rotationAnimation; } + private void validateVisibility() { + for (int i = mTargets.size() - 1; i >= 0; --i) { + if (reduceMode(mTargets.get(i).mReadyMode) != TRANSIT_CLOSE) { + return; + } + } + // All modes are CLOSE. The surfaces may be hidden by the animation unexpectedly. + // If the window container should be visible, then recover it. + mController.mStateValidators.add(() -> { + for (int i = mTargets.size() - 1; i >= 0; --i) { + final ChangeInfo change = mTargets.get(i); + if (!change.mContainer.isVisibleRequested()) continue; + Slog.e(TAG, "Force show for visible " + change.mContainer + + " which may be hidden by transition unexpectedly"); + change.mContainer.getSyncTransaction().show(change.mContainer.mSurfaceControl); + change.mContainer.scheduleAnimation(); + } + }); + } + /** Applies the new configuration for the changed displays. */ void applyDisplayChangeIfNeeded() { for (int i = mParticipants.size() - 1; i >= 0; --i) { @@ -2262,6 +2284,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { SurfaceControl mSnapshot; float mSnapshotLuma; + /** The mode which is set when the transition is ready. */ + @TransitionInfo.TransitionMode + int mReadyMode; + ChangeInfo(@NonNull WindowContainer origState) { mContainer = origState; mVisible = origState.isVisibleRequested();