Skip to content

Commit fee1a21

Browse files
Jeff BrownAndroid Git Automerger
authored andcommitted
am 1d2b445: Merge "Reduce auto-brightness jitter." into jb-mr1-dev
* commit '1d2b445d7431420b7cfbd9ef3fe4e326e121eeae': Reduce auto-brightness jitter.
2 parents 93b1787 + 1d2b445 commit fee1a21

File tree

2 files changed

+131
-141
lines changed

2 files changed

+131
-141
lines changed

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

Lines changed: 120 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -128,28 +128,33 @@ final class DisplayPowerController {
128128
private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
129129

130130
// Light sensor event rate in microseconds.
131-
private static final int LIGHT_SENSOR_RATE = 1000000;
131+
private static final int LIGHT_SENSOR_RATE = 500 * 1000;
132132

133133
// Brightness animation ramp rate in brightness units per second.
134134
private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
135-
private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
135+
private static final int BRIGHTNESS_RAMP_RATE_SLOW = 30;
136136

137-
// Filter time constant in milliseconds for computing a moving
138-
// average of light samples. Different constants are used
139-
// to calculate the average light level when adapting to brighter or
140-
// dimmer environments.
141-
// This parameter only controls the filtering of light samples.
142-
private static final long BRIGHTENING_LIGHT_TIME_CONSTANT = 600;
143-
private static final long DIMMING_LIGHT_TIME_CONSTANT = 4000;
137+
// IIR filter time constants in milliseconds for computing two moving averages of
138+
// the light samples. One is a long-term average and the other is a short-term average.
139+
// We can use these filters to assess trends in ambient brightness.
140+
// The short term average gives us a filtered but relatively low latency measurement.
141+
// The long term average informs us about the overall trend.
142+
private static final long SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 1000;
143+
private static final long LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 8000;
144144

145145
// Stability requirements in milliseconds for accepting a new brightness
146146
// level. This is used for debouncing the light sensor. Different constants
147-
// are used to debounce the light sensor when adapting to brighter or dimmer
148-
// environments.
147+
// are used to debounce the light sensor when adapting to brighter or darker environments.
149148
// This parameter controls how quickly brightness changes occur in response to
150-
// an observed change in light level.
151-
private static final long BRIGHTENING_LIGHT_DEBOUNCE = 2500;
152-
private static final long DIMMING_LIGHT_DEBOUNCE = 10000;
149+
// an observed change in light level following a previous change in the opposite direction.
150+
private static final long BRIGHTENING_LIGHT_DEBOUNCE = 5000;
151+
private static final long DARKENING_LIGHT_DEBOUNCE = 15000;
152+
153+
// Hysteresis constraints for brightening or darkening.
154+
// The recent lux must have changed by at least this fraction relative to the
155+
// current ambient lux before a change will be considered.
156+
private static final float BRIGHTENING_LIGHT_HYSTERESIS = 0.10f;
157+
private static final float DARKENING_LIGHT_HYSTERESIS = 0.20f;
153158

154159
private final Object mLock = new Object();
155160

@@ -284,39 +289,28 @@ final class DisplayPowerController {
284289
// The time when the light sensor was enabled.
285290
private long mLightSensorEnableTime;
286291

287-
// The currently accepted average light sensor value.
288-
private float mLightMeasurement;
289-
290-
// True if the light sensor measurement is valid.
291-
private boolean mLightMeasurementValid;
292-
293-
// The number of light sensor samples that have been collected since the
294-
// last time a light sensor reading was accepted.
295-
private int mRecentLightSamples;
296-
297-
// The moving average of recent light sensor values.
298-
private float mRecentLightAverage;
292+
// The currently accepted nominal ambient light level.
293+
private float mAmbientLux;
299294

300-
// True if recent light samples are getting brighter than the previous
301-
// stable light measurement.
302-
private boolean mRecentLightBrightening;
295+
// True if mAmbientLux holds a valid value.
296+
private boolean mAmbientLuxValid;
303297

304-
// The time constant to use for filtering based on whether the
305-
// light appears to be brightening or dimming.
306-
private long mRecentLightTimeConstant;
298+
// The time when the ambient lux was last brightened or darkened.
299+
private long mLastAmbientBrightenTime;
300+
private long mLastAmbientDarkenTime;
307301

308302
// The most recent light sample.
309-
private float mLastLightSample;
303+
private float mLastObservedLux;
310304

311305
// The time of the most light recent sample.
312-
private long mLastLightSampleTime;
306+
private long mLastObservedLuxTime;
313307

314-
// The time when we accumulated the first recent light sample into mRecentLightSamples.
315-
private long mFirstRecentLightSampleTime;
308+
// The number of light samples collected since the light sensor was enabled.
309+
private int mRecentLightSamples;
316310

317-
// The upcoming debounce light sensor time.
318-
// This is only valid when mLightMeasurementValue && mRecentLightSamples >= 1.
319-
private long mPendingLightSensorDebounceTime;
311+
// The long-term and short-term filtered light measurements.
312+
private float mRecentShortTermAverageLux;
313+
private float mRecentLongTermAverageLux;
320314

321315
// The screen brightness level that has been chosen by the auto-brightness
322316
// algorithm. The actual brightness should ramp towards this value.
@@ -873,7 +867,8 @@ private void setLightSensorEnabled(boolean enable, boolean updateAutoBrightness)
873867
} else {
874868
if (mLightSensorEnabled) {
875869
mLightSensorEnabled = false;
876-
mLightMeasurementValid = false;
870+
mAmbientLuxValid = false;
871+
mRecentLightSamples = 0;
877872
mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
878873
mSensorManager.unregisterListener(mLightSensorListener);
879874
}
@@ -884,114 +879,99 @@ private void setLightSensorEnabled(boolean enable, boolean updateAutoBrightness)
884879
}
885880

886881
private void handleLightSensorEvent(long time, float lux) {
887-
// Take the first few readings during the warm-up period and apply them
888-
// immediately without debouncing.
889-
if (!mLightMeasurementValid
890-
|| (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) {
891-
mLightMeasurement = lux;
892-
mLightMeasurementValid = true;
893-
mRecentLightSamples = 0;
894-
updateAutoBrightness(true);
882+
// Update our filters.
883+
mRecentLightSamples += 1;
884+
if (mRecentLightSamples == 1) {
885+
mRecentShortTermAverageLux = lux;
886+
mRecentLongTermAverageLux = lux;
887+
} else {
888+
final long timeDelta = time - mLastObservedLuxTime;
889+
mRecentShortTermAverageLux += (lux - mRecentShortTermAverageLux)
890+
* timeDelta / (SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
891+
mRecentLongTermAverageLux += (lux - mRecentLongTermAverageLux)
892+
* timeDelta / (LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
895893
}
896894

897-
// Update our moving average.
898-
if (lux != mLightMeasurement && (mRecentLightSamples == 0
899-
|| (lux < mLightMeasurement && mRecentLightBrightening)
900-
|| (lux > mLightMeasurement && !mRecentLightBrightening))) {
901-
// If the newest light sample doesn't seem to be going in the
902-
// same general direction as recent samples, then start over.
903-
setRecentLight(time, lux, lux > mLightMeasurement);
904-
} else if (mRecentLightSamples >= 1) {
905-
// Add the newest light sample to the moving average.
906-
accumulateRecentLight(time, lux);
907-
}
908-
if (DEBUG) {
909-
Slog.d(TAG, "handleLightSensorEvent: lux=" + lux
910-
+ ", mLightMeasurementValid=" + mLightMeasurementValid
911-
+ ", mLightMeasurement=" + mLightMeasurement
912-
+ ", mRecentLightSamples=" + mRecentLightSamples
913-
+ ", mRecentLightAverage=" + mRecentLightAverage
914-
+ ", mRecentLightBrightening=" + mRecentLightBrightening
915-
+ ", mRecentLightTimeConstant=" + mRecentLightTimeConstant
916-
+ ", mFirstRecentLightSampleTime="
917-
+ TimeUtils.formatUptime(mFirstRecentLightSampleTime)
918-
+ ", mPendingLightSensorDebounceTime="
919-
+ TimeUtils.formatUptime(mPendingLightSensorDebounceTime));
920-
}
895+
// Remember this sample value.
896+
mLastObservedLux = lux;
897+
mLastObservedLuxTime = time;
921898

922-
// Debounce.
899+
// Update the ambient lux level.
923900
mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
924-
debounceLightSensor();
925-
}
926-
927-
private void setRecentLight(long time, float lux, boolean brightening) {
928-
mRecentLightBrightening = brightening;
929-
mRecentLightTimeConstant = brightening ?
930-
BRIGHTENING_LIGHT_TIME_CONSTANT : DIMMING_LIGHT_TIME_CONSTANT;
931-
mRecentLightSamples = 1;
932-
mRecentLightAverage = lux;
933-
mLastLightSample = lux;
934-
mLastLightSampleTime = time;
935-
mFirstRecentLightSampleTime = time;
936-
mPendingLightSensorDebounceTime = time + (brightening ?
937-
BRIGHTENING_LIGHT_DEBOUNCE : DIMMING_LIGHT_DEBOUNCE);
901+
updateAmbientLux(time);
938902
}
939903

940-
private void accumulateRecentLight(long time, float lux) {
941-
final long timeDelta = time - mLastLightSampleTime;
942-
mRecentLightSamples += 1;
943-
mRecentLightAverage += (lux - mRecentLightAverage) *
944-
timeDelta / (mRecentLightTimeConstant + timeDelta);
945-
mLastLightSample = lux;
946-
mLastLightSampleTime = time;
947-
}
948-
949-
private void debounceLightSensor() {
950-
if (mLightMeasurementValid && mRecentLightSamples >= 1) {
951-
final long now = SystemClock.uptimeMillis();
952-
if (mPendingLightSensorDebounceTime <= now) {
953-
accumulateRecentLight(now, mLastLightSample);
954-
mLightMeasurement = mRecentLightAverage;
904+
private void updateAmbientLux(long time) {
905+
// If the light sensor was just turned on then immediately update our initial
906+
// estimate of the current ambient light level.
907+
if (!mAmbientLuxValid
908+
|| (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) {
909+
if (DEBUG) {
910+
Slog.d(TAG, "updateAmbientLux: Initializing, "
911+
+ "mAmbientLux=" + (mAmbientLuxValid ? mAmbientLux : -1)
912+
+ ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
913+
+ ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
914+
}
915+
mAmbientLux = mRecentShortTermAverageLux;
916+
mAmbientLuxValid = true;
917+
mLastAmbientBrightenTime = time;
918+
mLastAmbientDarkenTime = time;
919+
updateAutoBrightness(true);
920+
return;
921+
}
955922

923+
// Determine whether the ambient environment appears to be brightening.
924+
float minAmbientLux = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
925+
if (mRecentShortTermAverageLux > minAmbientLux
926+
&& mRecentLongTermAverageLux > minAmbientLux) {
927+
long debounceTime = mLastAmbientDarkenTime + BRIGHTENING_LIGHT_DEBOUNCE;
928+
if (time >= debounceTime) {
956929
if (DEBUG) {
957-
Slog.d(TAG, "debounceLightSensor: Accepted new measurement "
958-
+ mLightMeasurement + " after "
959-
+ (now - mFirstRecentLightSampleTime) + " ms based on "
960-
+ mRecentLightSamples + " recent samples.");
930+
Slog.d(TAG, "updateAmbientLux: Brightened: "
931+
+ "mAmbientLux=" + mAmbientLux
932+
+ ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
933+
+ ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
961934
}
962-
935+
mLastAmbientBrightenTime = time;
936+
mAmbientLux = mRecentShortTermAverageLux;
963937
updateAutoBrightness(true);
938+
} else {
939+
mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
940+
}
941+
return;
942+
}
964943

965-
// Now that we have debounced the light sensor data, we have the
966-
// option of either leaving the sensor in a debounced state or
967-
// restarting the debounce cycle by setting mRecentLightSamples to 0.
968-
//
969-
// If we leave the sensor debounced, then new average light measurements
970-
// may be accepted immediately as long as they are trending in the same
971-
// direction as they were before. If the measurements start
972-
// jittering or trending in the opposite direction then the debounce
973-
// cycle will automatically be restarted. The benefit is that the
974-
// auto-brightness control can be more responsive to changes over a
975-
// broad range.
976-
//
977-
// For now, we choose to be more responsive and leave the following line
978-
// commented out.
979-
//
980-
// mRecentLightSamples = 0;
944+
// Determine whether the ambient environment appears to be darkening.
945+
float maxAmbientLux = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
946+
if (mRecentShortTermAverageLux < maxAmbientLux
947+
&& mRecentLongTermAverageLux < maxAmbientLux) {
948+
long debounceTime = mLastAmbientBrightenTime + DARKENING_LIGHT_DEBOUNCE;
949+
if (time >= debounceTime) {
950+
if (DEBUG) {
951+
Slog.d(TAG, "updateAmbientLux: Darkened: "
952+
+ "mAmbientLux=" + mAmbientLux
953+
+ ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
954+
+ ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
955+
}
956+
mLastAmbientDarkenTime = time;
957+
mAmbientLux = mRecentShortTermAverageLux;
958+
updateAutoBrightness(true);
981959
} else {
982-
Message msg = mHandler.obtainMessage(MSG_LIGHT_SENSOR_DEBOUNCED);
983-
msg.setAsynchronous(true);
984-
mHandler.sendMessageAtTime(msg, mPendingLightSensorDebounceTime);
960+
mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
985961
}
986962
}
987963
}
988964

965+
private void debounceLightSensor() {
966+
updateAmbientLux(SystemClock.uptimeMillis());
967+
}
968+
989969
private void updateAutoBrightness(boolean sendUpdate) {
990-
if (!mLightMeasurementValid) {
970+
if (!mAmbientLuxValid) {
991971
return;
992972
}
993973

994-
float value = mScreenAutoBrightnessSpline.interpolate(mLightMeasurement);
974+
float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);
995975
float gamma = 1.0f;
996976

997977
if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
@@ -1031,7 +1011,7 @@ private void updateAutoBrightness(boolean sendUpdate) {
10311011
}
10321012

10331013
int newScreenAutoBrightness = clampScreenBrightness(
1034-
(int)Math.round(value * PowerManager.BRIGHTNESS_ON));
1014+
Math.round(value * PowerManager.BRIGHTNESS_ON));
10351015
if (mScreenAutoBrightness != newScreenAutoBrightness) {
10361016
if (DEBUG) {
10371017
Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
@@ -1152,19 +1132,18 @@ private void dumpLocal(PrintWriter pw) {
11521132
pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
11531133
pw.println(" mLightSensorEnableTime="
11541134
+ TimeUtils.formatUptime(mLightSensorEnableTime));
1155-
pw.println(" mLightMeasurement=" + mLightMeasurement);
1156-
pw.println(" mLightMeasurementValid=" + mLightMeasurementValid);
1157-
pw.println(" mLastLightSample=" + mLastLightSample);
1158-
pw.println(" mLastLightSampleTime="
1159-
+ TimeUtils.formatUptime(mLastLightSampleTime));
1135+
pw.println(" mAmbientLux=" + mAmbientLux);
1136+
pw.println(" mAmbientLuxValid=" + mAmbientLuxValid);
1137+
pw.println(" mLastAmbientBrightenTime="
1138+
+ TimeUtils.formatUptime(mLastAmbientBrightenTime));
1139+
pw.println(" mLastAmbientDimTime="
1140+
+ TimeUtils.formatUptime(mLastAmbientDarkenTime));
1141+
pw.println(" mLastObservedLux=" + mLastObservedLux);
1142+
pw.println(" mLastObservedLuxTime="
1143+
+ TimeUtils.formatUptime(mLastObservedLuxTime));
11601144
pw.println(" mRecentLightSamples=" + mRecentLightSamples);
1161-
pw.println(" mRecentLightAverage=" + mRecentLightAverage);
1162-
pw.println(" mRecentLightBrightening=" + mRecentLightBrightening);
1163-
pw.println(" mRecentLightTimeConstant=" + mRecentLightTimeConstant);
1164-
pw.println(" mFirstRecentLightSampleTime="
1165-
+ TimeUtils.formatUptime(mFirstRecentLightSampleTime));
1166-
pw.println(" mPendingLightSensorDebounceTime="
1167-
+ TimeUtils.formatUptime(mPendingLightSensorDebounceTime));
1145+
pw.println(" mRecentShortTermAverageLux=" + mRecentShortTermAverageLux);
1146+
pw.println(" mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
11681147
pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
11691148
pw.println(" mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
11701149
pw.println(" mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.android.server.power;
1818

19+
import android.util.Slog;
20+
1921
import com.android.server.LightsService;
2022

2123
import java.util.concurrent.Executor;
@@ -27,6 +29,9 @@
2729
* setting the backlight brightness is especially slow.
2830
*/
2931
final class PhotonicModulator {
32+
private static final String TAG = "PhotonicModulator";
33+
private static final boolean DEBUG = false;
34+
3035
private static final int UNKNOWN_LIGHT_VALUE = -1;
3136

3237
private final Object mLock = new Object();
@@ -58,6 +63,9 @@ public void setBrightness(int lightValue, boolean sync) {
5863
synchronized (mLock) {
5964
if (lightValue != mPendingLightValue) {
6065
mPendingLightValue = lightValue;
66+
if (DEBUG) {
67+
Slog.d(TAG, "Enqueuing request to change brightness to " + lightValue);
68+
}
6169
if (!mPendingChange) {
6270
mPendingChange = true;
6371
mSuspendBlocker.acquire();
@@ -91,6 +99,9 @@ public void run() {
9199
}
92100
mActualLightValue = newLightValue;
93101
}
102+
if (DEBUG) {
103+
Slog.d(TAG, "Setting brightness to " + newLightValue);
104+
}
94105
mLight.setBrightness(newLightValue);
95106
}
96107
}

0 commit comments

Comments
 (0)