Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d1d8402a authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Consider multiple show-when-locked activities for wallpaper

2 problems:
- ActivityRecord#mShowWhenLocked was not involved, i.e. if the
  app uses Activity#setShowWhenLocked rather than
  FLAG_SHOW_WHEN_LOCKED, the condition needsShowWhenLockedWallpaper
  is never satisfied.
- The useTopWallpaperAsTarget was always true if there exists one
  non fullscreen show-when-locked activity even if the wallpaper
  can be occluded by the opaque show-when-locked activity behind.

The first one is fixed by checking WindowState#canShowWhenLocked.
The second one is fixed by updating mNeedsShowWhenLockedWallpaper
when going through all windows from top to bottom.

Note that with shell transition, if the wallpaper becomes visible
unexpectedly, it will be collected into transition. And because
the wallpaper surface will be put on transition root surface that
may have higher z-order, which will cause the wallpaper to be
flickering when switching show-when-locked activities with scene
transition (covert to translucent).

Fix: 286172268
Test: WallpaperControllerTests#testShowWhenLockedWallpaperTarge
Change-Id: Ic029c9c42472f7061020e4ca47e325be1ee53787
parent f80ef935
Loading
Loading
Loading
Loading
+20 −20
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import static android.app.WallpaperManager.COMMAND_UNFREEZE;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
@@ -137,7 +136,8 @@ class WallpaperController {
    };

    private final ToBooleanFunction<WindowState> mFindWallpaperTargetFunction = w -> {
        if (!w.mTransitionController.isShellTransitionsEnabled()) {
        final boolean useShellTransition = w.mTransitionController.isShellTransitionsEnabled();
        if (!useShellTransition) {
            if (w.mActivityRecord != null && !w.mActivityRecord.isVisible()
                    && !w.mActivityRecord.isAnimating(TRANSITION | PARENTS)) {
                // If this window's app token is hidden and not animating, it is of no interest.
@@ -159,32 +159,25 @@ class WallpaperController {

        final WindowContainer animatingContainer = w.mActivityRecord != null
                ? w.mActivityRecord.getAnimatingContainer() : null;
        final boolean keyguardGoingAwayWithWallpaper = (animatingContainer != null
        if (!useShellTransition && animatingContainer != null
                && animatingContainer.isAnimating(TRANSITION | PARENTS)
                && AppTransition.isKeyguardGoingAwayTransitOld(animatingContainer.mTransit)
                && (animatingContainer.mTransitFlags
                & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0);

        boolean needsShowWhenLockedWallpaper = false;
        if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 && mService.mPolicy.isKeyguardLocked()) {
            final TransitionController tc = w.mTransitionController;
            final boolean isInTransition = tc.isShellTransitionsEnabled()
                    && tc.inTransition(w);
            if (mService.mPolicy.isKeyguardOccluded() || mService.mPolicy.isKeyguardUnoccluding()
                    || isInTransition) {
                & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0) {
            // Keep the wallpaper visible when Keyguard is going away.
            mFindResults.setUseTopWallpaperAsTarget(true);
        }

        if (mService.mPolicy.isKeyguardLocked() && w.canShowWhenLocked()) {
            if (mService.mPolicy.isKeyguardOccluded() || (useShellTransition
                    ? w.inTransition() : mService.mPolicy.isKeyguardUnoccluding())) {
                // The lowest show when locked window decides whether we need to put the wallpaper
                // behind.
                needsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs)
                mFindResults.mNeedsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs)
                        || (w.mActivityRecord != null && !w.mActivityRecord.fillsParent());
            }
        }

        if (keyguardGoingAwayWithWallpaper || needsShowWhenLockedWallpaper) {
            // Keep the wallpaper during Keyguard exit but also when it's needed for a
            // non-fullscreen show when locked activity.
            mFindResults.setUseTopWallpaperAsTarget(true);
        }

        final boolean animationWallpaper = animatingContainer != null
                && animatingContainer.getAnimation() != null
                && animatingContainer.getAnimation().getShowWallpaper();
@@ -691,7 +684,8 @@ class WallpaperController {

    private void findWallpaperTarget() {
        mFindResults.reset();
        if (mDisplayContent.getDefaultTaskDisplayArea()
        if (mService.mAtmService.mSupportsFreeformWindowManagement
                && mDisplayContent.getDefaultTaskDisplayArea()
                .isRootTaskVisible(WINDOWING_MODE_FREEFORM)) {
            // In freeform mode we set the wallpaper as its own target, so we don't need an
            // additional window to make it visible.
@@ -700,6 +694,10 @@ class WallpaperController {

        mDisplayContent.forAllWindows(mFindWallpapers, true /* traverseTopToBottom */);
        mDisplayContent.forAllWindows(mFindWallpaperTargetFunction, true /* traverseTopToBottom */);
        if (mFindResults.mNeedsShowWhenLockedWallpaper) {
            // Keep wallpaper visible if the show-when-locked activities doesn't fill screen.
            mFindResults.setUseTopWallpaperAsTarget(true);
        }

        if (mFindResults.wallpaperTarget == null && mFindResults.useTopWallpaperAsTarget) {
            mFindResults.setWallpaperTarget(
@@ -1084,6 +1082,7 @@ class WallpaperController {
        }

        TopWallpaper mTopWallpaper = new TopWallpaper();
        boolean mNeedsShowWhenLockedWallpaper;
        boolean useTopWallpaperAsTarget = false;
        WindowState wallpaperTarget = null;
        boolean isWallpaperTargetForLetterbox = false;
@@ -1132,6 +1131,7 @@ class WallpaperController {

        void reset() {
            mTopWallpaper.reset();
            mNeedsShowWhenLockedWallpaper = false;
            wallpaperTarget = null;
            useTopWallpaperAsTarget = false;
            isWallpaperTargetForLetterbox = false;
+5 −4
Original line number Diff line number Diff line
@@ -2983,10 +2983,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP

    @Override
    public boolean canShowWhenLocked() {
        final boolean showBecauseOfActivity =
                mActivityRecord != null && mActivityRecord.canShowWhenLocked();
        final boolean showBecauseOfWindow = (getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0;
        return showBecauseOfActivity || showBecauseOfWindow;
        if (mActivityRecord != null) {
            // It will also check if its windows contain FLAG_SHOW_WHEN_LOCKED.
            return mActivityRecord.canShowWhenLocked();
        }
        return (mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0;
    }

    /**
+26 −0
Original line number Diff line number Diff line
@@ -288,6 +288,32 @@ public class WallpaperControllerTests extends WindowTestsBase {
        assertEquals(homeWin, dc.mWallpaperController.getWallpaperTarget());
    }

    @Test
    public void testShowWhenLockedWallpaperTarget() {
        final WindowState wallpaperWindow = createWallpaperWindow(mDisplayContent);
        wallpaperWindow.mToken.asWallpaperToken().setShowWhenLocked(true);
        final WindowState behind = createWindow(null, TYPE_BASE_APPLICATION, "behind");
        final WindowState topTranslucent = createWindow(null, TYPE_BASE_APPLICATION,
                "topTranslucent");
        behind.mAttrs.width = behind.mAttrs.height = topTranslucent.mAttrs.width =
                topTranslucent.mAttrs.height = WindowManager.LayoutParams.MATCH_PARENT;
        topTranslucent.mAttrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
        doReturn(true).when(behind.mActivityRecord).fillsParent();
        doReturn(false).when(topTranslucent.mActivityRecord).fillsParent();

        spyOn(mWm.mPolicy);
        doReturn(true).when(mWm.mPolicy).isKeyguardLocked();
        doReturn(true).when(mWm.mPolicy).isKeyguardOccluded();
        mDisplayContent.mWallpaperController.adjustWallpaperWindows();
        // Wallpaper is visible because the show-when-locked activity is translucent.
        assertTrue(mDisplayContent.mWallpaperController.isWallpaperTarget(wallpaperWindow));

        behind.mActivityRecord.setShowWhenLocked(true);
        mDisplayContent.mWallpaperController.adjustWallpaperWindows();
        // Wallpaper is invisible because the lowest show-when-locked activity is opaque.
        assertTrue(mDisplayContent.mWallpaperController.isWallpaperTarget(null));
    }

    /**
     * Tests that the windowing mode of the wallpaper window must always be fullscreen.
     */