Add a mechanism to adjust auto-brightness at night.

Uses the twilight service to determine the hours of
sunrise and sunset.  Shortly after sunset or before sunrise
gradually start to apply a gamma correction factor to the
auto-brightness calculations to make the screen a little
dimmer at night.

The effect is relatively small and is mostly noticeable
in dark rooms.  This is just a first pass at the algorithm,
we can tweak the adjustment later to ensure that it has even less
impact in moderate or bright environments.

Change-Id: Idf89022a5d0bb52975e04779352d53fa63371178
This commit is contained in:
Jeff Brown
2012-08-21 22:14:26 -07:00
parent 2416e09649
commit aa202a6dc3
3 changed files with 90 additions and 5 deletions

View File

@@ -741,7 +741,12 @@ class ServerThread extends Thread {
w.getDefaultDisplay().getMetrics(metrics);
context.getResources().updateConfiguration(config, metrics);
power.systemReady();
try {
power.systemReady(twilight);
} catch (Throwable e) {
reportWtf("making Power Manager Service ready", e);
}
try {
pm.systemReady();
} catch (Throwable e) {

View File

@@ -17,6 +17,8 @@
package com.android.server.power;
import com.android.server.LightsService;
import com.android.server.TwilightService;
import com.android.server.TwilightService.TwilightState;
import android.animation.Animator;
import android.animation.ObjectAnimator;
@@ -88,6 +90,22 @@ final class DisplayPowerController {
// auto-brightness adjustment setting.
private static final float SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA = 3.0f;
// If true, enables the use of the current time as an auto-brightness adjustment.
// The basic idea here is to expand the dynamic range of auto-brightness
// when it is especially dark outside. The light sensor tends to perform
// poorly at low light levels so we compensate for it by making an
// assumption about the environment.
private static final boolean USE_TWILIGHT_ADJUSTMENT = true;
// Specifies the maximum magnitude of the time of day adjustment.
private static final float TWILIGHT_ADJUSTMENT_MAX_GAMMA = 1.5f;
// The amount of time after or before sunrise over which to start adjusting
// the gamma. We want the change to happen gradually so that it is below the
// threshold of perceptibility and so that the adjustment has maximum effect
// well after dusk.
private static final long TWILIGHT_ADJUSTMENT_TIME = DateUtils.HOUR_IN_MILLIS * 2;
private static final int ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS = 300;
private static final int ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS = 600;
@@ -148,6 +166,9 @@ final class DisplayPowerController {
// The lights service.
private final LightsService mLights;
// The twilight service.
private final TwilightService mTwilight;
// The sensor manager.
private final SensorManager mSensorManager;
@@ -291,11 +312,14 @@ final class DisplayPowerController {
private ObjectAnimator mElectronBeamOffAnimator;
private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
// Twilight changed. We might recalculate auto-brightness values.
private boolean mTwilightChanged;
/**
* Creates the display power controller.
*/
public DisplayPowerController(Looper looper, Context context, Notifier notifier,
LightsService lights, SuspendBlocker suspendBlocker,
LightsService lights, TwilightService twilight, SuspendBlocker suspendBlocker,
Callbacks callbacks, Handler callbackHandler) {
mHandler = new DisplayControllerHandler(looper);
mNotifier = notifier;
@@ -304,6 +328,7 @@ final class DisplayPowerController {
mCallbackHandler = callbackHandler;
mLights = lights;
mTwilight = twilight;
mSensorManager = new SystemSensorManager(mHandler.getLooper());
final Resources resources = context.getResources();
@@ -344,6 +369,10 @@ final class DisplayPowerController {
&& !DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
}
if (mUseSoftwareAutoBrightnessConfig && USE_TWILIGHT_ADJUSTMENT) {
mTwilight.registerListener(mTwilightListener, mHandler);
}
}
private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
@@ -486,7 +515,8 @@ final class DisplayPowerController {
// Update the power state request.
final boolean mustNotify;
boolean mustInitialize = false;
boolean updateAutoBrightness = false;
boolean updateAutoBrightness = mTwilightChanged;
mTwilightChanged = false;
synchronized (mLock) {
mPendingUpdatePowerStateLocked = false;
@@ -863,6 +893,22 @@ final class DisplayPowerController {
}
}
if (USE_TWILIGHT_ADJUSTMENT) {
TwilightState state = mTwilight.getCurrentState();
if (state != null && state.isNight()) {
final long now = System.currentTimeMillis();
final float earlyGamma =
getTwilightGamma(now, state.getYesterdaySunset(), state.getTodaySunrise());
final float lateGamma =
getTwilightGamma(now, state.getTodaySunset(), state.getTomorrowSunrise());
gamma *= earlyGamma * lateGamma;
if (DEBUG) {
Slog.d(TAG, "updateAutoBrightness: earlyGamma=" + earlyGamma
+ ", lateGamma=" + lateGamma);
}
}
}
if (gamma != 1.0f) {
final float in = value;
value = FloatMath.pow(value, gamma);
@@ -889,6 +935,29 @@ final class DisplayPowerController {
}
}
private static float getTwilightGamma(long now, long lastSunset, long nextSunrise) {
if (lastSunset < 0 || nextSunrise < 0
|| now < lastSunset || now > nextSunrise) {
return 1.0f;
}
if (now < lastSunset + TWILIGHT_ADJUSTMENT_TIME) {
return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
(float)(now - lastSunset) / TWILIGHT_ADJUSTMENT_TIME);
}
if (now > nextSunrise - TWILIGHT_ADJUSTMENT_TIME) {
return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
(float)(nextSunrise - now) / TWILIGHT_ADJUSTMENT_TIME);
}
return TWILIGHT_ADJUSTMENT_MAX_GAMMA;
}
private static float lerp(float x, float y, float alpha) {
return x + (y - x) * alpha;
}
private void sendOnStateChanged() {
mCallbackHandler.post(mOnStateChangedRunnable);
}
@@ -995,6 +1064,7 @@ final class DisplayPowerController {
pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
pw.println(" mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
pw.println(" mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
pw.println(" mTwilight.getCurrentState()=" + mTwilight.getCurrentState());
if (mElectronBeamOnAnimator != null) {
pw.println(" mElectronBeamOnAnimator.isStarted()=" +
@@ -1095,4 +1165,13 @@ final class DisplayPowerController {
// Not used.
}
};
private final TwilightService.TwilightListener mTwilightListener =
new TwilightService.TwilightListener() {
@Override
public void onTwilightStateChanged() {
mTwilightChanged = true;
updatePowerState();
}
};
}

View File

@@ -20,6 +20,7 @@ import com.android.internal.app.IBatteryStats;
import com.android.server.BatteryService;
import com.android.server.EventLogTags;
import com.android.server.LightsService;
import com.android.server.TwilightService;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService;
import com.android.server.display.DisplayManagerService;
@@ -318,7 +319,7 @@ public final class PowerManagerService extends IPowerManager.Stub
}
}
public void systemReady() {
public void systemReady(TwilightService twilight) {
synchronized (mLock) {
mSystemReady = true;
@@ -331,7 +332,7 @@ public final class PowerManagerService extends IPowerManager.Stub
createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
mPolicy, mScreenOnListener);
mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
mContext, mNotifier, mLightsService,
mContext, mNotifier, mLightsService, twilight,
createSuspendBlockerLocked("PowerManagerService.Display"),
mDisplayPowerControllerCallbacks, mHandler);