blob: 724e1260249d3e90821c1dc59fcc5e982811abdb [file] [log] [blame]
Jeff Brown96307042012-07-27 15:51:34 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.power;
18
19import com.android.server.LightsService;
Jeff Brownaa202a62012-08-21 22:14:26 -070020import com.android.server.TwilightService;
21import com.android.server.TwilightService.TwilightState;
Jeff Brown7f3994e2012-12-04 14:04:28 -080022import com.android.server.display.DisplayManagerService;
Jeff Brown96307042012-07-27 15:51:34 -070023
24import android.animation.Animator;
25import android.animation.ObjectAnimator;
26import android.content.Context;
27import android.content.res.Resources;
28import android.hardware.Sensor;
29import android.hardware.SensorEvent;
30import android.hardware.SensorEventListener;
31import android.hardware.SensorManager;
32import android.hardware.SystemSensorManager;
Jeff Brown96307042012-07-27 15:51:34 -070033import android.os.Handler;
34import android.os.Looper;
35import android.os.Message;
Jeff Brown330560f2012-08-21 22:10:57 -070036import android.os.PowerManager;
Jeff Brown96307042012-07-27 15:51:34 -070037import android.os.SystemClock;
Jeff Brown330560f2012-08-21 22:10:57 -070038import android.text.format.DateUtils;
39import android.util.FloatMath;
Jeff Brown96307042012-07-27 15:51:34 -070040import android.util.Slog;
Jeff Brown1a30b552012-08-16 01:31:11 -070041import android.util.Spline;
Jeff Brown96307042012-07-27 15:51:34 -070042import android.util.TimeUtils;
43
44import java.io.PrintWriter;
Jeff Brown96307042012-07-27 15:51:34 -070045
46/**
47 * Controls the power state of the display.
48 *
49 * Handles the proximity sensor, light sensor, and animations between states
50 * including the screen off animation.
51 *
52 * This component acts independently of the rest of the power manager service.
53 * In particular, it does not share any state and it only communicates
54 * via asynchronous callbacks to inform the power manager that something has
55 * changed.
56 *
57 * Everything this class does internally is serialized on its handler although
58 * it may be accessed by other threads from the outside.
59 *
60 * Note that the power manager service guarantees that it will hold a suspend
61 * blocker as long as the display is not ready. So most of the work done here
62 * does not need to worry about holding a suspend blocker unless it happens
63 * independently of the display ready signal.
64 *
65 * For debugging, you can make the electron beam and brightness animations run
66 * slower by changing the "animator duration scale" option in Development Settings.
67 */
68final class DisplayPowerController {
69 private static final String TAG = "DisplayPowerController";
70
71 private static boolean DEBUG = false;
72 private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
73 private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
74
Jeff Brown13c589b2012-08-16 16:20:54 -070075 // If true, uses the electron beam on animation.
76 // We might want to turn this off if we cannot get a guarantee that the screen
77 // actually turns on and starts showing new content after the call to set the
Jeff Brown5356c7dc2012-08-20 20:17:36 -070078 // screen state returns. Playing the animation can also be somewhat slow.
79 private static final boolean USE_ELECTRON_BEAM_ON_ANIMATION = false;
Jeff Brown13c589b2012-08-16 16:20:54 -070080
Jeff Brown330560f2012-08-21 22:10:57 -070081 // If true, enables the use of the screen auto-brightness adjustment setting.
Jeff Brown631938f2012-09-08 15:11:11 -070082 private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT =
83 PowerManager.useScreenAutoBrightnessAdjustmentFeature();
Jeff Brown330560f2012-08-21 22:10:57 -070084
85 // The maximum range of gamma adjustment possible using the screen
86 // auto-brightness adjustment setting.
87 private static final float SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA = 3.0f;
88
Jeff Brownb76eebff2012-10-05 22:26:44 -070089 // The minimum reduction in brightness when dimmed.
90 private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
91
Jeff Brownaa202a62012-08-21 22:14:26 -070092 // If true, enables the use of the current time as an auto-brightness adjustment.
93 // The basic idea here is to expand the dynamic range of auto-brightness
94 // when it is especially dark outside. The light sensor tends to perform
95 // poorly at low light levels so we compensate for it by making an
96 // assumption about the environment.
Jeff Browndb212842012-10-01 14:33:09 -070097 private static final boolean USE_TWILIGHT_ADJUSTMENT =
98 PowerManager.useTwilightAdjustmentFeature();
Jeff Brownaa202a62012-08-21 22:14:26 -070099
100 // Specifies the maximum magnitude of the time of day adjustment.
101 private static final float TWILIGHT_ADJUSTMENT_MAX_GAMMA = 1.5f;
102
103 // The amount of time after or before sunrise over which to start adjusting
104 // the gamma. We want the change to happen gradually so that it is below the
105 // threshold of perceptibility and so that the adjustment has maximum effect
106 // well after dusk.
107 private static final long TWILIGHT_ADJUSTMENT_TIME = DateUtils.HOUR_IN_MILLIS * 2;
108
Jeff Brown00a8f4f2012-08-21 23:11:46 -0700109 private static final int ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS = 250;
Jeff Brown3c584f22012-10-10 14:36:00 -0700110 private static final int ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS = 400;
Jeff Brown96307042012-07-27 15:51:34 -0700111
112 private static final int MSG_UPDATE_POWER_STATE = 1;
113 private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
114 private static final int MSG_LIGHT_SENSOR_DEBOUNCED = 3;
115
116 private static final int PROXIMITY_UNKNOWN = -1;
117 private static final int PROXIMITY_NEGATIVE = 0;
118 private static final int PROXIMITY_POSITIVE = 1;
119
Jeff Brown93cbbb22012-10-04 13:18:36 -0700120 // Proximity sensor debounce delay in milliseconds for positive or negative transitions.
121 private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
122 private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 500;
Jeff Brown96307042012-07-27 15:51:34 -0700123
124 // Trigger proximity if distance is less than 5 cm.
125 private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
126
Jeff Browne941b1e2012-10-22 16:50:25 -0700127 // Light sensor event rate in milliseconds.
128 private static final int LIGHT_SENSOR_RATE_MILLIS = 1000;
129
130 // A rate for generating synthetic light sensor events in the case where the light
131 // sensor hasn't reported any new data in a while and we need it to update the
132 // debounce filter. We only synthesize light sensor measurements when needed.
133 private static final int SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS =
134 LIGHT_SENSOR_RATE_MILLIS * 2;
Jeff Brown96307042012-07-27 15:51:34 -0700135
136 // Brightness animation ramp rate in brightness units per second.
137 private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
Jeff Browne941b1e2012-10-22 16:50:25 -0700138 private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
Jeff Brown96307042012-07-27 15:51:34 -0700139
Jeff Brown4f0e9692012-10-18 16:14:16 -0700140 // IIR filter time constants in milliseconds for computing two moving averages of
141 // the light samples. One is a long-term average and the other is a short-term average.
142 // We can use these filters to assess trends in ambient brightness.
143 // The short term average gives us a filtered but relatively low latency measurement.
144 // The long term average informs us about the overall trend.
145 private static final long SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 1000;
Jeff Browne941b1e2012-10-22 16:50:25 -0700146 private static final long LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 5000;
Jeff Brown06565b62012-08-15 21:10:32 -0700147
148 // Stability requirements in milliseconds for accepting a new brightness
149 // level. This is used for debouncing the light sensor. Different constants
Jeff Brown4f0e9692012-10-18 16:14:16 -0700150 // are used to debounce the light sensor when adapting to brighter or darker environments.
Jeff Brown06565b62012-08-15 21:10:32 -0700151 // This parameter controls how quickly brightness changes occur in response to
Jeff Browne941b1e2012-10-22 16:50:25 -0700152 // an observed change in light level that exceeds the hysteresis threshold.
153 private static final long BRIGHTENING_LIGHT_DEBOUNCE = 4000;
154 private static final long DARKENING_LIGHT_DEBOUNCE = 8000;
Jeff Brown4f0e9692012-10-18 16:14:16 -0700155
156 // Hysteresis constraints for brightening or darkening.
157 // The recent lux must have changed by at least this fraction relative to the
158 // current ambient lux before a change will be considered.
159 private static final float BRIGHTENING_LIGHT_HYSTERESIS = 0.10f;
160 private static final float DARKENING_LIGHT_HYSTERESIS = 0.20f;
Jeff Brown96307042012-07-27 15:51:34 -0700161
162 private final Object mLock = new Object();
163
164 // Notifier for sending asynchronous notifications.
165 private final Notifier mNotifier;
166
Jeff Brown9e316a12012-10-08 19:17:06 -0700167 // The display blanker.
168 private final DisplayBlanker mDisplayBlanker;
169
Jeff Brown96307042012-07-27 15:51:34 -0700170 // Our handler.
171 private final DisplayControllerHandler mHandler;
172
173 // Asynchronous callbacks into the power manager service.
174 // Only invoked from the handler thread while no locks are held.
175 private final Callbacks mCallbacks;
176 private Handler mCallbackHandler;
177
178 // The lights service.
179 private final LightsService mLights;
180
Jeff Brownaa202a62012-08-21 22:14:26 -0700181 // The twilight service.
182 private final TwilightService mTwilight;
183
Jeff Brownbd6e1502012-08-28 03:27:37 -0700184 // The display manager.
Jeff Brown7f3994e2012-12-04 14:04:28 -0800185 private final DisplayManagerService mDisplayManager;
Jeff Brownbd6e1502012-08-28 03:27:37 -0700186
Jeff Brown96307042012-07-27 15:51:34 -0700187 // The sensor manager.
188 private final SensorManager mSensorManager;
189
190 // The proximity sensor, or null if not available or needed.
191 private Sensor mProximitySensor;
192
193 // The light sensor, or null if not available or needed.
194 private Sensor mLightSensor;
195
196 // The dim screen brightness.
197 private final int mScreenBrightnessDimConfig;
198
Jeff Brownb76eebff2012-10-05 22:26:44 -0700199 // The minimum allowed brightness.
200 private final int mScreenBrightnessRangeMinimum;
201
202 // The maximum allowed brightness.
203 private final int mScreenBrightnessRangeMaximum;
204
Jeff Brown330560f2012-08-21 22:10:57 -0700205 // True if auto-brightness should be used.
Jeff Brown96307042012-07-27 15:51:34 -0700206 private boolean mUseSoftwareAutoBrightnessConfig;
Jeff Brown330560f2012-08-21 22:10:57 -0700207
208 // The auto-brightness spline adjustment.
209 // The brightness values have been scaled to a range of 0..1.
Jeff Brown1a30b552012-08-16 01:31:11 -0700210 private Spline mScreenAutoBrightnessSpline;
Jeff Brown96307042012-07-27 15:51:34 -0700211
212 // Amount of time to delay auto-brightness after screen on while waiting for
213 // the light sensor to warm-up in milliseconds.
214 // May be 0 if no warm-up is required.
215 private int mLightSensorWarmUpTimeConfig;
216
Jeff Brown252c2062012-10-08 16:21:01 -0700217 // True if we should fade the screen while turning it off, false if we should play
218 // a stylish electron beam animation instead.
219 private boolean mElectronBeamFadesConfig;
Jeff Browna52772f2012-10-04 18:38:09 -0700220
Jeff Brown96307042012-07-27 15:51:34 -0700221 // The pending power request.
222 // Initially null until the first call to requestPowerState.
223 // Guarded by mLock.
224 private DisplayPowerRequest mPendingRequestLocked;
225
226 // True if a request has been made to wait for the proximity sensor to go negative.
227 // Guarded by mLock.
228 private boolean mPendingWaitForNegativeProximityLocked;
229
230 // True if the pending power request or wait for negative proximity flag
231 // has been changed since the last update occurred.
232 // Guarded by mLock.
233 private boolean mPendingRequestChangedLocked;
234
235 // Set to true when the important parts of the pending power request have been applied.
236 // The important parts are mainly the screen state. Brightness changes may occur
237 // concurrently.
238 // Guarded by mLock.
239 private boolean mDisplayReadyLocked;
240
241 // Set to true if a power state update is required.
242 // Guarded by mLock.
243 private boolean mPendingUpdatePowerStateLocked;
244
245 /* The following state must only be accessed by the handler thread. */
246
247 // The currently requested power state.
248 // The power controller will progressively update its internal state to match
249 // the requested power state. Initially null until the first update.
250 private DisplayPowerRequest mPowerRequest;
251
252 // The current power state.
253 // Must only be accessed on the handler thread.
254 private DisplayPowerState mPowerState;
255
256 // True if the device should wait for negative proximity sensor before
257 // waking up the screen. This is set to false as soon as a negative
258 // proximity sensor measurement is observed or when the device is forced to
259 // go to sleep by the user. While true, the screen remains off.
260 private boolean mWaitingForNegativeProximity;
261
262 // The actual proximity sensor threshold value.
263 private float mProximityThreshold;
264
265 // Set to true if the proximity sensor listener has been registered
266 // with the sensor manager.
267 private boolean mProximitySensorEnabled;
268
269 // The debounced proximity sensor state.
270 private int mProximity = PROXIMITY_UNKNOWN;
271
272 // The raw non-debounced proximity sensor state.
273 private int mPendingProximity = PROXIMITY_UNKNOWN;
274 private long mPendingProximityDebounceTime;
275
276 // True if the screen was turned off because of the proximity sensor.
277 // When the screen turns on again, we report user activity to the power manager.
278 private boolean mScreenOffBecauseOfProximity;
279
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700280 // True if the screen on is being blocked.
281 private boolean mScreenOnWasBlocked;
282
283 // The elapsed real time when the screen on was blocked.
284 private long mScreenOnBlockStartRealTime;
285
Jeff Brown96307042012-07-27 15:51:34 -0700286 // Set to true if the light sensor is enabled.
287 private boolean mLightSensorEnabled;
288
289 // The time when the light sensor was enabled.
290 private long mLightSensorEnableTime;
291
Jeff Brown4f0e9692012-10-18 16:14:16 -0700292 // The currently accepted nominal ambient light level.
293 private float mAmbientLux;
Jeff Brown96307042012-07-27 15:51:34 -0700294
Jeff Brown4f0e9692012-10-18 16:14:16 -0700295 // True if mAmbientLux holds a valid value.
296 private boolean mAmbientLuxValid;
Jeff Brown96307042012-07-27 15:51:34 -0700297
Jeff Brown96307042012-07-27 15:51:34 -0700298 // The most recent light sample.
Jeff Brown4f0e9692012-10-18 16:14:16 -0700299 private float mLastObservedLux;
Jeff Brown96307042012-07-27 15:51:34 -0700300
301 // The time of the most light recent sample.
Jeff Brown4f0e9692012-10-18 16:14:16 -0700302 private long mLastObservedLuxTime;
Jeff Brown96307042012-07-27 15:51:34 -0700303
Jeff Brown4f0e9692012-10-18 16:14:16 -0700304 // The number of light samples collected since the light sensor was enabled.
305 private int mRecentLightSamples;
Jeff Brown06565b62012-08-15 21:10:32 -0700306
Jeff Brown4f0e9692012-10-18 16:14:16 -0700307 // The long-term and short-term filtered light measurements.
308 private float mRecentShortTermAverageLux;
309 private float mRecentLongTermAverageLux;
Jeff Brown96307042012-07-27 15:51:34 -0700310
Jeff Browne941b1e2012-10-22 16:50:25 -0700311 // The direction in which the average lux is moving relative to the current ambient lux.
312 // 0 if not changing or within hysteresis threshold.
313 // 1 if brightening beyond hysteresis threshold.
314 // -1 if darkening beyond hysteresis threshold.
315 private int mDebounceLuxDirection;
316
317 // The time when the average lux last changed direction.
318 private long mDebounceLuxTime;
319
Jeff Brown96307042012-07-27 15:51:34 -0700320 // The screen brightness level that has been chosen by the auto-brightness
321 // algorithm. The actual brightness should ramp towards this value.
322 // We preserve this value even when we stop using the light sensor so
323 // that we can quickly revert to the previous auto-brightness level
324 // while the light sensor warms up.
325 // Use -1 if there is no current auto-brightness value available.
326 private int mScreenAutoBrightness = -1;
327
Jeff Brown330560f2012-08-21 22:10:57 -0700328 // The last screen auto-brightness gamma. (For printing in dump() only.)
329 private float mLastScreenAutoBrightnessGamma = 1.0f;
330
Jeff Brown96307042012-07-27 15:51:34 -0700331 // True if the screen auto-brightness value is actually being used to
332 // set the display brightness.
333 private boolean mUsingScreenAutoBrightness;
334
335 // Animators.
336 private ObjectAnimator mElectronBeamOnAnimator;
337 private ObjectAnimator mElectronBeamOffAnimator;
338 private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
339
Jeff Brownaa202a62012-08-21 22:14:26 -0700340 // Twilight changed. We might recalculate auto-brightness values.
341 private boolean mTwilightChanged;
342
Jeff Brown96307042012-07-27 15:51:34 -0700343 /**
344 * Creates the display power controller.
345 */
346 public DisplayPowerController(Looper looper, Context context, Notifier notifier,
Jeff Brown32dafe22012-10-19 17:04:30 -0700347 LightsService lights, TwilightService twilight,
Jeff Brown7f3994e2012-12-04 14:04:28 -0800348 DisplayManagerService displayManager,
Jeff Brown9e316a12012-10-08 19:17:06 -0700349 DisplayBlanker displayBlanker,
Jeff Brown96307042012-07-27 15:51:34 -0700350 Callbacks callbacks, Handler callbackHandler) {
351 mHandler = new DisplayControllerHandler(looper);
352 mNotifier = notifier;
Jeff Brown9e316a12012-10-08 19:17:06 -0700353 mDisplayBlanker = displayBlanker;
Jeff Brown96307042012-07-27 15:51:34 -0700354 mCallbacks = callbacks;
355 mCallbackHandler = callbackHandler;
356
357 mLights = lights;
Jeff Brownaa202a62012-08-21 22:14:26 -0700358 mTwilight = twilight;
Jeff Brown96307042012-07-27 15:51:34 -0700359 mSensorManager = new SystemSensorManager(mHandler.getLooper());
Jeff Brown7f3994e2012-12-04 14:04:28 -0800360 mDisplayManager = displayManager;
Jeff Brown96307042012-07-27 15:51:34 -0700361
362 final Resources resources = context.getResources();
Jeff Brownb76eebff2012-10-05 22:26:44 -0700363
364 mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
365 com.android.internal.R.integer.config_screenBrightnessDim));
366
367 int screenBrightnessMinimum = Math.min(resources.getInteger(
368 com.android.internal.R.integer.config_screenBrightnessSettingMinimum),
369 mScreenBrightnessDimConfig);
370
Jeff Brown96307042012-07-27 15:51:34 -0700371 mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
372 com.android.internal.R.bool.config_automatic_brightness_available);
373 if (mUseSoftwareAutoBrightnessConfig) {
Jeff Brown1a30b552012-08-16 01:31:11 -0700374 int[] lux = resources.getIntArray(
Jeff Brown96307042012-07-27 15:51:34 -0700375 com.android.internal.R.array.config_autoBrightnessLevels);
Jeff Brown1a30b552012-08-16 01:31:11 -0700376 int[] screenBrightness = resources.getIntArray(
Jeff Brown96307042012-07-27 15:51:34 -0700377 com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
Jeff Brown1a30b552012-08-16 01:31:11 -0700378
379 mScreenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
380 if (mScreenAutoBrightnessSpline == null) {
Jeff Brown96307042012-07-27 15:51:34 -0700381 Slog.e(TAG, "Error in config.xml. config_autoBrightnessLcdBacklightValues "
Jeff Brown1a30b552012-08-16 01:31:11 -0700382 + "(size " + screenBrightness.length + ") "
383 + "must be monotic and have exactly one more entry than "
384 + "config_autoBrightnessLevels (size " + lux.length + ") "
385 + "which must be strictly increasing. "
Jeff Brown96307042012-07-27 15:51:34 -0700386 + "Auto-brightness will be disabled.");
387 mUseSoftwareAutoBrightnessConfig = false;
Jeff Brownb76eebff2012-10-05 22:26:44 -0700388 } else {
389 if (screenBrightness[0] < screenBrightnessMinimum) {
390 screenBrightnessMinimum = screenBrightness[0];
391 }
Jeff Brown96307042012-07-27 15:51:34 -0700392 }
393
394 mLightSensorWarmUpTimeConfig = resources.getInteger(
395 com.android.internal.R.integer.config_lightSensorWarmupTime);
396 }
397
Jeff Brownb76eebff2012-10-05 22:26:44 -0700398 mScreenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightnessMinimum);
399 mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
400
Jeff Brown252c2062012-10-08 16:21:01 -0700401 mElectronBeamFadesConfig = resources.getBoolean(
Jeff Browna52772f2012-10-04 18:38:09 -0700402 com.android.internal.R.bool.config_animateScreenLights);
403
Jeff Brown96307042012-07-27 15:51:34 -0700404 if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
405 mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
406 if (mProximitySensor != null) {
407 mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
408 TYPICAL_PROXIMITY_THRESHOLD);
409 }
410 }
411
412 if (mUseSoftwareAutoBrightnessConfig
413 && !DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
414 mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
415 }
Jeff Brownaa202a62012-08-21 22:14:26 -0700416
417 if (mUseSoftwareAutoBrightnessConfig && USE_TWILIGHT_ADJUSTMENT) {
418 mTwilight.registerListener(mTwilightListener, mHandler);
419 }
Jeff Brown96307042012-07-27 15:51:34 -0700420 }
421
Jeff Brown1a30b552012-08-16 01:31:11 -0700422 private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
423 try {
424 final int n = brightness.length;
425 float[] x = new float[n];
426 float[] y = new float[n];
Jeff Brownb76eebff2012-10-05 22:26:44 -0700427 y[0] = normalizeAbsoluteBrightness(brightness[0]);
Jeff Brown1a30b552012-08-16 01:31:11 -0700428 for (int i = 1; i < n; i++) {
429 x[i] = lux[i - 1];
Jeff Brownb76eebff2012-10-05 22:26:44 -0700430 y[i] = normalizeAbsoluteBrightness(brightness[i]);
Jeff Brown1a30b552012-08-16 01:31:11 -0700431 }
432
433 Spline spline = Spline.createMonotoneCubicSpline(x, y);
Jeff Brownb76eebff2012-10-05 22:26:44 -0700434 if (DEBUG) {
Jeff Brown1a30b552012-08-16 01:31:11 -0700435 Slog.d(TAG, "Auto-brightness spline: " + spline);
436 for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
437 Slog.d(TAG, String.format(" %7.1f: %7.1f", v, spline.interpolate(v)));
438 }
439 }
440 return spline;
441 } catch (IllegalArgumentException ex) {
442 Slog.e(TAG, "Could not create auto-brightness spline.", ex);
443 return null;
444 }
445 }
446
Jeff Brown96307042012-07-27 15:51:34 -0700447 /**
448 * Returns true if the proximity sensor screen-off function is available.
449 */
450 public boolean isProximitySensorAvailable() {
451 return mProximitySensor != null;
452 }
453
454 /**
455 * Requests a new power state.
456 * The controller makes a copy of the provided object and then
457 * begins adjusting the power state to match what was requested.
458 *
459 * @param request The requested power state.
460 * @param waitForNegativeProximity If true, issues a request to wait for
461 * negative proximity before turning the screen back on, assuming the screen
462 * was turned off by the proximity sensor.
463 * @return True if display is ready, false if there are important changes that must
464 * be made asynchronously (such as turning the screen on), in which case the caller
465 * should grab a wake lock, watch for {@link Callbacks#onStateChanged()} then try
466 * the request again later until the state converges.
467 */
468 public boolean requestPowerState(DisplayPowerRequest request,
469 boolean waitForNegativeProximity) {
470 if (DEBUG) {
471 Slog.d(TAG, "requestPowerState: "
472 + request + ", waitForNegativeProximity=" + waitForNegativeProximity);
473 }
474
475 synchronized (mLock) {
476 boolean changed = false;
477
478 if (waitForNegativeProximity
479 && !mPendingWaitForNegativeProximityLocked) {
480 mPendingWaitForNegativeProximityLocked = true;
481 changed = true;
482 }
483
484 if (mPendingRequestLocked == null) {
485 mPendingRequestLocked = new DisplayPowerRequest(request);
486 changed = true;
487 } else if (!mPendingRequestLocked.equals(request)) {
488 mPendingRequestLocked.copyFrom(request);
489 changed = true;
490 }
491
492 if (changed) {
493 mDisplayReadyLocked = false;
494 }
495
496 if (changed && !mPendingRequestChangedLocked) {
497 mPendingRequestChangedLocked = true;
498 sendUpdatePowerStateLocked();
499 }
500
501 return mDisplayReadyLocked;
502 }
503 }
504
505 private void sendUpdatePowerState() {
506 synchronized (mLock) {
507 sendUpdatePowerStateLocked();
508 }
509 }
510
511 private void sendUpdatePowerStateLocked() {
512 if (!mPendingUpdatePowerStateLocked) {
513 mPendingUpdatePowerStateLocked = true;
514 Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
515 msg.setAsynchronous(true);
516 mHandler.sendMessage(msg);
517 }
518 }
519
520 private void initialize() {
Jeff Browna52772f2012-10-04 18:38:09 -0700521 mPowerState = new DisplayPowerState(
Jeff Brown7f3994e2012-12-04 14:04:28 -0800522 new ElectronBeam(mDisplayManager), mDisplayBlanker,
Jeff Brown32dafe22012-10-19 17:04:30 -0700523 mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT));
Jeff Brown96307042012-07-27 15:51:34 -0700524
525 mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
526 mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
527 mElectronBeamOnAnimator.setDuration(ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS);
528 mElectronBeamOnAnimator.addListener(mAnimatorListener);
529
530 mElectronBeamOffAnimator = ObjectAnimator.ofFloat(
531 mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 1.0f, 0.0f);
532 mElectronBeamOffAnimator.setDuration(ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS);
533 mElectronBeamOffAnimator.addListener(mAnimatorListener);
534
535 mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
536 mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
537 }
538
539 private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
540 @Override
541 public void onAnimationStart(Animator animation) {
542 }
543 @Override
544 public void onAnimationEnd(Animator animation) {
545 sendUpdatePowerState();
546 }
547 @Override
548 public void onAnimationRepeat(Animator animation) {
549 }
550 @Override
551 public void onAnimationCancel(Animator animation) {
552 }
553 };
554
555 private void updatePowerState() {
556 // Update the power state request.
557 final boolean mustNotify;
558 boolean mustInitialize = false;
Jeff Brownaa202a62012-08-21 22:14:26 -0700559 boolean updateAutoBrightness = mTwilightChanged;
Jeff Browne941b1e2012-10-22 16:50:25 -0700560 boolean wasDim = false;
Jeff Brownaa202a62012-08-21 22:14:26 -0700561 mTwilightChanged = false;
Jeff Brown330560f2012-08-21 22:10:57 -0700562
Jeff Brown96307042012-07-27 15:51:34 -0700563 synchronized (mLock) {
564 mPendingUpdatePowerStateLocked = false;
565 if (mPendingRequestLocked == null) {
566 return; // wait until first actual power request
567 }
568
569 if (mPowerRequest == null) {
570 mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
571 mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
Jeff Brown6307a152012-08-20 13:24:23 -0700572 mPendingWaitForNegativeProximityLocked = false;
Jeff Brown96307042012-07-27 15:51:34 -0700573 mPendingRequestChangedLocked = false;
574 mustInitialize = true;
575 } else if (mPendingRequestChangedLocked) {
Jeff Brown330560f2012-08-21 22:10:57 -0700576 if (mPowerRequest.screenAutoBrightnessAdjustment
577 != mPendingRequestLocked.screenAutoBrightnessAdjustment) {
578 updateAutoBrightness = true;
579 }
Jeff Browne941b1e2012-10-22 16:50:25 -0700580 wasDim = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM);
Jeff Brown96307042012-07-27 15:51:34 -0700581 mPowerRequest.copyFrom(mPendingRequestLocked);
582 mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
Jeff Brown6307a152012-08-20 13:24:23 -0700583 mPendingWaitForNegativeProximityLocked = false;
Jeff Brown96307042012-07-27 15:51:34 -0700584 mPendingRequestChangedLocked = false;
585 mDisplayReadyLocked = false;
586 }
587
588 mustNotify = !mDisplayReadyLocked;
589 }
590
591 // Initialize things the first time the power state is changed.
592 if (mustInitialize) {
593 initialize();
594 }
595
Jeff Brown6307a152012-08-20 13:24:23 -0700596 // Apply the proximity sensor.
Jeff Brown96307042012-07-27 15:51:34 -0700597 if (mProximitySensor != null) {
Jeff Brown6307a152012-08-20 13:24:23 -0700598 if (mPowerRequest.useProximitySensor
599 && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
600 setProximitySensorEnabled(true);
601 if (!mScreenOffBecauseOfProximity
602 && mProximity == PROXIMITY_POSITIVE) {
603 mScreenOffBecauseOfProximity = true;
Jeff Brown93cbbb22012-10-04 13:18:36 -0700604 sendOnProximityPositive();
Jeff Brown6307a152012-08-20 13:24:23 -0700605 setScreenOn(false);
606 }
607 } else if (mWaitingForNegativeProximity
608 && mScreenOffBecauseOfProximity
609 && mProximity == PROXIMITY_POSITIVE
610 && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
611 setProximitySensorEnabled(true);
612 } else {
613 setProximitySensorEnabled(false);
614 mWaitingForNegativeProximity = false;
615 }
616 if (mScreenOffBecauseOfProximity
617 && mProximity != PROXIMITY_POSITIVE) {
Jeff Brown96307042012-07-27 15:51:34 -0700618 mScreenOffBecauseOfProximity = false;
619 sendOnProximityNegative();
620 }
Jeff Brown6307a152012-08-20 13:24:23 -0700621 } else {
622 mWaitingForNegativeProximity = false;
Jeff Brown96307042012-07-27 15:51:34 -0700623 }
624
625 // Turn on the light sensor if needed.
626 if (mLightSensor != null) {
627 setLightSensorEnabled(mPowerRequest.useAutoBrightness
Jeff Brown330560f2012-08-21 22:10:57 -0700628 && wantScreenOn(mPowerRequest.screenState), updateAutoBrightness);
Jeff Brown96307042012-07-27 15:51:34 -0700629 }
630
631 // Set the screen brightness.
Jeff Brownb76eebff2012-10-05 22:26:44 -0700632 if (wantScreenOn(mPowerRequest.screenState)) {
633 int target;
634 boolean slow;
Jeff Brown96307042012-07-27 15:51:34 -0700635 if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) {
636 // Use current auto-brightness value.
Jeff Brownb76eebff2012-10-05 22:26:44 -0700637 target = mScreenAutoBrightness;
638 slow = mUsingScreenAutoBrightness;
Jeff Brown96307042012-07-27 15:51:34 -0700639 mUsingScreenAutoBrightness = true;
640 } else {
641 // Light sensor is disabled or not ready yet.
642 // Use the current brightness setting from the request, which is expected
643 // provide a nominal default value for the case where auto-brightness
644 // is not ready yet.
Jeff Brownb76eebff2012-10-05 22:26:44 -0700645 target = mPowerRequest.screenBrightness;
646 slow = false;
Jeff Brown96307042012-07-27 15:51:34 -0700647 mUsingScreenAutoBrightness = false;
648 }
Jeff Brownb76eebff2012-10-05 22:26:44 -0700649 if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
Jeff Brown5244c932012-10-24 14:46:26 -0700650 // Dim quickly by at least some minimum amount.
Jeff Brownb76eebff2012-10-05 22:26:44 -0700651 target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
652 mScreenBrightnessDimConfig);
Jeff Brown5244c932012-10-24 14:46:26 -0700653 slow = false;
Jeff Browne941b1e2012-10-22 16:50:25 -0700654 } else if (wasDim) {
655 // Brighten quickly.
Jeff Brownb76eebff2012-10-05 22:26:44 -0700656 slow = false;
657 }
658 animateScreenBrightness(clampScreenBrightness(target),
659 slow ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
Jeff Brown96307042012-07-27 15:51:34 -0700660 } else {
661 // Screen is off. Don't bother changing the brightness.
662 mUsingScreenAutoBrightness = false;
663 }
664
665 // Animate the screen on or off.
666 if (!mScreenOffBecauseOfProximity) {
667 if (wantScreenOn(mPowerRequest.screenState)) {
668 // Want screen on.
669 // Wait for previous off animation to complete beforehand.
670 // It is relatively short but if we cancel it and switch to the
671 // on animation immediately then the results are pretty ugly.
672 if (!mElectronBeamOffAnimator.isStarted()) {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700673 // Turn the screen on. The contents of the screen may not yet
674 // be visible if the electron beam has not been dismissed because
675 // its last frame of animation is solid black.
676 setScreenOn(true);
677
678 if (mPowerRequest.blockScreenOn
679 && mPowerState.getElectronBeamLevel() == 0.0f) {
680 blockScreenOn();
Jeff Brown13c589b2012-08-16 16:20:54 -0700681 } else {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700682 unblockScreenOn();
Jeff Brownc38c9be2012-10-04 13:16:19 -0700683 if (USE_ELECTRON_BEAM_ON_ANIMATION) {
684 if (!mElectronBeamOnAnimator.isStarted()) {
685 if (mPowerState.getElectronBeamLevel() == 1.0f) {
686 mPowerState.dismissElectronBeam();
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700687 } else if (mPowerState.prepareElectronBeam(
Jeff Brown252c2062012-10-08 16:21:01 -0700688 mElectronBeamFadesConfig ?
689 ElectronBeam.MODE_FADE :
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700690 ElectronBeam.MODE_WARM_UP)) {
Jeff Brownc38c9be2012-10-04 13:16:19 -0700691 mElectronBeamOnAnimator.start();
692 } else {
693 mElectronBeamOnAnimator.end();
694 }
695 }
696 } else {
697 mPowerState.setElectronBeamLevel(1.0f);
698 mPowerState.dismissElectronBeam();
699 }
700 }
Jeff Brown96307042012-07-27 15:51:34 -0700701 }
702 } else {
703 // Want screen off.
704 // Wait for previous on animation to complete beforehand.
705 if (!mElectronBeamOnAnimator.isStarted()) {
706 if (!mElectronBeamOffAnimator.isStarted()) {
707 if (mPowerState.getElectronBeamLevel() == 0.0f) {
708 setScreenOn(false);
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700709 } else if (mPowerState.prepareElectronBeam(
Jeff Brown252c2062012-10-08 16:21:01 -0700710 mElectronBeamFadesConfig ?
711 ElectronBeam.MODE_FADE :
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700712 ElectronBeam.MODE_COOL_DOWN)
Jeff Brown96307042012-07-27 15:51:34 -0700713 && mPowerState.isScreenOn()) {
714 mElectronBeamOffAnimator.start();
715 } else {
716 mElectronBeamOffAnimator.end();
717 }
718 }
719 }
720 }
721 }
722
723 // Report whether the display is ready for use.
724 // We mostly care about the screen state here, ignoring brightness changes
725 // which will be handled asynchronously.
726 if (mustNotify
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700727 && !mScreenOnWasBlocked
Jeff Brown96307042012-07-27 15:51:34 -0700728 && !mElectronBeamOnAnimator.isStarted()
729 && !mElectronBeamOffAnimator.isStarted()
730 && mPowerState.waitUntilClean(mCleanListener)) {
731 synchronized (mLock) {
732 if (!mPendingRequestChangedLocked) {
733 mDisplayReadyLocked = true;
Jeff Brownc38c9be2012-10-04 13:16:19 -0700734
735 if (DEBUG) {
736 Slog.d(TAG, "Display ready!");
737 }
Jeff Brown96307042012-07-27 15:51:34 -0700738 }
739 }
740 sendOnStateChanged();
741 }
742 }
743
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700744 private void blockScreenOn() {
745 if (!mScreenOnWasBlocked) {
746 mScreenOnWasBlocked = true;
747 if (DEBUG) {
748 Slog.d(TAG, "Blocked screen on.");
749 mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
750 }
751 }
752 }
753
754 private void unblockScreenOn() {
755 if (mScreenOnWasBlocked) {
756 mScreenOnWasBlocked = false;
757 if (DEBUG) {
758 Slog.d(TAG, "Unblocked screen on after " +
759 (SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime) + " ms");
760 }
761 }
762 }
763
Jeff Brown96307042012-07-27 15:51:34 -0700764 private void setScreenOn(boolean on) {
765 if (!mPowerState.isScreenOn() == on) {
766 mPowerState.setScreenOn(on);
767 if (on) {
768 mNotifier.onScreenOn();
769 } else {
770 mNotifier.onScreenOff();
771 }
772 }
773 }
774
Jeff Brown330560f2012-08-21 22:10:57 -0700775 private int clampScreenBrightness(int value) {
Jeff Brownb76eebff2012-10-05 22:26:44 -0700776 return clamp(value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
777 }
778
779 private static int clampAbsoluteBrightness(int value) {
780 return clamp(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
781 }
782
783 private static int clamp(int value, int min, int max) {
784 if (value <= min) {
785 return min;
786 }
787 if (value >= max) {
788 return max;
789 }
790 return value;
791 }
792
793 private static float normalizeAbsoluteBrightness(int value) {
794 return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
Jeff Brown330560f2012-08-21 22:10:57 -0700795 }
796
Jeff Brown96307042012-07-27 15:51:34 -0700797 private void animateScreenBrightness(int target, int rate) {
798 if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
799 mNotifier.onScreenBrightness(target);
800 }
801 }
802
803 private final Runnable mCleanListener = new Runnable() {
804 @Override
805 public void run() {
806 sendUpdatePowerState();
807 }
808 };
809
810 private void setProximitySensorEnabled(boolean enable) {
811 if (enable) {
812 if (!mProximitySensorEnabled) {
813 mProximitySensorEnabled = true;
814 mPendingProximity = PROXIMITY_UNKNOWN;
815 mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
816 SensorManager.SENSOR_DELAY_NORMAL, mHandler);
817 }
818 } else {
819 if (mProximitySensorEnabled) {
820 mProximitySensorEnabled = false;
821 mProximity = PROXIMITY_UNKNOWN;
822 mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
823 mSensorManager.unregisterListener(mProximitySensorListener);
824 }
825 }
826 }
827
828 private void handleProximitySensorEvent(long time, boolean positive) {
829 if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
830 return; // no change
831 }
832 if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
833 return; // no change
834 }
835
836 // Only accept a proximity sensor reading if it remains
837 // stable for the entire debounce delay.
838 mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
Jeff Brown93cbbb22012-10-04 13:18:36 -0700839 if (positive) {
840 mPendingProximity = PROXIMITY_POSITIVE;
841 mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY;
842 } else {
843 mPendingProximity = PROXIMITY_NEGATIVE;
844 mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY;
845 }
Jeff Brown96307042012-07-27 15:51:34 -0700846 debounceProximitySensor();
847 }
848
849 private void debounceProximitySensor() {
850 if (mPendingProximity != PROXIMITY_UNKNOWN) {
851 final long now = SystemClock.uptimeMillis();
852 if (mPendingProximityDebounceTime <= now) {
853 mProximity = mPendingProximity;
854 sendUpdatePowerState();
855 } else {
856 Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
857 msg.setAsynchronous(true);
858 mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
859 }
860 }
861 }
862
Jeff Brown330560f2012-08-21 22:10:57 -0700863 private void setLightSensorEnabled(boolean enable, boolean updateAutoBrightness) {
Jeff Brown96307042012-07-27 15:51:34 -0700864 if (enable) {
865 if (!mLightSensorEnabled) {
Jeff Brown330560f2012-08-21 22:10:57 -0700866 updateAutoBrightness = true;
Jeff Brown96307042012-07-27 15:51:34 -0700867 mLightSensorEnabled = true;
868 mLightSensorEnableTime = SystemClock.uptimeMillis();
869 mSensorManager.registerListener(mLightSensorListener, mLightSensor,
Jeff Browne941b1e2012-10-22 16:50:25 -0700870 LIGHT_SENSOR_RATE_MILLIS * 1000, mHandler);
Jeff Brown96307042012-07-27 15:51:34 -0700871 }
872 } else {
873 if (mLightSensorEnabled) {
874 mLightSensorEnabled = false;
Jeff Brown4f0e9692012-10-18 16:14:16 -0700875 mAmbientLuxValid = false;
876 mRecentLightSamples = 0;
Jeff Brown96307042012-07-27 15:51:34 -0700877 mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
878 mSensorManager.unregisterListener(mLightSensorListener);
879 }
880 }
Jeff Brown330560f2012-08-21 22:10:57 -0700881 if (updateAutoBrightness) {
882 updateAutoBrightness(false);
883 }
Jeff Brown96307042012-07-27 15:51:34 -0700884 }
885
886 private void handleLightSensorEvent(long time, float lux) {
Jeff Browne941b1e2012-10-22 16:50:25 -0700887 mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
888
889 applyLightSensorMeasurement(time, lux);
890 updateAmbientLux(time);
891 }
892
893 private void applyLightSensorMeasurement(long time, float lux) {
Jeff Brown4f0e9692012-10-18 16:14:16 -0700894 // Update our filters.
Jeff Brown96307042012-07-27 15:51:34 -0700895 mRecentLightSamples += 1;
Jeff Brown4f0e9692012-10-18 16:14:16 -0700896 if (mRecentLightSamples == 1) {
897 mRecentShortTermAverageLux = lux;
898 mRecentLongTermAverageLux = lux;
899 } else {
900 final long timeDelta = time - mLastObservedLuxTime;
901 mRecentShortTermAverageLux += (lux - mRecentShortTermAverageLux)
902 * timeDelta / (SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
903 mRecentLongTermAverageLux += (lux - mRecentLongTermAverageLux)
904 * timeDelta / (LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
905 }
906
907 // Remember this sample value.
908 mLastObservedLux = lux;
909 mLastObservedLuxTime = time;
Jeff Brown96307042012-07-27 15:51:34 -0700910 }
911
Jeff Brown4f0e9692012-10-18 16:14:16 -0700912 private void updateAmbientLux(long time) {
913 // If the light sensor was just turned on then immediately update our initial
914 // estimate of the current ambient light level.
915 if (!mAmbientLuxValid
916 || (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) {
Jeff Brown4f0e9692012-10-18 16:14:16 -0700917 mAmbientLux = mRecentShortTermAverageLux;
918 mAmbientLuxValid = true;
Jeff Browne941b1e2012-10-22 16:50:25 -0700919 mDebounceLuxDirection = 0;
920 mDebounceLuxTime = time;
921 if (DEBUG) {
922 Slog.d(TAG, "updateAmbientLux: Initializing: "
923 + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
924 + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
925 + ", mAmbientLux=" + mAmbientLux);
926 }
Jeff Brown4f0e9692012-10-18 16:14:16 -0700927 updateAutoBrightness(true);
928 return;
929 }
Jeff Brown96307042012-07-27 15:51:34 -0700930
Jeff Brown4f0e9692012-10-18 16:14:16 -0700931 // Determine whether the ambient environment appears to be brightening.
Jeff Browne941b1e2012-10-22 16:50:25 -0700932 float brighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
933 if (mRecentShortTermAverageLux > brighteningLuxThreshold
934 && mRecentLongTermAverageLux > brighteningLuxThreshold) {
935 if (mDebounceLuxDirection <= 0) {
936 mDebounceLuxDirection = 1;
937 mDebounceLuxTime = time;
938 if (DEBUG) {
939 Slog.d(TAG, "updateAmbientLux: Possibly brightened, waiting for "
940 + BRIGHTENING_LIGHT_DEBOUNCE + " ms: "
941 + "brighteningLuxThreshold=" + brighteningLuxThreshold
942 + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
943 + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
944 + ", mAmbientLux=" + mAmbientLux);
945 }
946 }
947 long debounceTime = mDebounceLuxTime + BRIGHTENING_LIGHT_DEBOUNCE;
Jeff Brown4f0e9692012-10-18 16:14:16 -0700948 if (time >= debounceTime) {
Jeff Browne941b1e2012-10-22 16:50:25 -0700949 mAmbientLux = mRecentShortTermAverageLux;
Jeff Brown96307042012-07-27 15:51:34 -0700950 if (DEBUG) {
Jeff Brown4f0e9692012-10-18 16:14:16 -0700951 Slog.d(TAG, "updateAmbientLux: Brightened: "
Jeff Browne941b1e2012-10-22 16:50:25 -0700952 + "brighteningLuxThreshold=" + brighteningLuxThreshold
Jeff Brown4f0e9692012-10-18 16:14:16 -0700953 + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
Jeff Browne941b1e2012-10-22 16:50:25 -0700954 + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
955 + ", mAmbientLux=" + mAmbientLux);
Jeff Brown96307042012-07-27 15:51:34 -0700956 }
Jeff Brown96307042012-07-27 15:51:34 -0700957 updateAutoBrightness(true);
Jeff Brown96307042012-07-27 15:51:34 -0700958 } else {
Jeff Brown4f0e9692012-10-18 16:14:16 -0700959 mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
960 }
961 return;
962 }
963
964 // Determine whether the ambient environment appears to be darkening.
Jeff Browne941b1e2012-10-22 16:50:25 -0700965 float darkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
966 if (mRecentShortTermAverageLux < darkeningLuxThreshold
967 && mRecentLongTermAverageLux < darkeningLuxThreshold) {
968 if (mDebounceLuxDirection >= 0) {
969 mDebounceLuxDirection = -1;
970 mDebounceLuxTime = time;
971 if (DEBUG) {
972 Slog.d(TAG, "updateAmbientLux: Possibly darkened, waiting for "
973 + DARKENING_LIGHT_DEBOUNCE + " ms: "
974 + "darkeningLuxThreshold=" + darkeningLuxThreshold
975 + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
976 + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
977 + ", mAmbientLux=" + mAmbientLux);
978 }
979 }
980 long debounceTime = mDebounceLuxTime + DARKENING_LIGHT_DEBOUNCE;
Jeff Brown4f0e9692012-10-18 16:14:16 -0700981 if (time >= debounceTime) {
Jeff Browne941b1e2012-10-22 16:50:25 -0700982 // Be conservative about reducing the brightness, only reduce it a little bit
983 // at a time to avoid having to bump it up again soon.
984 mAmbientLux = Math.max(mRecentShortTermAverageLux, mRecentLongTermAverageLux);
Jeff Brown4f0e9692012-10-18 16:14:16 -0700985 if (DEBUG) {
986 Slog.d(TAG, "updateAmbientLux: Darkened: "
Jeff Browne941b1e2012-10-22 16:50:25 -0700987 + "darkeningLuxThreshold=" + darkeningLuxThreshold
Jeff Brown4f0e9692012-10-18 16:14:16 -0700988 + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
Jeff Browne941b1e2012-10-22 16:50:25 -0700989 + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
990 + ", mAmbientLux=" + mAmbientLux);
Jeff Brown4f0e9692012-10-18 16:14:16 -0700991 }
Jeff Brown4f0e9692012-10-18 16:14:16 -0700992 updateAutoBrightness(true);
993 } else {
994 mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
Jeff Brown96307042012-07-27 15:51:34 -0700995 }
Jeff Browne941b1e2012-10-22 16:50:25 -0700996 return;
997 }
998
999 // No change or change is within the hysteresis thresholds.
1000 if (mDebounceLuxDirection != 0) {
1001 mDebounceLuxDirection = 0;
1002 mDebounceLuxTime = time;
1003 if (DEBUG) {
1004 Slog.d(TAG, "updateAmbientLux: Canceled debounce: "
1005 + "brighteningLuxThreshold=" + brighteningLuxThreshold
1006 + ", darkeningLuxThreshold=" + darkeningLuxThreshold
1007 + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
1008 + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
1009 + ", mAmbientLux=" + mAmbientLux);
1010 }
1011 }
1012
1013 // If the light level does not change, then the sensor may not report
1014 // a new value. This can cause problems for the auto-brightness algorithm
1015 // because the filters might not be updated. To work around it, we want to
1016 // make sure to update the filters whenever the observed light level could
1017 // possibly exceed one of the hysteresis thresholds.
1018 if (mLastObservedLux > brighteningLuxThreshold
1019 || mLastObservedLux < darkeningLuxThreshold) {
1020 mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED,
1021 time + SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS);
Jeff Brown96307042012-07-27 15:51:34 -07001022 }
1023 }
1024
Jeff Brown4f0e9692012-10-18 16:14:16 -07001025 private void debounceLightSensor() {
Jeff Browne941b1e2012-10-22 16:50:25 -07001026 if (mLightSensorEnabled) {
1027 long time = SystemClock.uptimeMillis();
1028 if (time >= mLastObservedLuxTime + SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS) {
1029 if (DEBUG) {
1030 Slog.d(TAG, "debounceLightSensor: Synthesizing light sensor measurement "
1031 + "after " + (time - mLastObservedLuxTime) + " ms.");
1032 }
1033 applyLightSensorMeasurement(time, mLastObservedLux);
1034 }
1035 updateAmbientLux(time);
1036 }
Jeff Brown4f0e9692012-10-18 16:14:16 -07001037 }
1038
Jeff Brown96307042012-07-27 15:51:34 -07001039 private void updateAutoBrightness(boolean sendUpdate) {
Jeff Brown4f0e9692012-10-18 16:14:16 -07001040 if (!mAmbientLuxValid) {
Jeff Brown96307042012-07-27 15:51:34 -07001041 return;
1042 }
1043
Jeff Brown4f0e9692012-10-18 16:14:16 -07001044 float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);
Jeff Brown330560f2012-08-21 22:10:57 -07001045 float gamma = 1.0f;
1046
1047 if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
1048 && mPowerRequest.screenAutoBrightnessAdjustment != 0.0f) {
1049 final float adjGamma = FloatMath.pow(SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA,
1050 Math.min(1.0f, Math.max(-1.0f,
1051 -mPowerRequest.screenAutoBrightnessAdjustment)));
1052 gamma *= adjGamma;
1053 if (DEBUG) {
1054 Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma);
1055 }
1056 }
1057
Jeff Brownaa202a62012-08-21 22:14:26 -07001058 if (USE_TWILIGHT_ADJUSTMENT) {
1059 TwilightState state = mTwilight.getCurrentState();
1060 if (state != null && state.isNight()) {
1061 final long now = System.currentTimeMillis();
1062 final float earlyGamma =
1063 getTwilightGamma(now, state.getYesterdaySunset(), state.getTodaySunrise());
1064 final float lateGamma =
1065 getTwilightGamma(now, state.getTodaySunset(), state.getTomorrowSunrise());
1066 gamma *= earlyGamma * lateGamma;
1067 if (DEBUG) {
1068 Slog.d(TAG, "updateAutoBrightness: earlyGamma=" + earlyGamma
1069 + ", lateGamma=" + lateGamma);
1070 }
1071 }
1072 }
1073
Jeff Brown330560f2012-08-21 22:10:57 -07001074 if (gamma != 1.0f) {
1075 final float in = value;
1076 value = FloatMath.pow(value, gamma);
1077 if (DEBUG) {
1078 Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma
1079 + ", in=" + in + ", out=" + value);
1080 }
1081 }
1082
1083 int newScreenAutoBrightness = clampScreenBrightness(
Jeff Brown4f0e9692012-10-18 16:14:16 -07001084 Math.round(value * PowerManager.BRIGHTNESS_ON));
Jeff Brown96307042012-07-27 15:51:34 -07001085 if (mScreenAutoBrightness != newScreenAutoBrightness) {
1086 if (DEBUG) {
1087 Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
Jeff Brown330560f2012-08-21 22:10:57 -07001088 + mScreenAutoBrightness + ", newScreenAutoBrightness="
Jeff Brown1a30b552012-08-16 01:31:11 -07001089 + newScreenAutoBrightness);
Jeff Brown96307042012-07-27 15:51:34 -07001090 }
1091
1092 mScreenAutoBrightness = newScreenAutoBrightness;
Jeff Brown330560f2012-08-21 22:10:57 -07001093 mLastScreenAutoBrightnessGamma = gamma;
Jeff Brown96307042012-07-27 15:51:34 -07001094 if (sendUpdate) {
1095 sendUpdatePowerState();
1096 }
1097 }
1098 }
1099
Jeff Brownaa202a62012-08-21 22:14:26 -07001100 private static float getTwilightGamma(long now, long lastSunset, long nextSunrise) {
1101 if (lastSunset < 0 || nextSunrise < 0
1102 || now < lastSunset || now > nextSunrise) {
1103 return 1.0f;
1104 }
1105
1106 if (now < lastSunset + TWILIGHT_ADJUSTMENT_TIME) {
1107 return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
1108 (float)(now - lastSunset) / TWILIGHT_ADJUSTMENT_TIME);
1109 }
1110
1111 if (now > nextSunrise - TWILIGHT_ADJUSTMENT_TIME) {
1112 return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
1113 (float)(nextSunrise - now) / TWILIGHT_ADJUSTMENT_TIME);
1114 }
1115
1116 return TWILIGHT_ADJUSTMENT_MAX_GAMMA;
1117 }
1118
1119 private static float lerp(float x, float y, float alpha) {
1120 return x + (y - x) * alpha;
1121 }
1122
Jeff Brown96307042012-07-27 15:51:34 -07001123 private void sendOnStateChanged() {
1124 mCallbackHandler.post(mOnStateChangedRunnable);
1125 }
1126
1127 private final Runnable mOnStateChangedRunnable = new Runnable() {
1128 @Override
1129 public void run() {
1130 mCallbacks.onStateChanged();
1131 }
1132 };
1133
Jeff Brown93cbbb22012-10-04 13:18:36 -07001134 private void sendOnProximityPositive() {
1135 mCallbackHandler.post(mOnProximityPositiveRunnable);
1136 }
1137
1138 private final Runnable mOnProximityPositiveRunnable = new Runnable() {
1139 @Override
1140 public void run() {
1141 mCallbacks.onProximityPositive();
1142 }
1143 };
1144
Jeff Brown96307042012-07-27 15:51:34 -07001145 private void sendOnProximityNegative() {
1146 mCallbackHandler.post(mOnProximityNegativeRunnable);
1147 }
1148
1149 private final Runnable mOnProximityNegativeRunnable = new Runnable() {
1150 @Override
1151 public void run() {
1152 mCallbacks.onProximityNegative();
1153 }
1154 };
1155
Jeff Brownbd6e1502012-08-28 03:27:37 -07001156 public void dump(final PrintWriter pw) {
Jeff Brown96307042012-07-27 15:51:34 -07001157 synchronized (mLock) {
1158 pw.println();
1159 pw.println("Display Controller Locked State:");
1160 pw.println(" mDisplayReadyLocked=" + mDisplayReadyLocked);
1161 pw.println(" mPendingRequestLocked=" + mPendingRequestLocked);
1162 pw.println(" mPendingRequestChangedLocked=" + mPendingRequestChangedLocked);
1163 pw.println(" mPendingWaitForNegativeProximityLocked="
1164 + mPendingWaitForNegativeProximityLocked);
1165 pw.println(" mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked);
1166 }
1167
1168 pw.println();
1169 pw.println("Display Controller Configuration:");
1170 pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
Jeff Brownb76eebff2012-10-05 22:26:44 -07001171 pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
1172 pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
Jeff Brown96307042012-07-27 15:51:34 -07001173 pw.println(" mUseSoftwareAutoBrightnessConfig="
1174 + mUseSoftwareAutoBrightnessConfig);
Jeff Brown1a30b552012-08-16 01:31:11 -07001175 pw.println(" mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline);
Jeff Brown96307042012-07-27 15:51:34 -07001176 pw.println(" mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
1177
Jeff Brownbd6e1502012-08-28 03:27:37 -07001178 mHandler.runWithScissors(new Runnable() {
1179 @Override
1180 public void run() {
1181 dumpLocal(pw);
Jeff Brown96307042012-07-27 15:51:34 -07001182 }
Jeff Brown4ed8fe72012-08-30 18:18:29 -07001183 }, 1000);
Jeff Brown96307042012-07-27 15:51:34 -07001184 }
1185
1186 private void dumpLocal(PrintWriter pw) {
1187 pw.println();
1188 pw.println("Display Controller Thread State:");
1189 pw.println(" mPowerRequest=" + mPowerRequest);
1190 pw.println(" mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
1191
1192 pw.println(" mProximitySensor=" + mProximitySensor);
1193 pw.println(" mProximitySensorEnabled=" + mProximitySensorEnabled);
1194 pw.println(" mProximityThreshold=" + mProximityThreshold);
1195 pw.println(" mProximity=" + proximityToString(mProximity));
1196 pw.println(" mPendingProximity=" + proximityToString(mPendingProximity));
1197 pw.println(" mPendingProximityDebounceTime="
1198 + TimeUtils.formatUptime(mPendingProximityDebounceTime));
1199 pw.println(" mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
1200
1201 pw.println(" mLightSensor=" + mLightSensor);
1202 pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
1203 pw.println(" mLightSensorEnableTime="
1204 + TimeUtils.formatUptime(mLightSensorEnableTime));
Jeff Brown4f0e9692012-10-18 16:14:16 -07001205 pw.println(" mAmbientLux=" + mAmbientLux);
1206 pw.println(" mAmbientLuxValid=" + mAmbientLuxValid);
Jeff Brown4f0e9692012-10-18 16:14:16 -07001207 pw.println(" mLastObservedLux=" + mLastObservedLux);
1208 pw.println(" mLastObservedLuxTime="
1209 + TimeUtils.formatUptime(mLastObservedLuxTime));
Jeff Brown96307042012-07-27 15:51:34 -07001210 pw.println(" mRecentLightSamples=" + mRecentLightSamples);
Jeff Brown4f0e9692012-10-18 16:14:16 -07001211 pw.println(" mRecentShortTermAverageLux=" + mRecentShortTermAverageLux);
1212 pw.println(" mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
Jeff Browne941b1e2012-10-22 16:50:25 -07001213 pw.println(" mDebounceLuxDirection=" + mDebounceLuxDirection);
1214 pw.println(" mDebounceLuxTime=" + TimeUtils.formatUptime(mDebounceLuxTime));
Jeff Brown96307042012-07-27 15:51:34 -07001215 pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
1216 pw.println(" mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
Jeff Brown330560f2012-08-21 22:10:57 -07001217 pw.println(" mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
Jeff Brownaa202a62012-08-21 22:14:26 -07001218 pw.println(" mTwilight.getCurrentState()=" + mTwilight.getCurrentState());
Jeff Brown96307042012-07-27 15:51:34 -07001219
1220 if (mElectronBeamOnAnimator != null) {
1221 pw.println(" mElectronBeamOnAnimator.isStarted()=" +
1222 mElectronBeamOnAnimator.isStarted());
1223 }
1224 if (mElectronBeamOffAnimator != null) {
1225 pw.println(" mElectronBeamOffAnimator.isStarted()=" +
1226 mElectronBeamOffAnimator.isStarted());
1227 }
1228
1229 if (mPowerState != null) {
1230 mPowerState.dump(pw);
1231 }
1232 }
1233
1234 private static String proximityToString(int state) {
1235 switch (state) {
1236 case PROXIMITY_UNKNOWN:
1237 return "Unknown";
1238 case PROXIMITY_NEGATIVE:
1239 return "Negative";
1240 case PROXIMITY_POSITIVE:
1241 return "Positive";
1242 default:
1243 return Integer.toString(state);
1244 }
1245 }
1246
1247 private static boolean wantScreenOn(int state) {
1248 switch (state) {
1249 case DisplayPowerRequest.SCREEN_STATE_BRIGHT:
1250 case DisplayPowerRequest.SCREEN_STATE_DIM:
1251 return true;
1252 }
1253 return false;
1254 }
1255
1256 /**
1257 * Asynchronous callbacks from the power controller to the power manager service.
1258 */
1259 public interface Callbacks {
1260 void onStateChanged();
Jeff Brown93cbbb22012-10-04 13:18:36 -07001261 void onProximityPositive();
Jeff Brown96307042012-07-27 15:51:34 -07001262 void onProximityNegative();
1263 }
1264
1265 private final class DisplayControllerHandler extends Handler {
1266 public DisplayControllerHandler(Looper looper) {
Jeff Browna2910d02012-08-25 12:29:46 -07001267 super(looper, null, true /*async*/);
Jeff Brown96307042012-07-27 15:51:34 -07001268 }
1269
1270 @Override
1271 public void handleMessage(Message msg) {
1272 switch (msg.what) {
1273 case MSG_UPDATE_POWER_STATE:
1274 updatePowerState();
1275 break;
1276
1277 case MSG_PROXIMITY_SENSOR_DEBOUNCED:
1278 debounceProximitySensor();
1279 break;
1280
1281 case MSG_LIGHT_SENSOR_DEBOUNCED:
1282 debounceLightSensor();
1283 break;
1284 }
1285 }
1286 }
1287
1288 private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
1289 @Override
1290 public void onSensorChanged(SensorEvent event) {
1291 if (mProximitySensorEnabled) {
1292 final long time = SystemClock.uptimeMillis();
1293 final float distance = event.values[0];
1294 boolean positive = distance >= 0.0f && distance < mProximityThreshold;
1295 handleProximitySensorEvent(time, positive);
1296 }
1297 }
1298
1299 @Override
1300 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1301 // Not used.
1302 }
1303 };
1304
1305 private final SensorEventListener mLightSensorListener = new SensorEventListener() {
1306 @Override
1307 public void onSensorChanged(SensorEvent event) {
1308 if (mLightSensorEnabled) {
1309 final long time = SystemClock.uptimeMillis();
1310 final float lux = event.values[0];
1311 handleLightSensorEvent(time, lux);
1312 }
1313 }
1314
1315 @Override
1316 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1317 // Not used.
1318 }
1319 };
Jeff Brownaa202a62012-08-21 22:14:26 -07001320
1321 private final TwilightService.TwilightListener mTwilightListener =
1322 new TwilightService.TwilightListener() {
1323 @Override
1324 public void onTwilightStateChanged() {
1325 mTwilightChanged = true;
1326 updatePowerState();
1327 }
1328 };
Jeff Brown96307042012-07-27 15:51:34 -07001329}