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

Commit f71a0829 authored by Daniel Solomon's avatar Daniel Solomon Committed by android-build-merger
Browse files

Merge "Validate display white balance matrices" into qt-dev

am: 6ad38351

Change-Id: Ic31979721e1923343cc7dbe066653ff1597588f4
parents 2e09168d 6ad38351
Loading
Loading
Loading
Loading
+45 −3
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;

import java.io.PrintWriter;
import java.lang.System;

final class DisplayWhiteBalanceTintController extends TintController {

@@ -39,6 +40,7 @@ final class DisplayWhiteBalanceTintController extends TintController {
    private static final int NUM_VALUES_PER_PRIMARY = 3;
    // Four colors: red, green, blue, and white
    private static final int NUM_DISPLAY_PRIMARIES_VALS = 4 * NUM_VALUES_PER_PRIMARY;
    private static final int COLORSPACE_MATRIX_LENGTH = 9;

    private final Object mLock = new Object();
    @VisibleForTesting
@@ -46,14 +48,16 @@ final class DisplayWhiteBalanceTintController extends TintController {
    @VisibleForTesting
    int mTemperatureMax;
    private int mTemperatureDefault;
    private float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
    @VisibleForTesting
    float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
    @VisibleForTesting
    ColorSpace.Rgb mDisplayColorSpaceRGB;
    private float[] mChromaticAdaptationMatrix;
    @VisibleForTesting
    int mCurrentColorTemperature;
    private float[] mCurrentColorTemperatureXYZ;
    private boolean mSetUp = false;
    @VisibleForTesting
    boolean mSetUp = false;
    private float[] mMatrixDisplayWhiteBalance = new float[16];
    private Boolean mIsAvailable;

@@ -73,6 +77,16 @@ final class DisplayWhiteBalanceTintController extends TintController {
            }
        }

        // Make sure display color space is valid
        if (!isColorMatrixValid(displayColorSpaceRGB.getTransform())) {
            Slog.e(ColorDisplayService.TAG, "Invalid display color space RGB-to-XYZ transform");
            return;
        }
        if (!isColorMatrixValid(displayColorSpaceRGB.getInverseTransform())) {
            Slog.e(ColorDisplayService.TAG, "Invalid display color space XYZ-to-RGB transform");
            return;
        }

        final String[] nominalWhiteValues = res.getStringArray(
                R.array.config_displayWhiteBalanceDisplayNominalWhite);
        float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
@@ -157,11 +171,16 @@ final class DisplayWhiteBalanceTintController extends TintController {
            final float adaptedMaxG = result[1] + result[4] + result[7];
            final float adaptedMaxB = result[2] + result[5] + result[8];
            final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);

            Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
            for (int i = 0; i < result.length; i++) {
                result[i] /= denum;
                if (!isColorMatrixCoeffValid(result[i])) {
                    Slog.e(ColorDisplayService.TAG, "Invalid DWB color matrix");
                    return;
                }
            }

            Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
            java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
            java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
            java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
@@ -277,4 +296,27 @@ final class DisplayWhiteBalanceTintController extends TintController {

        return makeRgbColorSpaceFromXYZ(displayRedGreenBlueXYZ, displayWhiteXYZ);
    }

    private boolean isColorMatrixCoeffValid(float coeff) {
        if (Float.isNaN(coeff) || Float.isInfinite(coeff)) {
            return false;
        }

        return true;
    }

    private boolean isColorMatrixValid(float[] matrix) {
        if (matrix == null || matrix.length != COLORSPACE_MATRIX_LENGTH) {
            return false;
        }

        for (int i = 0; i < matrix.length; i++) {
            if (!isColorMatrixCoeffValid(matrix[i])) {
                return false;
            }
        }

        return true;
    }

}
+191 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.server.display.color;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;

import static com.google.common.truth.Truth.assertWithMessage;

import android.content.Context;
import android.content.res.Resources;
import android.os.Binder;
import android.os.IBinder;
import android.view.SurfaceControl;
import android.view.SurfaceControl.DisplayPrimaries;
import android.view.SurfaceControl.CieXyz;

import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

import com.android.internal.R;
import com.android.dx.mockito.inline.extended.ExtendedMockito;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;

@RunWith(AndroidJUnit4.class)
public class DisplayWhiteBalanceTintControllerTest {
    @Mock
    private Context mMockedContext;
    @Mock
    private Resources mMockedResources;

