Merge "Interpolate high light white balance" into qt-r1-dev

This commit is contained in:
TreeHugger Robot
2019-06-26 20:57:25 +00:00
committed by Android (Google) Code Review
5 changed files with 287 additions and 23 deletions

View File

@@ -4045,10 +4045,37 @@
</array>
<!-- See DisplayWhiteBalanceController.
The ambient color temperature (in cct) to which we fall back when the ambient brightness
drops beneath a certain threshold. -->
The ambient color temperature (in cct) to which we interpolate towards using the
the look up table generated by config_displayWhiteBalanceLowLightAmbientBrightnesses
and config_displayWhiteBalanceLowLightAmbientBiases. -->
<item name="config_displayWhiteBalanceLowLightAmbientColorTemperature" format="float" type="dimen">6500.0</item>
<!-- See DisplayWhiteBalanceController.
A float array containing a list of ambient brightnesses, in Lux. This array,
together with config_displayWhiteBalanceHighLightAmbientBiases, is used to generate a
lookup table used in DisplayWhiteBalanceController. This lookup table is used to map
ambient brightness readings to a bias, where the bias is used to linearly interpolate
between ambient color temperature and
config_displayWhiteBalanceHighLightAmbientColorTemperature.
This table is optional. If used, this array must,
1) Contain at least two entries
2) Be the same length as config_displayWhiteBalanceHighLightAmbientBiases. -->
<array name ="config_displayWhiteBalanceHighLightAmbientBrightnesses">
</array>
<!-- See DisplayWhiteBalanceController.
An array containing a list of biases. See
config_displayWhiteBalanceHighLightAmbientBrightnesses for additional details.
This array must be in the range of [0.0, 1.0]. -->
<array name ="config_displayWhiteBalanceHighLightAmbientBiases">
</array>
<!-- See DisplayWhiteBalanceController.
The ambient color temperature (in cct) to which we interpolate towards using the
the look up table generated by config_displayWhiteBalanceHighLightAmbientBrightnesses
and config_displayWhiteBalanceHighLightAmbientBiases. -->
<item name="config_displayWhiteBalanceHighLightAmbientColorTemperature" format="float" type="dimen">8000.0</item>
<!-- See DisplayWhiteBalanceController.
A float array containing a list of ambient color temperatures, in Kelvin. This array,
together with config_displayWhiteBalanceDisplayColorTemperatures, is used to generate a

View File

@@ -3750,6 +3750,9 @@
<java-symbol type="array" name="config_displayWhiteBalanceLowLightAmbientBrightnesses" />
<java-symbol type="array" name="config_displayWhiteBalanceLowLightAmbientBiases" />
<java-symbol type="dimen" name="config_displayWhiteBalanceLowLightAmbientColorTemperature" />
<java-symbol type="array" name="config_displayWhiteBalanceHighLightAmbientBrightnesses" />
<java-symbol type="array" name="config_displayWhiteBalanceHighLightAmbientBiases" />
<java-symbol type="dimen" name="config_displayWhiteBalanceHighLightAmbientColorTemperature" />
<java-symbol type="array" name="config_displayWhiteBalanceAmbientColorTemperatures" />
<java-symbol type="array" name="config_displayWhiteBalanceDisplayColorTemperatures" />
<java-symbol type="drawable" name="ic_action_open" />

View File

