Port lux and nit mappings from device config to display specific configs

Bug: 235345267
Test: atest DisplayDeviceConfigTest#testConfigValues
Change-Id: I857e32d1d5a50f4ac9b123c4dfe78bd300086d9b
This commit is contained in:
Rupesh Bansal
2022-08-22 10:30:27 +00:00
parent 6dae9d46b7
commit 716bd5ae8a
8 changed files with 300 additions and 56 deletions

View File

@@ -1562,8 +1562,7 @@
<bool name="config_enableIdleScreenBrightnessMode">false</bool>
<!-- Array of desired screen brightness in nits corresponding to the lux values
in the config_autoBrightnessLevels array. As with config_screenBrightnessMinimumNits and
config_screenBrightnessMaximumNits, the display brightness is defined as the measured
in the config_autoBrightnessLevels array. The display brightness is defined as the measured
brightness of an all-white image.
If this is defined then:
@@ -1584,7 +1583,7 @@
<array name="config_autoBrightnessDisplayValuesNitsIdle">
</array>
<!-- Array of output values for button backlight corresponding to the luX values
<!-- Array of output values for button backlight corresponding to the lux values
in the config_autoBrightnessLevels array. This array should have size one greater
than the size of the config_autoBrightnessLevels array.
The brightness values must be between 0 and 255 and be non-decreasing.

View File

@@ -116,10 +116,8 @@ public abstract class BrightnessMappingStrategy {
luxLevels = getLuxLevels(resources.getIntArray(
com.android.internal.R.array.config_autoBrightnessLevelsIdle));
} else {
brightnessLevelsNits = getFloatArray(resources.obtainTypedArray(
com.android.internal.R.array.config_autoBrightnessDisplayValuesNits));
luxLevels = getLuxLevels(resources.getIntArray(
com.android.internal.R.array.config_autoBrightnessLevels));
brightnessLevelsNits = displayDeviceConfig.getAutoBrightnessBrighteningLevelsNits();
luxLevels = displayDeviceConfig.getAutoBrightnessBrighteningLevelsLux();
}
// Display independent, mode independent values

View File