    private MockitoSession mSession;
    private Resources mResources;
    IBinder mDisplayToken;
    DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController;

    @Before
    public void setUp() {
        mSession = ExtendedMockito.mockitoSession()
                .initMocks(this)
                .mockStatic(SurfaceControl.class)
                .strictness(Strictness.LENIENT)
                .startMocking();

        mResources = InstrumentationRegistry.getContext().getResources();
        // These Resources are common to all tests.
        doReturn(mResources.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMin))
            .when(mMockedResources)
            .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMin);
        doReturn(mResources.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMax))
            .when(mMockedResources)
            .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMax);
        doReturn(mResources.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault))
            .when(mMockedResources)
            .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault);
        doReturn(mResources.getStringArray(R.array.config_displayWhiteBalanceDisplayNominalWhite))
            .when(mMockedResources)
            .getStringArray(R.array.config_displayWhiteBalanceDisplayNominalWhite);
        doReturn(mMockedResources).when(mMockedContext).getResources();

        mDisplayToken = new Binder();
        doReturn(mDisplayToken).when(() -> SurfaceControl.getInternalDisplayToken());
    }

    @After
    public void tearDown() throws Exception {
        if (mSession != null) {
            mSession.finishMocking();
        }
    }

    /**
     * Setup should succeed when SurfaceControl setup results in a valid color transform.
     */
    @Test
    public void displayWhiteBalance_setupWithSurfaceControl() {
        // Make SurfaceControl return sRGB primaries
        DisplayPrimaries displayPrimaries = new DisplayPrimaries();
        displayPrimaries.red = new CieXyz();
        displayPrimaries.red.X = 0.412315f;
        displayPrimaries.red.Y = 0.212600f;
        displayPrimaries.red.Z = 0.019327f;
        displayPrimaries.green = new CieXyz();
        displayPrimaries.green.X = 0.357600f;
        displayPrimaries.green.Y = 0.715200f;
        displayPrimaries.green.Z = 0.119200f;
        displayPrimaries.blue = new CieXyz();
        displayPrimaries.blue.X = 0.180500f;
        displayPrimaries.blue.Y = 0.072200f;
        displayPrimaries.blue.Z = 0.950633f;
        displayPrimaries.white = new CieXyz();
        displayPrimaries.white.X = 0.950456f;
        displayPrimaries.white.Y = 1.000000f;
        displayPrimaries.white.Z = 1.089058f;
        doReturn(displayPrimaries)
            .when(() -> SurfaceControl.getDisplayNativePrimaries(mDisplayToken));

        setUpTintController();
        assertWithMessage("Setup with valid SurfaceControl failed")
                .that(mDisplayWhiteBalanceTintController.mSetUp)
                .isTrue();
    }

    /**
     * Setup should fail when SurfaceControl setup results in an invalid color transform.
     */
    @Test
    public void displayWhiteBalance_setupWithInvalidSurfaceControlData() {
        // Make SurfaceControl return invalid display primaries
        DisplayPrimaries displayPrimaries = new DisplayPrimaries();
        displayPrimaries.red = new CieXyz();
        displayPrimaries.green = new CieXyz();
        displayPrimaries.blue = new CieXyz();
        displayPrimaries.white = new CieXyz();
        doReturn(displayPrimaries)
            .when(() -> SurfaceControl.getDisplayNativePrimaries(mDisplayToken));

        setUpTintController();
        assertWithMessage("Setup with invalid SurfaceControl succeeded")
                .that(mDisplayWhiteBalanceTintController.mSetUp)
                .isFalse();
    }

    /**
     * Setup should succeed when SurfaceControl setup fails and Resources result in a valid color
     * transform.
     */
    @Test
    public void displayWhiteBalance_setupWithResources() {
        // Use default (valid) Resources
        doReturn(mResources.getStringArray(R.array.config_displayWhiteBalanceDisplayPrimaries))
            .when(mMockedResources)
            .getStringArray(R.array.config_displayWhiteBalanceDisplayPrimaries);
        // Make SurfaceControl setup fail
        doReturn(null).when(() -> SurfaceControl.getDisplayNativePrimaries(mDisplayToken));

        setUpTintController();
        assertWithMessage("Setup with valid Resources failed")
                .that(mDisplayWhiteBalanceTintController.mSetUp)
                .isTrue();
    }

    /**
     * Setup should fail when SurfaceControl setup fails and Resources result in an invalid color
     * transform.
     */
    @Test
    public void displayWhiteBalance_setupWithInvalidResources() {
        // Use Resources with invalid color data
        doReturn(new String[] {
                "0", "0", "0", // Red X, Y, Z
                "0", "0", "0", // Green X, Y, Z
                "0", "0", "0", // Blue X, Y, Z
                "0", "0", "0", // White X, Y, Z
            })
            .when(mMockedResources)
            .getStringArray(R.array.config_displayWhiteBalanceDisplayPrimaries);
        // Make SurfaceControl setup fail
        doReturn(null).when(() -> SurfaceControl.getDisplayNativePrimaries(mDisplayToken));

        setUpTintController();
        assertWithMessage("Setup with invalid Resources succeeded")
                .that(mDisplayWhiteBalanceTintController.mSetUp)
                .isFalse();
    }

    private void setUpTintController() {
        mDisplayWhiteBalanceTintController = new DisplayWhiteBalanceTintController();
        mDisplayWhiteBalanceTintController.setUp(mMockedContext, true);
    }
}
+34 −0
Original line number Diff line number Diff line
@@ -18,6 +18,11 @@ package com.android.server.display.color;

