Add theme style flag to WallpaperColors

Theme colors should always be the same in sysui and launcher.
We're now sharing a hint HINT_SUPPORTS_DARK_THEME, to make sure
we're never out of sync.

Test: runtest -x tests/Internal/src/android/app/WallpaperColorsTest.java
Fixes: 63140091
Change-Id: Ibd196f540d77269df377804b0f4d4d0d20820067
This commit is contained in:
Lucas Dupin 2017-06-29 12:20:29 -07:00
parent 845a4035ae
commit 4bd24f36c5
3 changed files with 113 additions and 23 deletions

View File

@ -26,6 +26,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.Size;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.graphics.palette.Palette;
import com.android.internal.graphics.palette.VariationalKMeansQuantizer;
@ -50,6 +51,14 @@ public final class WallpaperColors implements Parcelable {
*/
public static final int HINT_SUPPORTS_DARK_TEXT = 0x1;
/**
* Specifies that dark theme is preferred over the current wallpaper for best presentation.
* <p>
* 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;
// Maximum size that a bitmap can have to keep our calculations sane
private static final int MAX_BITMAP_SIZE = 112;
@ -61,8 +70,10 @@ public final class WallpaperColors implements Parcelable {
// present in at least MIN_COLOR_OCCURRENCE of the image
private static final float MIN_COLOR_OCCURRENCE = 0.05f;
// Decides when dark theme is optimal for this wallpaper
private static final float DARK_THEME_MEAN_LUMINANCE = 0.25f;
// Minimum mean luminosity that an image needs to have to support dark text
private static final float BRIGHT_IMAGE_MEAN_LUMINANCE = 0.9f;
private static final float BRIGHT_IMAGE_MEAN_LUMINANCE = 0.75f;
// We also check if the image has dark pixels in it,
// to avoid bright images with some dark spots.
private static final float DARK_PIXEL_LUMINANCE = 0.45f;
@ -169,10 +180,7 @@ public final class WallpaperColors implements Parcelable {
}
}
int hints = 0;
if (calculateDarkTextSupport(bitmap)) {
hints |= HINT_SUPPORTS_DARK_TEXT;
}
int hints = calculateHints(bitmap);
return new WallpaperColors(primary, secondary, tertiary, hints);
}
@ -335,9 +343,9 @@ public final class WallpaperColors implements Parcelable {
* @param source What to read.
* @return Whether image supports dark text or not.
*/
private static boolean calculateDarkTextSupport(Bitmap source) {
private static int calculateHints(Bitmap source) {
if (source == null) {
return false;
return 0;
}
int[] pixels = new int[source.getWidth() * source.getHeight()];
@ -349,22 +357,29 @@ public final class WallpaperColors implements Parcelable {
// This bitmap was already resized to fit the maximum allowed area.
// Let's just loop through the pixels, no sweat!
float[] tmpHsl = new float[3];
for (int i = 0; i < pixels.length; i++) {
final float luminance = Color.luminance(pixels[i]);
ColorUtils.colorToHSL(pixels[i], tmpHsl);
final float luminance = tmpHsl[2];
final int alpha = Color.alpha(pixels[i]);
// Make sure we don't have a dark pixel mass that will
// make text illegible.
if (luminance < DARK_PIXEL_LUMINANCE && alpha != 0) {
darkPixels++;
if (darkPixels > maxDarkPixels) {
return false;
}
}
totalLuminance += luminance;
}
return totalLuminance / pixels.length > BRIGHT_IMAGE_MEAN_LUMINANCE;
int hints = 0;
double meanLuminance = totalLuminance / pixels.length;
if (meanLuminance > BRIGHT_IMAGE_MEAN_LUMINANCE && darkPixels < maxDarkPixels) {
hints |= HINT_SUPPORTS_DARK_TEXT;
}
if (meanLuminance < DARK_THEME_MEAN_LUMINANCE) {
hints |= HINT_SUPPORTS_DARK_THEME;
}
return hints;
}
private static Size calculateOptimalSize(int width, int height) {

View File

@ -4577,15 +4577,10 @@ public class StatusBar extends SystemUI implements DemoMode,
final boolean useDarkText = mColorExtractor.getColors(which, true /* ignoreVisibility */)
.supportsDarkText();
// And wallpaper defines if QS should be light or dark.
boolean useDarkTheme = false;
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;
}
WallpaperColors systemColors = mColorExtractor
.getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
final boolean useDarkTheme = systemColors != null
&& (systemColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;
// Enable/disable dark UI.
if (isUsingDarkTheme() != useDarkTheme) {

View File

@ -0,0 +1,80 @@
/*
* Copyright (C) 2017 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 android.app;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class WallpaperColorsTest {
@Test
public void supportsDarkTextOverrideTest() {
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",
(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",
(colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) == 0);
}
/**
* Sanity check to guarantee that white supports dark text and black doesn't
*/
@Test
public void colorHintsTest() {
Bitmap image = Bitmap.createBitmap(30, 30, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(image);
canvas.drawColor(Color.WHITE);
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);
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);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLACK);
canvas.drawColor(Color.WHITE);
canvas.drawRect(0, 0, 8, 8, paint);
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);
}
}