Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 835f5e41 authored by Lucas Dupin's avatar Lucas Dupin Committed by android-build-merger
Browse files

Merge "Scrim opacity must satisfy GAR" into oc-dr1-dev

am: f98facc3

Change-Id: I4c4eb814d8ea2152644665daf6fbd6eb28d81b06
parents e244efd6 f98facc3
Loading
Loading
Loading
Loading
+52 −5
Original line number Diff line number Diff line
@@ -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);
    }

}
 No newline at end of file
+17 −2
Original line number Diff line number Diff line
@@ -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());
        }

+41 −0
Original line number Diff line number Diff line
/*
 * 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);

    }
}