User OverlayIdentifier instead of @ColorInt

Migrated the feature flag to the new FeatureFlags infrastructure and
replaced the @ColorInt interface by a more flexible OverlayIdentifier.

Test: atest ThemeOverlayApplierTest
Test: atest ThemeOverlayControllerTest
Bug: 171916625
Change-Id: I701fd5bda2aca67c069f25a22d397d56b077d450
This commit is contained in:
Lucas Dupin
2021-01-29 10:24:47 -08:00
parent 651112fbeb
commit 4222ef1439
6 changed files with 203 additions and 255 deletions

View File

@@ -23,6 +23,7 @@
<bool name="flag_notif_updates">false</bool>
<bool name="flag_shade_is_opaque">false</bool>
<bool name="flag_monet">false</bool>
<!-- b/171917882 -->
<bool name="flag_notification_twocolumn">false</bool>

View File

@@ -78,4 +78,8 @@ public class FeatureFlags {
public boolean isToastStyleEnabled() {
return mFlagReader.isEnabled(R.bool.flag_toast_style);
}
public boolean isMonetEnabled() {
return mFlagReader.isEnabled(R.bool.flag_monet);
}
}

View File

@@ -15,11 +15,11 @@
*/
package com.android.systemui.theme;
import android.content.om.FabricatedOverlay;
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;
@@ -53,13 +53,6 @@ import java.util.stream.Collectors;
public class ThemeOverlayApplier implements Dumpable {
private static final String TAG = "ThemeOverlayApplier";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final boolean MONET_ENABLED = SystemProperties
.getBoolean("persist.sysui.monet", false);
@VisibleForTesting
static final String MONET_ACCENT_COLOR_PACKAGE = "com.android.theme.accentcolor.color";
@VisibleForTesting
static final String MONET_SYSTEM_PALETTE_PACKAGE = "com.android.theme.systemcolors.color";
@VisibleForTesting
static final String ANDROID_PACKAGE = "android";
@@ -68,10 +61,8 @@ public class ThemeOverlayApplier implements Dumpable {
@VisibleForTesting
static final String SYSUI_PACKAGE = "com.android.systemui";
@VisibleForTesting
static final String OVERLAY_CATEGORY_ACCENT_COLOR =
"android.theme.customization.accent_color";
@VisibleForTesting
static final String OVERLAY_CATEGORY_SYSTEM_PALETTE =
"android.theme.customization.system_palette";
@VisibleForTesting
@@ -120,16 +111,6 @@ public class ThemeOverlayApplier implements Dumpable {
OVERLAY_CATEGORY_ICON_ANDROID,
OVERLAY_CATEGORY_ICON_SYSUI);
/**
* List of main colors of Monet themes. These are extracted from overlays installed
* on the system.
*/
private final ArrayList<Integer> mMainSystemColors = new ArrayList<>();
/**
* Same as above, but providing accent colors instead of a system palette.
*/
private final ArrayList<Integer> mAccentColors = new ArrayList<>();
/* Allowed overlay categories for each target package. */
private final Map<String, Set<String>> mTargetPackageToCategories = new ArrayMap<>();
/* Target package for each overlay category. */
@@ -165,64 +146,17 @@ public class ThemeOverlayApplier implements Dumpable {
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_LAUNCHER, mLauncherPackage);
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_THEME_PICKER, mThemePickerPackage);
collectMonetSystemOverlays();
dumpManager.registerDumpable(TAG, this);
}
/**
* List of accent colors available as Monet overlays.
*/
List<Integer> getAvailableAccentColors() {
return mAccentColors;
}
/**
* List of main system colors available as Monet overlays.
*/
List<Integer> getAvailableSystemColors() {
return mMainSystemColors;
}
private void collectMonetSystemOverlays() {
if (!MONET_ENABLED) {
return;
}
List<OverlayInfo> androidOverlays = mOverlayManager
.getOverlayInfosForTarget(ANDROID_PACKAGE, UserHandle.SYSTEM);
for (OverlayInfo overlayInfo : androidOverlays) {
String packageName = overlayInfo.packageName;
if (DEBUG) {
Log.d(TAG, "Processing overlay " + packageName);
}
if (OVERLAY_CATEGORY_SYSTEM_PALETTE.equals(overlayInfo.category)
&& packageName.startsWith(MONET_SYSTEM_PALETTE_PACKAGE)) {
try {
String color = packageName.replace(MONET_SYSTEM_PALETTE_PACKAGE, "");
mMainSystemColors.add(Integer.parseInt(color, 16));
} catch (NumberFormatException e) {
Log.w(TAG, "Invalid package name for overlay " + packageName, e);
}
} else if (OVERLAY_CATEGORY_ACCENT_COLOR.equals(overlayInfo.category)
&& packageName.startsWith(MONET_ACCENT_COLOR_PACKAGE)) {
try {
String color = packageName.replace(MONET_ACCENT_COLOR_PACKAGE, "");
mAccentColors.add(Integer.parseInt(color, 16));
} catch (NumberFormatException e) {
Log.w(TAG, "Invalid package name for overlay " + packageName, e);
}
} else if (DEBUG) {
Log.d(TAG, "Unknown overlay: " + packageName + " category: "
+ overlayInfo.category);
}
}
}
/**
* Apply the set of overlay packages to the set of {@code UserHandle}s provided. Overlays that
* affect sysui will also be applied to the system user.
*/
void applyCurrentUserOverlays(
Map<String, String> categoryToPackage, Set<UserHandle> userHandles) {
Map<String, OverlayIdentifier> categoryToPackage,
FabricatedOverlay[] pendingCreation,
Set<UserHandle> userHandles) {
// Disable all overlays that have not been specified in the user setting.
final Set<String> overlayCategoriesToDisable = new HashSet<>(THEME_CATEGORIES);
overlayCategoriesToDisable.removeAll(categoryToPackage.keySet());
@@ -241,11 +175,16 @@ public class ThemeOverlayApplier implements Dumpable {
.collect(Collectors.toList());
OverlayManagerTransaction.Builder transaction = getTransactionBuilder();
if (pendingCreation != null) {
for (FabricatedOverlay overlay : pendingCreation) {
transaction.registerFabricatedOverlay(overlay);
}
}
// Toggle overlays in the order of THEME_CATEGORIES.
for (String category : THEME_CATEGORIES) {
if (categoryToPackage.containsKey(category)) {
OverlayIdentifier overlayInfo =
new OverlayIdentifier(categoryToPackage.get(category));
OverlayIdentifier overlayInfo = categoryToPackage.get(category);
setEnabled(transaction, overlayInfo, category, userHandles, true);
}
}
@@ -284,7 +223,7 @@ public class ThemeOverlayApplier implements Dumpable {
*/
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("mMainSystemColors=" + mMainSystemColors.size());
pw.println("mAccentColors=" + mAccentColors.size());
pw.println("mTargetPackageToCategories=" + mTargetPackageToCategories);
pw.println("mCategoryToTargetPackage=" + mCategoryToTargetPackage);
}
}

View File

@@ -18,6 +18,7 @@ package com.android.systemui.theme;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR;
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;
@@ -25,6 +26,8 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.om.FabricatedOverlay;
import android.content.om.OverlayIdentifier;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.graphics.Color;
@@ -40,7 +43,6 @@ import android.util.Log;
import androidx.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.systemui.Dumpable;
import com.android.systemui.SystemUI;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -48,6 +50,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.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
@@ -59,10 +62,10 @@ import org.json.JSONObject;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
import javax.inject.Inject;
@@ -77,9 +80,12 @@ import javax.inject.Inject;
*/
@SysUISingleton
public class ThemeOverlayController extends SystemUI implements Dumpable {
private static final String TAG = "ThemeOverlayController";
protected static final String TAG = "ThemeOverlayController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
protected static final int MAIN = 0;
protected static final int ACCENT = 1;
// If lock screen wallpaper colors should also be considered when selecting the theme.
// Doing this has performance impact, given that overlays would need to be swapped when
// the device unlocks.
@@ -95,16 +101,19 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
private final Handler mBgHandler;
private final WallpaperManager mWallpaperManager;
private final KeyguardStateController mKeyguardStateController;
private final boolean mIsMonetEnabled;
private WallpaperColors mLockColors;
private WallpaperColors mSystemColors;
// Color extracted from wallpaper, NOT the color used on the overlay
// If fabricated overlays were already created for the current theme.
private boolean mNeedsOverlayCreation;
// Dominant olor extracted from wallpaper, NOT the color used on the overlay
protected int mMainWallpaperColor = Color.TRANSPARENT;
// Color extracted from wallpaper, NOT the color used on the overlay
// Accent color extracted from wallpaper, NOT the color used on the overlay
protected int mWallpaperAccentColor = Color.TRANSPARENT;
// Main system color that maps to an overlay color
private int mSystemOverlayColor = Color.TRANSPARENT;
// Accent color that maps to an overlay color
private int mAccentOverlayColor = Color.TRANSPARENT;
// System colors overlay
private FabricatedOverlay mSystemOverlay;
// Accent colors overlay
private FabricatedOverlay mAccentOverlay;
@Inject
public ThemeOverlayController(Context context, BroadcastDispatcher broadcastDispatcher,
@@ -112,9 +121,10 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
@Background Executor bgExecutor, ThemeOverlayApplier themeOverlayApplier,
SecureSettings secureSettings, WallpaperManager wallpaperManager,
UserManager userManager, KeyguardStateController keyguardStateController,
DumpManager dumpManager) {
DumpManager dumpManager, FeatureFlags featureFlags) {
super(context);
mIsMonetEnabled = featureFlags.isMonetEnabled();
mBroadcastDispatcher = broadcastDispatcher;
mUserManager = userManager;
mBgExecutor = bgExecutor;
@@ -221,20 +231,16 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
mMainWallpaperColor = mainColor;
mWallpaperAccentColor = accentCandidate;
// Let's compare these colors to our finite set of overlays, and then pick an overlay.
List<Integer> systemColors = mThemeManager.getAvailableSystemColors();
List<Integer> accentColors = mThemeManager.getAvailableAccentColors();
if (systemColors.size() == 0 || accentColors.size() == 0) {
if (mIsMonetEnabled) {
mSystemOverlay = getOverlay(mMainWallpaperColor, MAIN);
mAccentOverlay = getOverlay(mWallpaperAccentColor, ACCENT);
mNeedsOverlayCreation = true;
if (DEBUG) {
Log.d(TAG, "Cannot apply system theme, palettes are unavailable");
Log.d(TAG, "fetched overlays. system: " + mSystemOverlay + " accent: "
+ mAccentOverlay);
}
return;
}
mSystemOverlayColor = getClosest(systemColors, mMainWallpaperColor);
mAccentOverlayColor = getClosest(accentColors, mWallpaperAccentColor);
updateThemeOverlays();
}
@@ -257,42 +263,10 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
}
/**
* Given a color and a list of candidates, return the candidate that's the most similar to the
* given color.
* Given a color candidate, return an overlay definition.
*/
protected int getClosest(List<Integer> candidates, int color) {
float[] hslMain = new float[3];
float[] hslCandidate = new float[3];
ColorUtils.RGBToHSL(Color.red(color), Color.green(color), Color.blue(color), hslMain);
hslMain[0] /= 360f;
// To close to white or black, let's use the default system theme instead of
// applying a colorized one.
if (hslMain[2] < 0.05 || hslMain[2] > 0.95) {
return Color.TRANSPARENT;
}
float minDistance = Float.MAX_VALUE;
int closestColor = Color.TRANSPARENT;
for (int candidate: candidates) {
ColorUtils.RGBToHSL(Color.red(candidate), Color.green(candidate), Color.blue(candidate),
hslCandidate);
hslCandidate[0] /= 360f;
float sqDistance = squared(hslCandidate[0] - hslMain[0])
+ squared(hslCandidate[1] - hslMain[1])
+ squared(hslCandidate[2] - hslMain[2]);
if (sqDistance < minDistance) {
minDistance = sqDistance;
closestColor = candidate;
}
}
return closestColor;
}
private static float squared(float f) {
return f * f;
protected @Nullable FabricatedOverlay getOverlay(int color, int type) {
return null;
}
private void updateThemeOverlays() {
@@ -301,20 +275,15 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
currentUser);
if (DEBUG) Log.d(TAG, "updateThemeOverlays. Setting: " + overlayPackageJson);
boolean hasSystemPalette = false;
boolean hasAccentColor = false;
final Map<String, String> categoryToPackage = new ArrayMap<>();
final Map<String, OverlayIdentifier> categoryToPackage = new ArrayMap<>();
if (!TextUtils.isEmpty(overlayPackageJson)) {
try {
JSONObject object = new JSONObject(overlayPackageJson);
for (String category : ThemeOverlayApplier.THEME_CATEGORIES) {
if (object.has(category)) {
if (category.equals(OVERLAY_CATEGORY_ACCENT_COLOR)) {
hasAccentColor = true;
} else if (category.equals(OVERLAY_CATEGORY_SYSTEM_PALETTE)) {
hasSystemPalette = true;
}
categoryToPackage.put(category, object.getString(category));
OverlayIdentifier identifier =
new OverlayIdentifier(object.getString(category));
categoryToPackage.put(category, identifier);
}
}
} catch (JSONException e) {
@@ -322,17 +291,41 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
}
}
// Let's apply the system palette, but only if it was not overridden by the style picker.
if (!hasSystemPalette && mSystemOverlayColor != Color.TRANSPARENT) {
categoryToPackage.put(OVERLAY_CATEGORY_SYSTEM_PALETTE,
ThemeOverlayApplier.MONET_SYSTEM_PALETTE_PACKAGE
+ getColorString(mSystemOverlayColor));
// Let's generate system overlay if the style picker decided to override it.
OverlayIdentifier systemPalette = categoryToPackage.get(OVERLAY_CATEGORY_SYSTEM_PALETTE);
if (mIsMonetEnabled && systemPalette != null && systemPalette.getPackageName() != null) {
try {
int color = Integer.parseInt(systemPalette.getPackageName().toLowerCase(), 16);
mSystemOverlay = getOverlay(color, MAIN);
mNeedsOverlayCreation = true;
categoryToPackage.remove(OVERLAY_CATEGORY_SYSTEM_PALETTE);
} catch (NumberFormatException e) {
Log.w(TAG, "Invalid color definition: " + systemPalette.getPackageName());
}
}
// Same for the accent color
if (!hasAccentColor && mAccentOverlayColor != Color.TRANSPARENT) {
categoryToPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR,
ThemeOverlayApplier.MONET_ACCENT_COLOR_PACKAGE
+ getColorString(mAccentOverlayColor));
// Same for accent color.
OverlayIdentifier accentPalette = categoryToPackage.get(OVERLAY_CATEGORY_ACCENT_COLOR);
if (mIsMonetEnabled && accentPalette != null && accentPalette.getPackageName() != null) {
try {
int color = Integer.parseInt(accentPalette.getPackageName().toLowerCase(), 16);
mAccentOverlay = getOverlay(color, ACCENT);
mNeedsOverlayCreation = true;
categoryToPackage.remove(OVERLAY_CATEGORY_ACCENT_COLOR);
} catch (NumberFormatException e) {
Log.w(TAG, "Invalid color definition: " + accentPalette.getPackageName());
}
}
// Compatibility with legacy themes, where full packages were defined, instead of just
// colors.
if (!categoryToPackage.containsKey(OVERLAY_CATEGORY_SYSTEM_PALETTE)
&& mSystemOverlay != null) {
categoryToPackage.put(OVERLAY_CATEGORY_SYSTEM_PALETTE, mSystemOverlay.getIdentifier());
}
if (!categoryToPackage.containsKey(OVERLAY_CATEGORY_ACCENT_COLOR)
&& mAccentOverlay != null) {
categoryToPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR, mAccentOverlay.getIdentifier());
}
Set<UserHandle> userHandles = Sets.newHashSet(UserHandle.of(currentUser));
@@ -341,28 +334,31 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
userHandles.add(userInfo.getUserHandle());
}
}
mThemeManager.applyCurrentUserOverlays(categoryToPackage, userHandles);
}
private String getColorString(int color) {
String colorString = Integer.toHexString(color).toUpperCase();
while (colorString.length() < 6) {
colorString = "0" + colorString;
if (DEBUG) {
Log.d(TAG, "Applying overlays: " + categoryToPackage.keySet().stream()
.map(key -> key + " -> " + categoryToPackage.get(key)).collect(
Collectors.joining(", ")));
}
// Remove alpha component
if (colorString.length() > 6) {
colorString = colorString.substring(colorString.length() - 6);
if (mNeedsOverlayCreation) {
mNeedsOverlayCreation = false;
mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[] {
mSystemOverlay, mAccentOverlay
}, userHandles);
} else {
mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, userHandles);
}
return colorString;
}
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("USE_LOCK_SCREEN_WALLPAPER=" + USE_LOCK_SCREEN_WALLPAPER);
pw.println("mLockColors=" + mLockColors);
pw.println("mSystemColors=" + mSystemColors);
pw.println("mMainWallpaperColor=" + Integer.toHexString(mMainWallpaperColor));
pw.println("mWallpaperAccentColor=" + Integer.toHexString(mWallpaperAccentColor));
pw.println("mSystemOverlayColor=" + Integer.toHexString(mSystemOverlayColor));
pw.println("mAccentOverlayColor=" + Integer.toHexString(mAccentOverlayColor));
pw.println("mSystemOverlayColor=" + mSystemOverlay);
pw.println("mAccentOverlayColor=" + mAccentOverlay);
pw.println("mIsMonetEnabled=" + mIsMonetEnabled);
pw.println("mNeedsOverlayCreation=" + mNeedsOverlayCreation);
}
}

