summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2012-10-18 23:22:14 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-10-18 23:23:57 -0700
commit1d2b445d7431420b7cfbd9ef3fe4e326e121eeae (patch)
treee363717ec922a62371117f6c5eafbf6e39515c00 /services
parent5831159b8d4cf85fa46e2c4cb8e7d9f750014d6f (diff)
parent4f0e969eabc336f6dfa31c6218efc1b3dec55139 (diff)
downloadframeworks_base-1d2b445d7431420b7cfbd9ef3fe4e326e121eeae.zip
frameworks_base-1d2b445d7431420b7cfbd9ef3fe4e326e121eeae.tar.gz
frameworks_base-1d2b445d7431420b7cfbd9ef3fe4e326e121eeae.tar.bz2
Merge "Reduce auto-brightness jitter." into jb-mr1-dev
Diffstat (limited to 'services')
-rw-r--r--services/java/com/android/server/power/DisplayPowerController.java261
-rw-r--r--services/java/com/android/server/power/PhotonicModulator.java11
2 files changed, 131 insertions, 141 deletions
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index 1561dba..661b949 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -128,28 +128,33 @@ final class DisplayPowerController {
private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
// Light sensor event rate in microseconds.
- private static final int LIGHT_SENSOR_RATE = 1000000;
+ private static final int LIGHT_SENSOR_RATE = 500 * 1000;
// Brightness animation ramp rate in brightness units per second.
private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
- private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
+ private static final int BRIGHTNESS_RAMP_RATE_SLOW = 30;
- // Filter time constant in milliseconds for computing a moving
- // average of light samples. Different constants are used
- // to calculate the average light level when adapting to brighter or
- // dimmer environments.
- // This parameter only controls the filtering of light samples.
- private static final long BRIGHTENING_LIGHT_TIME_CONSTANT = 600;
- private static final long DIMMING_LIGHT_TIME_CONSTANT = 4000;
+ // IIR filter time constants in milliseconds for computing two moving averages of
+ // the light samples. One is a long-term average and the other is a short-term average.
+ // We can use these filters to assess trends in ambient brightness.
+ // The short term average gives us a filtered but relatively low latency measurement.
+ // The long term average informs us about the overall trend.
+ private static final long SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 1000;
+ private static final long LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 8000;
// Stability requirements in milliseconds for accepting a new brightness
// level. This is used for debouncing the light sensor. Different constants
- // are used to debounce the light sensor when adapting to brighter or dimmer
- // environments.
+ // are used to debounce the light sensor when adapting to brighter or darker environments.
// This parameter controls how quickly brightness changes occur in response to
- // an observed change in light level.
- private static final long BRIGHTENING_LIGHT_DEBOUNCE = 2500;
- private static final long DIMMING_LIGHT_DEBOUNCE = 10000;
+ // an observed change in light level following a previous change in the opposite direction.
+ private static final long BRIGHTENING_LIGHT_DEBOUNCE = 5000;
+ private static final long DARKENING_LIGHT_DEBOUNCE = 15000;
+
+ // Hysteresis constraints for brightening or darkening.
+ // The recent lux must have changed by at least this fraction relative to the
+ // current ambient lux before a change will be considered.
+ private static final float BRIGHTENING_LIGHT_HYSTERESIS = 0.10f;
+ private static final float DARKENING_LIGHT_HYSTERESIS = 0.20f;
private final Object mLock = new Object();
@@ -284,39 +289,28 @@ final class DisplayPowerController {
// The time when the light sensor was enabled.
private long mLightSensorEnableTime;
- // The currently accepted average light sensor value.
- private float mLightMeasurement;
-
- // True if the light sensor measurement is valid.
- private boolean mLightMeasurementValid;
-
- // The number of light sensor samples that have been collected since the
- // last time a light sensor reading was accepted.
- private int mRecentLightSamples;
-
- // The moving average of recent light sensor values.
- private float mRecentLightAverage;
+ // The currently accepted nominal ambient light level.
+ private float mAmbientLux;
- // True if recent light samples are getting brighter than the previous
- // stable light measurement.
- private boolean mRecentLightBrightening;
+ // True if mAmbientLux holds a valid value.
+ private boolean mAmbientLuxValid;
- // The time constant to use for filtering based on whether the
- // light appears to be brightening or dimming.
- private long mRecentLightTimeConstant;
+ // The time when the ambient lux was last brightened or darkened.
+ private long mLastAmbientBrightenTime;
+ private long mLastAmbientDarkenTime;
// The most recent light sample.
- private float mLastLightSample;
+ private float mLastObservedLux;
// The time of the most light recent sample.
- private long mLastLightSampleTime;
+ private long mLastObservedLuxTime;
- // The time when we accumulated the first recent light sample into mRecentLightSamples.
- private long mFirstRecentLightSampleTime;
+ // The number of light samples collected since the light sensor was enabled.
+ private int mRecentLightSamples;
- // The upcoming debounce light sensor time.
- // This is only valid when mLightMeasurementValue && mRecentLightSamples >= 1.
- private long mPendingLightSensorDebounceTime;
+ // The long-term and short-term filtered light measurements.
+ private float mRecentShortTermAverageLux;
+ private float mRecentLongTermAverageLux;
// The screen brightness level that has been chosen by the auto-brightness
// algorithm. The actual brightness should ramp towards this value.
@@ -873,7 +867,8 @@ final class DisplayPowerController {
} else {
if (mLightSensorEnabled) {
mLightSensorEnabled = false;
- mLightMeasurementValid = false;
+ mAmbientLuxValid = false;
+ mRecentLightSamples = 0;
mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
mSensorManager.unregisterListener(mLightSensorListener);
}
@@ -884,114 +879,99 @@ final class DisplayPowerController {
}
private void handleLightSensorEvent(long time, float lux) {
- // Take the first few readings during the warm-up period and apply them
- // immediately without debouncing.
- if (!mLightMeasurementValid
- || (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) {
- mLightMeasurement = lux;
- mLightMeasurementValid = true;
- mRecentLightSamples = 0;
- updateAutoBrightness(true);
+ // Update our filters.
+ mRecentLightSamples += 1;
+ if (mRecentLightSamples == 1) {
+ mRecentShortTermAverageLux = lux;
+ mRecentLongTermAverageLux = lux;
+ } else {
+ final long timeDelta = time - mLastObservedLuxTime;
+ mRecentShortTermAverageLux += (lux - mRecentShortTermAverageLux)
+ * timeDelta / (SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
+ mRecentLongTermAverageLux += (lux - mRecentLongTermAverageLux)
+ * timeDelta / (LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
}
- // Update our moving average.
- if (lux != mLightMeasurement && (mRecentLightSamples == 0
- || (lux < mLightMeasurement && mRecentLightBrightening)
- || (lux > mLightMeasurement && !mRecentLightBrightening))) {
- // If the newest light sample doesn't seem to be going in the
- // same general direction as recent samples, then start over.
- setRecentLight(time, lux, lux > mLightMeasurement);
- } else if (mRecentLightSamples >= 1) {
- // Add the newest light sample to the moving average.
- accumulateRecentLight(time, lux);
- }
- if (DEBUG) {
- Slog.d(TAG, "handleLightSensorEvent: lux=" + lux
- + ", mLightMeasurementValid=" + mLightMeasurementValid
- + ", mLightMeasurement=" + mLightMeasurement
- + ", mRecentLightSamples=" + mRecentLightSamples
- + ", mRecentLightAverage=" + mRecentLightAverage
- + ", mRecentLightBrightening=" + mRecentLightBrightening
- + ", mRecentLightTimeConstant=" + mRecentLightTimeConstant
- + ", mFirstRecentLightSampleTime="
- + TimeUtils.formatUptime(mFirstRecentLightSampleTime)
- + ", mPendingLightSensorDebounceTime="
- + TimeUtils.formatUptime(mPendingLightSensorDebounceTime));
- }
+ // Remember this sample value.
+ mLastObservedLux = lux;
+ mLastObservedLuxTime = time;
- // Debounce.
+ // Update the ambient lux level.
mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
- debounceLightSensor();
- }
-
- private void setRecentLight(long time, float lux, boolean brightening) {
- mRecentLightBrightening = brightening;
- mRecentLightTimeConstant = brightening ?
- BRIGHTENING_LIGHT_TIME_CONSTANT : DIMMING_LIGHT_TIME_CONSTANT;
- mRecentLightSamples = 1;
- mRecentLightAverage = lux;
- mLastLightSample = lux;
- mLastLightSampleTime = time;
- mFirstRecentLightSampleTime = time;
- mPendingLightSensorDebounceTime = time + (brightening ?
- BRIGHTENING_LIGHT_DEBOUNCE : DIMMING_LIGHT_DEBOUNCE);
+ updateAmbientLux(time);
}
- private void accumulateRecentLight(long time, float lux) {
- final long timeDelta = time - mLastLightSampleTime;
- mRecentLightSamples += 1;
- mRecentLightAverage += (lux - mRecentLightAverage) *
- timeDelta / (mRecentLightTimeConstant + timeDelta);
- mLastLightSample = lux;
- mLastLightSampleTime = time;
- }
-
- private void debounceLightSensor() {
- if (mLightMeasurementValid && mRecentLightSamples >= 1) {
- final long now = SystemClock.uptimeMillis();
- if (mPendingLightSensorDebounceTime <= now) {
- accumulateRecentLight(now, mLastLightSample);
- mLightMeasurement = mRecentLightAverage;
+ private void updateAmbientLux(long time) {
+ // If the light sensor was just turned on then immediately update our initial
+ // estimate of the current ambient light level.
+ if (!mAmbientLuxValid
+ || (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) {
+ if (DEBUG) {
+ Slog.d(TAG, "updateAmbientLux: Initializing, "
+ + "mAmbientLux=" + (mAmbientLuxValid ? mAmbientLux : -1)
+ + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
+ + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
+ }
+ mAmbientLux = mRecentShortTermAverageLux;
+ mAmbientLuxValid = true;
+ mLastAmbientBrightenTime = time;
+ mLastAmbientDarkenTime = time;
+ updateAutoBrightness(true);
+ return;
+ }
+ // Determine whether the ambient environment appears to be brightening.
+ float minAmbientLux = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
+ if (mRecentShortTermAverageLux > minAmbientLux
+ && mRecentLongTermAverageLux > minAmbientLux) {
+ long debounceTime = mLastAmbientDarkenTime + BRIGHTENING_LIGHT_DEBOUNCE;
+ if (time >= debounceTime) {
if (DEBUG) {
- Slog.d(TAG, "debounceLightSensor: Accepted new measurement "
- + mLightMeasurement + " after "
- + (now - mFirstRecentLightSampleTime) + " ms based on "
- + mRecentLightSamples + " recent samples.");
+ Slog.d(TAG, "updateAmbientLux: Brightened: "
+ + "mAmbientLux=" + mAmbientLux
+ + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
+ + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
}
-
+ mLastAmbientBrightenTime = time;
+ mAmbientLux = mRecentShortTermAverageLux;
updateAutoBrightness(true);
+ } else {
+ mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
+ }
+ return;
+ }
- // Now that we have debounced the light sensor data, we have the
- // option of either leaving the sensor in a debounced state or
- // restarting the debounce cycle by setting mRecentLightSamples to 0.
- //
- // If we leave the sensor debounced, then new average light measurements
- // may be accepted immediately as long as they are trending in the same
- // direction as they were before. If the measurements start
- // jittering or trending in the opposite direction then the debounce
- // cycle will automatically be restarted. The benefit is that the
- // auto-brightness control can be more responsive to changes over a
- // broad range.
- //
- // For now, we choose to be more responsive and leave the following line
- // commented out.
- //
- // mRecentLightSamples = 0;
+ // Determine whether the ambient environment appears to be darkening.
+ float maxAmbientLux = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
+ if (mRecentShortTermAverageLux < maxAmbientLux
+ && mRecentLongTermAverageLux < maxAmbientLux) {
+ long debounceTime = mLastAmbientBrightenTime + DARKENING_LIGHT_DEBOUNCE;
+ if (time >= debounceTime) {
+ if (DEBUG) {
+ Slog.d(TAG, "updateAmbientLux: Darkened: "
+ + "mAmbientLux=" + mAmbientLux
+ + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
+ + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
+ }
+ mLastAmbientDarkenTime = time;
+ mAmbientLux = mRecentShortTermAverageLux;
+ updateAutoBrightness(true);
} else {
- Message msg = mHandler.obtainMessage(MSG_LIGHT_SENSOR_DEBOUNCED);
- msg.setAsynchronous(true);
- mHandler.sendMessageAtTime(msg, mPendingLightSensorDebounceTime);
+ mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
}
}
}
+ private void debounceLightSensor() {
+ updateAmbientLux(SystemClock.uptimeMillis());
+ }
+
private void updateAutoBrightness(boolean sendUpdate) {
- if (!mLightMeasurementValid) {
+ if (!mAmbientLuxValid) {
return;
}
- float value = mScreenAutoBrightnessSpline.interpolate(mLightMeasurement);
+ float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);
float gamma = 1.0f;
if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
@@ -1031,7 +1011,7 @@ final class DisplayPowerController {
}
int newScreenAutoBrightness = clampScreenBrightness(
- (int)Math.round(value * PowerManager.BRIGHTNESS_ON));
+ Math.round(value * PowerManager.BRIGHTNESS_ON));
if (mScreenAutoBrightness != newScreenAutoBrightness) {
if (DEBUG) {
Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
@@ -1152,19 +1132,18 @@ final class DisplayPowerController {
pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
pw.println(" mLightSensorEnableTime="
+ TimeUtils.formatUptime(mLightSensorEnableTime));
- pw.println(" mLightMeasurement=" + mLightMeasurement);
- pw.println(" mLightMeasurementValid=" + mLightMeasurementValid);
- pw.println(" mLastLightSample=" + mLastLightSample);
- pw.println(" mLastLightSampleTime="
- + TimeUtils.formatUptime(mLastLightSampleTime));
+ pw.println(" mAmbientLux=" + mAmbientLux);
+ pw.println(" mAmbientLuxValid=" + mAmbientLuxValid);
+ pw.println(" mLastAmbientBrightenTime="
+ + TimeUtils.formatUptime(mLastAmbientBrightenTime));
+ pw.println(" mLastAmbientDimTime="
+ + TimeUtils.formatUptime(mLastAmbientDarkenTime));
+ pw.println(" mLastObservedLux=" + mLastObservedLux);
+ pw.println(" mLastObservedLuxTime="
+ + TimeUtils.formatUptime(mLastObservedLuxTime));
pw.println(" mRecentLightSamples=" + mRecentLightSamples);
- pw.println(" mRecentLightAverage=" + mRecentLightAverage);
- pw.println(" mRecentLightBrightening=" + mRecentLightBrightening);
- pw.println(" mRecentLightTimeConstant=" + mRecentLightTimeConstant);
- pw.println(" mFirstRecentLightSampleTime="
- + TimeUtils.formatUptime(mFirstRecentLightSampleTime));
- pw.println(" mPendingLightSensorDebounceTime="
- + TimeUtils.formatUptime(mPendingLightSensorDebounceTime));
+ pw.println(" mRecentShortTermAverageLux=" + mRecentShortTermAverageLux);
+ pw.println(" mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
pw.println(" mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
pw.println(" mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
diff --git a/services/java/com/android/server/power/PhotonicModulator.java b/services/java/com/android/server/power/PhotonicModulator.java
index c9b5d90..648c0c5 100644
--- a/services/java/com/android/server/power/PhotonicModulator.java
+++ b/services/java/com/android/server/power/PhotonicModulator.java
@@ -16,6 +16,8 @@
package com.android.server.power;
+import android.util.Slog;
+
import com.android.server.LightsService;
import java.util.concurrent.Executor;
@@ -27,6 +29,9 @@ import java.util.concurrent.Executor;
* setting the backlight brightness is especially slow.
*/
final class PhotonicModulator {
+ private static final String TAG = "PhotonicModulator";
+ private static final boolean DEBUG = false;
+
private static final int UNKNOWN_LIGHT_VALUE = -1;
private final Object mLock = new Object();
@@ -58,6 +63,9 @@ final class PhotonicModulator {
synchronized (mLock) {
if (lightValue != mPendingLightValue) {
mPendingLightValue = lightValue;
+ if (DEBUG) {
+ Slog.d(TAG, "Enqueuing request to change brightness to " + lightValue);
+ }
if (!mPendingChange) {
mPendingChange = true;
mSuspendBlocker.acquire();
@@ -91,6 +99,9 @@ final class PhotonicModulator {
}
mActualLightValue = newLightValue;
}
+ if (DEBUG) {
+ Slog.d(TAG, "Setting brightness to " + newLightValue);
+ }
mLight.setBrightness(newLightValue);
}
}