DO NOT MERGE: Add light sample filtering logic for devices with

ambient light sensors that can be regularly obstructed.

Bug: 36869173

Change-Id: Ie2a1399c149c87df657b265911a7bb8417a1b8b9
This commit is contained in:
Julius D'souza
2017-04-04 19:39:05 -07:00
parent a686345759
commit 5b8250964b
4 changed files with 89 additions and 7 deletions

View File

@@ -1079,6 +1079,27 @@
to reduce it to preserve the battery. Value of 100% means no scaling. -->
<fraction name="config_screenAutoBrightnessDozeScaleFactor">100%</fraction>
<!-- What percentage of possible ambient light sensor values below the current ambient lux
calculation count count as valid samples. If a new lux sample is below
(current ambient lux) * (threshold), the light sample is saved in a separate dark light
buffer. When enough samples have accumulated continuously based off of the current light
sensor rate and config_autoBrightnessDarkAmbientLightHorizon, the current ambient
lux and screen brightness are recalculated; otherwise, the dark light buffer is cleared.
This is useful for devices where the ambient light sensor can expect regular light
obstruction, e.g. if the sensor is under the screen and a finger moves directly over the
relevant area.
This should be used with config_autoBrightnessDarkAmbientLightHorizon set to greater
than 0 and set to a value less than 100% to be enabled. -->
<fraction name="config_autoBrightnessDarkHorizonThresholdFactor">100%</fraction>
<!-- The amount of time that the dark light buffer should hold samples for in milliseconds;
see the description of config_autoBrightnessDarkHorizonThresholdFactor for details. This
should be used with config_autoBrightnessDarkHorizonThresholdFactor.
Set this to 0 to disable this feature. -->
<integer name="config_autoBrightnessDarkAmbientLightHorizon">0</integer>
<!-- When the screen is turned on, the previous estimate of the ambient light level at the time
the screen was turned off is restored and is used to determine the initial screen
brightness.

View File

@@ -1736,8 +1736,10 @@
<java-symbol type="dimen" name="default_minimal_size_resizable_task" />
<java-symbol type="fraction" name="config_screenAutoBrightnessDozeScaleFactor" />
<java-symbol type="fraction" name="config_autoBrightnessAdjustmentMaxGamma" />
<java-symbol type="fraction" name="config_autoBrightnessDarkHorizonThresholdFactor" />
<java-symbol type="integer" name="config_autoBrightnessAmbientLightHorizon"/>
<java-symbol type="integer" name="config_autoBrightnessBrighteningLightDebounce"/>
<java-symbol type="integer" name="config_autoBrightnessDarkAmbientLightHorizon"/>
<java-symbol type="integer" name="config_autoBrightnessDarkeningLightDebounce"/>
<java-symbol type="integer" name="config_autoBrightnessInitialLightSensorRate"/>
<java-symbol type="integer" name="config_autoBrightnessLightSensorRate"/>

View File

