Skip to content

Commit 6fd394a

Browse files
Jeff BrownAndroid (Google) Code Review
authored andcommitted
Merge "Improve auto-brightness hysteresis." into jb-mr1-dev
2 parents 8ed4822 + e941b1e commit 6fd394a

File tree

1 file changed

+124
-45
lines changed

1 file changed

+124
-45
lines changed

services/java/com/android/server/power/DisplayPowerController.java

Lines changed: 124 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -125,28 +125,34 @@ final class DisplayPowerController {
125125
// Trigger proximity if distance is less than 5 cm.
126126
private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
127127

128-
// Light sensor event rate in microseconds.
129-
private static final int LIGHT_SENSOR_RATE = 500 * 1000;
128+
// Light sensor event rate in milliseconds.
129+
private static final int LIGHT_SENSOR_RATE_MILLIS = 1000;
130+
131+
// A rate for generating synthetic light sensor events in the case where the light
132+
// sensor hasn't reported any new data in a while and we need it to update the
133+
// debounce filter. We only synthesize light sensor measurements when needed.
134+
private static final int SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS =
135+
LIGHT_SENSOR_RATE_MILLIS * 2;
130136

131137
// Brightness animation ramp rate in brightness units per second.
132138
private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
133-
private static final int BRIGHTNESS_RAMP_RATE_SLOW = 30;
139+
private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
134140

135141
// IIR filter time constants in milliseconds for computing two moving averages of
136142
// the light samples. One is a long-term average and the other is a short-term average.
137143
// We can use these filters to assess trends in ambient brightness.
138144
// The short term average gives us a filtered but relatively low latency measurement.
139145
// The long term average informs us about the overall trend.
140146
private static final long SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 1000;
141-
private static final long LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 8000;
147+
private static final long LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 5000;
142148

143149
// Stability requirements in milliseconds for accepting a new brightness
144150
// level. This is used for debouncing the light sensor. Different constants
145151
// are used to debounce the light sensor when adapting to brighter or darker environments.
146152
// This parameter controls how quickly brightness changes occur in response to
147-
// an observed change in light level following a previous change in the opposite direction.
148-
private static final long BRIGHTENING_LIGHT_DEBOUNCE = 5000;
149-
private static final long DARKENING_LIGHT_DEBOUNCE = 15000;
153+
// an observed change in light level that exceeds the hysteresis threshold.
154+
private static final long BRIGHTENING_LIGHT_DEBOUNCE = 4000;
155+
private static final long DARKENING_LIGHT_DEBOUNCE = 8000;
150156

151157
// Hysteresis constraints for brightening or darkening.
152158
// The recent lux must have changed by at least this fraction relative to the
@@ -290,10 +296,6 @@ final class DisplayPowerController {
290296
// True if mAmbientLux holds a valid value.
291297
private boolean mAmbientLuxValid;
292298

293-
// The time when the ambient lux was last brightened or darkened.
294-
private long mLastAmbientBrightenTime;
295-
private long mLastAmbientDarkenTime;
296-
297299
// The most recent light sample.
298300
private float mLastObservedLux;
299301

@@ -307,6 +309,15 @@ final class DisplayPowerController {
307309
private float mRecentShortTermAverageLux;
308310
private float mRecentLongTermAverageLux;
309311

312+
// The direction in which the average lux is moving relative to the current ambient lux.
313+
// 0 if not changing or within hysteresis threshold.
314+
// 1 if brightening beyond hysteresis threshold.
315+
// -1 if darkening beyond hysteresis threshold.
316+
private int mDebounceLuxDirection;
317+
318+
// The time when the average lux last changed direction.
319+
private long mDebounceLuxTime;
320+
310321
// The screen brightness level that has been chosen by the auto-brightness
311322
// algorithm. The actual brightness should ramp towards this value.
312323
// We preserve this value even when we stop using the light sensor so
@@ -547,6 +558,7 @@ private void updatePowerState() {
547558
final boolean mustNotify;
548559
boolean mustInitialize = false;
549560
boolean updateAutoBrightness = mTwilightChanged;
561+
boolean wasDim = false;
550562
mTwilightChanged = false;
551563

552564
synchronized (mLock) {
@@ -566,6 +578,7 @@ private void updatePowerState() {
566578
!= mPendingRequestLocked.screenAutoBrightnessAdjustment) {
567579
updateAutoBrightness = true;
568580
}
581+
wasDim = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM);
569582
mPowerRequest.copyFrom(mPendingRequestLocked);
570583
mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
571584
mPendingWaitForNegativeProximityLocked = false;
@@ -635,9 +648,12 @@ private void updatePowerState() {
635648
mUsingScreenAutoBrightness = false;
636649
}
637650
if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
638-
// Screen is dimmed. Sets an upper bound on everything else.
651+
// Dim slowly by at least some minimum amount.
639652
target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
640653
mScreenBrightnessDimConfig);
654+
slow = true;
655+
} else if (wasDim) {
656+
// Brighten quickly.
641657
slow = false;
642658
}
643659
animateScreenBrightness(clampScreenBrightness(target),
@@ -852,7 +868,7 @@ private void setLightSensorEnabled(boolean enable, boolean updateAutoBrightness)
852868
mLightSensorEnabled = true;
853869
mLightSensorEnableTime = SystemClock.uptimeMillis();
854870
mSensorManager.registerListener(mLightSensorListener, mLightSensor,
855-
LIGHT_SENSOR_RATE, mHandler);
871+
LIGHT_SENSOR_RATE_MILLIS * 1000, mHandler);
856872
}
857873
} else {
858874
if (mLightSensorEnabled) {
@@ -869,6 +885,13 @@ private void setLightSensorEnabled(boolean enable, boolean updateAutoBrightness)
869885
}
870886

871887
private void handleLightSensorEvent(long time, float lux) {
888+
mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
889+
890+
applyLightSensorMeasurement(time, lux);
891+
updateAmbientLux(time);
892+
}
893+
894+
private void applyLightSensorMeasurement(long time, float lux) {
872895
// Update our filters.
873896
mRecentLightSamples += 1;
874897
if (mRecentLightSamples == 1) {
@@ -885,45 +908,53 @@ private void handleLightSensorEvent(long time, float lux) {
885908
// Remember this sample value.
886909
mLastObservedLux = lux;
887910
mLastObservedLuxTime = time;
888-
889-
// Update the ambient lux level.
890-
mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
891-
updateAmbientLux(time);
892911
}
893912

894913
private void updateAmbientLux(long time) {
895914
// If the light sensor was just turned on then immediately update our initial
896915
// estimate of the current ambient light level.
897916
if (!mAmbientLuxValid
898917
|| (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) {
918+
mAmbientLux = mRecentShortTermAverageLux;
919+
mAmbientLuxValid = true;
920+
mDebounceLuxDirection = 0;
921+
mDebounceLuxTime = time;
899922
if (DEBUG) {
900-
Slog.d(TAG, "updateAmbientLux: Initializing, "
901-
+ "mAmbientLux=" + (mAmbientLuxValid ? mAmbientLux : -1)
923+
Slog.d(TAG, "updateAmbientLux: Initializing: "
902924
+ ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
903-
+ ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
925+
+ ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
926+
+ ", mAmbientLux=" + mAmbientLux);
904927
}
905-
mAmbientLux = mRecentShortTermAverageLux;
906-
mAmbientLuxValid = true;
907-
mLastAmbientBrightenTime = time;
908-
mLastAmbientDarkenTime = time;
909928
updateAutoBrightness(true);
910929
return;
911930
}
912931

913932
// Determine whether the ambient environment appears to be brightening.
914-
float minAmbientLux = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
915-
if (mRecentShortTermAverageLux > minAmbientLux
916-
&& mRecentLongTermAverageLux > minAmbientLux) {
917-
long debounceTime = mLastAmbientDarkenTime + BRIGHTENING_LIGHT_DEBOUNCE;
933+
float brighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
934+
if (mRecentShortTermAverageLux > brighteningLuxThreshold
935+
&& mRecentLongTermAverageLux > brighteningLuxThreshold) {
936+
if (mDebounceLuxDirection <= 0) {
937+
mDebounceLuxDirection = 1;
938+
mDebounceLuxTime = time;
939+
if (DEBUG) {
940+
Slog.d(TAG, "updateAmbientLux: Possibly brightened, waiting for "
941+
+ BRIGHTENING_LIGHT_DEBOUNCE + " ms: "
942+
+ "brighteningLuxThreshold=" + brighteningLuxThreshold
943+
+ ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
944+
+ ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
945+
+ ", mAmbientLux=" + mAmbientLux);
946+
}
947+
}
948+
long debounceTime = mDebounceLuxTime + BRIGHTENING_LIGHT_DEBOUNCE;
918949
if (time >= debounceTime) {
950+
mAmbientLux = mRecentShortTermAverageLux;
919951
if (DEBUG) {
920952
Slog.d(TAG, "updateAmbientLux: Brightened: "
921-
+ "mAmbientLux=" + mAmbientLux
953+
+ "brighteningLuxThreshold=" + brighteningLuxThreshold
922954
+ ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
923-
+ ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
955+
+ ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
956+
+ ", mAmbientLux=" + mAmbientLux);
924957
}
925-
mLastAmbientBrightenTime = time;
926-
mAmbientLux = mRecentShortTermAverageLux;
927958
updateAutoBrightness(true);
928959
} else {
929960
mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
@@ -932,28 +963,78 @@ private void updateAmbientLux(long time) {
932963
}
933964

934965
// Determine whether the ambient environment appears to be darkening.
935-
float maxAmbientLux = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
936-
if (mRecentShortTermAverageLux < maxAmbientLux
937-
&& mRecentLongTermAverageLux < maxAmbientLux) {
938-
long debounceTime = mLastAmbientBrightenTime + DARKENING_LIGHT_DEBOUNCE;
966+
float darkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
967+
if (mRecentShortTermAverageLux < darkeningLuxThreshold
968+
&& mRecentLongTermAverageLux < darkeningLuxThreshold) {
969+
if (mDebounceLuxDirection >= 0) {
970+
mDebounceLuxDirection = -1;
971+
mDebounceLuxTime = time;
972+
if (DEBUG) {
973+
Slog.d(TAG, "updateAmbientLux: Possibly darkened, waiting for "
974+
+ DARKENING_LIGHT_DEBOUNCE + " ms: "
975+
+ "darkeningLuxThreshold=" + darkeningLuxThreshold
976+
+ ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
977+
+ ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
978+
+ ", mAmbientLux=" + mAmbientLux);
979+
}
980+
}
981+
long debounceTime = mDebounceLuxTime + DARKENING_LIGHT_DEBOUNCE;
939982
if (time >= debounceTime) {
983+
// Be conservative about reducing the brightness, only reduce it a little bit
984+
// at a time to avoid having to bump it up again soon.
985+
mAmbientLux = Math.max(mRecentShortTermAverageLux, mRecentLongTermAverageLux);
940986
if (DEBUG) {
941987
Slog.d(TAG, "updateAmbientLux: Darkened: "
942-
+ "mAmbientLux=" + mAmbientLux
988+
+ "darkeningLuxThreshold=" + darkeningLuxThreshold
943989
+ ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
944-
+ ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
990+
+ ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
991+
+ ", mAmbientLux=" + mAmbientLux);
945992
}
946-
mLastAmbientDarkenTime = time;
947-
mAmbientLux = mRecentShortTermAverageLux;
948993
updateAutoBrightness(true);
949994
} else {
950995
mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
951996
}
997+
return;
998+
}
999+
1000+
// No change or change is within the hysteresis thresholds.
1001+
if (mDebounceLuxDirection != 0) {
1002+
mDebounceLuxDirection = 0;
1003+
mDebounceLuxTime = time;
1004+
if (DEBUG) {
1005+
Slog.d(TAG, "updateAmbientLux: Canceled debounce: "
1006+
+ "brighteningLuxThreshold=" + brighteningLuxThreshold
1007+
+ ", darkeningLuxThreshold=" + darkeningLuxThreshold
1008+
+ ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
1009+
+ ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
1010+
+ ", mAmbientLux=" + mAmbientLux);
1011+
}
1012+
}
1013+
1014+
// If the light level does not change, then the sensor may not report
1015+
// a new value. This can cause problems for the auto-brightness algorithm
1016+
// because the filters might not be updated. To work around it, we want to
1017+
// make sure to update the filters whenever the observed light level could
1018+
// possibly exceed one of the hysteresis thresholds.
1019+
if (mLastObservedLux > brighteningLuxThreshold
1020+
|| mLastObservedLux < darkeningLuxThreshold) {
1021+
mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED,
1022+
time + SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS);
9521023
}
9531024
}
9541025

9551026
private void debounceLightSensor() {
956-
updateAmbientLux(SystemClock.uptimeMillis());
1027+
if (mLightSensorEnabled) {
1028+
long time = SystemClock.uptimeMillis();
1029+
if (time >= mLastObservedLuxTime + SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS) {
1030+
if (DEBUG) {
1031+
Slog.d(TAG, "debounceLightSensor: Synthesizing light sensor measurement "
1032+
+ "after " + (time - mLastObservedLuxTime) + " ms.");
1033+
}
1034+
applyLightSensorMeasurement(time, mLastObservedLux);
1035+
}
1036+
updateAmbientLux(time);
1037+
}
9571038
}
9581039

9591040
private void updateAutoBrightness(boolean sendUpdate) {
@@ -1124,16 +1205,14 @@ private void dumpLocal(PrintWriter pw) {
11241205
+ TimeUtils.formatUptime(mLightSensorEnableTime));
11251206
pw.println(" mAmbientLux=" + mAmbientLux);
11261207
pw.println(" mAmbientLuxValid=" + mAmbientLuxValid);
1127-
pw.println(" mLastAmbientBrightenTime="
1128-
+ TimeUtils.formatUptime(mLastAmbientBrightenTime));
1129-
pw.println(" mLastAmbientDimTime="
1130-
+ TimeUtils.formatUptime(mLastAmbientDarkenTime));
11311208
pw.println(" mLastObservedLux=" + mLastObservedLux);
11321209
pw.println(" mLastObservedLuxTime="
11331210
+ TimeUtils.formatUptime(mLastObservedLuxTime));
11341211
pw.println(" mRecentLightSamples=" + mRecentLightSamples);
11351212
pw.println(" mRecentShortTermAverageLux=" + mRecentShortTermAverageLux);
11361213
pw.println(" mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
1214+
pw.println(" mDebounceLuxDirection=" + mDebounceLuxDirection);
1215+
pw.println(" mDebounceLuxTime=" + TimeUtils.formatUptime(mDebounceLuxTime));
11371216
pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
11381217
pw.println(" mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
11391218
pw.println(" mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);

0 commit comments

Comments
 (0)