import static com.google.common.truth.Truth.assertWithMessage;

import androidx.test.InstrumentationRegistry;

import java.lang.System;
import java.util.Arrays;

import org.junit.Before;
import org.junit.Test;

@@ -28,6 +33,8 @@ public class DisplayWhiteBalanceTintControllerTest {
    @Before
    public void setUp() {
        mDisplayWhiteBalanceTintController = new DisplayWhiteBalanceTintController();
        mDisplayWhiteBalanceTintController.setUp(InstrumentationRegistry.getContext(), true);
        mDisplayWhiteBalanceTintController.setActivated(true);
    }

    @Test
@@ -59,4 +66,31 @@ public class DisplayWhiteBalanceTintControllerTest {
                .isEqualTo(colorTemperature);
    }

    @Test
    public void displayWhiteBalance_setMatrixValidDwbCalculation() {
        float[] currentMatrix = mDisplayWhiteBalanceTintController.getMatrix();
        float[] oldMatrix = Arrays.copyOf(currentMatrix, currentMatrix.length);

        mDisplayWhiteBalanceTintController
                .setMatrix(mDisplayWhiteBalanceTintController.mCurrentColorTemperature + 1);
        assertWithMessage("DWB matrix did not change when setting a new temperature")
                .that(Arrays.equals(oldMatrix, currentMatrix))
                .isFalse();
    }

    @Test
    public void displayWhiteBalance_setMatrixInvalidDwbCalculation() {
        Arrays.fill(mDisplayWhiteBalanceTintController.mDisplayNominalWhiteXYZ, 0);
        mDisplayWhiteBalanceTintController
            .setMatrix(mDisplayWhiteBalanceTintController.mCurrentColorTemperature + 1);
        assertWithMessage("DWB matrix not set to identity after an invalid DWB calculation")
                .that(Arrays.equals(mDisplayWhiteBalanceTintController.getMatrix(),
                    new float[] {
                        1, 0, 0, 0,
                        0, 1, 0, 0,
                        0, 0, 1, 0,
                        0, 0, 0, 1
                    })
                ).isTrue();
    }
}