Loading core/java/android/app/WallpaperColors.java +11 −5 Original line number Diff line number Diff line Loading @@ -49,7 +49,7 @@ public final class WallpaperColors implements Parcelable { * eg. A launcher may set its text color to black if this flag is specified. * @hide */ public static final int HINT_SUPPORTS_DARK_TEXT = 0x1; public static final int HINT_SUPPORTS_DARK_TEXT = 1 << 0; /** * Specifies that dark theme is preferred over the current wallpaper for best presentation. Loading @@ -57,7 +57,13 @@ public final class WallpaperColors implements Parcelable { * eg. A launcher may set its drawer color to black if this flag is specified. * @hide */ public static final int HINT_SUPPORTS_DARK_THEME = 0x2; public static final int HINT_SUPPORTS_DARK_THEME = 1 << 1; /** * Specifies that this object was generated by extracting colors from a bitmap. * @hide */ public static final int HINT_FROM_BITMAP = 1 << 2; // Maximum size that a bitmap can have to keep our calculations sane private static final int MAX_BITMAP_SIZE = 112; Loading Loading @@ -180,13 +186,13 @@ public final class WallpaperColors implements Parcelable { } } int hints = calculateHints(bitmap); int hints = calculateDarkHints(bitmap); if (shouldRecycle) { bitmap.recycle(); } return new WallpaperColors(primary, secondary, tertiary, hints); return new WallpaperColors(primary, secondary, tertiary, HINT_FROM_BITMAP | hints); } /** Loading Loading @@ -348,7 +354,7 @@ public final class WallpaperColors implements Parcelable { * @param source What to read. * @return Whether image supports dark text or not. */ private static int calculateHints(Bitmap source) { private static int calculateDarkHints(Bitmap source) { if (source == null) { return 0; } Loading core/java/com/android/internal/colorextraction/types/Tonal.java +13 −8 Original line number Diff line number Diff line Loading @@ -111,18 +111,19 @@ public class Tonal implements ExtractionType { final List<Color> mainColors = inWallpaperColors.getMainColors(); final int mainColorsSize = mainColors.size(); final boolean supportsDarkText = (inWallpaperColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0; final int hints = inWallpaperColors.getColorHints(); final boolean supportsDarkText = (hints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0; final boolean generatedFromBitmap = (hints & WallpaperColors.HINT_FROM_BITMAP) != 0; if (mainColorsSize == 0) { return false; } // Tonal is not really a sort, it takes a color from the extracted // palette and finds a best fit amongst a collection of pre-defined // palettes. The best fit is tweaked to be closer to the source color // and replaces the original palette // Get the most preeminent, non-blacklisted color. // Decide what's the best color to use. // We have 2 options: // • Just pick the primary color // • Filter out blacklisted colors. This is useful when palette is generated // automatically from a bitmap. Color bestColor = null; final float[] hsl = new float[3]; for (int i = 0; i < mainColorsSize; i++) { Loading @@ -132,7 +133,7 @@ public class Tonal implements ExtractionType { Color.blue(colorValue), hsl); // Stop when we find a color that meets our criteria if (!isBlacklisted(hsl)) { if (!generatedFromBitmap || !isBlacklisted(hsl)) { bestColor = color; break; } Loading @@ -143,6 +144,10 @@ public class Tonal implements ExtractionType { return false; } // Tonal is not really a sort, it takes a color from the extracted // palette and finds a best fit amongst a collection of pre-defined // palettes. The best fit is tweaked to be closer to the source color // and replaces the original palette. int colorValue = bestColor.toArgb(); ColorUtils.RGBToHSL(Color.red(colorValue), Color.green(colorValue), Color.blue(colorValue), hsl); Loading tests/Internal/src/android/app/WallpaperColorsTest.java +15 −7 Original line number Diff line number Diff line Loading @@ -36,12 +36,12 @@ public class WallpaperColorsTest { final Color color = Color.valueOf(Color.WHITE); // Default should not support dark text! WallpaperColors colors = new WallpaperColors(color, null, null, 0); Assert.assertTrue("Default behavior is not to support dark text", Assert.assertTrue("Default behavior is not to support dark text.", (colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) == 0); // Override it colors = new WallpaperColors(color, null, null, WallpaperColors.HINT_SUPPORTS_DARK_TEXT); Assert.assertFalse("Forcing dark text support doesn't work", Assert.assertFalse("Forcing dark text support doesn't work.", (colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) == 0); } Loading @@ -57,15 +57,18 @@ public class WallpaperColorsTest { int hints = WallpaperColors.fromBitmap(image).getColorHints(); boolean supportsDarkText = (hints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0; boolean supportsDarkTheme = (hints & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0; Assert.assertTrue("White surface should support dark text", supportsDarkText); Assert.assertFalse("White surface shouldn't support dark theme", supportsDarkTheme); boolean fromBitmap = (hints & WallpaperColors.HINT_FROM_BITMAP) != 0; Assert.assertTrue("White surface should support dark text.", supportsDarkText); Assert.assertFalse("White surface shouldn't support dark theme.", supportsDarkTheme); Assert.assertTrue("From bitmap should be true if object was created " + "using WallpaperColors#fromBitmap.", fromBitmap); canvas.drawColor(Color.BLACK); hints = WallpaperColors.fromBitmap(image).getColorHints(); supportsDarkText = (hints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0; supportsDarkTheme = (hints & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0; Assert.assertFalse("Black surface shouldn't support dark text", supportsDarkText); Assert.assertTrue("Black surface should support dark theme", supportsDarkTheme); Assert.assertFalse("Black surface shouldn't support dark text.", supportsDarkText); Assert.assertTrue("Black surface should support dark theme.", supportsDarkTheme); Paint paint = new Paint(); paint.setStyle(Paint.Style.FILL); Loading @@ -75,7 +78,12 @@ public class WallpaperColorsTest { supportsDarkText = (WallpaperColors.fromBitmap(image) .getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0; Assert.assertFalse("Light surface shouldn't support dark text " + "when it contains dark pixels", supportsDarkText); + "when it contains dark pixels.", supportsDarkText); WallpaperColors colors = new WallpaperColors(Color.valueOf(Color.GREEN), null, null); fromBitmap = (colors.getColorHints() & WallpaperColors.HINT_FROM_BITMAP) != 0; Assert.assertFalse("Object created from public constructor should not contain " + "HINT_FROM_BITMAP.", fromBitmap); } /** Loading tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java +26 −7 Original line number Diff line number Diff line Loading @@ -99,20 +99,39 @@ public class TonalTest { } @Test public void tonal_excludeBlacklistedColor() { public void tonal_blacklistTest() { // Make sure that palette generation will fail. Tonal tonal = new Tonal(InstrumentationRegistry.getContext()); final Tonal tonal = new Tonal(InstrumentationRegistry.getContext()); // Creating a WallpaperColors object that contains *only* blacklisted colors. float[] hsl = tonal.getBlacklistedColors().get(0).getCenter(); WallpaperColors colors = new WallpaperColors(Color.valueOf(ColorUtils.HSLToColor(hsl)), null, null, 0); final float[] hsl = tonal.getBlacklistedColors().get(0).getCenter(); final int blacklistedColor = ColorUtils.HSLToColor(hsl); WallpaperColors colorsFromBitmap = new WallpaperColors(Color.valueOf(blacklistedColor), null, null, WallpaperColors.HINT_FROM_BITMAP); // Make sure that palette generation will fail GradientColors normal = new GradientColors(); tonal.extractInto(colors, normal, new GradientColors(), final GradientColors normal = new GradientColors(); tonal.extractInto(colorsFromBitmap, normal, new GradientColors(), new GradientColors()); assertTrue("Cannot generate a tonal palette from blacklisted colors.", normal.getMainColor() == Tonal.MAIN_COLOR_DARK); } @Test public void tonal_ignoreBlacklistTest() { final Tonal tonal = new Tonal(InstrumentationRegistry.getContext()); // Creating a WallpaperColors object that contains *only* blacklisted colors. final float[] hsl = tonal.getBlacklistedColors().get(0).getCenter(); final int blacklistedColor = ColorUtils.HSLToColor(hsl); WallpaperColors colors = new WallpaperColors(Color.valueOf(blacklistedColor), null, null); // Blacklist should be ignored when HINT_FROM_BITMAP isn't present. final GradientColors normal = new GradientColors(); tonal.extractInto(colors, normal, new GradientColors(), new GradientColors()); assertTrue("Blacklist should never be used on WallpaperColors generated using " + "default constructor.", normal.getMainColor() == blacklistedColor); } } Loading
core/java/android/app/WallpaperColors.java +11 −5 Original line number Diff line number Diff line Loading @@ -49,7 +49,7 @@ public final class WallpaperColors implements Parcelable { * eg. A launcher may set its text color to black if this flag is specified. * @hide */ public static final int HINT_SUPPORTS_DARK_TEXT = 0x1; public static final int HINT_SUPPORTS_DARK_TEXT = 1 << 0; /** * Specifies that dark theme is preferred over the current wallpaper for best presentation. Loading @@ -57,7 +57,13 @@ public final class WallpaperColors implements Parcelable { * eg. A launcher may set its drawer color to black if this flag is specified. * @hide */ public static final int HINT_SUPPORTS_DARK_THEME = 0x2; public static final int HINT_SUPPORTS_DARK_THEME = 1 << 1; /** * Specifies that this object was generated by extracting colors from a bitmap. * @hide */ public static final int HINT_FROM_BITMAP = 1 << 2; // Maximum size that a bitmap can have to keep our calculations sane private static final int MAX_BITMAP_SIZE = 112; Loading Loading @@ -180,13 +186,13 @@ public final class WallpaperColors implements Parcelable { } } int hints = calculateHints(bitmap); int hints = calculateDarkHints(bitmap); if (shouldRecycle) { bitmap.recycle(); } return new WallpaperColors(primary, secondary, tertiary, hints); return new WallpaperColors(primary, secondary, tertiary, HINT_FROM_BITMAP | hints); } /** Loading Loading @@ -348,7 +354,7 @@ public final class WallpaperColors implements Parcelable { * @param source What to read. * @return Whether image supports dark text or not. */ private static int calculateHints(Bitmap source) { private static int calculateDarkHints(Bitmap source) { if (source == null) { return 0; } Loading
core/java/com/android/internal/colorextraction/types/Tonal.java +13 −8 Original line number Diff line number Diff line Loading @@ -111,18 +111,19 @@ public class Tonal implements ExtractionType { final List<Color> mainColors = inWallpaperColors.getMainColors(); final int mainColorsSize = mainColors.size(); final boolean supportsDarkText = (inWallpaperColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0; final int hints = inWallpaperColors.getColorHints(); final boolean supportsDarkText = (hints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0; final boolean generatedFromBitmap = (hints & WallpaperColors.HINT_FROM_BITMAP) != 0; if (mainColorsSize == 0) { return false; } // Tonal is not really a sort, it takes a color from the extracted // palette and finds a best fit amongst a collection of pre-defined // palettes. The best fit is tweaked to be closer to the source color // and replaces the original palette // Get the most preeminent, non-blacklisted color. // Decide what's the best color to use. // We have 2 options: // • Just pick the primary color // • Filter out blacklisted colors. This is useful when palette is generated // automatically from a bitmap. Color bestColor = null; final float[] hsl = new float[3]; for (int i = 0; i < mainColorsSize; i++) { Loading @@ -132,7 +133,7 @@ public class Tonal implements ExtractionType { Color.blue(colorValue), hsl); // Stop when we find a color that meets our criteria if (!isBlacklisted(hsl)) { if (!generatedFromBitmap || !isBlacklisted(hsl)) { bestColor = color; break; } Loading @@ -143,6 +144,10 @@ public class Tonal implements ExtractionType { return false; } // Tonal is not really a sort, it takes a color from the extracted // palette and finds a best fit amongst a collection of pre-defined // palettes. The best fit is tweaked to be closer to the source color // and replaces the original palette. int colorValue = bestColor.toArgb(); ColorUtils.RGBToHSL(Color.red(colorValue), Color.green(colorValue), Color.blue(colorValue), hsl); Loading
tests/Internal/src/android/app/WallpaperColorsTest.java +15 −7 Original line number Diff line number Diff line Loading @@ -36,12 +36,12 @@ public class WallpaperColorsTest { final Color color = Color.valueOf(Color.WHITE); // Default should not support dark text! WallpaperColors colors = new WallpaperColors(color, null, null, 0); Assert.assertTrue("Default behavior is not to support dark text", Assert.assertTrue("Default behavior is not to support dark text.", (colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) == 0); // Override it colors = new WallpaperColors(color, null, null, WallpaperColors.HINT_SUPPORTS_DARK_TEXT); Assert.assertFalse("Forcing dark text support doesn't work", Assert.assertFalse("Forcing dark text support doesn't work.", (colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) == 0); } Loading @@ -57,15 +57,18 @@ public class WallpaperColorsTest { int hints = WallpaperColors.fromBitmap(image).getColorHints(); boolean supportsDarkText = (hints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0; boolean supportsDarkTheme = (hints & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0; Assert.assertTrue("White surface should support dark text", supportsDarkText); Assert.assertFalse("White surface shouldn't support dark theme", supportsDarkTheme); boolean fromBitmap = (hints & WallpaperColors.HINT_FROM_BITMAP) != 0; Assert.assertTrue("White surface should support dark text.", supportsDarkText); Assert.assertFalse("White surface shouldn't support dark theme.", supportsDarkTheme); Assert.assertTrue("From bitmap should be true if object was created " + "using WallpaperColors#fromBitmap.", fromBitmap); canvas.drawColor(Color.BLACK); hints = WallpaperColors.fromBitmap(image).getColorHints(); supportsDarkText = (hints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0; supportsDarkTheme = (hints & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0; Assert.assertFalse("Black surface shouldn't support dark text", supportsDarkText); Assert.assertTrue("Black surface should support dark theme", supportsDarkTheme); Assert.assertFalse("Black surface shouldn't support dark text.", supportsDarkText); Assert.assertTrue("Black surface should support dark theme.", supportsDarkTheme); Paint paint = new Paint(); paint.setStyle(Paint.Style.FILL); Loading @@ -75,7 +78,12 @@ public class WallpaperColorsTest { supportsDarkText = (WallpaperColors.fromBitmap(image) .getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0; Assert.assertFalse("Light surface shouldn't support dark text " + "when it contains dark pixels", supportsDarkText); + "when it contains dark pixels.", supportsDarkText); WallpaperColors colors = new WallpaperColors(Color.valueOf(Color.GREEN), null, null); fromBitmap = (colors.getColorHints() & WallpaperColors.HINT_FROM_BITMAP) != 0; Assert.assertFalse("Object created from public constructor should not contain " + "HINT_FROM_BITMAP.", fromBitmap); } /** Loading
tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java +26 −7 Original line number Diff line number Diff line Loading @@ -99,20 +99,39 @@ public class TonalTest { } @Test public void tonal_excludeBlacklistedColor() { public void tonal_blacklistTest() { // Make sure that palette generation will fail. Tonal tonal = new Tonal(InstrumentationRegistry.getContext()); final Tonal tonal = new Tonal(InstrumentationRegistry.getContext()); // Creating a WallpaperColors object that contains *only* blacklisted colors. float[] hsl = tonal.getBlacklistedColors().get(0).getCenter(); WallpaperColors colors = new WallpaperColors(Color.valueOf(ColorUtils.HSLToColor(hsl)), null, null, 0); final float[] hsl = tonal.getBlacklistedColors().get(0).getCenter(); final int blacklistedColor = ColorUtils.HSLToColor(hsl); WallpaperColors colorsFromBitmap = new WallpaperColors(Color.valueOf(blacklistedColor), null, null, WallpaperColors.HINT_FROM_BITMAP); // Make sure that palette generation will fail GradientColors normal = new GradientColors(); tonal.extractInto(colors, normal, new GradientColors(), final GradientColors normal = new GradientColors(); tonal.extractInto(colorsFromBitmap, normal, new GradientColors(), new GradientColors()); assertTrue("Cannot generate a tonal palette from blacklisted colors.", normal.getMainColor() == Tonal.MAIN_COLOR_DARK); } @Test public void tonal_ignoreBlacklistTest() { final Tonal tonal = new Tonal(InstrumentationRegistry.getContext()); // Creating a WallpaperColors object that contains *only* blacklisted colors. final float[] hsl = tonal.getBlacklistedColors().get(0).getCenter(); final int blacklistedColor = ColorUtils.HSLToColor(hsl); WallpaperColors colors = new WallpaperColors(Color.valueOf(blacklistedColor), null, null); // Blacklist should be ignored when HINT_FROM_BITMAP isn't present. final GradientColors normal = new GradientColors(); tonal.extractInto(colors, normal, new GradientColors(), new GradientColors()); assertTrue("Blacklist should never be used on WallpaperColors generated using " + "default constructor.", normal.getMainColor() == blacklistedColor); } }