Merge "Let wallpaper colors drive system theme"
This commit is contained in:
@@ -23,6 +23,7 @@ import android.annotation.SuppressLint;
|
||||
import android.app.INotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.om.OverlayManager;
|
||||
import android.hardware.display.AmbientDisplayConfiguration;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
@@ -43,6 +44,7 @@ import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.keyguard.ViewMediatorCallback;
|
||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||
import com.android.systemui.Prefs;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.accessibility.ModeSwitchesController;
|
||||
import com.android.systemui.accessibility.SystemActions;
|
||||
import com.android.systemui.assist.AssistManager;
|
||||
@@ -78,6 +80,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
import com.android.systemui.statusbar.policy.DataSaverController;
|
||||
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
|
||||
import com.android.systemui.statusbar.policy.NetworkController;
|
||||
import com.android.systemui.theme.ThemeOverlayApplier;
|
||||
import com.android.systemui.util.leak.LeakDetector;
|
||||
import com.android.wm.shell.pip.Pip;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
@@ -193,6 +196,17 @@ public class DependencyProvider {
|
||||
return new PluginManagerImpl(context, new PluginInitializerImpl());
|
||||
}
|
||||
|
||||
/** */
|
||||
@SysUISingleton
|
||||
@Provides
|
||||
static ThemeOverlayApplier provideThemeOverlayManager(Context context,
|
||||
@Background Executor bgExecutor, OverlayManager overlayManager,
|
||||
DumpManager dumpManager) {
|
||||
return new ThemeOverlayApplier(overlayManager, bgExecutor,
|
||||
context.getString(R.string.launcher_overlayable_package),
|
||||
context.getString(R.string.themepicker_overlayable_package), dumpManager);
|
||||
}
|
||||
|
||||
/** */
|
||||
@Provides
|
||||
@SysUISingleton
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.app.role.RoleManager;
|
||||
import android.app.trust.TrustManager;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.om.OverlayManager;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.content.pm.PackageManager;
|
||||
@@ -351,7 +352,7 @@ public class FrameworkServicesModule {
|
||||
|
||||
@Provides
|
||||
static WallpaperManager provideWallpaperManager(Context context) {
|
||||
return (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
|
||||
return context.getSystemService(WallpaperManager.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -361,6 +362,12 @@ public class FrameworkServicesModule {
|
||||
return context.getSystemService(WifiManager.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static OverlayManager provideOverlayManager(Context context) {
|
||||
return context.getSystemService(OverlayManager.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static WindowManager provideWindowManager(Context context) {
|
||||
|
||||
@@ -21,11 +21,18 @@ import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.systemui.Dumpable;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
|
||||
import com.google.android.collect.Lists;
|
||||
import com.google.android.collect.Sets;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -34,9 +41,19 @@ import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
class ThemeOverlayManager {
|
||||
/**
|
||||
* Responsible for orchestrating overlays, based on user preferences and other inputs from
|
||||
* {@link ThemeOverlayController}.
|
||||
*/
|
||||
@SysUISingleton
|
||||
public class ThemeOverlayApplier implements Dumpable {
|
||||
private static final String TAG = "ThemeOverlayManager";
|
||||
private static final boolean DEBUG = false;
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
@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";
|
||||
@@ -46,7 +63,11 @@ class ThemeOverlayManager {
|
||||
static final String SYSUI_PACKAGE = "com.android.systemui";
|
||||
|
||||
@VisibleForTesting
|
||||
static final String OVERLAY_CATEGORY_COLOR = "android.theme.customization.accent_color";
|
||||
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
|
||||
static final String OVERLAY_CATEGORY_FONT = "android.theme.customization.font";
|
||||
@VisibleForTesting
|
||||
@@ -73,24 +94,36 @@ class ThemeOverlayManager {
|
||||
* starts with launcher and grouped by target package.
|
||||
*/
|
||||
static final List<String> THEME_CATEGORIES = Lists.newArrayList(
|
||||
OVERLAY_CATEGORY_SYSTEM_PALETTE,
|
||||
OVERLAY_CATEGORY_ICON_LAUNCHER,
|
||||
OVERLAY_CATEGORY_SHAPE,
|
||||
OVERLAY_CATEGORY_FONT,
|
||||
OVERLAY_CATEGORY_COLOR,
|
||||
OVERLAY_CATEGORY_ACCENT_COLOR,
|
||||
OVERLAY_CATEGORY_ICON_ANDROID,
|
||||
OVERLAY_CATEGORY_ICON_SYSUI,
|
||||
OVERLAY_CATEGORY_ICON_SETTINGS,
|
||||
OVERLAY_CATEGORY_ICON_THEME_PICKER);
|
||||
|
||||
/* Categories that need to applied to the current user as well as the system user. */
|
||||
/* Categories that need to be applied to the current user as well as the system user. */
|
||||
@VisibleForTesting
|
||||
static final Set<String> SYSTEM_USER_CATEGORIES = Sets.newHashSet(
|
||||
OVERLAY_CATEGORY_COLOR,
|
||||
OVERLAY_CATEGORY_SYSTEM_PALETTE,
|
||||
OVERLAY_CATEGORY_ACCENT_COLOR,
|
||||
OVERLAY_CATEGORY_FONT,
|
||||
OVERLAY_CATEGORY_SHAPE,
|
||||
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. */
|
||||
@@ -100,15 +133,15 @@ class ThemeOverlayManager {
|
||||
private final String mLauncherPackage;
|
||||
private final String mThemePickerPackage;
|
||||
|
||||
ThemeOverlayManager(OverlayManager overlayManager, Executor executor,
|
||||
String launcherPackage, String themePickerPackage) {
|
||||
public ThemeOverlayApplier(OverlayManager overlayManager, Executor executor,
|
||||
String launcherPackage, String themePickerPackage, DumpManager dumpManager) {
|
||||
mOverlayManager = overlayManager;
|
||||
mExecutor = executor;
|
||||
mLauncherPackage = launcherPackage;
|
||||
mThemePickerPackage = themePickerPackage;
|
||||
mTargetPackageToCategories.put(ANDROID_PACKAGE, Sets.newHashSet(
|
||||
OVERLAY_CATEGORY_COLOR, OVERLAY_CATEGORY_FONT,
|
||||
OVERLAY_CATEGORY_SHAPE, OVERLAY_CATEGORY_ICON_ANDROID));
|
||||
OVERLAY_CATEGORY_SYSTEM_PALETTE, OVERLAY_CATEGORY_ACCENT_COLOR,
|
||||
OVERLAY_CATEGORY_FONT, OVERLAY_CATEGORY_SHAPE, OVERLAY_CATEGORY_ICON_ANDROID));
|
||||
mTargetPackageToCategories.put(SYSUI_PACKAGE,
|
||||
Sets.newHashSet(OVERLAY_CATEGORY_ICON_SYSUI));
|
||||
mTargetPackageToCategories.put(SETTINGS_PACKAGE,
|
||||
@@ -117,7 +150,7 @@ class ThemeOverlayManager {
|
||||
Sets.newHashSet(OVERLAY_CATEGORY_ICON_LAUNCHER));
|
||||
mTargetPackageToCategories.put(mThemePickerPackage,
|
||||
Sets.newHashSet(OVERLAY_CATEGORY_ICON_THEME_PICKER));
|
||||
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_COLOR, ANDROID_PACKAGE);
|
||||
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR, ANDROID_PACKAGE);
|
||||
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_FONT, ANDROID_PACKAGE);
|
||||
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_SHAPE, ANDROID_PACKAGE);
|
||||
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_ANDROID, ANDROID_PACKAGE);
|
||||
@@ -125,6 +158,54 @@ class ThemeOverlayManager {
|
||||
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_SETTINGS, SETTINGS_PACKAGE);
|
||||
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() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,4 +265,13 @@ class ThemeOverlayManager {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @inherit
|
||||
*/
|
||||
@Override
|
||||
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
|
||||
pw.println("mMainSystemColors=" + mMainSystemColors.size());
|
||||
pw.println("mAccentColors=" + mAccentColors.size());
|
||||
}
|
||||
}
|
||||
@@ -15,16 +15,20 @@
|
||||
*/
|
||||
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.app.ActivityManager;
|
||||
import android.app.WallpaperColors;
|
||||
import android.app.WallpaperManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.om.OverlayManager;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.database.ContentObserver;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Handler;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
@@ -33,20 +37,32 @@ import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.systemui.R;
|
||||
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;
|
||||
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.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.settings.SecureSettings;
|
||||
|
||||
import com.google.android.collect.Sets;
|
||||
|
||||
import org.json.JSONException;
|
||||
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 javax.inject.Inject;
|
||||
|
||||
@@ -60,49 +76,76 @@ import javax.inject.Inject;
|
||||
* associated work profiles
|
||||
*/
|
||||
@SysUISingleton
|
||||
public class ThemeOverlayController extends SystemUI {
|
||||
public class ThemeOverlayController extends SystemUI implements Dumpable {
|
||||
private static final String TAG = "ThemeOverlayController";
|
||||
private static final boolean DEBUG = false;
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
private ThemeOverlayManager mThemeManager;
|
||||
private UserManager mUserManager;
|
||||
private BroadcastDispatcher mBroadcastDispatcher;
|
||||
// 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.
|
||||
@VisibleForTesting
|
||||
static final boolean USE_LOCK_SCREEN_WALLPAPER = false;
|
||||
|
||||
private final ThemeOverlayApplier mThemeManager;
|
||||
private final UserManager mUserManager;
|
||||
private final BroadcastDispatcher mBroadcastDispatcher;
|
||||
private final Executor mBgExecutor;
|
||||
private final SecureSettings mSecureSettings;
|
||||
private final Executor mMainExecutor;
|
||||
private final Handler mBgHandler;
|
||||
private final WallpaperManager mWallpaperManager;
|
||||
private final KeyguardStateController mKeyguardStateController;
|
||||
private WallpaperColors mLockColors;
|
||||
private WallpaperColors mSystemColors;
|
||||
// Color extracted from wallpaper, NOT the color used on the overlay
|
||||
private int mMainWallpaperColor = Color.TRANSPARENT;
|
||||
// Color extracted from wallpaper, NOT the color used on the overlay
|
||||
private 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;
|
||||
|
||||
@Inject
|
||||
public ThemeOverlayController(Context context, BroadcastDispatcher broadcastDispatcher,
|
||||
@Background Handler bgHandler) {
|
||||
@Background Handler bgHandler, @Main Executor mainExecutor,
|
||||
@Background Executor bgExecutor, ThemeOverlayApplier themeOverlayApplier,
|
||||
SecureSettings secureSettings, WallpaperManager wallpaperManager,
|
||||
UserManager userManager, KeyguardStateController keyguardStateController,
|
||||
DumpManager dumpManager) {
|
||||
super(context);
|
||||
|
||||
mBroadcastDispatcher = broadcastDispatcher;
|
||||
mUserManager = userManager;
|
||||
mBgExecutor = bgExecutor;
|
||||
mMainExecutor = mainExecutor;
|
||||
mBgHandler = bgHandler;
|
||||
mThemeManager = themeOverlayApplier;
|
||||
mSecureSettings = secureSettings;
|
||||
mWallpaperManager = wallpaperManager;
|
||||
mKeyguardStateController = keyguardStateController;
|
||||
dumpManager.registerDumpable(TAG, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (DEBUG) Log.d(TAG, "Start");
|
||||
mUserManager = mContext.getSystemService(UserManager.class);
|
||||
mThemeManager = new ThemeOverlayManager(
|
||||
mContext.getSystemService(OverlayManager.class),
|
||||
AsyncTask.THREAD_POOL_EXECUTOR,
|
||||
mContext.getString(R.string.launcher_overlayable_package),
|
||||
mContext.getString(R.string.themepicker_overlayable_package));
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_USER_SWITCHED);
|
||||
filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
|
||||
mBroadcastDispatcher.registerReceiverWithHandler(new BroadcastReceiver() {
|
||||
mBroadcastDispatcher.registerReceiver(new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
|
||||
updateThemeOverlays();
|
||||
}
|
||||
}, filter, mBgHandler, UserHandle.ALL);
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
}, filter, mBgExecutor, UserHandle.ALL);
|
||||
mSecureSettings.registerContentObserverForUser(
|
||||
Settings.Secure.getUriFor(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES),
|
||||
false,
|
||||
new ContentObserver(mBgHandler) {
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Collection<Uri> uris, int flags,
|
||||
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) {
|
||||
@@ -111,20 +154,147 @@ public class ThemeOverlayController extends SystemUI {
|
||||
}
|
||||
},
|
||||
UserHandle.USER_ALL);
|
||||
|
||||
// Upon boot, make sure we have the most up to date colors
|
||||
mBgExecutor.execute(() -> {
|
||||
WallpaperColors lockColors = mWallpaperManager.getWallpaperColors(
|
||||
WallpaperManager.FLAG_LOCK);
|
||||
WallpaperColors systemColor = mWallpaperManager.getWallpaperColors(
|
||||
WallpaperManager.FLAG_SYSTEM);
|
||||
mMainExecutor.execute(() -> {
|
||||
if (USE_LOCK_SCREEN_WALLPAPER) {
|
||||
mLockColors = lockColors;
|
||||
}
|
||||
mSystemColors = systemColor;
|
||||
reevaluateSystemTheme();
|
||||
});
|
||||
});
|
||||
if (USE_LOCK_SCREEN_WALLPAPER) {
|
||||
mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
|
||||
@Override
|
||||
public void onKeyguardShowingChanged() {
|
||||
if (mLockColors == null) {
|
||||
return;
|
||||
}
|
||||
// It's possible that the user has a lock screen wallpaper. On this case we'll
|
||||
// end up with different colors after unlocking.
|
||||
reevaluateSystemTheme();
|
||||
}
|
||||
});
|
||||
}
|
||||
mWallpaperManager.addOnColorsChangedListener((wallpaperColors, which) -> {
|
||||
if (USE_LOCK_SCREEN_WALLPAPER && (which & WallpaperManager.FLAG_LOCK) != 0) {
|
||||
mLockColors = wallpaperColors;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "got new lock colors: " + wallpaperColors + " where: " + which);
|
||||
}
|
||||
}
|
||||
if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
|
||||
mSystemColors = wallpaperColors;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "got new lock colors: " + wallpaperColors + " where: " + which);
|
||||
}
|
||||
}
|
||||
reevaluateSystemTheme();
|
||||
}, null, UserHandle.USER_ALL);
|
||||
}
|
||||
|
||||
private void reevaluateSystemTheme() {
|
||||
if (mLockColors == null && mSystemColors == null) {
|
||||
Log.w(TAG, "Cannot update theme, colors are null");
|
||||
return;
|
||||
}
|
||||
WallpaperColors currentColor =
|
||||
mKeyguardStateController.isShowing() && mLockColors != null
|
||||
? mLockColors : mSystemColors;
|
||||
int mainColor = currentColor.getPrimaryColor().toArgb();
|
||||
|
||||
//TODO(b/172860591) implement more complex logic for picking accent color.
|
||||
//For now, picking the secondary should be enough.
|
||||
Color accentCandidate = currentColor.getSecondaryColor();
|
||||
if (accentCandidate == null) {
|
||||
accentCandidate = currentColor.getTertiaryColor();
|
||||
}
|
||||
if (accentCandidate == null) {
|
||||
accentCandidate = currentColor.getPrimaryColor();
|
||||
}
|
||||
|
||||
if (mMainWallpaperColor == mainColor && mWallpaperAccentColor == accentCandidate.toArgb()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mMainWallpaperColor = mainColor;
|
||||
mWallpaperAccentColor = accentCandidate.toArgb();
|
||||
|
||||
// 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 (DEBUG) {
|
||||
Log.d(TAG, "Cannot apply system theme, palettes are unavailable");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mSystemOverlayColor = getClosest(systemColors, mMainWallpaperColor);
|
||||
mAccentOverlayColor = getClosest(accentColors, mWallpaperAccentColor);
|
||||
|
||||
updateThemeOverlays();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a color and a list of candidates, return the candidate that's the most similar to the
|
||||
* given color.
|
||||
*/
|
||||
private static 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private void updateThemeOverlays() {
|
||||
final int currentUser = ActivityManager.getCurrentUser();
|
||||
final String overlayPackageJson = Settings.Secure.getStringForUser(
|
||||
mContext.getContentResolver(), Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
|
||||
final String overlayPackageJson = mSecureSettings.getStringForUser(
|
||||
Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
|
||||
currentUser);
|
||||
if (DEBUG) Log.d(TAG, "updateThemeOverlays: " + overlayPackageJson);
|
||||
boolean hasSystemPalette = false;
|
||||
boolean hasAccentColor = false;
|
||||
final Map<String, String> categoryToPackage = new ArrayMap<>();
|
||||
if (!TextUtils.isEmpty(overlayPackageJson)) {
|
||||
try {
|
||||
JSONObject object = new JSONObject(overlayPackageJson);
|
||||
for (String category : ThemeOverlayManager.THEME_CATEGORIES) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -132,6 +302,20 @@ public class ThemeOverlayController extends SystemUI {
|
||||
Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
+ Integer.toHexString(mSystemOverlayColor).toUpperCase());
|
||||
}
|
||||
// Same for the accent color
|
||||
if (!hasAccentColor && mAccentOverlayColor != Color.TRANSPARENT) {
|
||||
categoryToPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR,
|
||||
ThemeOverlayApplier.MONET_ACCENT_COLOR_PACKAGE
|
||||
+ Integer.toHexString(mAccentOverlayColor).toUpperCase());
|
||||
}
|
||||
|
||||
Set<UserHandle> userHandles = Sets.newHashSet(UserHandle.of(currentUser));
|
||||
for (UserInfo userInfo : mUserManager.getEnabledProfiles(currentUser)) {
|
||||
if (userInfo.isManagedProfile()) {
|
||||
@@ -140,4 +324,14 @@ public class ThemeOverlayController extends SystemUI {
|
||||
}
|
||||
mThemeManager.applyCurrentUserOverlays(categoryToPackage, userHandles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,22 +15,24 @@
|
||||
*/
|
||||
package com.android.systemui.theme;
|
||||
|
||||
import static com.android.systemui.theme.ThemeOverlayManager.ANDROID_PACKAGE;
|
||||
import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_COLOR;
|
||||
import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_FONT;
|
||||
import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_ANDROID;
|
||||
import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_LAUNCHER;
|
||||
import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_SETTINGS;
|
||||
import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_SYSUI;
|
||||
import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_THEME_PICKER;
|
||||
import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_SHAPE;
|
||||
import static com.android.systemui.theme.ThemeOverlayManager.SETTINGS_PACKAGE;
|
||||
import static com.android.systemui.theme.ThemeOverlayManager.SYSTEM_USER_CATEGORIES;
|
||||
import static com.android.systemui.theme.ThemeOverlayManager.SYSUI_PACKAGE;
|
||||
import static com.android.systemui.theme.ThemeOverlayManager.THEME_CATEGORIES;
|
||||
import static com.android.systemui.theme.ThemeOverlayApplier.ANDROID_PACKAGE;
|
||||
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR;
|
||||
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_FONT;
|
||||
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_ANDROID;
|
||||
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_LAUNCHER;
|
||||
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_SETTINGS;
|
||||
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_SYSUI;
|
||||
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_THEME_PICKER;
|
||||
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SHAPE;
|
||||
import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE;
|
||||
import static com.android.systemui.theme.ThemeOverlayApplier.SETTINGS_PACKAGE;
|
||||
import static com.android.systemui.theme.ThemeOverlayApplier.SYSTEM_USER_CATEGORIES;
|
||||
import static com.android.systemui.theme.ThemeOverlayApplier.SYSUI_PACKAGE;
|
||||
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.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -44,6 +46,7 @@ import android.testing.TestableLooper;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
|
||||
import com.google.android.collect.Maps;
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -63,7 +66,7 @@ import java.util.Set;
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper
|
||||
public class ThemeOverlayManagerTest extends SysuiTestCase {
|
||||
public class ThemeOverlayApplierTest extends SysuiTestCase {
|
||||
private static final String TEST_DISABLED_PREFIX = "com.example.";
|
||||
private static final String TEST_ENABLED_PREFIX = "com.example.enabled.";
|
||||
|
||||
@@ -82,26 +85,32 @@ public class ThemeOverlayManagerTest extends SysuiTestCase {
|
||||
|
||||
@Mock
|
||||
OverlayManager mOverlayManager;
|
||||
@Mock
|
||||
DumpManager mDumpManager;
|
||||
|
||||
private ThemeOverlayManager mManager;
|
||||
private ThemeOverlayApplier mManager;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mManager = new ThemeOverlayManager(mOverlayManager, MoreExecutors.directExecutor(),
|
||||
LAUNCHER_PACKAGE, THEMEPICKER_PACKAGE);
|
||||
mManager = new ThemeOverlayApplier(mOverlayManager, MoreExecutors.directExecutor(),
|
||||
LAUNCHER_PACKAGE, THEMEPICKER_PACKAGE, mDumpManager);
|
||||
when(mOverlayManager.getOverlayInfosForTarget(ANDROID_PACKAGE, UserHandle.SYSTEM))
|
||||
.thenReturn(Lists.newArrayList(
|
||||
createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_COLOR,
|
||||
ANDROID_PACKAGE, OVERLAY_CATEGORY_COLOR, false),
|
||||
createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_ACCENT_COLOR,
|
||||
ANDROID_PACKAGE, OVERLAY_CATEGORY_ACCENT_COLOR, false),
|
||||
createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_SYSTEM_PALETTE,
|
||||
ANDROID_PACKAGE, OVERLAY_CATEGORY_SYSTEM_PALETTE, false),
|
||||
createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_FONT,
|
||||
ANDROID_PACKAGE, OVERLAY_CATEGORY_FONT, false),
|
||||
createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_SHAPE,
|
||||
ANDROID_PACKAGE, OVERLAY_CATEGORY_SHAPE, false),
|
||||
createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_ICON_ANDROID,
|
||||
ANDROID_PACKAGE, OVERLAY_CATEGORY_ICON_ANDROID, false),
|
||||
createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_COLOR,
|
||||
ANDROID_PACKAGE, OVERLAY_CATEGORY_COLOR, true),
|
||||
createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ACCENT_COLOR,
|
||||
ANDROID_PACKAGE, OVERLAY_CATEGORY_ACCENT_COLOR, true),
|
||||
createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_SYSTEM_PALETTE,
|
||||
ANDROID_PACKAGE, OVERLAY_CATEGORY_SYSTEM_PALETTE, true),
|
||||
createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_FONT,
|
||||
ANDROID_PACKAGE, OVERLAY_CATEGORY_FONT, true),
|
||||
createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_SHAPE,
|
||||
@@ -132,6 +141,8 @@ public class ThemeOverlayManagerTest extends SysuiTestCase {
|
||||
THEMEPICKER_PACKAGE, OVERLAY_CATEGORY_ICON_THEME_PICKER, false),
|
||||
createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_THEME_PICKER,
|
||||
THEMEPICKER_PACKAGE, OVERLAY_CATEGORY_ICON_THEME_PICKER, true)));
|
||||
clearInvocations(mOverlayManager);
|
||||
verify(mDumpManager).registerDumpable(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
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.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.WallpaperColors;
|
||||
import android.app.WallpaperManager;
|
||||
import android.graphics.Color;
|
||||
import android.os.Handler;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
|
||||
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.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.settings.SecureSettings;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
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;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
public class ThemeOverlayControllerTest extends SysuiTestCase {
|
||||
|
||||
private ThemeOverlayController mThemeOverlayController;
|
||||
@Mock
|
||||
private Executor mBgExecutor;
|
||||
@Mock
|
||||
private Executor mMainExecutor;
|
||||
@Mock
|
||||
private BroadcastDispatcher mBroadcastDispatcher;
|
||||
@Mock
|
||||
private Handler mBgHandler;
|
||||
@Mock
|
||||
private ThemeOverlayApplier mThemeOverlayApplier;
|
||||
@Mock
|
||||
private SecureSettings mSecureSettings;
|
||||
@Mock
|
||||
private WallpaperManager mWallpaperManager;
|
||||
@Mock
|
||||
private UserManager mUserManager;
|
||||
@Mock
|
||||
private KeyguardStateController mKeyguardStateController;
|
||||
@Mock
|
||||
private DumpManager mDumpManager;
|
||||
@Captor
|
||||
private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallback;
|
||||
@Captor
|
||||
private ArgumentCaptor<WallpaperManager.OnColorsChangedListener> mColorsListener;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mThemeOverlayController = new ThemeOverlayController(null /* context */,
|
||||
mBroadcastDispatcher, mBgHandler, mMainExecutor, mBgExecutor, mThemeOverlayApplier,
|
||||
mSecureSettings, mWallpaperManager, mUserManager, mKeyguardStateController,
|
||||
mDumpManager);
|
||||
|
||||
mThemeOverlayController.start();
|
||||
if (USE_LOCK_SCREEN_WALLPAPER) {
|
||||
verify(mKeyguardStateController).addCallback(
|
||||
mKeyguardStateControllerCallback.capture());
|
||||
}
|
||||
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);
|
||||
when(mThemeOverlayApplier.getAvailableAccentColors()).thenReturn(colorList);
|
||||
when(mThemeOverlayApplier.getAvailableSystemColors()).thenReturn(colorList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void start_checksWallpaper() {
|
||||
ArgumentCaptor<Runnable> registrationRunnable = ArgumentCaptor.forClass(Runnable.class);
|
||||
verify(mBgExecutor).execute(registrationRunnable.capture());
|
||||
|
||||
registrationRunnable.getValue().run();
|
||||
verify(mWallpaperManager).getWallpaperColors(eq(WallpaperManager.FLAG_LOCK));
|
||||
verify(mWallpaperManager).getWallpaperColors(eq(WallpaperManager.FLAG_SYSTEM));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onWallpaperColorsChanged_setsTheme() {
|
||||
// Should ask for a new theme when wallpaper colors change
|
||||
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);
|
||||
|
||||
verify(mThemeOverlayApplier).getAvailableSystemColors();
|
||||
verify(mThemeOverlayApplier).getAvailableAccentColors();
|
||||
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
|
||||
+ Integer.toHexString(Color.RED).toUpperCase());
|
||||
assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_ACCENT_COLOR))
|
||||
.isEqualTo(MONET_ACCENT_COLOR_PACKAGE
|
||||
+ Integer.toHexString(Color.BLUE).toUpperCase());
|
||||
|
||||
// Should not ask again if changed to same value
|
||||
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
|
||||
verifyNoMoreInteractions(mThemeOverlayApplier);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onWallpaperColorsChanged_preservesWallpaperPickerTheme() {
|
||||
// Should ask for a new theme when wallpaper colors change
|
||||
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
|
||||
Color.valueOf(Color.BLUE), null);
|
||||
|
||||
String jsonString =
|
||||
"{\"android.theme.customization.system_palette\":\"override.package.name\"}";
|
||||
when(mSecureSettings.getStringForUser(
|
||||
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
|
||||
.thenReturn(jsonString);
|
||||
|
||||
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
|
||||
ArgumentCaptor<Map<String, String>> themeOverlays = ArgumentCaptor.forClass(Map.class);
|
||||
|
||||
verify(mThemeOverlayApplier).getAvailableSystemColors();
|
||||
verify(mThemeOverlayApplier).getAvailableAccentColors();
|
||||
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("override.package.name");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user