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

Commit a11d68dc authored by James O'Leary's avatar James O'Leary
Browse files

Allow wallpaper color updates if screen off

Originally, we planned to only allow one color update per boot cycle,
preventing jank from wallpapers that may too eagerly send update events
at runtime.

To better accommodate live wallpapers, while continuing to avoid jank
at runtime, we will allow color updates once the screen is off.

Also, any color updates received when the screen is on are cached, and
when the screen is turned off, they will be processed.

Test: added tests to ThemeOverlayControllerTest, one confirms
colors are not processed when the screen is on, and once the screen is
off, they are processed. Another test confirms this behavior does not
conflict with the expected behavior during setup wizard: _no_ color
updates are processed until the device is fully setup, avoiding janky
Activity restarts.
Bug: 183792317

Change-Id: Ie48558d7724572271d7d8262835b5eba48174fd3
parent 07791ca5
Loading
Loading
Loading
Loading
+40 −6
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package com.android.systemui.theme;

import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_PRESET;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE;
@@ -52,6 +53,7 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -113,6 +115,12 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
    private FabricatedOverlay mNeutralOverlay;
    // If wallpaper color event will be accepted and change the UI colors.
    private boolean mAcceptColorEvents = true;
    // If non-null, colors that were sent to the framework, and processing was deferred until
    // the next time the screen is off.
    private WallpaperColors mDeferredWallpaperColors;
    private int mDeferredWallpaperColorsFlags;
    private WakefulnessLifecycle mWakefulnessLifecycle;

    // Defers changing themes until Setup Wizard is done.
    private boolean mDeferredThemeEvaluation;
    // Determines if we should ignore THEME_CUSTOMIZATION_OVERLAY_PACKAGES setting changes.
@@ -135,18 +143,28 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
            };

    private final OnColorsChangedListener mOnColorsChangedListener = (wallpaperColors, which) -> {
        if (!mAcceptColorEvents) {
            Log.i(TAG, "Wallpaper color event rejected: " + wallpaperColors);
        if (!mAcceptColorEvents && mWakefulnessLifecycle.getWakefulness() != WAKEFULNESS_ASLEEP) {
            mDeferredWallpaperColors = wallpaperColors;
            mDeferredWallpaperColorsFlags = which;
            Log.i(TAG, "colors received; processing deferred until screen off: " + wallpaperColors);
            return;
        }

        if (wallpaperColors != null) {
            mAcceptColorEvents = false;
            // Any cache of colors deferred for process is now stale.
            mDeferredWallpaperColors = null;
            mDeferredWallpaperColorsFlags = 0;
        }

        handleWallpaperColors(wallpaperColors, which);
    };

    private void handleWallpaperColors(WallpaperColors wallpaperColors, int flags) {
        final boolean hadWallpaperColors = mSystemColors != null;
        if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
        if ((flags & WallpaperManager.FLAG_SYSTEM) != 0) {
            mSystemColors = wallpaperColors;
            if (DEBUG) Log.d(TAG, "got new colors: " + wallpaperColors + " where: " + which);
            if (DEBUG) Log.d(TAG, "got new colors: " + wallpaperColors + " where: " + flags);
        }

        if (mDeviceProvisionedController != null
@@ -197,7 +215,7 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
            }
        }
        reevaluateSystemTheme(false /* forceReload */);
    };
    }

    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
@@ -224,7 +242,8 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
            @Background Executor bgExecutor, ThemeOverlayApplier themeOverlayApplier,
            SecureSettings secureSettings, WallpaperManager wallpaperManager,
            UserManager userManager, DeviceProvisionedController deviceProvisionedController,
            UserTracker userTracker, DumpManager dumpManager, FeatureFlags featureFlags) {
            UserTracker userTracker, DumpManager dumpManager, FeatureFlags featureFlags,
            WakefulnessLifecycle wakefulnessLifecycle) {
        super(context);

        mIsMonetEnabled = featureFlags.isMonetEnabled();
@@ -238,6 +257,7 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
        mSecureSettings = secureSettings;
        mWallpaperManager = wallpaperManager;
        mUserTracker = userTracker;
        mWakefulnessLifecycle = wakefulnessLifecycle;
        dumpManager.registerDumpable(TAG, this);
    }

