Loading core/res/res/values/config.xml +29 −2 Original line number Diff line number Diff line Loading @@ -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 Loading core/res/res/values/symbols.xml +3 −0 Original line number Diff line number Diff line Loading @@ -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" /> Loading services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java +65 −6 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ public class DisplayWhiteBalanceController implements private DisplayWhiteBalanceThrottler mThrottler; private final float mLowLightAmbientColorTemperature; private final float mHighLightAmbientColorTemperature; private float mAmbientColorTemperature; Loading @@ -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. Loading @@ -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). Loading @@ -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); Loading @@ -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; Loading @@ -158,8 +180,36 @@ 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; } } Loading Loading @@ -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); Loading @@ -273,6 +324,8 @@ public class DisplayWhiteBalanceController implements + mAmbientToDisplayColorTemperatureSpline); writer.println(" mLowLightAmbientBrightnessToBiasSpline=" + mLowLightAmbientBrightnessToBiasSpline); writer.println(" mHighLightAmbientBrightnessToBiasSpline=" + mHighLightAmbientBrightnessToBiasSpline); } @Override // AmbientSensor.AmbientBrightnessSensor.Callbacks Loading Loading @@ -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) { Loading services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java +11 −0 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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); Loading services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java +179 −15 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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 { Loading @@ -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()); Loading @@ -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 Loading Loading @@ -216,16 +232,27 @@ 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); Loading @@ -239,6 +266,135 @@ public final class AmbientLuxTest { 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); 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); } } 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, Loading @@ -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++) { Loading Loading
core/res/res/values/config.xml +29 −2 Original line number Diff line number Diff line Loading @@ -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 Loading
core/res/res/values/symbols.xml +3 −0 Original line number Diff line number Diff line Loading @@ -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" /> Loading
services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java +65 −6 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ public class DisplayWhiteBalanceController implements private DisplayWhiteBalanceThrottler mThrottler; private final float mLowLightAmbientColorTemperature; private final float mHighLightAmbientColorTemperature; private float mAmbientColorTemperature; Loading @@ -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. Loading @@ -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). Loading @@ -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); Loading @@ -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; Loading @@ -158,8 +180,36 @@ 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; } } Loading Loading @@ -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); Loading @@ -273,6 +324,8 @@ public class DisplayWhiteBalanceController implements + mAmbientToDisplayColorTemperatureSpline); writer.println(" mLowLightAmbientBrightnessToBiasSpline=" + mLowLightAmbientBrightnessToBiasSpline); writer.println(" mHighLightAmbientBrightnessToBiasSpline=" + mHighLightAmbientBrightnessToBiasSpline); } @Override // AmbientSensor.AmbientBrightnessSensor.Callbacks Loading Loading @@ -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) { Loading
services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java +11 −0 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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); Loading
services/tests/servicestests/src/com/android/server/display/whitebalance/AmbientLuxTest.java +179 −15 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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 { Loading @@ -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()); Loading @@ -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 Loading Loading @@ -216,16 +232,27 @@ 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); Loading @@ -239,6 +266,135 @@ public final class AmbientLuxTest { 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); 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); } } 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, Loading @@ -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++) { Loading