View File

@@ -34,10 +34,12 @@ 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.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.om.FabricatedOverlay;
import android.content.om.OverlayIdentifier;
import android.content.om.OverlayInfo;
import android.content.om.OverlayManager;
@@ -73,11 +75,12 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
private static final String TEST_DISABLED_PREFIX = "com.example.";
private static final String TEST_ENABLED_PREFIX = "com.example.enabled.";
private static final Map<String, String> ALL_CATEGORIES_MAP = Maps.newArrayMap();
private static final Map<String, OverlayIdentifier> ALL_CATEGORIES_MAP = Maps.newArrayMap();
static {
for (String category : THEME_CATEGORIES) {
ALL_CATEGORIES_MAP.put(category, TEST_DISABLED_PREFIX + category);
ALL_CATEGORIES_MAP.put(category,
new OverlayIdentifier(TEST_DISABLED_PREFIX + category));
}
}
@@ -157,27 +160,26 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
@Test
public void allCategoriesSpecified_allEnabledExclusively() {
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, TEST_USER_HANDLES);
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER_HANDLES);
verify(mOverlayManager).commit(any());
for (String overlayPackage : ALL_CATEGORIES_MAP.values()) {
verify(mTransactionBuilder).setEnabled(eq(new OverlayIdentifier(overlayPackage)),
eq(true), eq(TEST_USER.getIdentifier()));
for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) {
verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true),
eq(TEST_USER.getIdentifier()));
}
}
@Test
public void allCategoriesSpecified_sysuiCategoriesAlsoAppliedToSysuiUser() {
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, TEST_USER_HANDLES);
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER_HANDLES);
for (Map.Entry<String, String> entry : ALL_CATEGORIES_MAP.entrySet()) {
for (Map.Entry<String, OverlayIdentifier> entry : ALL_CATEGORIES_MAP.entrySet()) {
if (SYSTEM_USER_CATEGORIES.contains(entry.getKey())) {
verify(mTransactionBuilder).setEnabled(eq(new OverlayIdentifier(entry.getValue())),
eq(true), eq(UserHandle.SYSTEM.getIdentifier()));
verify(mTransactionBuilder).setEnabled(eq(entry.getValue()), eq(true),
eq(UserHandle.SYSTEM.getIdentifier()));
} else {
verify(mTransactionBuilder, never()).setEnabled(
eq(new OverlayIdentifier(entry.getValue())),
eq(true), eq(UserHandle.SYSTEM.getIdentifier()));
eq(entry.getValue()), eq(true), eq(UserHandle.SYSTEM.getIdentifier()));
}
}
}
@@ -187,19 +189,34 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES);
UserHandle newUserHandle = UserHandle.of(10);
userHandles.add(newUserHandle);
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, userHandles);
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, userHandles);
for (String overlayPackage : ALL_CATEGORIES_MAP.values()) {
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()));
for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) {
verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true),
eq(TEST_USER.getIdentifier()));
verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true),
eq(newUserHandle.getIdentifier()));
}
}
@Test
public void applyCurrentUserOverlays_createsPendingOverlays() {
Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES);
UserHandle newUserHandle = UserHandle.of(10);
userHandles.add(newUserHandle);
FabricatedOverlay[] pendingCreation = new FabricatedOverlay[] {
mock(FabricatedOverlay.class)
};
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, pendingCreation, userHandles);
for (FabricatedOverlay overlay : pendingCreation) {
verify(mTransactionBuilder).registerFabricatedOverlay(eq(overlay));
}
}
@Test
public void allCategoriesSpecified_overlayManagerNotQueried() {
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, TEST_USER_HANDLES);
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER_HANDLES);
verify(mOverlayManager, never())
.getOverlayInfosForTarget(anyString(), any(UserHandle.class));
@@ -207,15 +224,15 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
@Test
public void someCategoriesSpecified_specifiedEnabled_unspecifiedDisabled() {
Map<String, String> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP);
Map<String, OverlayIdentifier> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP);
categoryToPackage.remove(OVERLAY_CATEGORY_ICON_SETTINGS);
categoryToPackage.remove(OVERLAY_CATEGORY_ICON_ANDROID);
mManager.applyCurrentUserOverlays(categoryToPackage, TEST_USER_HANDLES);
mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER_HANDLES);
for (String overlayPackage : categoryToPackage.values()) {
verify(mTransactionBuilder).setEnabled(eq(new OverlayIdentifier(overlayPackage)),
eq(true), eq(TEST_USER.getIdentifier()));
for (OverlayIdentifier overlayPackage : categoryToPackage.values()) {
verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true),
eq(TEST_USER.getIdentifier()));
}
verify(mTransactionBuilder).setEnabled(
eq(new OverlayIdentifier(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_SETTINGS)),
@@ -227,7 +244,7 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
@Test
public void zeroCategoriesSpecified_allDisabled() {
mManager.applyCurrentUserOverlays(Maps.newArrayMap(), TEST_USER_HANDLES);
mManager.applyCurrentUserOverlays(Maps.newArrayMap(), null, TEST_USER_HANDLES);
for (String category : THEME_CATEGORIES) {
verify(mTransactionBuilder).setEnabled(
@@ -238,10 +255,10 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
@Test
public void nonThemeCategorySpecified_ignored() {
Map<String, String> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP);
categoryToPackage.put("blah.category", "com.example.blah.category");
Map<String, OverlayIdentifier> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP);
categoryToPackage.put("blah.category", new OverlayIdentifier("com.example.blah.category"));
mManager.applyCurrentUserOverlays(categoryToPackage, TEST_USER_HANDLES);
mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER_HANDLES);
verify(mTransactionBuilder, never()).setEnabled(
eq(new OverlayIdentifier("com.example.blah.category")), eq(false),
@@ -253,10 +270,10 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
@Test
public void overlayManagerOnlyQueriedForUnspecifiedPackages() {
Map<String, String> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP);
Map<String, OverlayIdentifier> categoryToPackage = new HashMap<>(ALL_CATEGORIES_MAP);
categoryToPackage.remove(OVERLAY_CATEGORY_ICON_SETTINGS);
mManager.applyCurrentUserOverlays(categoryToPackage, TEST_USER_HANDLES);
mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER_HANDLES);
verify(mOverlayManager).getOverlayInfosForTarget(SETTINGS_PACKAGE, UserHandle.SYSTEM);
verify(mOverlayManager, never()).getOverlayInfosForTarget(ANDROID_PACKAGE,
@@ -270,7 +287,8 @@ public class ThemeOverlayApplierTest extends SysuiTestCase {
private static OverlayInfo createOverlayInfo(String packageName, String targetPackageName,
String category, boolean enabled) {
return new OverlayInfo(packageName, targetPackageName, null, category, "",
enabled ? OverlayInfo.STATE_ENABLED : OverlayInfo.STATE_DISABLED, 0, 0, false);
return new OverlayInfo(packageName, null, targetPackageName, null, category, "",
enabled ? OverlayInfo.STATE_ENABLED : OverlayInfo.STATE_DISABLED, 0, 0, false,
false);
}
}

View File

@@ -16,8 +16,6 @@
package com.android.systemui.theme;
import static com.android.systemui.theme.ThemeOverlayApplier.MONET_ACCENT_COLOR_PACKAGE;
import static com.android.systemui.theme.ThemeOverlayApplier.MONET_SYSTEM_PALETTE_PACKAGE;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR;
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE;
import static com.android.systemui.theme.ThemeOverlayController.USE_LOCK_SCREEN_WALLPAPER;
@@ -27,12 +25,15 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.content.om.FabricatedOverlay;
import android.content.om.OverlayIdentifier;
import android.graphics.Color;
import android.os.Handler;
import android.os.UserHandle;
@@ -40,11 +41,13 @@ import android.os.UserManager;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import androidx.annotation.Nullable;
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.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
@@ -56,7 +59,6 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
@@ -85,6 +87,8 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
private KeyguardStateController mKeyguardStateController;
@Mock
private DumpManager mDumpManager;
@Mock
private FeatureFlags mFeatureFlags;
@Captor
private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallback;
@Captor
@@ -93,10 +97,20 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
when(mFeatureFlags.isMonetEnabled()).thenReturn(true);
mThemeOverlayController = new ThemeOverlayController(null /* context */,
mBroadcastDispatcher, mBgHandler, mMainExecutor, mBgExecutor, mThemeOverlayApplier,
mSecureSettings, mWallpaperManager, mUserManager, mKeyguardStateController,
mDumpManager);
mDumpManager, mFeatureFlags) {
@Nullable
@Override
protected FabricatedOverlay getOverlay(int color, int type) {
FabricatedOverlay overlay = mock(FabricatedOverlay.class);
when(overlay.getIdentifier())
.thenReturn(new OverlayIdentifier(Integer.toHexString(color | 0xff000000)));
return overlay;
}
};
mThemeOverlayController.start();
if (USE_LOCK_SCREEN_WALLPAPER) {
@@ -106,10 +120,6 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
verify(mWallpaperManager).addOnColorsChangedListener(mColorsListener.capture(), eq(null),
eq(UserHandle.USER_ALL));
verify(mDumpManager).registerDumpable(any(), any());
List<Integer> colorList = List.of(Color.RED, Color.BLUE, 0x0CCCCC, 0x000CCC);
when(mThemeOverlayApplier.getAvailableAccentColors()).thenReturn(colorList);
when(mThemeOverlayApplier.getAvailableSystemColors()).thenReturn(colorList);
}
@Test
@@ -128,66 +138,23 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
ArgumentCaptor<Map<String, String>> themeOverlays = ArgumentCaptor.forClass(Map.class);
ArgumentCaptor<Map<String, OverlayIdentifier>> themeOverlays =
ArgumentCaptor.forClass(Map.class);
verify(mThemeOverlayApplier).getAvailableSystemColors();
verify(mThemeOverlayApplier).getAvailableAccentColors();
verify(mThemeOverlayApplier).applyCurrentUserOverlays(themeOverlays.capture(), any());
verify(mThemeOverlayApplier)
.applyCurrentUserOverlays(themeOverlays.capture(), any(), any());
// Assert that we received the colors that we were expecting
assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
.isEqualTo(MONET_SYSTEM_PALETTE_PACKAGE + "FF0000");
.isEqualTo(new OverlayIdentifier("ffff0000"));
assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_ACCENT_COLOR))
.isEqualTo(MONET_ACCENT_COLOR_PACKAGE + "0000FF");
.isEqualTo(new OverlayIdentifier("ff0000ff"));
// Should not ask again if changed to same value
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
verifyNoMoreInteractions(mThemeOverlayApplier);
}
@Test
public void onWallpaperColorsChanged_whiteTheme() {
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.WHITE),
Color.valueOf(Color.BLUE), null);
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
ArgumentCaptor<Map<String, String>> themeOverlays = ArgumentCaptor.forClass(Map.class);
verify(mThemeOverlayApplier).applyCurrentUserOverlays(themeOverlays.capture(), any());
// Assert that we received the colors that we were expecting
assertThat(themeOverlays.getValue().containsKey(OVERLAY_CATEGORY_SYSTEM_PALETTE)).isFalse();
}
@Test
public void onWallpaperColorsChanged_blackTheme() {
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.BLACK),
Color.valueOf(Color.BLUE), null);
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
ArgumentCaptor<Map<String, String>> themeOverlays = ArgumentCaptor.forClass(Map.class);
verify(mThemeOverlayApplier).applyCurrentUserOverlays(themeOverlays.capture(), any());
// Assert that we received the colors that we were expecting
assertThat(themeOverlays.getValue().containsKey(OVERLAY_CATEGORY_SYSTEM_PALETTE)).isFalse();
}
@Test
public void onWallpaperColorsChanged_addsLeadingZerosToColors() {
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(0x0CCCCC),
Color.valueOf(0x000CCC), null);
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
ArgumentCaptor<Map<String, String>> themeOverlays = ArgumentCaptor.forClass(Map.class);
verify(mThemeOverlayApplier).applyCurrentUserOverlays(themeOverlays.capture(), any());
// Assert that we received the colors that we were expecting
assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
.isEqualTo(MONET_SYSTEM_PALETTE_PACKAGE + "0CCCCC");
assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_ACCENT_COLOR))
.isEqualTo(MONET_ACCENT_COLOR_PACKAGE + "000CCC");
}
@Test
public void onWallpaperColorsChanged_preservesWallpaperPickerTheme() {
// Should ask for a new theme when wallpaper colors change
@@ -201,14 +168,37 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
.thenReturn(jsonString);
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
ArgumentCaptor<Map<String, String>> themeOverlays = ArgumentCaptor.forClass(Map.class);
ArgumentCaptor<Map<String, OverlayIdentifier>> themeOverlays =
ArgumentCaptor.forClass(Map.class);
verify(mThemeOverlayApplier).getAvailableSystemColors();
verify(mThemeOverlayApplier).getAvailableAccentColors();
verify(mThemeOverlayApplier).applyCurrentUserOverlays(themeOverlays.capture(), any());
verify(mThemeOverlayApplier)
.applyCurrentUserOverlays(themeOverlays.capture(), any(), any());
// Assert that we received the colors that we were expecting
assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
.isEqualTo("override.package.name");
.isEqualTo(new OverlayIdentifier("override.package.name"));
}
@Test
public void onWallpaperColorsChanged_parsesColorsFromWallpaperPicker() {
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
String jsonString =
"{\"android.theme.customization.system_palette\":\"00FF00\"}";
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
ArgumentCaptor<Map<String, OverlayIdentifier>> themeOverlays =
ArgumentCaptor.forClass(Map.class);
verify(mThemeOverlayApplier)
.applyCurrentUserOverlays(themeOverlays.capture(), any(), any());
// Assert that we received the colors that we were expecting
assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
.isEqualTo(new OverlayIdentifier("ff00ff00"));
}
}