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:
parent
845a4035ae
commit
4bd24f36c5
@ -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) {
|
||||
|
@ -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) {
|
||||
|
80
tests/Internal/src/android/app/WallpaperColorsTest.java
Normal file
80
tests/Internal/src/android/app/WallpaperColorsTest.java
Normal 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);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user