From dd6be4764a337628651f6384fcb18c4e43c7722a Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Tue, 22 Jun 2021 14:13:27 -0700 Subject: [PATCH] Keep wallpaper as a special-case in transitions Wallpaper unfortunately needs to be handled specially by transition players because of it's arrangement in the hierarchy (being in a separate root displayareay) and because it has specific ordering mechanics during animations. Now that DisplayAreas are "organized", they interfere with wallpaper's handling as a special-case in a transition. To prevent this, explicitly prevent any of wallpaper's ancestor displayareas from being part of the transition. Bug: 187461719 Test: launch a landscape app from portrait launcher. Observe wallpaper not disappearing. Change-Id: Id9e86f14d380b5ed8050b303edf5f1b48875ff20 --- .../com/android/server/wm/Transition.java | 16 ++++---- .../android/server/wm/TransitionTests.java | 38 +++++++++++++++++++ 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 8e18da14d3b31..c8ae776c1d140 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -777,6 +777,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe if (reportIfNotTop(wc)) { tmpList.add(wc); } + // Wallpaper must be the top (regardless of how nested it is in DisplayAreas). + boolean skipIntermediateReports = isWallpaper(wc); for (WindowContainer p = wc.getParent(); p != null; p = p.getParent()) { if (!p.isAttached() || !changes.get(p).hasChanged(p)) { // Again, we're skipping no-ops @@ -785,7 +787,9 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe if (participants.contains(p)) { topParent = p; break; - } else if (reportIfNotTop(p)) { + } else if (isWallpaper(p)) { + skipIntermediateReports = true; + } else if (reportIfNotTop(p) && !skipIntermediateReports) { tmpList.add(p); } } @@ -871,17 +875,11 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe } // Find the top-most shared ancestor of app targets - WindowContainer ancestor = null; - for (int i = appTargets.size() - 1; i >= 0; --i) { - final WindowContainer wc = appTargets.valueAt(i); - ancestor = wc; - break; - } - if (ancestor == null) { + if (appTargets.isEmpty()) { out.setRootLeash(new SurfaceControl(), 0, 0); return out; } - ancestor = ancestor.getParent(); + WindowContainer ancestor = appTargets.valueAt(appTargets.size() - 1).getParent(); // Go up ancestor parent chain until all targets are descendants. ancestorLoop: diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index 2dfb3a1a84bc1..45e5f8e55f8ae 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -338,6 +338,44 @@ public class TransitionTests extends WindowTestsBase { tasks[showWallpaperTask].mRemoteToken.toWindowContainerToken()).getFlags()); } + @Test + public void testTargets_noIntermediatesToWallpaper() { + final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN); + + final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, + mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */); + // Make DA organized so we can check that they don't get included. + WindowContainer parent = wallpaperWindowToken.getParent(); + while (parent != null && parent != mDisplayContent) { + if (parent.asDisplayArea() != null) { + parent.asDisplayArea().setOrganizer( + mock(android.window.IDisplayAreaOrganizer.class), true /* skipAppear */); + } + parent = parent.getParent(); + } + final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, wallpaperWindowToken, + "wallpaperWindow"); + wallpaperWindowToken.setVisibleRequested(false); + transition.collect(wallpaperWindowToken); + wallpaperWindowToken.setVisibleRequested(true); + wallpaperWindow.mHasSurface = true; + doReturn(true).when(mDisplayContent).isAttached(); + transition.collect(mDisplayContent); + mDisplayContent.getWindowConfiguration().setRotation( + (mDisplayContent.getWindowConfiguration().getRotation() + 1) % 4); + + ArraySet targets = Transition.calculateTargets( + transition.mParticipants, transition.mChanges); + TransitionInfo info = Transition.calculateTransitionInfo( + 0, 0, targets, transition.mChanges); + // The wallpaper is not organized, so it won't have a token; however, it will be marked + // as IS_WALLPAPER + assertEquals(FLAG_IS_WALLPAPER, info.getChanges().get(0).getFlags()); + // Make sure no intermediate display areas were pulled in between wallpaper and display. + assertEquals(mDisplayContent.mRemoteToken.toWindowContainerToken(), + info.getChanges().get(0).getParent()); + } + @Test public void testIndependent() { final Transition transition = createTestTransition(TRANSIT_OPEN);