@@ -64,6 +64,7 @@ public class DisplayWhiteBalanceController implements
private DisplayWhiteBalanceThrottler mThrottler;
private final float mLowLightAmbientColorTemperature;
private final float mHighLightAmbientColorTemperature;
private float mAmbientColorTemperature;
@@ -83,9 +84,17 @@ public class DisplayWhiteBalanceController implements
// A piecewise linear relationship between ambient and display color temperatures.
private Spline.LinearSpline mAmbientToDisplayColorTemperatureSpline;
// In very low or very high brightness conditions ambient EQ should to set to a default
// instead of using mAmbientToDisplayColorTemperatureSpline. However, setting ambient EQ
// based on thresholds can cause the display to rapidly change color temperature. To solve
// this, mLowLightAmbientBrightnessToBiasSpline and mHighLightAmbientBrightnessToBiasSpline
// are used to smoothly interpolate from ambient color temperature to the defaults.
// A piecewise linear relationship between low light brightness and low light bias.
private Spline.LinearSpline mLowLightAmbientBrightnessToBiasSpline;
// A piecewise linear relationship between high light brightness and high light bias.
private Spline.LinearSpline mHighLightAmbientBrightnessToBiasSpline;
/**
* @param brightnessSensor
* The sensor used to detect changes in the ambient brightness.
@@ -100,12 +109,22 @@ public class DisplayWhiteBalanceController implements
* @param throttler
* The throttler used to determine whether the new display color temperature should be
* updated or not.
* @param lowLightAmbientBrightnessThreshold
* The ambient brightness threshold beneath which we fall back to a fixed ambient color
* temperature.
* @param lowLightAmbientBrightnesses
* The ambient brightness used to map the ambient brightnesses to the biases used to
* interpolate to lowLightAmbientColorTemperature.
* @param lowLightAmbientBiases
* The biases used to map the ambient brightnesses to the biases used to interpolate to
* lowLightAmbientColorTemperature.
* @param lowLightAmbientColorTemperature
* The ambient color temperature to which we fall back when the ambient brightness drops
* beneath a certain threshold.
* The ambient color temperature to which we interpolate to based on the low light curve.
* @param highLightAmbientBrightnesses
* The ambient brightness used to map the ambient brightnesses to the biases used to
* interpolate to highLightAmbientColorTemperature.
* @param highLightAmbientBiases
* The biases used to map the ambient brightnesses to the biases used to interpolate to
* highLightAmbientColorTemperature.
* @param highLightAmbientColorTemperature
* The ambient color temperature to which we interpolate to based on the high light curve.
* @param ambientColorTemperatures
* The ambient color tempeartures used to map the ambient color temperature to the display
* color temperature (or null if no mapping is necessary).
@@ -128,6 +147,8 @@ public class DisplayWhiteBalanceController implements
@NonNull DisplayWhiteBalanceThrottler throttler,
float[] lowLightAmbientBrightnesses, float[] lowLightAmbientBiases,
float lowLightAmbientColorTemperature,
float[] highLightAmbientBrightnesses, float[] highLightAmbientBiases,
float highLightAmbientColorTemperature,
float[] ambientColorTemperatures, float[] displayColorTemperatures) {
validateArguments(brightnessSensor, brightnessFilter, colorTemperatureSensor,
colorTemperatureFilter, throttler);
@@ -140,6 +161,7 @@ public class DisplayWhiteBalanceController implements
mColorTemperatureFilter = colorTemperatureFilter;
mThrottler = throttler;
mLowLightAmbientColorTemperature = lowLightAmbientColorTemperature;
mHighLightAmbientColorTemperature = highLightAmbientColorTemperature;
mAmbientColorTemperature = -1.0f;
mPendingAmbientColorTemperature = -1.0f;
mLastAmbientColorTemperature = -1.0f;
@@ -158,11 +180,39 @@ public class DisplayWhiteBalanceController implements
mLowLightAmbientBrightnessToBiasSpline.interpolate(Float.POSITIVE_INFINITY)
!= 1.0f) {
Slog.d(TAG, "invalid low light ambient brightness to bias spline, "
+ "bias must begin at 0.0 and end at 1.0");
+ "bias must begin at 0.0 and end at 1.0.");
mLowLightAmbientBrightnessToBiasSpline = null;
}
}
try {
mHighLightAmbientBrightnessToBiasSpline = new Spline.LinearSpline(
highLightAmbientBrightnesses, highLightAmbientBiases);
} catch (Exception e) {
Slog.e(TAG, "failed to create high light ambient brightness to bias spline.", e);
mHighLightAmbientBrightnessToBiasSpline = null;
}
if (mHighLightAmbientBrightnessToBiasSpline != null) {
if (mHighLightAmbientBrightnessToBiasSpline.interpolate(0.0f) != 0.0f ||
mHighLightAmbientBrightnessToBiasSpline.interpolate(Float.POSITIVE_INFINITY)
!= 1.0f) {
Slog.d(TAG, "invalid high light ambient brightness to bias spline, "
+ "bias must begin at 0.0 and end at 1.0.");
mHighLightAmbientBrightnessToBiasSpline = null;
}
}
if (mLowLightAmbientBrightnessToBiasSpline != null &&
mHighLightAmbientBrightnessToBiasSpline != null) {
if (lowLightAmbientBrightnesses[lowLightAmbientBrightnesses.length - 1] >
highLightAmbientBrightnesses[0]) {
Slog.d(TAG, "invalid low light and high light ambient brightness to bias spline "
+ "combination, defined domains must not intersect.");
mLowLightAmbientBrightnessToBiasSpline = null;
mHighLightAmbientBrightnessToBiasSpline = null;
}
}
try {
mAmbientToDisplayColorTemperatureSpline = new Spline.LinearSpline(
ambientColorTemperatures, displayColorTemperatures);
@@ -264,6 +314,7 @@ public class DisplayWhiteBalanceController implements
mColorTemperatureFilter.dump(writer);
mThrottler.dump(writer);
writer.println(" mLowLightAmbientColorTemperature=" + mLowLightAmbientColorTemperature);
writer.println(" mHighLightAmbientColorTemperature=" + mHighLightAmbientColorTemperature);
writer.println(" mAmbientColorTemperature=" + mAmbientColorTemperature);
writer.println(" mPendingAmbientColorTemperature=" + mPendingAmbientColorTemperature);
writer.println(" mLastAmbientColorTemperature=" + mLastAmbientColorTemperature);
@@ -273,6 +324,8 @@ public class DisplayWhiteBalanceController implements
+ mAmbientToDisplayColorTemperatureSpline);
writer.println(" mLowLightAmbientBrightnessToBiasSpline="
+ mLowLightAmbientBrightnessToBiasSpline);
writer.println(" mHighLightAmbientBrightnessToBiasSpline="
+ mHighLightAmbientBrightnessToBiasSpline);
}
@Override // AmbientSensor.AmbientBrightnessSensor.Callbacks
@@ -309,6 +362,12 @@ public class DisplayWhiteBalanceController implements
bias * ambientColorTemperature + (1.0f - bias)
* mLowLightAmbientColorTemperature;
}
if (mHighLightAmbientBrightnessToBiasSpline != null) {
float bias = mHighLightAmbientBrightnessToBiasSpline.interpolate(ambientBrightness);
ambientColorTemperature =
(1.0f - bias) * ambientColorTemperature + bias
* mHighLightAmbientColorTemperature;
}
if (mAmbientColorTemperatureOverride != -1.0f) {
if (mLoggingEnabled) {

View File

@@ -72,6 +72,15 @@ public class DisplayWhiteBalanceFactory {
final float lowLightAmbientColorTemperature = getFloat(resources,
com.android.internal.R.dimen
.config_displayWhiteBalanceLowLightAmbientColorTemperature);
final float[] displayWhiteBalanceHighLightAmbientBrightnesses = getFloatArray(resources,
com.android.internal.R.array
.config_displayWhiteBalanceHighLightAmbientBrightnesses);
final float[] displayWhiteBalanceHighLightAmbientBiases = getFloatArray(resources,
com.android.internal.R.array
.config_displayWhiteBalanceHighLightAmbientBiases);
final float highLightAmbientColorTemperature = getFloat(resources,
com.android.internal.R.dimen
.config_displayWhiteBalanceHighLightAmbientColorTemperature);
final float[] ambientColorTemperatures = getFloatArray(resources,
com.android.internal.R.array.config_displayWhiteBalanceAmbientColorTemperatures);
final float[] displayColorTempeartures = getFloatArray(resources,
@@ -80,6 +89,8 @@ public class DisplayWhiteBalanceFactory {
brightnessSensor, brightnessFilter, colorTemperatureSensor, colorTemperatureFilter,
throttler, displayWhiteBalanceLowLightAmbientBrightnesses,
displayWhiteBalanceLowLightAmbientBiases, lowLightAmbientColorTemperature,
displayWhiteBalanceHighLightAmbientBrightnesses,
displayWhiteBalanceHighLightAmbientBiases, highLightAmbientColorTemperature,
ambientColorTemperatures, displayColorTempeartures);
brightnessSensor.setCallbacks(controller);
colorTemperatureSensor.setCallbacks(controller);

View File

@@ -23,7 +23,12 @@ import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.eq;
import org.mockito.stubbing.Answer;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
@@ -56,7 +61,8 @@ import java.util.List;
public final class AmbientLuxTest {
private static final int AMBIENT_COLOR_TYPE = 20705;
private static final String AMBIENT_COLOR_TYPE_STR = "colorSensoryDensoryDoc";
private static final float LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE = 5700;
private static final float LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE = 5432.1f;
private static final float HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE = 3456.7f;
private Handler mHandler = new Handler(Looper.getMainLooper());
private Sensor mLightSensor;
@@ -68,6 +74,8 @@ public final class AmbientLuxTest {
@Mock private TypedArray mBrightnesses;
@Mock private TypedArray mBiases;
@Mock private TypedArray mHighLightBrightnesses;
@Mock private TypedArray mHighLightBiases;
@Before
public void setUp() throws Exception {
@@ -89,9 +97,10 @@ public final class AmbientLuxTest {
when(mResourcesSpy.getInteger(
R.integer.config_displayWhiteBalanceIncreaseDebounce))
.thenReturn(0);
when(mResourcesSpy.getFloat(
R.dimen.config_displayWhiteBalanceLowLightAmbientColorTemperature))
.thenReturn(LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE);
mockResourcesFloat(R.dimen.config_displayWhiteBalanceLowLightAmbientColorTemperature,
LOW_LIGHT_AMBIENT_COLOR_TEMPERATURE);
mockResourcesFloat(R.dimen.config_displayWhiteBalanceHighLightAmbientColorTemperature,
HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE);
when(mResourcesSpy.obtainTypedArray(
R.array.config_displayWhiteBalanceAmbientColorTemperatures))
.thenReturn(createTypedArray());
@@ -105,6 +114,13 @@ public final class AmbientLuxTest {
when(mResourcesSpy.obtainTypedArray(
R.array.config_displayWhiteBalanceLowLightAmbientBiases))
.thenReturn(mBiases);
when(mResourcesSpy.obtainTypedArray(
R.array.config_displayWhiteBalanceHighLightAmbientBrightnesses))
.thenReturn(mHighLightBrightnesses);
when(mResourcesSpy.obtainTypedArray(
R.array.config_displayWhiteBalanceHighLightAmbientBiases))
.thenReturn(mHighLightBiases);
mockThrottler();
}
@Test
@@ -216,16 +232,119 @@ public final class AmbientLuxTest {
}
@Test
public void testSpline_InvalidBiases() throws Exception {
float[][] invalidBrightnesses =
{{10.0f, 1000.0f}, {10.0f, 1000.0f}, {10.0f, 1000.0f}, {10.0f, 1000.0f},
{10.0f, 1000.0f}, {-1.0f, 1.0f}, {-1.0f, 1.0f}};
float[][] invalidBiases =
{{0.0f, 2.0f}, {0.0f, 0.9f}, {0.1f, 1.0f}, {-0.1f, 1.0f},
{0.1f, 1.1f}, {0.0f, 1.0f}, {-2.0f, 1.0f}};
for (int i = 0; i < invalidBrightnesses.length; ++i) {
setBrightnesses(invalidBrightnesses[i][0], invalidBrightnesses[i][1]);
setBiases(invalidBiases[i][0], invalidBiases[i][1]);
public void testSpline_InvalidEndBias() throws Exception {
setBrightnesses(10.0f, 1000.0f);
setBiases(0.0f, 2.0f);
DisplayWhiteBalanceController controller =
DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
final float ambientColorTemperature = 8000.0f;
setEstimatedColorTemperature(controller, ambientColorTemperature);
controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
for (float luxOverride = 0.1f; luxOverride <= 10000; luxOverride *= 10) {
setEstimatedBrightnessAndUpdate(controller, luxOverride);
assertEquals(controller.mPendingAmbientColorTemperature,
ambientColorTemperature, 0.001);
}
}
@Test
public void testSpline_InvalidBeginBias() throws Exception {
setBrightnesses(10.0f, 1000.0f);
setBiases(0.1f, 1.0f);
DisplayWhiteBalanceController controller =
DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
final float ambientColorTemperature = 8000.0f;
setEstimatedColorTemperature(controller, ambientColorTemperature);
controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
for (float luxOverride = 0.1f; luxOverride <= 10000; luxOverride *= 10) {
setEstimatedBrightnessAndUpdate(controller, luxOverride);
assertEquals(controller.mPendingAmbientColorTemperature,
ambientColorTemperature, 0.001);
}
}
@Test
public void testSpline_OneSegmentHighLight() throws Exception {
final float lowerBrightness = 10.0f;
final float upperBrightness = 50.0f;
setHighLightBrightnesses(lowerBrightness, upperBrightness);
setHighLightBiases(0.0f, 1.0f);
DisplayWhiteBalanceController controller =
DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
final float ambientColorTemperature = 8000.0f;
setEstimatedColorTemperature(controller, ambientColorTemperature);
controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
for (float t = 0.0f; t <= 1.0f; t += 0.1f) {
setEstimatedBrightnessAndUpdate(controller,
mix(lowerBrightness, upperBrightness, t));
assertEquals(controller.mPendingAmbientColorTemperature,
mix(HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE, ambientColorTemperature, 1.0f - t),
0.001);
}
setEstimatedBrightnessAndUpdate(controller, upperBrightness + 1.0f);
assertEquals(controller.mPendingAmbientColorTemperature,
HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE, 0.001);
setEstimatedBrightnessAndUpdate(controller, 0.0f);
assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature, 0.001);
}
@Test
public void testSpline_TwoSegmentsHighLight() throws Exception {
final float brightness0 = 10.0f;
final float brightness1 = 50.0f;
final float brightness2 = 60.0f;
setHighLightBrightnesses(brightness0, brightness1, brightness2);
final float bias0 = 0.0f;
final float bias1 = 0.25f;
final float bias2 = 1.0f;
setHighLightBiases(bias0, bias1, bias2);
DisplayWhiteBalanceController controller =
DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
final float ambientColorTemperature = 6000.0f;
setEstimatedColorTemperature(controller, ambientColorTemperature);
controller.mBrightnessFilter = spy(controller.mBrightnessFilter);
for (float t = 0.0f; t <= 1.0f; t += 0.1f) {
float luxOverride = mix(brightness0, brightness1, t);
setEstimatedBrightnessAndUpdate(controller, luxOverride);
float bias = mix(bias0, bias1, t);
assertEquals(controller.mPendingAmbientColorTemperature,
mix(HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE, ambientColorTemperature, 1.0f - bias),
0.01);
}
for (float t = 0.0f; t <= 1.0f; t += 0.1f) {
float luxOverride = mix(brightness1, brightness2, t);
setEstimatedBrightnessAndUpdate(controller, luxOverride);
float bias = mix(bias1, bias2, t);
assertEquals(controller.mPendingAmbientColorTemperature,
mix(HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE, ambientColorTemperature, 1.0f - bias),
0.01);
}
setEstimatedBrightnessAndUpdate(controller, brightness2 + 1.0f);
assertEquals(controller.mPendingAmbientColorTemperature,
HIGH_LIGHT_AMBIENT_COLOR_TEMPERATURE, 0.001);
setEstimatedBrightnessAndUpdate(controller, 0.0f);
assertEquals(controller.mPendingAmbientColorTemperature, ambientColorTemperature, 0.001);
}
@Test
public void testSpline_InvalidCombinations() throws Exception {
setBrightnesses(100.0f, 200.0f);
setBiases(0.0f, 1.0f);
setHighLightBrightnesses(150.0f, 250.0f);
setHighLightBiases(0.0f, 1.0f);
DisplayWhiteBalanceController controller =
DisplayWhiteBalanceFactory.create(mHandler, mSensorManagerMock, mResourcesSpy);
@@ -238,7 +357,44 @@ public final class AmbientLuxTest {
assertEquals(controller.mPendingAmbientColorTemperature,
ambientColorTemperature, 0.001);
}
}
}
void mockThrottler() {
when(mResourcesSpy.getInteger(
R.integer.config_displayWhiteBalanceDecreaseDebounce)).thenReturn(0);
when(mResourcesSpy.getInteger(
R.integer.config_displayWhiteBalanceIncreaseDebounce)).thenReturn(0);
TypedArray base = mResourcesSpy.obtainTypedArray(
R.array.config_displayWhiteBalanceBaseThresholds);
TypedArray inc = mResourcesSpy.obtainTypedArray(
R.array.config_displayWhiteBalanceIncreaseThresholds);
TypedArray dec = mResourcesSpy.obtainTypedArray(
R.array.config_displayWhiteBalanceDecreaseThresholds);
base = spy(base);
inc = spy(inc);
dec = spy(dec);
when(mResourcesSpy.obtainTypedArray(
R.array.config_displayWhiteBalanceBaseThresholds)).thenReturn(base);
when(mResourcesSpy.obtainTypedArray(
R.array.config_displayWhiteBalanceIncreaseThresholds)).thenReturn(inc);
when(mResourcesSpy.obtainTypedArray(
R.array.config_displayWhiteBalanceDecreaseThresholds)).thenReturn(dec);
setFloatArrayResource(base, new float[]{0.0f});
setFloatArrayResource(inc, new float[]{0.0f});
setFloatArrayResource(dec, new float[]{0.0f});
}
private void mockResourcesFloat(int id, float floatValue) {
doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) {
TypedValue value = (TypedValue)invocation.getArgument(1);
value.type = TypedValue.TYPE_FLOAT;
value.data = Float.floatToIntBits(floatValue);
return null;
}
}).when(mResourcesSpy).getValue(
eq(id),
any(TypedValue.class), eq(true));
}
private void setEstimatedColorTemperature(DisplayWhiteBalanceController controller,
@@ -262,6 +418,14 @@ public final class AmbientLuxTest {
setFloatArrayResource(mBiases, vals);
}
private void setHighLightBrightnesses(float... vals) {
setFloatArrayResource(mHighLightBrightnesses, vals);
}
private void setHighLightBiases(float... vals) {
setFloatArrayResource(mHighLightBiases, vals);
}
private void setFloatArrayResource(TypedArray array, float[] vals) {
when(array.length()).thenReturn(vals.length);
for (int i = 0; i < vals.length; i++) {