@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
import android.os.Environment;
@@ -149,12 +150,22 @@ import javax.xml.datatype.DatatypeConfigurationException;
* </quirks>
*
* <autoBrightness>
* <brighteningLightDebounceMillis>
* <brighteningLightDebounceMillis>
* 2000
* </brighteningLightDebounceMillis>
* </brighteningLightDebounceMillis>
* <darkeningLightDebounceMillis>
* 1000
* </darkeningLightDebounceMillis>
* <displayBrightnessMapping>
* <displayBrightnessPoint>
* <lux>50</lux>
* <nits>45</nits>
* </displayBrightnessPoint>
* <displayBrightnessPoint>
* <lux>80</lux>
* <nits>75</nits>
* </displayBrightnessPoint>
* </displayBrightnessMapping>
* </autoBrightness>
*
* <screenBrightnessRampFastDecrease>0.01</screenBrightnessRampFastDecrease>
@@ -268,6 +279,39 @@ public class DisplayDeviceConfig {
// for the corresponding values above
private float[] mBrightness;
/**
* Array of desired screen brightness in nits corresponding to the lux values
* in the mBrightnessLevelsLux array. The display brightness is defined as the
* measured brightness of an all-white image. The brightness values must be non-negative and
* non-decreasing. This must be overridden in platform specific overlays
*/
private float[] mBrightnessLevelsNits;
/**
* Array of light sensor lux values to define our levels for auto backlight
* brightness support.
* The N entries of this array define N + 1 control points as follows:
* (1-based arrays)
*
* Point 1: (0, value[1]): lux <= 0
* Point 2: (level[1], value[2]): 0 < lux <= level[1]
* Point 3: (level[2], value[3]): level[2] < lux <= level[3]
* ...
* Point N+1: (level[N], value[N+1]): level[N] < lux
*
* The control points must be strictly increasing. Each control point
* corresponds to an entry in the brightness backlight values arrays.
* For example, if lux == level[1] (first element of the levels array)
* then the brightness will be determined by value[2] (second element
* of the brightness values array).
*
* Spline interpolation is used to determine the auto-brightness
* backlight values for lux levels between these control points.
*
*/
private float[] mBrightnessLevelsLux;
private float mBacklightMinimum = Float.NaN;
private float mBacklightMaximum = Float.NaN;
private float mBrightnessDefault = Float.NaN;
@@ -661,6 +705,20 @@ public class DisplayDeviceConfig {
return mAutoBrightnessBrighteningLightDebounce;
}
/**
* @return Auto brightness brightening ambient lux levels
*/
public float[] getAutoBrightnessBrighteningLevelsLux() {
return mBrightnessLevelsLux;
}
/**
* @return Auto brightness brightening nits levels
*/
public float[] getAutoBrightnessBrighteningLevelsNits() {
return mBrightnessLevelsNits;
}
@Override
public String toString() {
return "DisplayDeviceConfig{"
@@ -703,6 +761,8 @@ public class DisplayDeviceConfig {
+ mAutoBrightnessBrighteningLightDebounce
+ ", mAutoBrightnessDarkeningLightDebounce= "
+ mAutoBrightnessDarkeningLightDebounce
+ ", mBrightnessLevelsLux= " + Arrays.toString(mBrightnessLevelsLux)
+ ", mBrightnessLevelsNits= " + Arrays.toString(mBrightnessLevelsNits)
+ "}";
}
@@ -779,6 +839,7 @@ public class DisplayDeviceConfig {
loadBrightnessRampsFromConfigXml();
loadAmbientLightSensorFromConfigXml();
setProxSensorUnspecified();
loadAutoBrightnessConfigsFromConfigXml();
mLoadedFrom = "<config.xml>";
}
@@ -991,6 +1052,7 @@ public class DisplayDeviceConfig {
private void loadAutoBrightnessConfigValues(DisplayConfiguration config) {
loadAutoBrightnessBrighteningLightDebounce(config.getAutoBrightness());
loadAutoBrightnessDarkeningLightDebounce(config.getAutoBrightness());
loadAutoBrightnessDisplayBrightnessMapping(config.getAutoBrightness());
}
/**
@@ -1023,6 +1085,33 @@ public class DisplayDeviceConfig {
}
}
/**
* Loads the auto-brightness display brightness mappings. Internally, this takes care of
* loading the value from the display config, and if not present, falls back to config.xml.
*/
private void loadAutoBrightnessDisplayBrightnessMapping(AutoBrightness autoBrightnessConfig) {
if (autoBrightnessConfig == null
|| autoBrightnessConfig.getDisplayBrightnessMapping() == null) {
mBrightnessLevelsNits = getFloatArray(mContext.getResources()
.obtainTypedArray(com.android.internal.R.array
.config_autoBrightnessDisplayValuesNits));
mBrightnessLevelsLux = getFloatArray(mContext.getResources()
.obtainTypedArray(com.android.internal.R.array
.config_autoBrightnessLevels));
} else {
final int size = autoBrightnessConfig.getDisplayBrightnessMapping()
.getDisplayBrightnessPoint().size();
mBrightnessLevelsNits = new float[size];
mBrightnessLevelsLux = new float[size];
for (int i = 0; i < size; i++) {
mBrightnessLevelsNits[i] = autoBrightnessConfig.getDisplayBrightnessMapping()
.getDisplayBrightnessPoint().get(i).getNits().floatValue();
mBrightnessLevelsLux[i] = autoBrightnessConfig.getDisplayBrightnessMapping()
.getDisplayBrightnessPoint().get(i).getLux().floatValue();
}
}
}
private void loadBrightnessMapFromConfigXml() {
// Use the config.xml mapping
final Resources res = mContext.getResources();
@@ -1248,6 +1337,10 @@ public class DisplayDeviceConfig {
com.android.internal.R.string.config_displayLightSensorType);
}
private void loadAutoBrightnessConfigsFromConfigXml() {
loadAutoBrightnessDisplayBrightnessMapping(null /*AutoBrightnessConfig*/);
}
private void loadAmbientLightSensorFromDdc(DisplayConfiguration config) {
final SensorDetails sensorDetails = config.getLightSensor();
if (sensorDetails != null) {
@@ -1390,6 +1483,22 @@ public class DisplayDeviceConfig {
}
}
/**
* Extracts a float array from the specified {@link TypedArray}.
*
* @param array The array to convert.
* @return the given array as a float array.
*/
public static float[] getFloatArray(TypedArray array) {
final int n = array.length();
float[] vals = new float[n];
for (int i = 0; i < n; i++) {
vals[i] = array.getFloat(i, PowerManager.BRIGHTNESS_OFF_FLOAT);
}
array.recycle();
return vals;
}
static class SensorData {
public String type;
public String name;

View File

@@ -1,33 +0,0 @@
<!--
Copyright (C) 2022 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.
-->
<xs:schema version="2.0"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="autoBrightness">
<xs:sequence>
<!-- Sets the debounce for autoBrightness brightening in millis-->
<xs:element name="brighteningLightDebounceMillis" type="xs:nonNegativeInteger"
minOccurs="0" maxOccurs="1">
<xs:annotation name="final"/>
</xs:element>
<!-- Sets the debounce for autoBrightness darkening in millis-->
<xs:element name="darkeningLightDebounceMillis" type="xs:nonNegativeInteger"
minOccurs="0" maxOccurs="1">
<xs:annotation name="final"/>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>

View File

@@ -23,7 +23,6 @@
<xs:schema version="2.0"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:include schemaLocation="autobrightness.xsd" />
<xs:element name="displayConfiguration">
<xs:complexType>
<xs:sequence>
@@ -343,4 +342,74 @@
<xs:annotation name="final"/>
</xs:element>
</xs:complexType>
<xs:complexType name="autoBrightness">
<xs:sequence>
<!-- Sets the debounce for autoBrightness brightening in millis-->
<xs:element name="brighteningLightDebounceMillis" type="xs:nonNegativeInteger"
minOccurs="0" maxOccurs="1">
<xs:annotation name="final"/>
</xs:element>
<!-- Sets the debounce for autoBrightness darkening in millis-->
<xs:element name="darkeningLightDebounceMillis" type="xs:nonNegativeInteger"
minOccurs="0" maxOccurs="1">
<xs:annotation name="final"/>
</xs:element>
<!-- Sets the brightness mapping of the desired screen brightness in nits to the
corresponding lux for the current display -->
<xs:element name="displayBrightnessMapping" type="displayBrightnessMapping"
minOccurs="0" maxOccurs="1">
<xs:annotation name="final"/>
</xs:element>
</xs:sequence>
</xs:complexType>
<!-- Represents the brightness mapping of the desired screen brightness in nits to the
corresponding lux for the current display -->
<xs:complexType name="displayBrightnessMapping">
<xs:sequence>
<!-- Sets the list of display brightness points, each representing the desired screen
brightness in nits to the corresponding lux for the current display
The N entries of this array define N + 1 control points as follows:
(1-based arrays)
Point 1: (0, nits[1]): currentLux <= 0
Point 2: (lux[1], nits[2]): 0 < currentLux <= lux[1]
Point 3: (lux[2], nits[3]): lux[2] < currentLux <= lux[3]
...
Point N+1: (lux[N], nits[N+1]): lux[N] < currentLux
The control points must be strictly increasing. Each control point
corresponds to an entry in the brightness backlight values arrays.
For example, if currentLux == lux[1] (first element of the levels array)
then the brightness will be determined by nits[2] (second element
of the brightness values array).
-->
<xs:element name="displayBrightnessPoint" type="displayBrightnessPoint"
minOccurs="1" maxOccurs="unbounded">
<xs:annotation name="final"/>
</xs:element>
</xs:sequence>
</xs:complexType>
<!-- Represents a point in the display brightness mapping, representing the lux level from the
light sensor to the desired screen brightness in nits at this level -->
<xs:complexType name="displayBrightnessPoint">
<xs:sequence>
<!-- The lux level from the light sensor. This must be a non-negative integer -->
<xs:element name="lux" type="xs:nonNegativeInteger"
minOccurs="1" maxOccurs="1">
<xs:annotation name="final"/>
</xs:element>
<!-- Desired screen brightness in nits corresponding to the suggested lux values.
The display brightness is defined as the measured brightness of an all-white image.
This must be a non-negative integer -->
<xs:element name="nits" type="xs:nonNegativeInteger"
minOccurs="1" maxOccurs="1">
<xs:annotation name="final"/>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>

View File

@@ -5,8 +5,10 @@ package com.android.server.display.config {
ctor public AutoBrightness();
method public final java.math.BigInteger getBrighteningLightDebounceMillis();
method public final java.math.BigInteger getDarkeningLightDebounceMillis();
method public final com.android.server.display.config.DisplayBrightnessMapping getDisplayBrightnessMapping();
method public final void setBrighteningLightDebounceMillis(java.math.BigInteger);
method public final void setDarkeningLightDebounceMillis(java.math.BigInteger);
method public final void setDisplayBrightnessMapping(com.android.server.display.config.DisplayBrightnessMapping);
}
public class BrightnessThresholds {
@@ -43,6 +45,19 @@ package com.android.server.display.config {
method public java.util.List<com.android.server.display.config.Density> getDensity();
}
public class DisplayBrightnessMapping {
ctor public DisplayBrightnessMapping();
method public final java.util.List<com.android.server.display.config.DisplayBrightnessPoint> getDisplayBrightnessPoint();
}
public class DisplayBrightnessPoint {
ctor public DisplayBrightnessPoint();
method public final java.math.BigInteger getLux();
method public final java.math.BigInteger getNits();
method public final void setLux(java.math.BigInteger);
method public final void setNits(java.math.BigInteger);
}
public class DisplayConfiguration {
ctor public DisplayConfiguration();
method @NonNull public final com.android.server.display.config.Thresholds getAmbientBrightnessChangeThresholds();

View File

@@ -149,6 +149,12 @@ public class LocalDisplayAdapterTest {
.thenReturn(mockArray);
when(mMockedResources.obtainTypedArray(R.array.config_roundedCornerBottomRadiusArray))
.thenReturn(mockArray);
when(mMockedResources.obtainTypedArray(
com.android.internal.R.array.config_autoBrightnessDisplayValuesNits))
.thenReturn(mockArray);
when(mMockedResources.obtainTypedArray(
com.android.internal.R.array.config_autoBrightnessLevels))
.thenReturn(mockArray);
}
@After

View File

@@ -19,16 +19,19 @@ package com.android.server.display;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -52,22 +55,16 @@ public final class DisplayDeviceConfigTest {
private Resources mResources;
@Before
public void setUp() throws IOException {
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mContext.getResources()).thenReturn(mResources);
mockDeviceConfigs();
try {
Path tempFile = Files.createTempFile("display_config", ".tmp");
Files.write(tempFile, getContent().getBytes(StandardCharsets.UTF_8));
mDisplayDeviceConfig = new DisplayDeviceConfig(mContext);
mDisplayDeviceConfig.initFromFile(tempFile.toFile());
} catch (IOException e) {
throw new IOException("Failed to setup the display device config.", e);
}
}
@Test
public void testConfigValues() {
public void testConfigValuesFromDisplayConfig() throws IOException {
setupDisplayDeviceConfigFromDisplayConfigFile();
assertEquals(mDisplayDeviceConfig.getAmbientHorizonLong(), 5000);
assertEquals(mDisplayDeviceConfig.getAmbientHorizonShort(), 50);
assertEquals(mDisplayDeviceConfig.getBrightnessRampDecreaseMaxMillis(), 3000);
@@ -88,10 +85,24 @@ public final class DisplayDeviceConfigTest {
assertEquals(mDisplayDeviceConfig.getScreenDarkeningMinThreshold(), 0.002, 0.000001f);
assertEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLightDebounce(), 2000);
assertEquals(mDisplayDeviceConfig.getAutoBrightnessDarkeningLightDebounce(), 1000);
assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(), new
float[]{50.0f, 80.0f}, 0.0f);
assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(), new
float[]{45.0f, 75.0f}, 0.0f);
// Todo(brup): Add asserts for BrightnessThrottlingData, DensityMapping,
// HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
// Also add test for the case where optional display configs are null
}
@Test
public void testConfigValuesFromDeviceConfig() {
setupDisplayDeviceConfigFromDeviceConfigFile();
assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(), new
float[]{0.0f, 110.0f, 500.0f}, 0.0f);
assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(), new
float[]{2.0f, 200.0f, 600.0f}, 0.0f);
// Todo(brup): Add asserts for BrightnessThrottlingData, DensityMapping,
// HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
}
private String getContent() {
@@ -114,6 +125,16 @@ public final class DisplayDeviceConfigTest {
+ "<autoBrightness>\n"
+ "<brighteningLightDebounceMillis>2000</brighteningLightDebounceMillis>\n"
+ "<darkeningLightDebounceMillis>1000</darkeningLightDebounceMillis>\n"
+ "<displayBrightnessMapping>\n"
+ "<displayBrightnessPoint>\n"
+ "<lux>50</lux>\n"
+ "<nits>45</nits>\n"
+ "</displayBrightnessPoint>\n"
+ "<displayBrightnessPoint>\n"
+ "<lux>80</lux>\n"
+ "<nits>75</nits>\n"
+ "</displayBrightnessPoint>\n"
+ "</displayBrightnessMapping>\n"
+ "</autoBrightness>\n"
+ "<highBrightnessMode enabled=\"true\">\n"
+ "<transitionPoint>0.62</transitionPoint>\n"
@@ -185,4 +206,64 @@ public final class DisplayDeviceConfigTest {
when(mResources.getFloat(com.android.internal.R.dimen
.config_screenBrightnessSettingMaximumFloat)).thenReturn(1.0f);
}
private void setupDisplayDeviceConfigFromDisplayConfigFile() throws IOException {
Path tempFile = Files.createTempFile("display_config", ".tmp");
Files.write(tempFile, getContent().getBytes(StandardCharsets.UTF_8));
mDisplayDeviceConfig = new DisplayDeviceConfig(mContext);
mDisplayDeviceConfig.initFromFile(tempFile.toFile());
}
private void setupDisplayDeviceConfigFromDeviceConfigFile() {
TypedArray screenBrightnessNits = createFloatTypedArray(new float[]{2.0f, 250.0f, 650.0f});
when(mResources.obtainTypedArray(
com.android.internal.R.array.config_screenBrightnessNits))
.thenReturn(screenBrightnessNits);
TypedArray screenBrightnessBacklight = createFloatTypedArray(new
float[]{0.0f, 120.0f, 255.0f});
when(mResources.obtainTypedArray(
com.android.internal.R.array.config_screenBrightnessBacklight))
.thenReturn(screenBrightnessBacklight);
when(mResources.getIntArray(com.android.internal.R.array
.config_screenBrightnessBacklight)).thenReturn(new int[]{0, 120, 255});
when(mResources.getIntArray(com.android.internal.R.array
.config_autoBrightnessLevels)).thenReturn(new int[]{30, 80});
when(mResources.getIntArray(com.android.internal.R.array
.config_autoBrightnessDisplayValuesNits)).thenReturn(new int[]{25, 55});
TypedArray screenBrightnessLevelNits = createFloatTypedArray(new
float[]{2.0f, 200.0f, 600.0f});
when(mResources.obtainTypedArray(
com.android.internal.R.array.config_autoBrightnessDisplayValuesNits))
.thenReturn(screenBrightnessLevelNits);
TypedArray screenBrightnessLevelLux = createFloatTypedArray(new
float[]{0.0f, 110.0f, 500.0f});
when(mResources.obtainTypedArray(
com.android.internal.R.array.config_autoBrightnessLevels))
.thenReturn(screenBrightnessLevelLux);
mDisplayDeviceConfig = DisplayDeviceConfig.create(mContext, true);
}
private TypedArray createFloatTypedArray(float[] vals) {
TypedArray mockArray = mock(TypedArray.class);
when(mockArray.length()).thenAnswer(invocation -> {
return vals.length;
});
when(mockArray.getFloat(anyInt(), anyFloat())).thenAnswer(invocation -> {
final float def = (float) invocation.getArguments()[1];
if (vals == null) {
return def;
}
int idx = (int) invocation.getArguments()[0];
if (idx >= 0 && idx < vals.length) {
return vals[idx];
} else {
return def;
}
});
return mockArray;
}
}