@@ -35,11 +35,13 @@ import android.os.SystemClock;
import android.text.format.DateUtils;
import android.util.EventLog;
import android.util.MathUtils;
import android.util.Pair;
import android.util.Spline;
import android.util.Slog;
import android.util.TimeUtils;
import java.io.PrintWriter;
import java.util.ArrayDeque;
class AutomaticBrightnessController {
private static final String TAG = "AutomaticBrightnessController";
@@ -111,6 +113,9 @@ class AutomaticBrightnessController {
// Period of time in which to consider light samples in milliseconds.
private final int mAmbientLightHorizon;
// Period of time in which to consider light samples below the current ambient lux threshold.
private final int mDarkAmbientLightHorizon;
// The intercept used for the weighting calculation. This is used in order to keep all possible
// weighting values positive.
private final int mWeightingIntercept;
@@ -139,6 +144,10 @@ class AutomaticBrightnessController {
private float mBrighteningLuxThreshold;
private float mDarkeningLuxThreshold;
// The percentage of possible values below the current ambient lux which we put in the dark
// ambient light buffer.
private final float mDarkHorizonThresholdFactor;
// The most recent light sample.
private float mLastObservedLux;
@@ -148,6 +157,14 @@ class AutomaticBrightnessController {
// The number of light samples collected since the light sensor was enabled.
private int mRecentLightSamples;
// The number of light samples that will be held in the deque before being moved to the
// light ring buffer.
private int mDarkAmbientLightSampleSize;
// A deque containing the light sensor readings below the current ambient lux threshold
// when the display is not dozing.
private ArrayDeque<Pair<Long, Float>> mDarkAmbientLightDeque;
// A ring buffer containing all of the recent ambient light sensor readings.
private AmbientLightRingBuffer mAmbientLightRingBuffer;
@@ -203,7 +220,7 @@ class AutomaticBrightnessController {
long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
int ambientLightHorizon, float autoBrightnessAdjustmentMaxGamma,
boolean activeDozeLightSensor, boolean useNewSensorSamplesForDoze,
LuxLevels luxLevels) {
float darkHorizonThresholdFactor, int darkAmbientLightHorizon, LuxLevels luxLevels) {
mCallbacks = callbacks;
mTwilight = LocalServices.getService(TwilightManager.class);
mSensorManager = sensorManager;
@@ -223,6 +240,8 @@ class AutomaticBrightnessController {
mScreenAutoBrightnessAdjustmentMaxGamma = autoBrightnessAdjustmentMaxGamma;
mUseNewSensorSamplesForDoze = useNewSensorSamplesForDoze;
mUseActiveDozeLightSensorConfig = activeDozeLightSensor;
mDarkHorizonThresholdFactor = darkHorizonThresholdFactor;
mDarkAmbientLightHorizon = darkAmbientLightHorizon;
mLuxLevels = luxLevels;
mHandler = new AutomaticBrightnessHandler(looper);
@@ -231,6 +250,10 @@ class AutomaticBrightnessController {
mInitialHorizonAmbientLightRingBuffer =
new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
mDarkAmbientLightSampleSize =
(int) Math.ceil(darkAmbientLightHorizon / mNormalLightSensorRate);
mDarkAmbientLightDeque = new ArrayDeque<>();
if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
}
@@ -344,6 +367,7 @@ class AutomaticBrightnessController {
mCurrentLightSensorRate = -1;
mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
mSensorManager.unregisterListener(mLightSensorListener);
mDarkAmbientLightDeque.clear();
}
}
return false;
@@ -375,12 +399,41 @@ class AutomaticBrightnessController {
if (time <= mLightSensorEnableTime + mAmbientLightHorizon) {
mInitialHorizonAmbientLightRingBuffer.push(time, lux);
}
mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
mAmbientLightRingBuffer.push(time, lux);
// Remember this sample value.
mLastObservedLux = lux;
mLastObservedLuxTime = time;
// Only consider light samples for the dark light deque when not dozing.
// and once we've collected enough samples regularly.
if (mDarkAmbientLightHorizon > 0
&& !mDozing
&& mRecentLightSamples >= mDarkAmbientLightSampleSize
&& mAmbientLux * mDarkHorizonThresholdFactor >= lux) {
mDarkAmbientLightDeque.addLast(new Pair(time, lux));
if (DEBUG) {
Slog.d(TAG, "applyLightSensorMeasurement: light sample filtered to deque: "
+ mDarkAmbientLightDeque.size() + " / " + mDarkAmbientLightSampleSize);
}
if (mDarkAmbientLightSampleSize <= mDarkAmbientLightDeque.size()) {
if (DEBUG) {
Slog.d(TAG, "applyLightSensorMeasurement: moving filtered samples from the "
+ "deque to the light ring buffer.");
}
for (Pair<Long, Float> lightSample : mDarkAmbientLightDeque) {
mAmbientLightRingBuffer.push(lightSample.first, lightSample.second);
}
mDarkAmbientLightDeque.clear();
mLastObservedLux = lux;
mLastObservedLuxTime = time;
updateAmbientLux();
}
} else {
mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
mAmbientLightRingBuffer.push(time, lux);
mDarkAmbientLightDeque.clear();
// Remember this sample value.
mLastObservedLux = lux;
mLastObservedLuxTime = time;
}
}
private void adjustLightSensorRate(int lightSensorRate) {

View File

@@ -363,6 +363,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
final float dozeScaleFactor = resources.getFraction(
com.android.internal.R.fraction.config_screenAutoBrightnessDozeScaleFactor,
1, 1);
final float darkHorizonThresholdFactor = resources.getFraction(
com.android.internal.R.fraction.config_autoBrightnessDarkHorizonThresholdFactor,
1, 1);
final int darkAmbientLightHorizon = resources.getInteger(
com.android.internal.R.integer.config_autoBrightnessDarkAmbientLightHorizon);
// hysteresis configs
int[] brightHysteresisLevels = resources.getIntArray(
@@ -410,7 +415,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
autoBrightnessResetAmbientLuxAfterWarmUp, ambientLightHorizon,
autoBrightnessAdjustmentMaxGamma, mUseActiveDozeLightSensorConfig,
useNewSensorSamplesForDoze, luxLevels);
useNewSensorSamplesForDoze, darkHorizonThresholdFactor,
darkAmbientLightHorizon, luxLevels);
}
}