@@ -302,6 +322,20 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
        }
        mWallpaperManager.addOnColorsChangedListener(mOnColorsChangedListener, null,
                UserHandle.USER_ALL);
        mWakefulnessLifecycle.addObserver(new WakefulnessLifecycle.Observer() {
            @Override
            public void onFinishedGoingToSleep() {
                if (mDeferredWallpaperColors != null) {
                    WallpaperColors colors = mDeferredWallpaperColors;
                    int flags = mDeferredWallpaperColorsFlags;

                    mDeferredWallpaperColors = null;
                    mDeferredWallpaperColorsFlags = 0;

                    handleWallpaperColors(colors, flags);
                }
            }
        });
    }

    private void reevaluateSystemTheme(boolean forceReload) {
+59 −3
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.theme;

import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE;

@@ -51,6 +52,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -99,22 +101,26 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
    private DeviceProvisionedController mDeviceProvisionedController;
    @Mock
    private FeatureFlags mFeatureFlags;
    @Mock
    private WakefulnessLifecycle mWakefulnessLifecycle;
    @Captor
    private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiver;
    @Captor
    private ArgumentCaptor<WallpaperManager.OnColorsChangedListener> mColorsListener;
    @Captor
    private ArgumentCaptor<DeviceProvisionedListener> mDeviceProvisionedListener;

    @Captor
    private ArgumentCaptor<WakefulnessLifecycle.Observer> mWakefulnessLifecycleObserver;
    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        when(mFeatureFlags.isMonetEnabled()).thenReturn(true);
        when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE);
        when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
        mThemeOverlayController = new ThemeOverlayController(null /* context */,
                mBroadcastDispatcher, mBgHandler, mMainExecutor, mBgExecutor, mThemeOverlayApplier,
                mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
                mUserTracker, mDumpManager, mFeatureFlags) {
                mUserTracker, mDumpManager, mFeatureFlags, mWakefulnessLifecycle) {
            @Nullable
            @Override
            protected FabricatedOverlay getOverlay(int color, int type) {
@@ -125,11 +131,13 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
            }
        };

        mWakefulnessLifecycle.dispatchFinishedWakingUp();
        mThemeOverlayController.start();
        verify(mWallpaperManager).addOnColorsChangedListener(mColorsListener.capture(), eq(null),
                eq(UserHandle.USER_ALL));
        verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiver.capture(), any(),
                eq(mMainExecutor), any());
        verify(mWakefulnessLifecycle).addObserver(mWakefulnessLifecycleObserver.capture());
        verify(mDumpManager).registerDumpable(any(), any());
        verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture());
    }
@@ -283,7 +291,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
        mThemeOverlayController = new ThemeOverlayController(null /* context */,
                mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier,
                mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
                mUserTracker, mDumpManager, mFeatureFlags) {
                mUserTracker, mDumpManager, mFeatureFlags, mWakefulnessLifecycle) {
            @Nullable
            @Override
            protected FabricatedOverlay getOverlay(int color, int type) {
@@ -316,6 +324,54 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
    }

    @Test
    public void onWallpaperColorsChanged_screenOff_deviceSetupNotFinished_doesNotProcessQueued() {
        when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(false);
        mDeviceProvisionedListener.getValue().onUserSetupChanged();


        // Second color application is not applied.
        WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
                Color.valueOf(Color.BLUE), null);
        mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);

        clearInvocations(mThemeOverlayApplier);

        // Device went to sleep and second set of colors was applied.
        mainColors =  new WallpaperColors(Color.valueOf(Color.BLUE),
                Color.valueOf(Color.RED), null);
        mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
        verify(mThemeOverlayApplier, never())
                .applyCurrentUserOverlays(any(), any(), anyInt(), any());

        mWakefulnessLifecycle.dispatchFinishedGoingToSleep();
        verify(mThemeOverlayApplier, never())
                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
    }

    @Test
    public void onWallpaperColorsChanged_screenOff_processesQueued() {
        when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
        mDeviceProvisionedListener.getValue().onUserSetupChanged();

        // Second color application is not applied.
        WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
                Color.valueOf(Color.BLUE), null);
        mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);

        clearInvocations(mThemeOverlayApplier);

        // Device went to sleep and second set of colors was applied.
        mainColors =  new WallpaperColors(Color.valueOf(Color.BLUE),
                Color.valueOf(Color.RED), null);
        mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
        verify(mThemeOverlayApplier, never())
                .applyCurrentUserOverlays(any(), any(), anyInt(), any());

        mWakefulnessLifecycleObserver.getValue().onFinishedGoingToSleep();
        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
    }

    @Test
    public void onWallpaperColorsChanged_parsesColorsFromWallpaperPicker() {
        WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),