Merge "In-app gradient color based on systemui theme." into oc-dr1-dev
This commit is contained in:
@@ -43,10 +43,6 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener
|
||||
|
||||
private static final String TAG = "ColorExtractor";
|
||||
|
||||
public static final int FALLBACK_COLOR = 0xff83888d;
|
||||
|
||||
private int mMainFallbackColor = FALLBACK_COLOR;
|
||||
private int mSecondaryFallbackColor = FALLBACK_COLOR;
|
||||
private final SparseArray<GradientColors[]> mGradientColors;
|
||||
private final ArrayList<OnColorsChangedListener> mOnColorsChangedListeners;
|
||||
private final Context mContext;
|
||||
@@ -73,6 +69,9 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener
|
||||
}
|
||||
|
||||
mOnColorsChangedListeners = new ArrayList<>();
|
||||
GradientColors[] systemColors = mGradientColors.get(WallpaperManager.FLAG_SYSTEM);
|
||||
GradientColors[] lockColors = mGradientColors.get(WallpaperManager.FLAG_LOCK);
|
||||
|
||||
WallpaperManager wallpaperManager = mContext.getSystemService(WallpaperManager.class);
|
||||
if (wallpaperManager == null) {
|
||||
Log.w(TAG, "Can't listen to color changes!");
|
||||
@@ -83,23 +82,18 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener
|
||||
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(mLockColors,
|
||||
lockColors[TYPE_NORMAL],
|
||||
lockColors[TYPE_DARK],
|
||||
lockColors[TYPE_EXTRA_DARK]);
|
||||
triggerColorsChanged(WallpaperManager.FLAG_SYSTEM
|
||||
| WallpaperManager.FLAG_LOCK);
|
||||
Trace.endSection();
|
||||
}
|
||||
|
||||
// Initialize all gradients with the current colors
|
||||
extractInto(mSystemColors,
|
||||
systemColors[TYPE_NORMAL],
|
||||
systemColors[TYPE_DARK],
|
||||
systemColors[TYPE_EXTRA_DARK]);
|
||||
extractInto(mLockColors,
|
||||
lockColors[TYPE_NORMAL],
|
||||
lockColors[TYPE_DARK],
|
||||
lockColors[TYPE_EXTRA_DARK]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,25 +175,8 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener
|
||||
private void extractInto(WallpaperColors inWallpaperColors,
|
||||
GradientColors outGradientColorsNormal, GradientColors outGradientColorsDark,
|
||||
GradientColors outGradientColorsExtraDark) {
|
||||
if (inWallpaperColors == null) {
|
||||
applyFallback(outGradientColorsNormal);
|
||||
applyFallback(outGradientColorsDark);
|
||||
applyFallback(outGradientColorsExtraDark);
|
||||
return;
|
||||
}
|
||||
boolean success = mExtractionType.extractInto(inWallpaperColors, outGradientColorsNormal,
|
||||
mExtractionType.extractInto(inWallpaperColors, outGradientColorsNormal,
|
||||
outGradientColorsDark, outGradientColorsExtraDark);
|
||||
if (!success) {
|
||||
applyFallback(outGradientColorsNormal);
|
||||
applyFallback(outGradientColorsDark);
|
||||
applyFallback(outGradientColorsExtraDark);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyFallback(GradientColors outGradientColors) {
|
||||
outGradientColors.setMainColor(mMainFallbackColor);
|
||||
outGradientColors.setSecondaryColor(mSecondaryFallbackColor);
|
||||
outGradientColors.setSupportsDarkText(false);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
@@ -218,8 +195,8 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener
|
||||
}
|
||||
|
||||
public static class GradientColors {
|
||||
private int mMainColor = FALLBACK_COLOR;
|
||||
private int mSecondaryColor = FALLBACK_COLOR;
|
||||
private int mMainColor;
|
||||
private int mSecondaryColor;
|
||||
private boolean mSupportsDarkText;
|
||||
|
||||
public void setMainColor(int mainColor) {
|
||||
|
||||
@@ -38,9 +38,8 @@ public interface ExtractionType {
|
||||
* @param outGradientColorsNormal object that should receive normal colors
|
||||
* @param outGradientColorsDark object that should receive dark colors
|
||||
* @param outGradientColorsExtraDark object that should receive extra dark colors
|
||||
* @return true if successful.
|
||||
*/
|
||||
boolean extractInto(WallpaperColors inWallpaperColors,
|
||||
void extractInto(WallpaperColors inWallpaperColors,
|
||||
ColorExtractor.GradientColors outGradientColorsNormal,
|
||||
ColorExtractor.GradientColors outGradientColorsDark,
|
||||
ColorExtractor.GradientColors outGradientColorsExtraDark);
|
||||
|
||||
@@ -44,24 +44,54 @@ public class Tonal implements ExtractionType {
|
||||
|
||||
private static final boolean DEBUG = true;
|
||||
|
||||
public static final int MAIN_COLOR_LIGHT = 0xffe0e0e0;
|
||||
public static final int SECONDARY_COLOR_LIGHT = 0xff9e9e9e;
|
||||
public static final int MAIN_COLOR_DARK = 0xff212121;
|
||||
public static final int SECONDARY_COLOR_DARK = 0xff000000;
|
||||
|
||||
// Temporary variable to avoid allocations
|
||||
private float[] mTmpHSL = new float[3];
|
||||
|
||||
/**
|
||||
* Grab colors from WallpaperColors as set them into GradientColors
|
||||
* Grab colors from WallpaperColors and set them into GradientColors.
|
||||
* Also applies the default gradient in case extraction fails.
|
||||
*
|
||||
* @param inWallpaperColors input
|
||||
* @param outColorsNormal colors for normal theme
|
||||
* @param outColorsDark colors for dar theme
|
||||
* @param outColorsExtraDark colors for extra dark theme
|
||||
* @return true if successful
|
||||
* @param inWallpaperColors Input.
|
||||
* @param outColorsNormal Colors for normal theme.
|
||||
* @param outColorsDark Colors for dar theme.
|
||||
* @param outColorsExtraDark Colors for extra dark theme.
|
||||
*/
|
||||
public boolean extractInto(@NonNull WallpaperColors inWallpaperColors,
|
||||
public void extractInto(@Nullable WallpaperColors inWallpaperColors,
|
||||
@NonNull GradientColors outColorsNormal, @NonNull GradientColors outColorsDark,
|
||||
@NonNull GradientColors outColorsExtraDark) {
|
||||
boolean success = runTonalExtraction(inWallpaperColors, outColorsNormal, outColorsDark,
|
||||
outColorsExtraDark);
|
||||
if (!success) {
|
||||
applyFallback(inWallpaperColors, outColorsNormal, outColorsDark, outColorsExtraDark);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Grab colors from WallpaperColors and set them into GradientColors.
|
||||
*
|
||||
* @param inWallpaperColors Input.
|
||||
* @param outColorsNormal Colors for normal theme.
|
||||
* @param outColorsDark Colors for dar theme.
|
||||
* @param outColorsExtraDark Colors for extra dark theme.
|
||||
* @return True if succeeded or false if failed.
|
||||
*/
|
||||
private boolean runTonalExtraction(@Nullable WallpaperColors inWallpaperColors,
|
||||
@NonNull GradientColors outColorsNormal, @NonNull GradientColors outColorsDark,
|
||||
@NonNull GradientColors outColorsExtraDark) {
|
||||
|
||||
if (inWallpaperColors == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final List<Color> mainColors = inWallpaperColors.getMainColors();
|
||||
final int mainColorsSize = mainColors.size();
|
||||
final boolean supportsDarkText = (inWallpaperColors.getColorHints() &
|
||||
WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0;
|
||||
|
||||
if (mainColorsSize == 0) {
|
||||
return false;
|
||||
@@ -120,7 +150,6 @@ public class Tonal implements ExtractionType {
|
||||
float[] s = fit(palette.s, hsl[1], fitIndex, 0.0f, 1.0f);
|
||||
float[] l = fit(palette.l, hsl[2], fitIndex, 0.0f, 1.0f);
|
||||
|
||||
final int textInversionIndex = h.length - 3;
|
||||
if (DEBUG) {
|
||||
StringBuilder builder = new StringBuilder("Tonal Palette - index: " + fitIndex +
|
||||
". Main color: " + Integer.toHexString(getColorInt(fitIndex, h, s, l)) +
|
||||
@@ -135,21 +164,38 @@ public class Tonal implements ExtractionType {
|
||||
Log.d(TAG, builder.toString());
|
||||
}
|
||||
|
||||
int primaryIndex = fitIndex;
|
||||
int mainColor = getColorInt(primaryIndex, h, s, l);
|
||||
|
||||
// We might want use the fallback in case the extracted color is brighter than our
|
||||
// light fallback or darker than our dark fallback.
|
||||
ColorUtils.colorToHSL(mainColor, mTmpHSL);
|
||||
final float mainLuminosity = mTmpHSL[2];
|
||||
ColorUtils.colorToHSL(MAIN_COLOR_LIGHT, mTmpHSL);
|
||||
final float lightLuminosity = mTmpHSL[2];
|
||||
if (mainLuminosity > lightLuminosity) {
|
||||
return false;
|
||||
}
|
||||
ColorUtils.colorToHSL(MAIN_COLOR_DARK, mTmpHSL);
|
||||
final float darkLuminosity = mTmpHSL[2];
|
||||
if (mainLuminosity < darkLuminosity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Normal colors:
|
||||
// best fit + a 2 colors offset
|
||||
int primaryIndex = fitIndex;
|
||||
outColorsNormal.setMainColor(mainColor);
|
||||
int secondaryIndex = primaryIndex + (primaryIndex >= 2 ? -2 : 2);
|
||||
outColorsNormal.setMainColor(getColorInt(primaryIndex, h, s, l));
|
||||
outColorsNormal.setSecondaryColor(getColorInt(secondaryIndex, h, s, l));
|
||||
|
||||
// Dark colors:
|
||||
// Stops at 4th color, only lighter if dark text is supported
|
||||
if (fitIndex < 2) {
|
||||
primaryIndex = 0;
|
||||
} else if (fitIndex < textInversionIndex) {
|
||||
primaryIndex = Math.min(fitIndex, 3);
|
||||
} else {
|
||||
if (supportsDarkText) {
|
||||
primaryIndex = h.length - 1;
|
||||
} else if (fitIndex < 2) {
|
||||
primaryIndex = 0;
|
||||
} else {
|
||||
primaryIndex = Math.min(fitIndex, 3);
|
||||
}
|
||||
secondaryIndex = primaryIndex + (primaryIndex >= 2 ? -2 : 2);
|
||||
outColorsDark.setMainColor(getColorInt(primaryIndex, h, s, l));
|
||||
@@ -157,18 +203,17 @@ public class Tonal implements ExtractionType {
|
||||
|
||||
// Extra Dark:
|
||||
// Stay close to dark colors until dark text is supported
|
||||
if (fitIndex < 2) {
|
||||
primaryIndex = 0;
|
||||
} else if (fitIndex < textInversionIndex) {
|
||||
primaryIndex = 2;
|
||||
} else {
|
||||
if (supportsDarkText) {
|
||||
primaryIndex = h.length - 1;
|
||||
} else if (fitIndex < 2) {
|
||||
primaryIndex = 0;
|
||||
} else {
|
||||
primaryIndex = 2;
|
||||
}
|
||||
secondaryIndex = primaryIndex + (primaryIndex >= 2 ? -2 : 2);
|
||||
outColorsExtraDark.setMainColor(getColorInt(primaryIndex, h, s, l));
|
||||
outColorsExtraDark.setSecondaryColor(getColorInt(secondaryIndex, h, s, l));
|
||||
|
||||
final boolean supportsDarkText = fitIndex >= textInversionIndex;
|
||||
outColorsNormal.setSupportsDarkText(supportsDarkText);
|
||||
outColorsDark.setSupportsDarkText(supportsDarkText);
|
||||
outColorsExtraDark.setSupportsDarkText(supportsDarkText);
|
||||
@@ -181,6 +226,33 @@ public class Tonal implements ExtractionType {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void applyFallback(@Nullable WallpaperColors inWallpaperColors,
|
||||
GradientColors outColorsNormal, GradientColors outColorsDark,
|
||||
GradientColors outColorsExtraDark) {
|
||||
applyFallback(inWallpaperColors, outColorsNormal);
|
||||
applyFallback(inWallpaperColors, outColorsDark);
|
||||
applyFallback(inWallpaperColors, outColorsExtraDark);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the gradient to the light or dark fallbacks based on the current wallpaper colors.
|
||||
*
|
||||
* @param inWallpaperColors Colors to read.
|
||||
* @param outGradientColors Destination.
|
||||
*/
|
||||
public static void applyFallback(@Nullable WallpaperColors inWallpaperColors,
|
||||
@NonNull GradientColors outGradientColors) {
|
||||
boolean light = inWallpaperColors != null
|
||||
&& (inWallpaperColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT)
|
||||
!= 0;
|
||||
int innerColor = light ? MAIN_COLOR_LIGHT : MAIN_COLOR_DARK;
|
||||
int outerColor = light ? SECONDARY_COLOR_LIGHT : SECONDARY_COLOR_DARK;
|
||||
|
||||
outGradientColors.setMainColor(innerColor);
|
||||
outGradientColors.setSecondaryColor(outerColor);
|
||||
outGradientColors.setSupportsDarkText(light);
|
||||
}
|
||||
|
||||
private int getColorInt(int fitIndex, float[] h, float[] s, float[] l) {
|
||||
mTmpHSL[0] = fract(h[fitIndex]) * 360.0f;
|
||||
mTmpHSL[1] = s[fitIndex];
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.systemui.colorextraction;
|
||||
|
||||
import android.app.WallpaperColors;
|
||||
import android.app.WallpaperManager;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
@@ -47,10 +48,10 @@ public class SysuiColorExtractor extends ColorExtractor {
|
||||
@VisibleForTesting
|
||||
public SysuiColorExtractor(Context context, ExtractionType type, boolean registerVisibility) {
|
||||
super(context, type);
|
||||
|
||||
mWpHiddenColors = new GradientColors();
|
||||
mWpHiddenColors.setMainColor(FALLBACK_COLOR);
|
||||
mWpHiddenColors.setSecondaryColor(FALLBACK_COLOR);
|
||||
|
||||
WallpaperColors systemColors = getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
|
||||
updateDefaultGradients(systemColors);
|
||||
|
||||
if (registerVisibility) {
|
||||
try {
|
||||
@@ -71,6 +72,24 @@ public class SysuiColorExtractor extends ColorExtractor {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDefaultGradients(WallpaperColors colors) {
|
||||
Tonal.applyFallback(colors, mWpHiddenColors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onColorsChanged(WallpaperColors colors, int which) {
|
||||
super.onColorsChanged(colors, which);
|
||||
|
||||
if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
|
||||
updateDefaultGradients(colors);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
GradientColors getFallbackColors() {
|
||||
return mWpHiddenColors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get TYPE_NORMAL colors when wallpaper is visible, or fallback otherwise.
|
||||
*
|
||||
|
||||
@@ -48,14 +48,12 @@ public class SysuiColorExtractorTests extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void getColors_usesGreyIfWallpaperNotVisible() {
|
||||
ColorExtractor.GradientColors fallbackColors = new ColorExtractor.GradientColors();
|
||||
fallbackColors.setMainColor(ColorExtractor.FALLBACK_COLOR);
|
||||
fallbackColors.setSecondaryColor(ColorExtractor.FALLBACK_COLOR);
|
||||
|
||||
SysuiColorExtractor extractor = new SysuiColorExtractor(getContext(), new Tonal(), false);
|
||||
simulateEvent(extractor);
|
||||
extractor.setWallpaperVisible(false);
|
||||
|
||||
ColorExtractor.GradientColors fallbackColors = extractor.getFallbackColors();
|
||||
|
||||
for (int which : sWhich) {
|
||||
for (int type : sTypes) {
|
||||
assertEquals("Not using fallback!", extractor.getColors(which, type),
|
||||
@@ -76,7 +74,6 @@ public class SysuiColorExtractorTests extends SysuiTestCase {
|
||||
outGradientColorsNormal.set(colors);
|
||||
outGradientColorsDark.set(colors);
|
||||
outGradientColorsExtraDark.set(colors);
|
||||
return true;
|
||||
}, false);
|
||||
simulateEvent(extractor);
|
||||
extractor.setWallpaperVisible(true);
|
||||
@@ -91,7 +88,7 @@ public class SysuiColorExtractorTests extends SysuiTestCase {
|
||||
|
||||
private void simulateEvent(SysuiColorExtractor extractor) {
|
||||
// Let's fake a color event
|
||||
extractor.onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK), null, null, 0),
|
||||
extractor.onColorsChanged(new WallpaperColors(Color.valueOf(Color.GREEN), null, null, 0),
|
||||
WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK);
|
||||
}
|
||||
}
|
||||
@@ -61,21 +61,6 @@ public class ColorExtractorTest {
|
||||
.extractInto(any(), any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getColors_usesFallbackIfFails() {
|
||||
ExtractionType alwaysFail =
|
||||
(inWallpaperColors, outGradientColorsNormal, outGradientColorsDark,
|
||||
outGradientColorsExtraDark) -> false;
|
||||
ColorExtractor extractor = new ColorExtractor(mContext, alwaysFail);
|
||||
GradientColors colors = extractor.getColors(WallpaperManager.FLAG_SYSTEM);
|
||||
|
||||
assertEquals("Should be using the fallback color.",
|
||||
colors.getMainColor(), ColorExtractor.FALLBACK_COLOR);
|
||||
assertEquals("Should be using the fallback color.",
|
||||
colors.getSecondaryColor(), ColorExtractor.FALLBACK_COLOR);
|
||||
assertFalse("Dark text support should be false.", colors.supportsDarkText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getColors_usesExtractedColors() {
|
||||
GradientColors colorsExpectedNormal = new GradientColors();
|
||||
@@ -96,8 +81,6 @@ public class ColorExtractorTest {
|
||||
outGradientColorsNormal.set(colorsExpectedNormal);
|
||||
outGradientColorsDark.set(colorsExpectedDark);
|
||||
outGradientColorsExtraDark.set(colorsExpectedExtraDark);
|
||||
// Successful extraction
|
||||
return true;
|
||||
};
|
||||
ColorExtractor extractor = new ColorExtractor(mContext, type);
|
||||
|
||||
|
||||
@@ -39,6 +39,31 @@ import java.util.Arrays;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class TonalTest {
|
||||
|
||||
@Test
|
||||
public void extractInto_usesFallback() {
|
||||
GradientColors normal = new GradientColors();
|
||||
Tonal tonal = new Tonal();
|
||||
tonal.extractInto(null, normal, new GradientColors(),
|
||||
new GradientColors());
|
||||
assertFalse("Should use fallback color if WallpaperColors is null.",
|
||||
normal.getMainColor() == Tonal.MAIN_COLOR_LIGHT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void extractInto_usesFallbackWhenTooLightOrDark() {
|
||||
GradientColors normal = new GradientColors();
|
||||
Tonal tonal = new Tonal();
|
||||
tonal.extractInto(new WallpaperColors(Color.valueOf(0xff000000), null, null, 0),
|
||||
normal, new GradientColors(), new GradientColors());
|
||||
assertTrue("Should use fallback color if WallpaperColors is too dark.",
|
||||
normal.getMainColor() == Tonal.MAIN_COLOR_DARK);
|
||||
|
||||
tonal.extractInto(new WallpaperColors(Color.valueOf(0xffffffff), null, null, 0),
|
||||
normal, new GradientColors(), new GradientColors());
|
||||
assertTrue("Should use fallback color if WallpaperColors is too light.",
|
||||
normal.getMainColor() == Tonal.MAIN_COLOR_LIGHT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void colorRange_containsColor() {
|
||||
Tonal.ColorRange colorRange = new Tonal.ColorRange(new Range<>(0f, 50f),
|
||||
@@ -72,8 +97,10 @@ public class TonalTest {
|
||||
|
||||
// Make sure that palette generation will fail
|
||||
Tonal tonal = new Tonal();
|
||||
boolean success = tonal.extractInto(colors, new GradientColors(), new GradientColors(),
|
||||
GradientColors normal = new GradientColors();
|
||||
tonal.extractInto(colors, normal, new GradientColors(),
|
||||
new GradientColors());
|
||||
assertFalse("Cannot generate a tonal palette from blacklisted colors ", success);
|
||||
assertFalse("Cannot generate a tonal palette from blacklisted colors.",
|
||||
normal.getMainColor() == Tonal.MAIN_COLOR_LIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user