Merge "Scrim opacity must satisfy GAR" into oc-dr1-dev am: f98facc3b8
am: 58d7a76e8d
Change-Id: Ie155db391504fc788036c2a9defae375b6a0b510
This commit is contained in:
@@ -105,6 +105,31 @@ public final class ColorUtils {
|
||||
return Math.max(luminance1, luminance2) / Math.min(luminance1, luminance2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the minimum alpha value which can be applied to {@code background} so that would
|
||||
* have a contrast value of at least {@code minContrastRatio} when alpha blended to
|
||||
* {@code foreground}.
|
||||
*
|
||||
* @param foreground the foreground color
|
||||
* @param background the background color, opacity will be ignored
|
||||
* @param minContrastRatio the minimum contrast ratio
|
||||
* @return the alpha value in the range 0-255, or -1 if no value could be calculated
|
||||
*/
|
||||
public static int calculateMinimumBackgroundAlpha(@ColorInt int foreground,
|
||||
@ColorInt int background, float minContrastRatio) {
|
||||
// Ignore initial alpha that the background might have since this is
|
||||
// what we're trying to calculate.
|
||||
background = setAlphaComponent(background, 255);
|
||||
final int leastContrastyColor = setAlphaComponent(foreground, 255);
|
||||
return binaryAlphaSearch(foreground, background, minContrastRatio, (fg, bg, alpha) -> {
|
||||
int testBackground = blendARGB(leastContrastyColor, bg, alpha/255f);
|
||||
// Float rounding might set this alpha to something other that 255,
|
||||
// raising an exception in calculateContrast.
|
||||
testBackground = setAlphaComponent(testBackground, 255);
|
||||
return calculateContrast(fg, testBackground);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the minimum alpha value which can be applied to {@code foreground} so that would
|
||||
* have a contrast value of at least {@code minContrastRatio} when compared to
|
||||
@@ -122,14 +147,33 @@ public final class ColorUtils {
|
||||
+ Integer.toHexString(background));
|
||||
}
|
||||
|
||||
ContrastCalculator contrastCalculator = (fg, bg, alpha) -> {
|
||||
int testForeground = setAlphaComponent(fg, alpha);
|
||||
return calculateContrast(testForeground, bg);
|
||||
};
|
||||
|
||||
// First lets check that a fully opaque foreground has sufficient contrast
|
||||
int testForeground = setAlphaComponent(foreground, 255);
|
||||
double testRatio = calculateContrast(testForeground, background);
|
||||
double testRatio = contrastCalculator.calculateContrast(foreground, background, 255);
|
||||
if (testRatio < minContrastRatio) {
|
||||
// Fully opaque foreground does not have sufficient contrast, return error
|
||||
return -1;
|
||||
}
|
||||
foreground = setAlphaComponent(foreground, 255);
|
||||
return binaryAlphaSearch(foreground, background, minContrastRatio, contrastCalculator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the alpha value using binary search based on a given contrast evaluation function
|
||||
* and target contrast that needs to be satisfied.
|
||||
*
|
||||
* @param foreground the foreground color
|
||||
* @param background the opaque background color
|
||||
* @param minContrastRatio the minimum contrast ratio
|
||||
* @param calculator function that calculates contrast
|
||||
* @return the alpha value in the range 0-255, or -1 if no value could be calculated
|
||||
*/
|
||||
private static int binaryAlphaSearch(@ColorInt int foreground, @ColorInt int background,
|
||||
float minContrastRatio, ContrastCalculator calculator) {
|
||||
// Binary search to find a value with the minimum value which provides sufficient contrast
|
||||
int numIterations = 0;
|
||||
int minAlpha = 0;
|
||||
@@ -139,9 +183,8 @@ public final class ColorUtils {
|
||||
(maxAlpha - minAlpha) > MIN_ALPHA_SEARCH_PRECISION) {
|
||||
final int testAlpha = (minAlpha + maxAlpha) / 2;
|
||||
|
||||
testForeground = setAlphaComponent(foreground, testAlpha);
|
||||
testRatio = calculateContrast(testForeground, background);
|
||||
|
||||
final double testRatio = calculator.calculateContrast(foreground, background,
|
||||
testAlpha);
|
||||
if (testRatio < minContrastRatio) {
|
||||
minAlpha = testAlpha;
|
||||
} else {
|
||||
@@ -615,4 +658,8 @@ public final class ColorUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
private interface ContrastCalculator {
|
||||
double calculateContrast(int foreground, int background, int alpha);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import android.view.animation.PathInterpolator;
|
||||
import com.android.internal.colorextraction.ColorExtractor;
|
||||
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
|
||||
import com.android.internal.colorextraction.ColorExtractor.OnColorsChangedListener;
|
||||
import com.android.internal.graphics.ColorUtils;
|
||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
@@ -88,6 +89,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
|
||||
private boolean mNeedsDrawableColorUpdate;
|
||||
|
||||
protected float mScrimBehindAlpha;
|
||||
protected float mScrimBehindAlphaResValue;
|
||||
protected float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
|
||||
protected float mScrimBehindAlphaUnlocking = SCRIM_BEHIND_ALPHA_UNLOCKING;
|
||||
|
||||
@@ -142,7 +144,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
|
||||
mUnlockMethodCache = UnlockMethodCache.getInstance(context);
|
||||
mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
|
||||
mLightBarController = lightBarController;
|
||||
mScrimBehindAlpha = context.getResources().getFloat(R.dimen.scrim_behind_alpha);
|
||||
mScrimBehindAlphaResValue = context.getResources().getFloat(R.dimen.scrim_behind_alpha);
|
||||
// Scrim alpha is initially set to the value on the resource but might be changed
|
||||
// to make sure that text on top of it is legible.
|
||||
mScrimBehindAlpha = mScrimBehindAlphaResValue;
|
||||
|
||||
mColorExtractor = Dependency.get(SysuiColorExtractor.class);
|
||||
mColorExtractor.addOnColorsChangedListener(this);
|
||||
@@ -342,20 +347,30 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
|
||||
}
|
||||
|
||||
protected void updateScrims() {
|
||||
// Make sure we have the right gradients
|
||||
// Make sure we have the right gradients and their opacities will satisfy GAR.
|
||||
if (mNeedsDrawableColorUpdate) {
|
||||
mNeedsDrawableColorUpdate = false;
|
||||
final GradientColors currentScrimColors;
|
||||
if (mKeyguardShowing) {
|
||||
// Always animate color changes if we're seeing the keyguard
|
||||
mScrimInFront.setColors(mLockColors, true /* animated */);
|
||||
mScrimBehind.setColors(mLockColors, true /* animated */);
|
||||
currentScrimColors = mLockColors;
|
||||
} else {
|
||||
// Only animate scrim color if the scrim view is actually visible
|
||||
boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0;
|
||||
boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0;
|
||||
mScrimInFront.setColors(mSystemColors, animateScrimInFront);
|
||||
mScrimBehind.setColors(mSystemColors, animateScrimBehind);
|
||||
currentScrimColors = mSystemColors;
|
||||
}
|
||||
|
||||
// Calculate minimum scrim opacity for white or black text.
|
||||
int textColor = currentScrimColors.supportsDarkText() ? Color.BLACK : Color.WHITE;
|
||||
int mainColor = currentScrimColors.getMainColor();
|
||||
float minOpacity = ColorUtils.calculateMinimumBackgroundAlpha(textColor, mainColor,
|
||||
4.5f /* minimumContrast */) / 255f;
|
||||
mScrimBehindAlpha = Math.max(mScrimBehindAlphaResValue, minOpacity);
|
||||
mLightBarController.setScrimColor(mScrimInFront.getColors());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 com.android.internal.graphics;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.support.test.filters.SmallTest;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@SmallTest
|
||||
public class ColorUtilsTest {
|
||||
|
||||
@Test
|
||||
public void calculateMinimumBackgroundAlpha_satisfiestContrast() {
|
||||
|
||||
int alpha = ColorUtils.calculateMinimumBackgroundAlpha(Color.WHITE, Color.BLACK, 4.5f);
|
||||
assertTrue("Alpha doesn't need to be 255 to satisfy contrast", alpha < 255);
|
||||
|
||||
int worstCase = ColorUtils.blendARGB(Color.WHITE, Color.BLACK, alpha/255f);
|
||||
worstCase = ColorUtils.setAlphaComponent(worstCase, 255);
|
||||
double contrast = ColorUtils.calculateContrast(Color.WHITE, worstCase);
|
||||
assertTrue("Blended color should satisfy contrast", contrast >= 4.5);
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user