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

Commit a89d3fa6 authored by Lucas Dupin's avatar Lucas Dupin
Browse files

Defer color events until end of SUW

Color events might recreate activities, disrupting the setup wizard flow

Test: atest ThemeOverlayControllerTest
Test: manual
Bug: 182560740
Change-Id: Id924b3356c37c533dfbcb92048f95295a29a3dfd
parent 74d4d029
Loading
Loading
Loading
Loading
+83 −39
Original line number Diff line number Diff line
@@ -19,9 +19,9 @@ import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_AC
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE;

import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.app.WallpaperManager.OnColorsChangedListener;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -49,8 +49,10 @@ 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.settings.UserTracker;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.util.settings.SecureSettings;

import org.json.JSONException;
@@ -92,8 +94,9 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
    private final Executor mMainExecutor;
    private final Handler mBgHandler;
    private final WallpaperManager mWallpaperManager;
    private final KeyguardStateController mKeyguardStateController;
    private final boolean mIsMonetEnabled;
    private final UserTracker mUserTracker;
    private DeviceProvisionedController mDeviceProvisionedController;
    private WallpaperColors mSystemColors;
    // If fabricated overlays were already created for the current theme.
    private boolean mNeedsOverlayCreation;
@@ -107,17 +110,76 @@ 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;
    // Defers changing themes until Setup Wizard is done.
    private boolean mDeferredThemeEvaluation;

    private final DeviceProvisionedListener mDeviceProvisionedListener =
            new DeviceProvisionedListener() {
                @Override
                public void onUserSetupChanged() {
                    if (!mDeviceProvisionedController.isCurrentUserSetup()) {
                        return;
                    }
                    if (!mDeferredThemeEvaluation) {
                        return;
                    }
                    Log.i(TAG, "Applying deferred theme");
                    mDeferredThemeEvaluation = false;
                    reevaluateSystemTheme(true /* forceReload */);
                }
            };

    private final OnColorsChangedListener mOnColorsChangedListener = (wallpaperColors, which) -> {
        if (!mAcceptColorEvents) {
            Log.i(TAG, "Wallpaper color event rejected: " + wallpaperColors);
            return;
        }
        if (wallpaperColors != null) {
            mAcceptColorEvents = false;
        }

        if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
            mSystemColors = wallpaperColors;
            if (DEBUG) {
                Log.d(TAG, "got new lock colors: " + wallpaperColors + " where: " + which);
            }
        }

        if (mDeviceProvisionedController != null
                && !mDeviceProvisionedController.isCurrentUserSetup()) {
            Log.i(TAG, "Wallpaper color event deferred until setup is finished: "
                    + wallpaperColors);
            mDeferredThemeEvaluation = true;
            return;
        }
        reevaluateSystemTheme(false /* forceReload */);
    };

    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())
                    || Intent.ACTION_MANAGED_PROFILE_ADDED.equals(intent.getAction())) {
                if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
                reevaluateSystemTheme(true /* forceReload */);
            } else if (Intent.ACTION_WALLPAPER_CHANGED.equals(intent.getAction())) {
                mAcceptColorEvents = true;
                Log.i(TAG, "Allowing color events again");
            }
        }
    };

    @Inject
    public ThemeOverlayController(Context context, BroadcastDispatcher broadcastDispatcher,
            @Background Handler bgHandler, @Main Executor mainExecutor,
            @Background Executor bgExecutor, ThemeOverlayApplier themeOverlayApplier,
            SecureSettings secureSettings, WallpaperManager wallpaperManager,
            UserManager userManager, KeyguardStateController keyguardStateController,
            DumpManager dumpManager, FeatureFlags featureFlags) {
            UserManager userManager, DeviceProvisionedController deviceProvisionedController,
            UserTracker userTracker, DumpManager dumpManager, FeatureFlags featureFlags) {
        super(context);

        mIsMonetEnabled = featureFlags.isMonetEnabled();
        mDeviceProvisionedController = deviceProvisionedController;
        mBroadcastDispatcher = broadcastDispatcher;
        mUserManager = userManager;
        mBgExecutor = bgExecutor;
@@ -126,7 +188,7 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
        mThemeManager = themeOverlayApplier;
        mSecureSettings = secureSettings;
        mWallpaperManager = wallpaperManager;
        mKeyguardStateController = keyguardStateController;
        mUserTracker = userTracker;
        dumpManager.registerDumpable(TAG, this);
    }

