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

Commit 1dbb239b authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Preserve wallpaper visible state for a while when display switches

Because screen may be turned off when switching display, the wallpaper
service will be notified with invisible state. And then its rendering
thread could be stopped. If the size change is delivered when the
renderer is not active, it won't update in time. That may cause to
flicker after the display is turned on.

Note that currently RWC#createSleepToken is always called on display
switch no matter screen will turn on or keep off. So the invocation of
onSleepingWithDisplaySwitch and onSleptOrScreenTurnedOn should be
paired to consume the preserved state.

The preserved visible state will be canceled by 3 conditions:
1. The display has turned on.
2. The device goes to sleep state.
3. The 1s timeout is reached.

Bug: 301443073
Test: Set "always" to Continue to use apps on fold".
      Use live wallpaper.
      Fold the device while top is launcher and screen is on.
      The wallpaper is not flicking with old size.
Change-Id: I09c630a94d39bb21388d6bedcdd3b423a060fda0
parent cdde529a
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -254,6 +254,13 @@ public class WallpaperManager {
     */
    public static final String COMMAND_GOING_TO_SLEEP = "android.wallpaper.goingtosleep";

    /**
     * Command for {@link #sendWallpaperCommand}: reported when a physical display switch event
     * happens, e.g. fold and unfold.
     * @hide
     */
    public static final String COMMAND_DISPLAY_SWITCH = "android.wallpaper.displayswitch";

    /**
     * Command for {@link #sendWallpaperCommand}: reported when the wallpaper that was already
     * set is re-applied by the user.
+37 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.service.wallpaper;

import static android.app.WallpaperManager.COMMAND_DISPLAY_SWITCH;
import static android.app.WallpaperManager.COMMAND_FREEZE;
import static android.app.WallpaperManager.COMMAND_UNFREEZE;
import static android.app.WallpaperManager.SetWallpaperFlags;
@@ -153,6 +154,7 @@ public abstract class WallpaperService extends Service {
    static final boolean DEBUG = false;
    static final float MIN_PAGE_ALLOWED_MARGIN = .05f;
    private static final int MIN_BITMAP_SCREENSHOT_WIDTH = 64;
    private static final long PRESERVE_VISIBLE_TIMEOUT_MS = 1000;
    private static final long DEFAULT_UPDATE_SCREENSHOT_DURATION = 60 * 1000; //Once per minute
    private static final @NonNull RectF LOCAL_COLOR_BOUNDS =
            new RectF(0, 0, 1, 1);
@@ -165,6 +167,7 @@ public abstract class WallpaperService extends Service {

    private static final int MSG_UPDATE_SURFACE = 10000;
    private static final int MSG_VISIBILITY_CHANGED = 10010;
    private static final int MSG_REFRESH_VISIBILITY = 10011;
    private static final int MSG_WALLPAPER_OFFSETS = 10020;
    private static final int MSG_WALLPAPER_COMMAND = 10025;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -248,6 +251,11 @@ public abstract class WallpaperService extends Service {
         */
        private boolean mIsScreenTurningOn;
        boolean mReportedVisible;
        /**
         * This is used with {@link #PRESERVE_VISIBLE_TIMEOUT_MS} to avoid intermediate visibility
         * changes if the display may be toggled in a short time, e.g. display switch.
         */
        boolean mPreserveVisible;
        boolean mDestroyed;
        // Set to true after receiving WallpaperManager#COMMAND_FREEZE. It's reset back to false
        // after receiving WallpaperManager#COMMAND_UNFREEZE. COMMAND_FREEZE is fully applied once
@@ -1084,6 +1092,9 @@ public abstract class WallpaperService extends Service {
            if (pendingCount != 0) {
                out.print(prefix); out.print("mPendingResizeCount="); out.println(pendingCount);
            }
            if (mPreserveVisible) {
                out.print(prefix); out.print("mPreserveVisible=true");
            }
            synchronized (mLock) {
                out.print(prefix); out.print("mPendingXOffset="); out.print(mPendingXOffset);
                        out.print(" mPendingXOffset="); out.println(mPendingXOffset);
@@ -1643,7 +1654,8 @@ public abstract class WallpaperService extends Service {
                                ? false
                                : mIWallpaperEngine.mInfo.supportsAmbientMode();
                // Report visibility only if display is fully on or wallpaper supports ambient mode.
                boolean visible = mVisible && (displayFullyOn || supportsAmbientMode);
                final boolean visible = (mVisible && (displayFullyOn || supportsAmbientMode))
                        || mPreserveVisible;
                if (DEBUG) {
                    Log.v(
                            TAG,
@@ -2080,6 +2092,9 @@ public abstract class WallpaperService extends Service {
            if (!mDestroyed) {
                if (COMMAND_FREEZE.equals(cmd.action) || COMMAND_UNFREEZE.equals(cmd.action)) {
                    updateFrozenState(/* frozenRequested= */ !COMMAND_UNFREEZE.equals(cmd.action));
                } else if (COMMAND_DISPLAY_SWITCH.equals(cmd.action)) {
                    handleDisplaySwitch(cmd.z == 1 /* startToSwitch */);
                    return;
                }
                result = onCommand(cmd.action, cmd.x, cmd.y, cmd.z,
                        cmd.extras, cmd.sync);
@@ -2095,6 +2110,23 @@ public abstract class WallpaperService extends Service {
            }
        }

        private void handleDisplaySwitch(boolean startToSwitch) {
            if (startToSwitch && mReportedVisible) {
                // The display may be off/on in a short time when the display is switching.
                // Keep the visible state until onScreenTurnedOn or !startToSwitch is received, so
                // the rendering thread can be active to redraw in time when receiving size change.
                mPreserveVisible = true;
                mCaller.removeMessages(MSG_REFRESH_VISIBILITY);
                mCaller.sendMessageDelayed(mCaller.obtainMessage(MSG_REFRESH_VISIBILITY),
                        PRESERVE_VISIBLE_TIMEOUT_MS);
            } else if (!startToSwitch && mPreserveVisible) {
                // The switch is finished, so restore to actual visibility.
                mPreserveVisible = false;
                mCaller.removeMessages(MSG_REFRESH_VISIBILITY);
                reportVisibility(false /* forceReport */);
            }
        }

        private void updateFrozenState(boolean frozenRequested) {
            if (mIWallpaperEngine.mInfo == null
                    // Procees the unfreeze command in case the wallaper became static while
@@ -2638,6 +2670,10 @@ public abstract class WallpaperService extends Service {
                            + ": " + message.arg1);
                    mEngine.doVisibilityChanged(message.arg1 != 0);
                    break;
                case MSG_REFRESH_VISIBILITY:
                    mEngine.mPreserveVisible = false;
                    mEngine.reportVisibility(false /* forceReport */);
                    break;
                case MSG_UPDATE_SCREEN_TURNING_ON:
                    if (DEBUG) {
                        Log.v(TAG,
+2 −1
Original line number Diff line number Diff line
@@ -5634,7 +5634,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurningOn",
                    0 /* cookie */);
            updateScreenOffSleepToken(false /* acquire */, false /* isSwappingDisplay */);
            mDefaultDisplayPolicy.screenTurnedOn(screenOnListener);
            mDefaultDisplayPolicy.screenTurningOn(screenOnListener);
            mBootAnimationDismissable = false;

            synchronized (mLock) {
@@ -5676,6 +5676,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                mKeyguardDelegate.onScreenTurnedOn();
            }
        }
        mDefaultDisplayPolicy.screenTurnedOn();
        reportScreenStateToVrManager(true);
    }

+10 −1
Original line number Diff line number Diff line
@@ -794,6 +794,9 @@ public class DisplayPolicy {
            }
            mService.mAtmService.mKeyguardController.updateDeferTransitionForAod(
                    mAwake /* waiting */);
            if (!awake) {
                mDisplayContent.mWallpaperController.onDisplaySwitchFinished();
            }
        }
    }

@@ -836,7 +839,8 @@ public class DisplayPolicy {
        mRemoteInsetsControllerControlsSystemBars = remoteInsetsControllerControlsSystemBars;
    }

    public void screenTurnedOn(ScreenOnListener screenOnListener) {
    /** Prepares to turn on screen. The given listener is used to notify that it is ready. */
    public void screenTurningOn(ScreenOnListener screenOnListener) {
        WindowProcessController visibleDozeUiProcess = null;
        synchronized (mLock) {
            mScreenOnEarly = true;
@@ -858,6 +862,11 @@ public class DisplayPolicy {
        }
    }

    /** It is called after {@link #finishScreenTurningOn}. This runs on PowerManager's thread. */
    public void screenTurnedOn() {
        mDisplayContent.mWallpaperController.onDisplaySwitchFinished();
    }

    public void screenTurnedOff() {
        synchronized (mLock) {
            mScreenOnEarly = false;
+3 −0
Original line number Diff line number Diff line
@@ -2784,6 +2784,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
        } else {
            throw new RuntimeException("Create the same sleep token twice: " + token);
        }
        if (isSwappingDisplay) {
            display.mWallpaperController.onDisplaySwitchStarted();
        }
        return token;
    }

Loading