WallpaperColors caching and synchronization
Making sure that colors are being cached in
WallpaperManagerService and that sysui won't
force a new color extraction.
Fixes: 62958267
Test: manual, reboot, look at systrace
Test: runtest -x cts/tests/app/src/android/app/cts/WallpaperManagerTest.java
Change-Id: Ic079a8e3d4d4ad65947b718dcc544f795c16f152
diff --git a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/ColorExtractor.java b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/ColorExtractor.java
index 2d794fb..62fcef3 100644
--- a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/ColorExtractor.java
+++ b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/ColorExtractor.java
@@ -16,12 +16,14 @@
package com.google.android.colorextraction;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.WallpaperColors;
import android.app.WallpaperManager;
import android.content.Context;
-import android.support.annotation.NonNull;
+import android.os.AsyncTask;
+import android.os.Trace;
import android.support.annotation.VisibleForTesting;
-import android.support.v4.graphics.ColorUtils;
import android.util.Log;
import android.util.SparseArray;
@@ -29,6 +31,7 @@
import com.google.android.colorextraction.types.Tonal;
import java.util.ArrayList;
+import java.util.List;
/**
* Class to process wallpaper colors and generate a tonal palette based on them.
@@ -50,6 +53,8 @@
private final ArrayList<OnColorsChangedListener> mOnColorsChangedListeners;
private final Context mContext;
private final ExtractionType mExtractionType;
+ private WallpaperColors mSystemColors;
+ private WallpaperColors mLockColors;
public ColorExtractor(Context context) {
this(context, new Tonal());
@@ -70,7 +75,6 @@
}
mOnColorsChangedListeners = new ArrayList<>();
-
WallpaperManager wallpaperManager = mContext.getSystemService(WallpaperManager.class);
if (wallpaperManager == null) {
Log.w(TAG, "Can't listen to color changes!");
@@ -78,17 +82,25 @@
wallpaperManager.addOnColorsChangedListener(this);
// Initialize all gradients with the current colors
- GradientColors[] systemColors = mGradientColors.get(WallpaperManager.FLAG_SYSTEM);
- extractInto(wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_SYSTEM),
+ Trace.beginSection("ColorExtractor#getWallpaperColors");
+ mSystemColors = wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
+ mLockColors = wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_LOCK);
+
+ GradientColors[] systemColors = mGradientColors.get(
+ WallpaperManager.FLAG_SYSTEM);
+ extractInto(mSystemColors,
systemColors[TYPE_NORMAL],
systemColors[TYPE_DARK],
systemColors[TYPE_EXTRA_DARK]);
GradientColors[] lockColors = mGradientColors.get(WallpaperManager.FLAG_LOCK);
- extractInto(wallpaperManager.getWallpaperColors(WallpaperManager.FLAG_LOCK),
+ extractInto(mLockColors,
lockColors[TYPE_NORMAL],
lockColors[TYPE_DARK],
lockColors[TYPE_EXTRA_DARK]);
+ triggerColorsChanged(WallpaperManager.FLAG_SYSTEM
+ | WallpaperManager.FLAG_LOCK);
+ Trace.endSection();
}
}
@@ -110,6 +122,7 @@
* @param type TYPE_NORMAL, TYPE_DARK or TYPE_EXTRA_DARK
* @return colors
*/
+ @NonNull
public GradientColors getColors(int which, int type) {
if (type != TYPE_NORMAL && type != TYPE_DARK && type != TYPE_EXTRA_DARK) {
throw new IllegalArgumentException(
@@ -121,16 +134,35 @@
return mGradientColors.get(which)[type];
}
+ /**
+ * Get the last available WallpaperColors without forcing new extraction.
+ *
+ * @param which FLAG_LOCK or FLAG_SYSTEM
+ * @return Last cached colors
+ */
+ @Nullable
+ public WallpaperColors getWallpaperColors(int which) {
+ if (which == WallpaperManager.FLAG_LOCK) {
+ return mLockColors;
+ } else if (which == WallpaperManager.FLAG_SYSTEM) {
+ return mSystemColors;
+ } else {
+ throw new IllegalArgumentException("Invalid value for which: " + which);
+ }
+ }
+
@Override
public void onColorsChanged(WallpaperColors colors, int which) {
boolean changed = false;
if ((which & WallpaperManager.FLAG_LOCK) != 0) {
+ mLockColors = colors;
GradientColors[] lockColors = mGradientColors.get(WallpaperManager.FLAG_LOCK);
extractInto(colors, lockColors[TYPE_NORMAL], lockColors[TYPE_DARK],
lockColors[TYPE_EXTRA_DARK]);
changed = true;
}
if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
+ mSystemColors = colors;
GradientColors[] systemColors = mGradientColors.get(WallpaperManager.FLAG_SYSTEM);
extractInto(colors, systemColors[TYPE_NORMAL], systemColors[TYPE_DARK],
systemColors[TYPE_EXTRA_DARK]);
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index bb44123..776d076 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -268,6 +268,9 @@
mProviders.put(AccessibilityManagerWrapper.class,
() -> new AccessibilityManagerWrapper(mContext));
+ // Creating a new instance will trigger color extraction.
+ // Thankfully this only happens once - during boot - and WallpaperManagerService
+ // loads colors from cache.
mProviders.put(SysuiColorExtractor.class, () -> new SysuiColorExtractor(mContext));
mProviders.put(TunablePaddingService.class, () -> new TunablePaddingService());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 754c344..0bd58df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -304,8 +304,8 @@
mNeedsDrawableColorUpdate = false;
if (mKeyguardShowing) {
// Always animate color changes if we're seeing the keyguard
- mScrimInFront.setColors(mLockColors);
- mScrimBehind.setColors(mLockColors);
+ mScrimInFront.setColors(mLockColors, true /* animated */);
+ mScrimBehind.setColors(mLockColors, true /* animated */);
} else {
// Only animate scrim color if the scrim view is actually visible
boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index f6fab44..2118fbd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -4559,16 +4559,13 @@
.supportsDarkText();
// And wallpaper defines if QS should be light or dark.
boolean useDarkTheme = false;
- final WallpaperManager wallpaperManager = mContext.getSystemService(WallpaperManager.class);
- if (wallpaperManager != null) {
- WallpaperColors wallpaperColors = wallpaperManager
- .getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
- if (wallpaperColors != null) {
- final int mainColor = wallpaperColors.getPrimaryColor().toArgb();
- final float[] hsl = new float[3];
- ColorUtils.colorToHSL(mainColor, hsl);
- useDarkTheme = hsl[2] < 0.2f;
- }
+ final WallpaperColors systemColors =
+ mColorExtractor.getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
+ if (systemColors != null) {
+ int mainColor = systemColors.getPrimaryColor().toArgb();
+ float[] hsl = new float[3];
+ ColorUtils.colorToHSL(mainColor, hsl);
+ useDarkTheme = hsl[2] < 0.2f;
}
// Enable/disable dark UI.
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index dfcc166..2aa524c 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -32,6 +32,7 @@
import android.app.IWallpaperManagerCallback;
import android.app.PendingIntent;
import android.app.UserSwitchObserver;
+import android.app.WallpaperColors;
import android.app.WallpaperInfo;
import android.app.WallpaperManager;
import android.app.admin.DevicePolicyManager;
@@ -55,7 +56,6 @@
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -64,8 +64,8 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
-import android.os.Process;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SELinux;
@@ -76,12 +76,10 @@
import android.service.wallpaper.IWallpaperConnection;
import android.service.wallpaper.IWallpaperEngine;
import android.service.wallpaper.IWallpaperService;
-import android.app.WallpaperColors;
import android.service.wallpaper.WallpaperService;
import android.system.ErrnoException;
import android.system.Os;
import android.util.EventLog;
-import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
@@ -99,7 +97,6 @@
import com.android.server.FgThread;
import com.android.server.SystemService;
-import java.util.ArrayList;
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -347,32 +344,44 @@
needsExtraction = wallpaper.primaryColors == null;
}
- // This should not be synchronized because color extraction
- // might take a while.
+ // Let's notify the current values, it's fine if it's null, it just means
+ // that we don't know yet.
+ notifyColorListeners(wallpaper.primaryColors, which);
+
if (needsExtraction) {
extractColors(wallpaper);
+ notifyColorListeners(wallpaper.primaryColors, which);
}
+ }
+ private void notifyColorListeners(WallpaperColors wallpaperColors, int which) {
+ final IWallpaperManagerCallback[] listeners;
+ final IWallpaperManagerCallback keyguardListener;
synchronized (mLock) {
- final int n = mColorsChangedListeners.beginBroadcast();
- for (int i = 0; i < n; i++) {
- IWallpaperManagerCallback callback = mColorsChangedListeners.getBroadcastItem(i);
- try {
- callback.onWallpaperColorsChanged(wallpaper.primaryColors, which);
- } catch (RemoteException e) {
- // Callback is gone, it's not necessary to unregister it since
- // RemoteCallbackList#getBroadcastItem will take care of it.
- }
+ // Make a synchronized copy of the listeners to avoid concurrent list modification.
+ int callbackCount = mColorsChangedListeners.beginBroadcast();
+ listeners = new IWallpaperManagerCallback[callbackCount];
+ for (int i = 0; i < callbackCount; i++) {
+ listeners[i] = mColorsChangedListeners.getBroadcastItem(i);
}
mColorsChangedListeners.finishBroadcast();
+ keyguardListener = mKeyguardListener;
+ }
- final IWallpaperManagerCallback cb = mKeyguardListener;
- if (cb != null) {
- try {
- cb.onWallpaperColorsChanged(wallpaper.primaryColors, which);
- } catch (RemoteException e) {
- // Oh well it went away; no big deal
- }
+ for (int i = 0; i < listeners.length; i++) {
+ try {
+ listeners[i].onWallpaperColorsChanged(wallpaperColors, which);
+ } catch (RemoteException e) {
+ // Callback is gone, it's not necessary to unregister it since
+ // RemoteCallbackList#getBroadcastItem will take care of it.
+ }
+ }
+
+ if (keyguardListener != null) {
+ try {
+ keyguardListener.onWallpaperColorsChanged(wallpaperColors, which);
+ } catch (RemoteException e) {
+ // Oh well it went away; no big deal
}
}
}
@@ -414,6 +423,9 @@
synchronized (mLock) {
if (wallpaper.wallpaperId == wallpaperId) {
wallpaper.primaryColors = colors;
+ // Now that we have the colors, let's save them into the xml
+ // to avoid having to run this again.
+ saveSettingsLocked(wallpaper.userId);
} else {
Slog.w(TAG, "Not setting primary colors since wallpaper changed");
}
@@ -1366,6 +1378,7 @@
RuntimeException e = null;
try {
+ wallpaper.primaryColors = null;
wallpaper.imageWallpaperPending = false;
if (userId != mCurrentUserId) return;
if (bindWallpaperComponentLocked(defaultFailed
@@ -1843,6 +1856,7 @@
try {
wallpaper.imageWallpaperPending = false;
if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {
+ wallpaper.primaryColors = null;
wallpaper.wallpaperId = makeWallpaperIdLocked();
notifyCallbacksLocked(wallpaper);
shouldNotifyColors = true;
@@ -1979,7 +1993,6 @@
}
wallpaper.wallpaperComponent = componentName;
wallpaper.connection = newConn;
- wallpaper.primaryColors = null;
newConn.mReply = reply;
try {
if (wallpaper.userId == mCurrentUserId) {
@@ -2185,7 +2198,7 @@
out.attribute(null, "colorValue"+i, Integer.toString(wc.toArgb()));
}
}
- out.attribute(null, "supportsDarkText",
+ out.attribute(null, "colorHints",
Integer.toString(wallpaper.primaryColors.getColorHints()));
}
@@ -2422,7 +2435,6 @@
int colorsCount = getAttributeInt(parser, "colorsCount", 0);
if (colorsCount > 0) {
Color primary = null, secondary = null, tertiary = null;
- final List<Color> colors = new ArrayList<>();
for (int i = 0; i < colorsCount; i++) {
Color color = Color.valueOf(getAttributeInt(parser, "colorValue" + i, 0));
if (i == 0) {