@@ -137,19 +199,8 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
        filter.addAction(Intent.ACTION_USER_SWITCHED);
        filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
        filter.addAction(Intent.ACTION_WALLPAPER_CHANGED);
        mBroadcastDispatcher.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())
                        || Intent.ACTION_MANAGED_PROFILE_ADDED.equals(intent.getAction())) {
                    if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
                    reevaluateSystemTheme(true /* forceReload */);
                } else if (Intent.ACTION_WALLPAPER_CHANGED.equals(intent.getAction())) {
                    mAcceptColorEvents = true;
                    Log.i(TAG, "Allowing color events again");
                }
            }
        }, filter, mMainExecutor, UserHandle.ALL);
        mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, mMainExecutor,
                UserHandle.ALL);
        mSecureSettings.registerContentObserverForUser(
                Settings.Secure.getUriFor(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES),
                false,
@@ -158,12 +209,19 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
                    public void onChange(boolean selfChange, Collection<Uri> collection, int flags,
                            int userId) {
                        if (DEBUG) Log.d(TAG, "Overlay changed for user: " + userId);
                        if (ActivityManager.getCurrentUser() == userId) {
                            reevaluateSystemTheme(true /* forceReload */);
                        if (mUserTracker.getUserId() != userId) {
                            return;
                        }
                        if (!mDeviceProvisionedController.isUserSetup(userId)) {
                            Log.i(TAG, "Theme application deferred when setting changed.");
                            mDeferredThemeEvaluation = true;
                            return;
                        }
                        reevaluateSystemTheme(true /* forceReload */);
                    }
                },
                UserHandle.USER_ALL);
        mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);

        // Upon boot, make sure we have the most up to date colors
        mBgExecutor.execute(() -> {
@@ -174,23 +232,8 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
                reevaluateSystemTheme(false /* forceReload */);
            });
        });
        mWallpaperManager.addOnColorsChangedListener((wallpaperColors, which) -> {
            if (!mAcceptColorEvents) {
                Log.i(TAG, "Wallpaper color event rejected: " + wallpaperColors);
                return;
            }
            if (wallpaperColors != null && mAcceptColorEvents) {
                mAcceptColorEvents = false;
            }

            if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
                mSystemColors = wallpaperColors;
                if (DEBUG) {
                    Log.d(TAG, "got new lock colors: " + wallpaperColors + " where: " + which);
                }
            }
            reevaluateSystemTheme(false /* forceReload */);
        }, null, UserHandle.USER_ALL);
        mWallpaperManager.addOnColorsChangedListener(mOnColorsChangedListener, null,
                UserHandle.USER_ALL);
    }

    private void reevaluateSystemTheme(boolean forceReload) {
@@ -252,7 +295,7 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
    }

    private void updateThemeOverlays() {
        final int currentUser = ActivityManager.getCurrentUser();
        final int currentUser = mUserTracker.getUserId();
        final String overlayPackageJson = mSecureSettings.getStringForUser(
                Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
                currentUser);
@@ -360,5 +403,6 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
        pw.println("mIsMonetEnabled=" + mIsMonetEnabled);
        pw.println("mNeedsOverlayCreation=" + mNeedsOverlayCreation);
        pw.println("mAcceptColorEvents=" + mAcceptColorEvents);
        pw.println("mDeferredThemeEvaluation=" + mDeferredThemeEvaluation);
    }
}
+30 −4
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@@ -49,8 +51,10 @@ 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.settings.UserTracker;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.util.settings.SecureSettings;

import org.junit.Before;
@@ -86,24 +90,29 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
    @Mock
    private UserManager mUserManager;
    @Mock
    private KeyguardStateController mKeyguardStateController;
    private UserTracker mUserTracker;
    @Mock
    private DumpManager mDumpManager;
    @Mock
    private DeviceProvisionedController mDeviceProvisionedController;
    @Mock
    private FeatureFlags mFeatureFlags;
    @Captor
    private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiver;
    @Captor
    private ArgumentCaptor<WallpaperManager.OnColorsChangedListener> mColorsListener;
    @Captor
    private ArgumentCaptor<DeviceProvisionedListener> mDeviceProvisionedListener;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        when(mFeatureFlags.isMonetEnabled()).thenReturn(true);
        when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
        mThemeOverlayController = new ThemeOverlayController(null /* context */,
                mBroadcastDispatcher, mBgHandler, mMainExecutor, mBgExecutor, mThemeOverlayApplier,
                mSecureSettings, mWallpaperManager, mUserManager, mKeyguardStateController,
                mDumpManager, mFeatureFlags) {
                mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController,
                mUserTracker, mDumpManager, mFeatureFlags) {
            @Nullable
            @Override
            protected FabricatedOverlay getOverlay(int color, int type) {
@@ -120,6 +129,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
        verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiver.capture(), any(),
                eq(mMainExecutor), any());
        verify(mDumpManager).registerDumpable(any(), any());
        verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture());
    }

    @Test
@@ -190,6 +200,22 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
                .isEqualTo(new OverlayIdentifier("override.package.name"));
    }

    @Test
    public void onWallpaperColorsChanged_defersUntilSetupIsCompleted() {
        reset(mDeviceProvisionedController);
        WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
                Color.valueOf(Color.BLUE), null);
        mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);

        verify(mThemeOverlayApplier, never())
                .applyCurrentUserOverlays(any(), any(), anyInt(), any());

        when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
        mDeviceProvisionedListener.getValue().onUserSetupChanged();

        verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
    }

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