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

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

Apply theme in single transaction

Fixes: 173048361
Test: atest ThemeOverlayApplierTest
Change-Id: Ie4b56117411c0185c606e9ecdf30f165291bf400
parent a7f6e5ea
Loading
Loading
Loading
Loading
+32 −25
Original line number Diff line number Diff line
@@ -15,12 +15,15 @@
 */
package com.android.systemui.theme;

import android.content.om.OverlayIdentifier;
import android.content.om.OverlayInfo;
import android.content.om.OverlayManager;
import android.content.om.OverlayManagerTransaction;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;

import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
@@ -229,47 +232,51 @@ public class ThemeOverlayApplier implements Dumpable {
        final List<OverlayInfo> overlays = new ArrayList<>();
        targetPackagesToQuery.forEach(targetPackage -> overlays.addAll(mOverlayManager
                .getOverlayInfosForTarget(targetPackage, UserHandle.SYSTEM)));
        final Map<String, String> overlaysToDisable = overlays.stream()
        final List<Pair<String, String>> overlaysToDisable = overlays.stream()
                .filter(o ->
                        mTargetPackageToCategories.get(o.targetPackageName).contains(o.category))
                .filter(o -> overlayCategoriesToDisable.contains(o.category))
                .filter(o -> o.isEnabled())
                .collect(Collectors.toMap((o) -> o.category, (o) -> o.packageName));
                .map(o -> new Pair<>(o.category, o.packageName))
                .collect(Collectors.toList());

        OverlayManagerTransaction.Builder transaction = getTransactionBuilder();
        // Toggle overlays in the order of THEME_CATEGORIES.
        for (String category : THEME_CATEGORIES) {
            if (categoryToPackage.containsKey(category)) {
                setEnabled(categoryToPackage.get(category), category, userHandles, true);
            } else if (overlaysToDisable.containsKey(category)) {
                setEnabled(overlaysToDisable.get(category), category, userHandles, false);
                OverlayIdentifier overlayInfo =
                        new OverlayIdentifier(categoryToPackage.get(category));
                setEnabled(transaction, overlayInfo, category, userHandles, true);
            }
        }
        for (Pair<String, String> packageToDisable : overlaysToDisable) {
            OverlayIdentifier overlayInfo = new OverlayIdentifier(packageToDisable.second);
            setEnabled(transaction, overlayInfo, packageToDisable.first, userHandles, false);
        }

    private void setEnabled(
            String packageName, String category, Set<UserHandle> handles, boolean enabled) {
        for (UserHandle userHandle : handles) {
            setEnabledAsync(packageName, userHandle, enabled);
        }
        if (!handles.contains(UserHandle.SYSTEM) && SYSTEM_USER_CATEGORIES.contains(category)) {
            setEnabledAsync(packageName, UserHandle.SYSTEM, enabled);
        mExecutor.execute(() -> {
            mOverlayManager.commit(transaction.build());
        });
    }

    @VisibleForTesting
    protected OverlayManagerTransaction.Builder getTransactionBuilder() {
        return new OverlayManagerTransaction.Builder();
    }

    private void setEnabledAsync(String pkg, UserHandle userHandle, boolean enabled) {
        mExecutor.execute(() -> {
            if (DEBUG) Log.d(TAG, String.format("setEnabled: %s %s %b", pkg, userHandle, enabled));
            try {
                if (enabled) {
                    mOverlayManager.setEnabledExclusiveInCategory(pkg, userHandle);
                } else {
                    mOverlayManager.setEnabled(pkg, false, userHandle);
    private void setEnabled(OverlayManagerTransaction.Builder transaction,
            OverlayIdentifier identifier, String category, Set<UserHandle> handles,
            boolean enabled) {
        if (DEBUG) {
            Log.d(TAG, "setEnabled: " + identifier.getPackageName() + " category: "
                    + category + ": " + enabled);
        }
            } catch (SecurityException | IllegalStateException e) {
                Log.e(TAG,
                        String.format("setEnabled failed: %s %s %b", pkg, userHandle, enabled), e);
        for (UserHandle userHandle : handles) {
            transaction.setEnabled(identifier, enabled, userHandle.getIdentifier());
        }
        if (!handles.contains(UserHandle.SYSTEM) && SYSTEM_USER_CATEGORIES.contains(category)) {
            transaction.setEnabled(identifier, enabled, UserHandle.SYSTEM.getIdentifier());
        }
        });
    }

    /**
+40 −17
Original line number Diff line number Diff line
@@ -32,13 +32,16 @@ import static com.android.systemui.theme.ThemeOverlayApplier.THEME_CATEGORIES;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.om.OverlayIdentifier;
import android.content.om.OverlayInfo;
import android.content.om.OverlayManager;
import android.content.om.OverlayManagerTransaction;
import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -87,6 +90,8 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
    OverlayManager mOverlayManager;
    @Mock
    DumpManager mDumpManager;
    @Mock
    OverlayManagerTransaction.Builder mTransactionBuilder;

    private ThemeOverlayApplier mManager;

@@ -94,7 +99,12 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
    public void setup() throws Exception {
        MockitoAnnotations.initMocks(this);
        mManager = new ThemeOverlayApplier(mOverlayManager, MoreExecutors.directExecutor(),
                LAUNCHER_PACKAGE, THEMEPICKER_PACKAGE, mDumpManager);
                LAUNCHER_PACKAGE, THEMEPICKER_PACKAGE, mDumpManager) {
            @Override
            protected OverlayManagerTransaction.Builder getTransactionBuilder() {
                return mTransactionBuilder;
            }
        };
        when(mOverlayManager.getOverlayInfosForTarget(ANDROID_PACKAGE, UserHandle.SYSTEM))
                .thenReturn(Lists.newArrayList(
                        createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_ACCENT_COLOR,
@@ -148,9 +158,11 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
    @Test
    public void allCategoriesSpecified_allEnabledExclusively() {
        mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, TEST_USER_HANDLES);
        verify(mOverlayManager).commit(any());

        for (String overlayPackage : ALL_CATEGORIES_MAP.values()) {
            verify(mOverlayManager).setEnabledExclusiveInCategory(overlayPackage, TEST_USER);
            verify(mTransactionBuilder).setEnabled(eq(new OverlayIdentifier(overlayPackage)),
                    eq(true), eq(TEST_USER.getIdentifier()));
        }
    }

@@ -160,11 +172,12 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {

        for (Map.Entry<String, String> entry : ALL_CATEGORIES_MAP.entrySet()) {
            if (SYSTEM_USER_CATEGORIES.contains(entry.getKey())) {
                verify(mOverlayManager).setEnabledExclusiveInCategory(
                        entry.getValue(), UserHandle.SYSTEM);
                verify(mTransactionBuilder).setEnabled(eq(new OverlayIdentifier(entry.getValue())),
                        eq(true), eq(UserHandle.SYSTEM.getIdentifier()));
            } else {
                verify(mOverlayManager, never()).setEnabledExclusiveInCategory(
                        entry.getValue(), UserHandle.SYSTEM);
                verify(mTransactionBuilder, never()).setEnabled(
                        eq(new OverlayIdentifier(entry.getValue())),
                        eq(true), eq(UserHandle.SYSTEM.getIdentifier()));
            }
        }
    }
@@ -177,8 +190,10 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
        mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, userHandles);

        for (String overlayPackage : ALL_CATEGORIES_MAP.values()) {
            verify(mOverlayManager).setEnabledExclusiveInCategory(overlayPackage, TEST_USER);
            verify(mOverlayManager).setEnabledExclusiveInCategory(overlayPackage, newUserHandle);
            verify(mTransactionBuilder).setEnabled(eq(new OverlayIdentifier(overlayPackage)),
                    eq(true), eq(TEST_USER.getIdentifier()));
            verify(mTransactionBuilder).setEnabled(eq(new OverlayIdentifier(overlayPackage)),
                    eq(true), eq(newUserHandle.getIdentifier()));
        }
    }

@@ -199,12 +214,15 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
        mManager.applyCurrentUserOverlays(categoryToPackage, TEST_USER_HANDLES);

        for (String overlayPackage : categoryToPackage.values()) {
            verify(mOverlayManager).setEnabledExclusiveInCategory(overlayPackage, TEST_USER);
            verify(mTransactionBuilder).setEnabled(eq(new OverlayIdentifier(overlayPackage)),
                    eq(true), eq(TEST_USER.getIdentifier()));
        }
        verify(mOverlayManager).setEnabled(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_SETTINGS,
                false, TEST_USER);
        verify(mOverlayManager).setEnabled(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_ANDROID,
                false, TEST_USER);
        verify(mTransactionBuilder).setEnabled(
                eq(new OverlayIdentifier(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_SETTINGS)),
                eq(false), eq(TEST_USER.getIdentifier()));
        verify(mTransactionBuilder).setEnabled(
                eq(new OverlayIdentifier(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_ANDROID)),
                eq(false), eq(TEST_USER.getIdentifier()));
    }

    @Test
@@ -212,7 +230,9 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
        mManager.applyCurrentUserOverlays(Maps.newArrayMap(), TEST_USER_HANDLES);

        for (String category : THEME_CATEGORIES) {
            verify(mOverlayManager).setEnabled(TEST_ENABLED_PREFIX + category, false, TEST_USER);
            verify(mTransactionBuilder).setEnabled(
                    eq(new OverlayIdentifier(TEST_ENABLED_PREFIX + category)), eq(false),
                    eq(TEST_USER.getIdentifier()));
        }
    }

@@ -223,9 +243,12 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {

        mManager.applyCurrentUserOverlays(categoryToPackage, TEST_USER_HANDLES);

        verify(mOverlayManager, never()).setEnabled("com.example.blah.category", false, TEST_USER);
        verify(mOverlayManager, never()).setEnabledExclusiveInCategory("com.example.blah.category",
                TEST_USER);
        verify(mTransactionBuilder, never()).setEnabled(
                eq(new OverlayIdentifier("com.example.blah.category")), eq(false),
                eq(TEST_USER.getIdentifier()));
        verify(mTransactionBuilder, never()).setEnabled(
                eq(new OverlayIdentifier("com.example.blah.category")), eq(true),
                eq(TEST_USER.getIdentifier()));
    }

    @Test