blob: 317fec05d41ad80473c1f7f96e0a25473f28c813 [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 Brown96307042012-07-27 15:51:34 -070022
23import android.animation.Animator;
24import android.animation.ObjectAnimator;
25import android.content.Context;
26import android.content.res.Resources;
27import android.hardware.Sensor;
28import android.hardware.SensorEvent;
29import android.hardware.SensorEventListener;
30import android.hardware.SensorManager;
31import android.hardware.SystemSensorManager;
Jeff Brown98365d72012-08-19 20:30:52 -070032import android.hardware.display.DisplayManager;
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;
Jeff Brown98365d72012-08-19 20:30:52 -070043import android.view.Display;
Jeff Brown96307042012-07-27 15:51:34 -070044
45import java.io.PrintWriter;
Jeff Brown96307042012-07-27 15:51:34 -070046
47/**
48 * Controls the power state of the display.
49 *
50 * Handles the proximity sensor, light sensor, and animations between states
51 * including the screen off animation.
52 *
53 * This component acts independently of the rest of the power manager service.
54 * In particular, it does not share any state and it only communicates
55 * via asynchronous callbacks to inform the power manager that something has
56 * changed.
57 *
58 * Everything this class does internally is serialized on its handler although
59 * it may be accessed by other threads from the outside.
60 *
61 * Note that the power manager service guarantees that it will hold a suspend
62 * blocker as long as the display is not ready. So most of the work done here
63 * does not need to worry about holding a suspend blocker unless it happens
64 * independently of the display ready signal.
65 *
66 * For debugging, you can make the electron beam and brightness animations run
67 * slower by changing the "animator duration scale" option in Development Settings.
68 */
69final class DisplayPowerController {
70 private static final String TAG = "DisplayPowerController";
71
72 private static boolean DEBUG = false;
73 private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
74 private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
75
Jeff Brown13c589b2012-08-16 16:20:54 -070076 // If true, uses the electron beam on animation.
77 // We might want to turn this off if we cannot get a guarantee that the screen
78 // actually turns on and starts showing new content after the call to set the
Jeff Brown5356c7dc2012-08-20 20:17:36 -070079 // screen state returns. Playing the animation can also be somewhat slow.
80 private static final boolean USE_ELECTRON_BEAM_ON_ANIMATION = false;
Jeff Brown13c589b2012-08-16 16:20:54 -070081
Jeff Brown330560f2012-08-21 22:10:57 -070082 // If true, enables the use of the screen auto-brightness adjustment setting.
Jeff Brown631938f2012-09-08 15:11:11 -070083 private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT =
84 PowerManager.useScreenAutoBrightnessAdjustmentFeature();
Jeff Brown330560f2012-08-21 22:10:57 -070085
86 // The maximum range of gamma adjustment possible using the screen
87 // auto-brightness adjustment setting.
88 private static final float SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA = 3.0f;
89
Jeff Brownb76eebff2012-10-05 22:26:44 -070090 // The minimum reduction in brightness when dimmed.
91 private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
92
Jeff Brownaa202a62012-08-21 22:14:26 -070093 // If true, enables the use of the current time as an auto-brightness adjustment.
94 // The basic idea here is to expand the dynamic range of auto-brightness
95 // when it is especially dark outside. The light sensor tends to perform
96 // poorly at low light levels so we compensate for it by making an
97 // assumption about the environment.
Jeff Browndb212842012-10-01 14:33:09 -070098 private static final boolean USE_TWILIGHT_ADJUSTMENT =
99 PowerManager.useTwilightAdjustmentFeature();
Jeff Brownaa202a62012-08-21 22:14:26 -0700100
101 // Specifies the maximum magnitude of the time of day adjustment.
102 private static final float TWILIGHT_ADJUSTMENT_MAX_GAMMA = 1.5f;
103
104 // The amount of time after or before sunrise over which to start adjusting
105 // the gamma. We want the change to happen gradually so that it is below the
106 // threshold of perceptibility and so that the adjustment has maximum effect
107 // well after dusk.
108 private static final long TWILIGHT_ADJUSTMENT_TIME = DateUtils.HOUR_IN_MILLIS * 2;
109
Jeff Brown00a8f4f2012-08-21 23:11:46 -0700110 private static final int ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS = 250;
Jeff Brown3c584f22012-10-10 14:36:00 -0700111 private static final int ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS = 400;
Jeff Brown96307042012-07-27 15:51:34 -0700112
113 private static final int MSG_UPDATE_POWER_STATE = 1;
114 private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
115 private static final int MSG_LIGHT_SENSOR_DEBOUNCED = 3;
116
117 private static final int PROXIMITY_UNKNOWN = -1;
118 private static final int PROXIMITY_NEGATIVE = 0;
119 private static final int PROXIMITY_POSITIVE = 1;
120
Jeff Brown93cbbb22012-10-04 13:18:36 -0700121 // Proximity sensor debounce delay in milliseconds for positive or negative transitions.
122 private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
123 private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 500;
Jeff Brown96307042012-07-27 15:51:34 -0700124
125 // Trigger proximity if distance is less than 5 cm.
126 private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
127
Jeff Browne941b1e2012-10-22 16:50:25 -0700128 // Light sensor event rate in milliseconds.
129 private static final int LIGHT_SENSOR_RATE_MILLIS = 1000;
130
131 // A rate for generating synthetic light sensor events in the case where the light
132 // sensor hasn't reported any new data in a while and we need it to update the
133 // debounce filter. We only synthesize light sensor measurements when needed.
134 private static final int SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS =
135 LIGHT_SENSOR_RATE_MILLIS * 2;
Jeff Brown96307042012-07-27 15:51:34 -0700136
137 // Brightness animation ramp rate in brightness units per second.
138 private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
Jeff Browne941b1e2012-10-22 16:50:25 -0700139 private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
Jeff Brown96307042012-07-27 15:51:34 -0700140
Jeff Brown4f0e9692012-10-18 16:14:16 -0700141 // IIR filter time constants in milliseconds for computing two moving averages of
142 // the light samples. One is a long-term average and the other is a short-term average.
143 // We can use these filters to assess trends in ambient brightness.
144 // The short term average gives us a filtered but relatively low latency measurement.
145 // The long term average informs us about the overall trend.
146 private static final long SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 1000;
Jeff Browne941b1e2012-10-22 16:50:25 -0700147 private static final long LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 5000;
Jeff Brown06565b62012-08-15 21:10:32 -0700148
149 // Stability requirements in milliseconds for accepting a new brightness
150 // level. This is used for debouncing the light sensor. Different constants
Jeff Brown4f0e9692012-10-18 16:14:16 -0700151 // are used to debounce the light sensor when adapting to brighter or darker environments.
Jeff Brown06565b62012-08-15 21:10:32 -0700152 // This parameter controls how quickly brightness changes occur in response to
Jeff Browne941b1e2012-10-22 16:50:25 -0700153 // an observed change in light level that exceeds the hysteresis threshold.
154 private static final long BRIGHTENING_LIGHT_DEBOUNCE = 4000;
155 private static final long DARKENING_LIGHT_DEBOUNCE = 8000;
Jeff Brown4f0e9692012-10-18 16:14:16 -0700156
157 // Hysteresis constraints for brightening or darkening.
158 // The recent lux must have changed by at least this fraction relative to the
159 // current ambient lux before a change will be considered.
160 private static final float BRIGHTENING_LIGHT_HYSTERESIS = 0.10f;
161 private static final float DARKENING_LIGHT_HYSTERESIS = 0.20f;
Jeff Brown96307042012-07-27 15:51:34 -0700162
163 private final Object mLock = new Object();
164
165 // Notifier for sending asynchronous notifications.
166 private final Notifier mNotifier;
167
Jeff Brown9e316a12012-10-08 19:17:06 -0700168 // The display blanker.
169 private final DisplayBlanker mDisplayBlanker;
170
Jeff Brown96307042012-07-27 15:51:34 -0700171 // Our handler.
172 private final DisplayControllerHandler mHandler;
173
174 // Asynchronous callbacks into the power manager service.
175 // Only invoked from the handler thread while no locks are held.
176 private final Callbacks mCallbacks;
177 private Handler mCallbackHandler;
178
179 // The lights service.
180 private final LightsService mLights;
181
Jeff Brownaa202a62012-08-21 22:14:26 -0700182 // The twilight service.
183 private final TwilightService mTwilight;
184
Jeff Brownbd6e1502012-08-28 03:27:37 -0700185 // The display manager.
186 private final DisplayManager mDisplayManager;
187
Jeff Brown96307042012-07-27 15:51:34 -0700188 // The sensor manager.
189 private final SensorManager mSensorManager;
190
191 // The proximity sensor, or null if not available or needed.
192 private Sensor mProximitySensor;
193
194 // The light sensor, or null if not available or needed.
195 private Sensor mLightSensor;
196
197 // The dim screen brightness.
198 private final int mScreenBrightnessDimConfig;
199
Jeff Brownb76eebff2012-10-05 22:26:44 -0700200 // The minimum allowed brightness.
201 private final int mScreenBrightnessRangeMinimum;
202
203 // The maximum allowed brightness.
204 private final int mScreenBrightnessRangeMaximum;
205
Jeff Brown330560f2012-08-21 22:10:57 -0700206 // True if auto-brightness should be used.
Jeff Brown96307042012-07-27 15:51:34 -0700207 private boolean mUseSoftwareAutoBrightnessConfig;
Jeff Brown330560f2012-08-21 22:10:57 -0700208
209 // The auto-brightness spline adjustment.
210 // The brightness values have been scaled to a range of 0..1.
Jeff Brown1a30b552012-08-16 01:31:11 -0700211 private Spline mScreenAutoBrightnessSpline;
Jeff Brown96307042012-07-27 15:51:34 -0700212
213 // Amount of time to delay auto-brightness after screen on while waiting for
214 // the light sensor to warm-up in milliseconds.
215 // May be 0 if no warm-up is required.
216 private int mLightSensorWarmUpTimeConfig;
217
Jeff Brown252c2062012-10-08 16:21:01 -0700218 // True if we should fade the screen while turning it off, false if we should play
219 // a stylish electron beam animation instead.
220 private boolean mElectronBeamFadesConfig;
Jeff Browna52772f2012-10-04 18:38:09 -0700221
Jeff Brown96307042012-07-27 15:51:34 -0700222 // The pending power request.
223 // Initially null until the first call to requestPowerState.
224 // Guarded by mLock.
225 private DisplayPowerRequest mPendingRequestLocked;
226
227 // True if a request has been made to wait for the proximity sensor to go negative.
228 // Guarded by mLock.
229 private boolean mPendingWaitForNegativeProximityLocked;
230
231 // True if the pending power request or wait for negative proximity flag
232 // has been changed since the last update occurred.
233 // Guarded by mLock.
234 private boolean mPendingRequestChangedLocked;
235
236 // Set to true when the important parts of the pending power request have been applied.
237 // The important parts are mainly the screen state. Brightness changes may occur
238 // concurrently.
239 // Guarded by mLock.
240 private boolean mDisplayReadyLocked;
241
242 // Set to true if a power state update is required.
243 // Guarded by mLock.
244 private boolean mPendingUpdatePowerStateLocked;
245
246 /* The following state must only be accessed by the handler thread. */
247
248 // The currently requested power state.
249 // The power controller will progressively update its internal state to match
250 // the requested power state. Initially null until the first update.
251 private DisplayPowerRequest mPowerRequest;
252
253 // The current power state.
254 // Must only be accessed on the handler thread.
255 private DisplayPowerState mPowerState;
256
257 // True if the device should wait for negative proximity sensor before
258 // waking up the screen. This is set to false as soon as a negative
259 // proximity sensor measurement is observed or when the device is forced to
260 // go to sleep by the user. While true, the screen remains off.
261 private boolean mWaitingForNegativeProximity;
262
263 // The actual proximity sensor threshold value.
264 private float mProximityThreshold;
265
266 // Set to true if the proximity sensor listener has been registered
267 // with the sensor manager.
268 private boolean mProximitySensorEnabled;
269
270 // The debounced proximity sensor state.
271 private int mProximity = PROXIMITY_UNKNOWN;
272
273 // The raw non-debounced proximity sensor state.
274 private int mPendingProximity = PROXIMITY_UNKNOWN;
275 private long mPendingProximityDebounceTime;
276
277 // True if the screen was turned off because of the proximity sensor.
278 // When the screen turns on again, we report user activity to the power manager.
279 private boolean mScreenOffBecauseOfProximity;
280
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700281 // True if the screen on is being blocked.
282 private boolean mScreenOnWasBlocked;
283
284 // The elapsed real time when the screen on was blocked.
285 private long mScreenOnBlockStartRealTime;
286
Jeff Brown96307042012-07-27 15:51:34 -0700287 // Set to true if the light sensor is enabled.
288 private boolean mLightSensorEnabled;
289
290 // The time when the light sensor was enabled.
291 private long mLightSensorEnableTime;
292
Jeff Brown4f0e9692012-10-18 16:14:16 -0700293 // The currently accepted nominal ambient light level.
294 private float mAmbientLux;
Jeff Brown96307042012-07-27 15:51:34 -0700295
Jeff Brown4f0e9692012-10-18 16:14:16 -0700296 // True if mAmbientLux holds a valid value.
297 private boolean mAmbientLuxValid;
Jeff Brown96307042012-07-27 15:51:34 -0700298
Jeff Brown96307042012-07-27 15:51:34 -0700299 // The most recent light sample.
Jeff Brown4f0e9692012-10-18 16:14:16 -0700300 private float mLastObservedLux;
Jeff Brown96307042012-07-27 15:51:34 -0700301
302 // The time of the most light recent sample.
Jeff Brown4f0e9692012-10-18 16:14:16 -0700303 private long mLastObservedLuxTime;
Jeff Brown96307042012-07-27 15:51:34 -0700304
Jeff Brown4f0e9692012-10-18 16:14:16 -0700305 // The number of light samples collected since the light sensor was enabled.
306 private int mRecentLightSamples;
Jeff Brown06565b62012-08-15 21:10:32 -0700307
Jeff Brown4f0e9692012-10-18 16:14:16 -0700308 // The long-term and short-term filtered light measurements.
309 private float mRecentShortTermAverageLux;
310 private float mRecentLongTermAverageLux;
Jeff Brown96307042012-07-27 15:51:34 -0700311
Jeff Browne941b1e2012-10-22 16:50:25 -0700312 // The direction in which the average lux is moving relative to the current ambient lux.
313 // 0 if not changing or within hysteresis threshold.
314 // 1 if brightening beyond hysteresis threshold.
315 // -1 if darkening beyond hysteresis threshold.
316 private int mDebounceLuxDirection;
317
318 // The time when the average lux last changed direction.
319 private long mDebounceLuxTime;
320
Jeff Brown96307042012-07-27 15:51:34 -0700321 // The screen brightness level that has been chosen by the auto-brightness
322 // algorithm. The actual brightness should ramp towards this value.
323 // We preserve this value even when we stop using the light sensor so
324 // that we can quickly revert to the previous auto-brightness level
325 // while the light sensor warms up.
326 // Use -1 if there is no current auto-brightness value available.
327 private int mScreenAutoBrightness = -1;
328
Jeff Brown330560f2012-08-21 22:10:57 -0700329 // The last screen auto-brightness gamma. (For printing in dump() only.)
330 private float mLastScreenAutoBrightnessGamma = 1.0f;
331
Jeff Brown96307042012-07-27 15:51:34 -0700332 // True if the screen auto-brightness value is actually being used to
333 // set the display brightness.
334 private boolean mUsingScreenAutoBrightness;
335
336 // Animators.
337 private ObjectAnimator mElectronBeamOnAnimator;
338 private ObjectAnimator mElectronBeamOffAnimator;
339 private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
340
Jeff Brownaa202a62012-08-21 22:14:26 -0700341 // Twilight changed. We might recalculate auto-brightness values.
342 private boolean mTwilightChanged;
343
Jeff Brown96307042012-07-27 15:51:34 -0700344 /**
345 * Creates the display power controller.
346 */
347 public DisplayPowerController(Looper looper, Context context, Notifier notifier,
Jeff Brown32dafe22012-10-19 17:04:30 -0700348 LightsService lights, TwilightService twilight,
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 Brownbd6e1502012-08-28 03:27:37 -0700360 mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
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 Brownbd6e1502012-08-28 03:27:37 -0700521 Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
Jeff Browna52772f2012-10-04 18:38:09 -0700522 mPowerState = new DisplayPowerState(
Jeff Brown32dafe22012-10-19 17:04:30 -0700523 new ElectronBeam(display), mDisplayBlanker,
524 mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT));
Jeff Brown96307042012-07-27 15:51:34 -0700525
526 mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
527 mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
528 mElectronBeamOnAnimator.setDuration(ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS);
529 mElectronBeamOnAnimator.addListener(mAnimatorListener);
530
531 mElectronBeamOffAnimator = ObjectAnimator.ofFloat(
532 mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 1.0f, 0.0f);
533 mElectronBeamOffAnimator.setDuration(ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS);
534 mElectronBeamOffAnimator.addListener(mAnimatorListener);
535
536 mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
537 mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
538 }
539
540 private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
541 @Override
542 public void onAnimationStart(Animator animation) {
543 }
544 @Override
545 public void onAnimationEnd(Animator animation) {
546 sendUpdatePowerState();
547 }
548 @Override
549 public void onAnimationRepeat(Animator animation) {
550 }
551 @Override
552 public void onAnimationCancel(Animator animation) {
553 }
554 };
555
556 private void updatePowerState() {
557 // Update the power state request.
558 final boolean mustNotify;
559 boolean mustInitialize = false;
Jeff Brownaa202a62012-08-21 22:14:26 -0700560 boolean updateAutoBrightness = mTwilightChanged;
Jeff Browne941b1e2012-10-22 16:50:25 -0700561 boolean wasDim = false;
Jeff Brownaa202a62012-08-21 22:14:26 -0700562 mTwilightChanged = false;
Jeff Brown330560f2012-08-21 22:10:57 -0700563
Jeff Brown96307042012-07-27 15:51:34 -0700564 synchronized (mLock) {
565 mPendingUpdatePowerStateLocked = false;
566 if (mPendingRequestLocked == null) {
567 return; // wait until first actual power request
568 }
569
570 if (mPowerRequest == null) {
571 mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
572 mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
Jeff Brown6307a152012-08-20 13:24:23 -0700573 mPendingWaitForNegativeProximityLocked = false;
Jeff Brown96307042012-07-27 15:51:34 -0700574 mPendingRequestChangedLocked = false;
575 mustInitialize = true;
576 } else if (mPendingRequestChangedLocked) {
Jeff Brown330560f2012-08-21 22:10:57 -0700577 if (mPowerRequest.screenAutoBrightnessAdjustment
578 != mPendingRequestLocked.screenAutoBrightnessAdjustment) {
579 updateAutoBrightness = true;
580 }
Jeff Browne941b1e2012-10-22 16:50:25 -0700581 wasDim = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM);
Jeff Brown96307042012-07-27 15:51:34 -0700582 mPowerRequest.copyFrom(mPendingRequestLocked);
583 mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
Jeff Brown6307a152012-08-20 13:24:23 -0700584 mPendingWaitForNegativeProximityLocked = false;
Jeff Brown96307042012-07-27 15:51:34 -0700585 mPendingRequestChangedLocked = false;
586 mDisplayReadyLocked = false;
587 }
588
589 mustNotify = !mDisplayReadyLocked;
590 }
591
592 // Initialize things the first time the power state is changed.
593 if (mustInitialize) {
594 initialize();
595 }
596
Jeff Brown6307a152012-08-20 13:24:23 -0700597 // Apply the proximity sensor.
Jeff Brown96307042012-07-27 15:51:34 -0700598 if (mProximitySensor != null) {
Jeff Brown6307a152012-08-20 13:24:23 -0700599 if (mPowerRequest.useProximitySensor
600 && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
601 setProximitySensorEnabled(true);
602 if (!mScreenOffBecauseOfProximity
603 && mProximity == PROXIMITY_POSITIVE) {
604 mScreenOffBecauseOfProximity = true;
Jeff Brown93cbbb22012-10-04 13:18:36 -0700605 sendOnProximityPositive();
Jeff Brown6307a152012-08-20 13:24:23 -0700606 setScreenOn(false);
607 }
608 } else if (mWaitingForNegativeProximity
609 && mScreenOffBecauseOfProximity
610 && mProximity == PROXIMITY_POSITIVE
611 && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
612 setProximitySensorEnabled(true);
613 } else {
614 setProximitySensorEnabled(false);
615 mWaitingForNegativeProximity = false;
616 }
617 if (mScreenOffBecauseOfProximity
618 && mProximity != PROXIMITY_POSITIVE) {
Jeff Brown96307042012-07-27 15:51:34 -0700619 mScreenOffBecauseOfProximity = false;
620 sendOnProximityNegative();
621 }
Jeff Brown6307a152012-08-20 13:24:23 -0700622 } else {
623 mWaitingForNegativeProximity = false;
Jeff Brown96307042012-07-27 15:51:34 -0700624 }
625
626 // Turn on the light sensor if needed.
627 if (mLightSensor != null) {
628 setLightSensorEnabled(mPowerRequest.useAutoBrightness
Jeff Brown330560f2012-08-21 22:10:57 -0700629 && wantScreenOn(mPowerRequest.screenState), updateAutoBrightness);
Jeff Brown96307042012-07-27 15:51:34 -0700630 }
631
632 // Set the screen brightness.
Jeff Brownb76eebff2012-10-05 22:26:44 -0700633 if (wantScreenOn(mPowerRequest.screenState)) {
634 int target;
635 boolean slow;
Jeff Brown96307042012-07-27 15:51:34 -0700636 if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) {
637 // Use current auto-brightness value.
Jeff Brownb76eebff2012-10-05 22:26:44 -0700638 target = mScreenAutoBrightness;
639 slow = mUsingScreenAutoBrightness;
Jeff Brown96307042012-07-27 15:51:34 -0700640 mUsingScreenAutoBrightness = true;
641 } else {
642 // Light sensor is disabled or not ready yet.
643 // Use the current brightness setting from the request, which is expected
644 // provide a nominal default value for the case where auto-brightness
645 // is not ready yet.
Jeff Brownb76eebff2012-10-05 22:26:44 -0700646 target = mPowerRequest.screenBrightness;
647 slow = false;
Jeff Brown96307042012-07-27 15:51:34 -0700648 mUsingScreenAutoBrightness = false;
649 }
Jeff Brownb76eebff2012-10-05 22:26:44 -0700650 if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
Jeff Brown5244c932012-10-24 14:46:26 -0700651 // Dim quickly by at least some minimum amount.
Jeff Brownb76eebff2012-10-05 22:26:44 -0700652 target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
653 mScreenBrightnessDimConfig);
Jeff Brown5244c932012-10-24 14:46:26 -0700654 slow = false;
Jeff Browne941b1e2012-10-22 16:50:25 -0700655 } else if (wasDim) {
656 // Brighten quickly.
Jeff Brownb76eebff2012-10-05 22:26:44 -0700657 slow = false;
658 }
659 animateScreenBrightness(clampScreenBrightness(target),
660 slow ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
Jeff Brown96307042012-07-27 15:51:34 -0700661 } else {
662 // Screen is off. Don't bother changing the brightness.
663 mUsingScreenAutoBrightness = false;
664 }
665
666 // Animate the screen on or off.
667 if (!mScreenOffBecauseOfProximity) {
668 if (wantScreenOn(mPowerRequest.screenState)) {
669 // Want screen on.
670 // Wait for previous off animation to complete beforehand.
671 // It is relatively short but if we cancel it and switch to the
672 // on animation immediately then the results are pretty ugly.
673 if (!mElectronBeamOffAnimator.isStarted()) {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700674 // Turn the screen on. The contents of the screen may not yet
675 // be visible if the electron beam has not been dismissed because
676 // its last frame of animation is solid black.
677 setScreenOn(true);
678
679 if (mPowerRequest.blockScreenOn
680 && mPowerState.getElectronBeamLevel() == 0.0f) {
681 blockScreenOn();
Jeff Brown13c589b2012-08-16 16:20:54 -0700682 } else {
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700683 unblockScreenOn();
Jeff Brownc38c9be2012-10-04 13:16:19 -0700684 if (USE_ELECTRON_BEAM_ON_ANIMATION) {
685 if (!mElectronBeamOnAnimator.isStarted()) {
686 if (mPowerState.getElectronBeamLevel() == 1.0f) {
687 mPowerState.dismissElectronBeam();
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700688 } else if (mPowerState.prepareElectronBeam(
Jeff Brown252c2062012-10-08 16:21:01 -0700689 mElectronBeamFadesConfig ?
690 ElectronBeam.MODE_FADE :
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700691 ElectronBeam.MODE_WARM_UP)) {
Jeff Brownc38c9be2012-10-04 13:16:19 -0700692 mElectronBeamOnAnimator.start();
693 } else {
694 mElectronBeamOnAnimator.end();
695 }
696 }
697 } else {
698 mPowerState.setElectronBeamLevel(1.0f);
699 mPowerState.dismissElectronBeam();
700 }
701 }
Jeff Brown96307042012-07-27 15:51:34 -0700702 }
703 } else {
704 // Want screen off.
705 // Wait for previous on animation to complete beforehand.
706 if (!mElectronBeamOnAnimator.isStarted()) {
707 if (!mElectronBeamOffAnimator.isStarted()) {
708 if (mPowerState.getElectronBeamLevel() == 0.0f) {
709 setScreenOn(false);
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700710 } else if (mPowerState.prepareElectronBeam(
Jeff Brown252c2062012-10-08 16:21:01 -0700711 mElectronBeamFadesConfig ?
712 ElectronBeam.MODE_FADE :
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700713 ElectronBeam.MODE_COOL_DOWN)
Jeff Brown96307042012-07-27 15:51:34 -0700714 && mPowerState.isScreenOn()) {
715 mElectronBeamOffAnimator.start();
716 } else {
717 mElectronBeamOffAnimator.end();
718 }
719 }
720 }
721 }
722 }
723
724 // Report whether the display is ready for use.
725 // We mostly care about the screen state here, ignoring brightness changes
726 // which will be handled asynchronously.
727 if (mustNotify
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700728 && !mScreenOnWasBlocked
Jeff Brown96307042012-07-27 15:51:34 -0700729 && !mElectronBeamOnAnimator.isStarted()
730 && !mElectronBeamOffAnimator.isStarted()
731 && mPowerState.waitUntilClean(mCleanListener)) {
732 synchronized (mLock) {
733 if (!mPendingRequestChangedLocked) {
734 mDisplayReadyLocked = true;
Jeff Brownc38c9be2012-10-04 13:16:19 -0700735
736 if (DEBUG) {
737 Slog.d(TAG, "Display ready!");
738 }
Jeff Brown96307042012-07-27 15:51:34 -0700739 }
740 }
741 sendOnStateChanged();
742 }
743 }
744
Jeff Brown8b9cf1c2012-10-07 14:54:17 -0700745 private void blockScreenOn() {
746 if (!mScreenOnWasBlocked) {
747 mScreenOnWasBlocked = true;
748 if (DEBUG) {
749 Slog.d(TAG, "Blocked screen on.");
750 mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
751 }
752 }
753 }
754
755 private void unblockScreenOn() {
756 if (mScreenOnWasBlocked) {
757 mScreenOnWasBlocked = false;
758 if (DEBUG) {
759 Slog.d(TAG, "Unblocked screen on after " +
760 (SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime) + " ms");
761 }
762 }
763 }
764
Jeff Brown96307042012-07-27 15:51:34 -0700765 private void setScreenOn(boolean on) {
766 if (!mPowerState.isScreenOn() == on) {
767 mPowerState.setScreenOn(on);
768 if (on) {
769 mNotifier.onScreenOn();
770 } else {
771 mNotifier.onScreenOff();
772 }
773 }
774 }
775
Jeff Brown330560f2012-08-21 22:10:57 -0700776 private int clampScreenBrightness(int value) {
Jeff Brownb76eebff2012-10-05 22:26:44 -0700777 return clamp(value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
778 }
779
780 private static int clampAbsoluteBrightness(int value) {
781 return clamp(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
782 }
783
784 private static int clamp(int value, int min, int max) {
785 if (value <= min) {
786 return min;
787 }
788 if (value >= max) {
789 return max;
790 }
791 return value;
792 }
793
794 private static float normalizeAbsoluteBrightness(int value) {
795 return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
Jeff Brown330560f2012-08-21 22:10:57 -0700796 }
797
Jeff Brown96307042012-07-27 15:51:34 -0700798 private void animateScreenBrightness(int target, int rate) {
799 if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
800 mNotifier.onScreenBrightness(target);
801 }
802 }
803
804 private final Runnable mCleanListener = new Runnable() {
805 @Override
806 public void run() {
807 sendUpdatePowerState();
808 }
809 };
810
811 private void setProximitySensorEnabled(boolean enable) {
812 if (enable) {
813 if (!mProximitySensorEnabled) {
814 mProximitySensorEnabled = true;
815 mPendingProximity = PROXIMITY_UNKNOWN;
816 mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
817 SensorManager.SENSOR_DELAY_NORMAL, mHandler);
818 }
819 } else {
820 if (mProximitySensorEnabled) {
821 mProximitySensorEnabled = false;
822 mProximity = PROXIMITY_UNKNOWN;
823 mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
824 mSensorManager.unregisterListener(mProximitySensorListener);
825 }
826 }
827 }
828
829 private void handleProximitySensorEvent(long time, boolean positive) {
830 if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
831 return; // no change
832 }
833 if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
834 return; // no change
835 }
836
837 // Only accept a proximity sensor reading if it remains
838 // stable for the entire debounce delay.
839 mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
Jeff Brown93cbbb22012-10-04 13:18:36 -0700840 if (positive) {
841 mPendingProximity = PROXIMITY_POSITIVE;
842 mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY;
843 } else {
844 mPendingProximity = PROXIMITY_NEGATIVE;
845 mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY;
846 }
Jeff Brown96307042012-07-27 15:51:34 -0700847 debounceProximitySensor();
848 }
849
850 private void debounceProximitySensor() {
851 if (mPendingProximity != PROXIMITY_UNKNOWN) {
852 final long now = SystemClock.uptimeMillis();
853 if (mPendingProximityDebounceTime <= now) {
854 mProximity = mPendingProximity;
855 sendUpdatePowerState();
856 } else {
857 Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
858 msg.setAsynchronous(true);
859 mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
860 }
861 }
862 }
863
Jeff Brown330560f2012-08-21 22:10:57 -0700864 private void setLightSensorEnabled(boolean enable, boolean updateAutoBrightness) {
Jeff Brown96307042012-07-27 15:51:34 -0700865 if (enable) {
866 if (!mLightSensorEnabled) {
Jeff Brown330560f2012-08-21 22:10:57 -0700867 updateAutoBrightness = true;
Jeff Brown96307042012-07-27 15:51:34 -0700868 mLightSensorEnabled = true;
869 mLightSensorEnableTime = SystemClock.uptimeMillis();
870 mSensorManager.registerListener(mLightSensorListener, mLightSensor,
Jeff Browne941b1e2012-10-22 16:50:25 -0700871 LIGHT_SENSOR_RATE_MILLIS * 1000, mHandler);
Jeff Brown96307042012-07-27 15:51:34 -0700872 }
873 } else {
874 if (mLightSensorEnabled) {
875 mLightSensorEnabled = false;
Jeff Brown4f0e9692012-10-18 16:14:16 -0700876 mAmbientLuxValid = false;
877 mRecentLightSamples = 0;
Jeff Brown96307042012-07-27 15:51:34 -0700878 mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
879 mSensorManager.unregisterListener(mLightSensorListener);
880 }
881 }
Jeff Brown330560f2012-08-21 22:10:57 -0700882 if (updateAutoBrightness) {
883 updateAutoBrightness(false);
884 }
Jeff Brown96307042012-07-27 15:51:34 -0700885 }
886
887 private void handleLightSensorEvent(long time, float lux) {
Jeff Browne941b1e2012-10-22 16:50:25 -0700888 mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
889
890 applyLightSensorMeasurement(time, lux);
891 updateAmbientLux(time);
892 }
893
894 private void applyLightSensorMeasurement(long time, float lux) {
Jeff Brown4f0e9692012-10-18 16:14:16 -0700895 // Update our filters.
Jeff Brown96307042012-07-27 15:51:34 -0700896 mRecentLightSamples += 1;
Jeff Brown4f0e9692012-10-18 16:14:16 -0700897 if (mRecentLightSamples == 1) {
898 mRecentShortTermAverageLux = lux;
899 mRecentLongTermAverageLux = lux;
900 } else {
901 final long timeDelta = time - mLastObservedLuxTime;
902 mRecentShortTermAverageLux += (lux - mRecentShortTermAverageLux)
903 * timeDelta / (SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
904 mRecentLongTermAverageLux += (lux - mRecentLongTermAverageLux)
905 * timeDelta / (LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
906 }
907
908 // Remember this sample value.
909 mLastObservedLux = lux;
910 mLastObservedLuxTime = time;
Jeff Brown96307042012-07-27 15:51:34 -0700911 }
912
Jeff Brown4f0e9692012-10-18 16:14:16 -0700913 private void updateAmbientLux(long time) {
914 // If the light sensor was just turned on then immediately update our initial
915 // estimate of the current ambient light level.
916 if (!mAmbientLuxValid
917 || (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) {
Jeff Brown4f0e9692012-10-18 16:14:16 -0700918 mAmbientLux = mRecentShortTermAverageLux;
919 mAmbientLuxValid = true;
Jeff Browne941b1e2012-10-22 16:50:25 -0700920 mDebounceLuxDirection = 0;
921 mDebounceLuxTime = time;
922 if (DEBUG) {
923 Slog.d(TAG, "updateAmbientLux: Initializing: "
924 + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
925 + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
926 + ", mAmbientLux=" + mAmbientLux);
927 }
Jeff Brown4f0e9692012-10-18 16:14:16 -0700928 updateAutoBrightness(true);
929 return;
930 }
Jeff Brown96307042012-07-27 15:51:34 -0700931
Jeff Brown4f0e9692012-10-18 16:14:16 -0700932 // Determine whether the ambient environment appears to be brightening.
Jeff Browne941b1e2012-10-22 16:50:25 -0700933 float brighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
934 if (mRecentShortTermAverageLux > brighteningLuxThreshold
935 && mRecentLongTermAverageLux > brighteningLuxThreshold) {
936 if (mDebounceLuxDirection <= 0) {
937 mDebounceLuxDirection = 1;
938 mDebounceLuxTime = time;
939 if (DEBUG) {
940 Slog.d(TAG, "updateAmbientLux: Possibly brightened, waiting for "
941 + BRIGHTENING_LIGHT_DEBOUNCE + " ms: "
942 + "brighteningLuxThreshold=" + brighteningLuxThreshold
943 + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
944 + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
945 + ", mAmbientLux=" + mAmbientLux);
946 }
947 }
948 long debounceTime = mDebounceLuxTime + BRIGHTENING_LIGHT_DEBOUNCE;
Jeff Brown4f0e9692012-10-18 16:14:16 -0700949 if (time >= debounceTime) {
Jeff Browne941b1e2012-10-22 16:50:25 -0700950 mAmbientLux = mRecentShortTermAverageLux;
Jeff Brown96307042012-07-27 15:51:34 -0700951 if (DEBUG) {
Jeff Brown4f0e9692012-10-18 16:14:16 -0700952 Slog.d(TAG, "updateAmbientLux: Brightened: "
Jeff Browne941b1e2012-10-22 16:50:25 -0700953 + "brighteningLuxThreshold=" + brighteningLuxThreshold
Jeff Brown4f0e9692012-10-18 16:14:16 -0700954 + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
Jeff Browne941b1e2012-10-22 16:50:25 -0700955 + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
956 + ", mAmbientLux=" + mAmbientLux);
Jeff Brown96307042012-07-27 15:51:34 -0700957 }
Jeff Brown96307042012-07-27 15:51:34 -0700958 updateAutoBrightness(true);
Jeff Brown96307042012-07-27 15:51:34 -0700959 } else {
Jeff Brown4f0e9692012-10-18 16:14:16 -0700960 mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
961 }
962 return;
963 }
964
965 // Determine whether the ambient environment appears to be darkening.
Jeff Browne941b1e2012-10-22 16:50:25 -0700966 float darkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
967 if (mRecentShortTermAverageLux < darkeningLuxThreshold
968 && mRecentLongTermAverageLux < darkeningLuxThreshold) {
969 if (mDebounceLuxDirection >= 0) {
970 mDebounceLuxDirection = -1;
971 mDebounceLuxTime = time;
972 if (DEBUG) {
973 Slog.d(TAG, "updateAmbientLux: Possibly darkened, waiting for "
974 + DARKENING_LIGHT_DEBOUNCE + " ms: "
975 + "darkeningLuxThreshold=" + darkeningLuxThreshold
976 + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
977 + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
978 + ", mAmbientLux=" + mAmbientLux);
979 }
980 }
981 long debounceTime = mDebounceLuxTime + DARKENING_LIGHT_DEBOUNCE;
Jeff Brown4f0e9692012-10-18 16:14:16 -0700982 if (time >= debounceTime) {
Jeff Browne941b1e2012-10-22 16:50:25 -0700983 // Be conservative about reducing the brightness, only reduce it a little bit
984 // at a time to avoid having to bump it up again soon.
985 mAmbientLux = Math.max(mRecentShortTermAverageLux, mRecentLongTermAverageLux);
Jeff Brown4f0e9692012-10-18 16:14:16 -0700986 if (DEBUG) {
987 Slog.d(TAG, "updateAmbientLux: Darkened: "
Jeff Browne941b1e2012-10-22 16:50:25 -0700988 + "darkeningLuxThreshold=" + darkeningLuxThreshold
Jeff Brown4f0e9692012-10-18 16:14:16 -0700989 + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
Jeff Browne941b1e2012-10-22 16:50:25 -0700990 + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
991 + ", mAmbientLux=" + mAmbientLux);
Jeff Brown4f0e9692012-10-18 16:14:16 -0700992 }
Jeff Brown4f0e9692012-10-18 16:14:16 -0700993 updateAutoBrightness(true);
994 } else {
995 mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
Jeff Brown96307042012-07-27 15:51:34 -0700996 }
Jeff Browne941b1e2012-10-22 16:50:25 -0700997 return;
998 }
999
1000 // No change or change is within the hysteresis thresholds.
1001 if (mDebounceLuxDirection != 0) {
1002 mDebounceLuxDirection = 0;
1003 mDebounceLuxTime = time;
1004 if (DEBUG) {
1005 Slog.d(TAG, "updateAmbientLux: Canceled debounce: "
1006 + "brighteningLuxThreshold=" + brighteningLuxThreshold
1007 + ", darkeningLuxThreshold=" + darkeningLuxThreshold
1008 + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
1009 + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
1010 + ", mAmbientLux=" + mAmbientLux);
1011 }
1012 }
1013
1014 // If the light level does not change, then the sensor may not report
1015 // a new value. This can cause problems for the auto-brightness algorithm
1016 // because the filters might not be updated. To work around it, we want to
1017 // make sure to update the filters whenever the observed light level could
1018 // possibly exceed one of the hysteresis thresholds.
1019 if (mLastObservedLux > brighteningLuxThreshold
1020 || mLastObservedLux < darkeningLuxThreshold) {
1021 mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED,
1022 time + SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS);
Jeff Brown96307042012-07-27 15:51:34 -07001023 }
1024 }
1025
Jeff Brown4f0e9692012-10-18 16:14:16 -07001026 private void debounceLightSensor() {
Jeff Browne941b1e2012-10-22 16:50:25 -07001027 if (mLightSensorEnabled) {
1028 long time = SystemClock.uptimeMillis();
1029 if (time >= mLastObservedLuxTime + SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS) {
1030 if (DEBUG) {
1031 Slog.d(TAG, "debounceLightSensor: Synthesizing light sensor measurement "
1032 + "after " + (time - mLastObservedLuxTime) + " ms.");
1033 }
1034 applyLightSensorMeasurement(time, mLastObservedLux);
1035 }
1036 updateAmbientLux(time);
1037 }
Jeff Brown4f0e9692012-10-18 16:14:16 -07001038 }
1039
Jeff Brown96307042012-07-27 15:51:34 -07001040 private void updateAutoBrightness(boolean sendUpdate) {
Jeff Brown4f0e9692012-10-18 16:14:16 -07001041 if (!mAmbientLuxValid) {
Jeff Brown96307042012-07-27 15:51:34 -07001042 return;
1043 }
1044
Jeff Brown4f0e9692012-10-18 16:14:16 -07001045 float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);
Jeff Brown330560f2012-08-21 22:10:57 -07001046 float gamma = 1.0f;
1047
1048 if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
1049 && mPowerRequest.screenAutoBrightnessAdjustment != 0.0f) {
1050 final float adjGamma = FloatMath.pow(SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA,
1051 Math.min(1.0f, Math.max(-1.0f,
1052 -mPowerRequest.screenAutoBrightnessAdjustment)));
1053 gamma *= adjGamma;
1054 if (DEBUG) {
1055 Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma);
1056 }
1057 }
1058
Jeff Brownaa202a62012-08-21 22:14:26 -07001059 if (USE_TWILIGHT_ADJUSTMENT) {
1060 TwilightState state = mTwilight.getCurrentState();
1061 if (state != null && state.isNight()) {
1062 final long now = System.currentTimeMillis();
1063 final float earlyGamma =
1064 getTwilightGamma(now, state.getYesterdaySunset(), state.getTodaySunrise());
1065 final float lateGamma =
1066 getTwilightGamma(now, state.getTodaySunset(), state.getTomorrowSunrise());
1067 gamma *= earlyGamma * lateGamma;
1068 if (DEBUG) {
1069 Slog.d(TAG, "updateAutoBrightness: earlyGamma=" + earlyGamma
1070 + ", lateGamma=" + lateGamma);
1071 }
1072 }
1073 }
1074
Jeff Brown330560f2012-08-21 22:10:57 -07001075 if (gamma != 1.0f) {
1076 final float in = value;
1077 value = FloatMath.pow(value, gamma);
1078 if (DEBUG) {
1079 Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma
1080 + ", in=" + in + ", out=" + value);
1081 }
1082 }
1083
1084 int newScreenAutoBrightness = clampScreenBrightness(
Jeff Brown4f0e9692012-10-18 16:14:16 -07001085 Math.round(value * PowerManager.BRIGHTNESS_ON));
Jeff Brown96307042012-07-27 15:51:34 -07001086 if (mScreenAutoBrightness != newScreenAutoBrightness) {
1087 if (DEBUG) {
1088 Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
Jeff Brown330560f2012-08-21 22:10:57 -07001089 + mScreenAutoBrightness + ", newScreenAutoBrightness="
Jeff Brown1a30b552012-08-16 01:31:11 -07001090 + newScreenAutoBrightness);
Jeff Brown96307042012-07-27 15:51:34 -07001091 }
1092
1093 mScreenAutoBrightness = newScreenAutoBrightness;
Jeff Brown330560f2012-08-21 22:10:57 -07001094 mLastScreenAutoBrightnessGamma = gamma;
Jeff Brown96307042012-07-27 15:51:34 -07001095 if (sendUpdate) {
1096 sendUpdatePowerState();
1097 }
1098 }
1099 }
1100
Jeff Brownaa202a62012-08-21 22:14:26 -07001101 private static float getTwilightGamma(long now, long lastSunset, long nextSunrise) {
1102 if (lastSunset < 0 || nextSunrise < 0
1103 || now < lastSunset || now > nextSunrise) {
1104 return 1.0f;
1105 }
1106
1107 if (now < lastSunset + TWILIGHT_ADJUSTMENT_TIME) {
1108 return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
1109 (float)(now - lastSunset) / TWILIGHT_ADJUSTMENT_TIME);
1110 }
1111
1112 if (now > nextSunrise - TWILIGHT_ADJUSTMENT_TIME) {
1113 return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
1114 (float)(nextSunrise - now) / TWILIGHT_ADJUSTMENT_TIME);
1115 }
1116
1117 return TWILIGHT_ADJUSTMENT_MAX_GAMMA;
1118 }
1119
1120 private static float lerp(float x, float y, float alpha) {
1121 return x + (y - x) * alpha;
1122 }
1123
Jeff Brown96307042012-07-27 15:51:34 -07001124 private void sendOnStateChanged() {
1125 mCallbackHandler.post(mOnStateChangedRunnable);
1126 }
1127
1128 private final Runnable mOnStateChangedRunnable = new Runnable() {
1129 @Override
1130 public void run() {
1131 mCallbacks.onStateChanged();
1132 }
1133 };
1134
Jeff Brown93cbbb22012-10-04 13:18:36 -07001135 private void sendOnProximityPositive() {
1136 mCallbackHandler.post(mOnProximityPositiveRunnable);
1137 }
1138
1139 private final Runnable mOnProximityPositiveRunnable = new Runnable() {
1140 @Override
1141 public void run() {
1142 mCallbacks.onProximityPositive();
1143 }
1144 };
1145
Jeff Brown96307042012-07-27 15:51:34 -07001146 private void sendOnProximityNegative() {
1147 mCallbackHandler.post(mOnProximityNegativeRunnable);
1148 }
1149
1150 private final Runnable mOnProximityNegativeRunnable = new Runnable() {
1151 @Override
1152 public void run() {
1153 mCallbacks.onProximityNegative();
1154 }
1155 };
1156
Jeff Brownbd6e1502012-08-28 03:27:37 -07001157 public void dump(final PrintWriter pw) {
Jeff Brown96307042012-07-27 15:51:34 -07001158 synchronized (mLock) {
1159 pw.println();
1160 pw.println("Display Controller Locked State:");
1161 pw.println(" mDisplayReadyLocked=" + mDisplayReadyLocked);
1162 pw.println(" mPendingRequestLocked=" + mPendingRequestLocked);
1163 pw.println(" mPendingRequestChangedLocked=" + mPendingRequestChangedLocked);
1164 pw.println(" mPendingWaitForNegativeProximityLocked="
1165 + mPendingWaitForNegativeProximityLocked);
1166 pw.println(" mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked);
1167 }
1168
1169 pw.println();
1170 pw.println("Display Controller Configuration:");
1171 pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
Jeff Brownb76eebff2012-10-05 22:26:44 -07001172 pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
1173 pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
Jeff Brown96307042012-07-27 15:51:34 -07001174 pw.println(" mUseSoftwareAutoBrightnessConfig="
1175 + mUseSoftwareAutoBrightnessConfig);
Jeff Brown1a30b552012-08-16 01:31:11 -07001176 pw.println(" mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline);
Jeff Brown96307042012-07-27 15:51:34 -07001177 pw.println(" mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
1178
Jeff Brownbd6e1502012-08-28 03:27:37 -07001179 mHandler.runWithScissors(new Runnable() {
1180 @Override
1181 public void run() {
1182 dumpLocal(pw);
Jeff Brown96307042012-07-27 15:51:34 -07001183 }
Jeff Brown4ed8fe72012-08-30 18:18:29 -07001184 }, 1000);
Jeff Brown96307042012-07-27 15:51:34 -07001185 }
1186
1187 private void dumpLocal(PrintWriter pw) {
1188 pw.println();
1189 pw.println("Display Controller Thread State:");
1190 pw.println(" mPowerRequest=" + mPowerRequest);
1191 pw.println(" mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
1192
1193 pw.println(" mProximitySensor=" + mProximitySensor);
1194 pw.println(" mProximitySensorEnabled=" + mProximitySensorEnabled);
1195 pw.println(" mProximityThreshold=" + mProximityThreshold);
1196 pw.println(" mProximity=" + proximityToString(mProximity));
1197 pw.println(" mPendingProximity=" + proximityToString(mPendingProximity));
1198 pw.println(" mPendingProximityDebounceTime="
1199 + TimeUtils.formatUptime(mPendingProximityDebounceTime));
1200 pw.println(" mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
1201
1202 pw.println(" mLightSensor=" + mLightSensor);
1203 pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
1204 pw.println(" mLightSensorEnableTime="
1205 + TimeUtils.formatUptime(mLightSensorEnableTime));
Jeff Brown4f0e9692012-10-18 16:14:16 -07001206 pw.println(" mAmbientLux=" + mAmbientLux);
1207 pw.println(" mAmbientLuxValid=" + mAmbientLuxValid);
Jeff Brown4f0e9692012-10-18 16:14:16 -07001208 pw.println(" mLastObservedLux=" + mLastObservedLux);
1209 pw.println(" mLastObservedLuxTime="
1210 + TimeUtils.formatUptime(mLastObservedLuxTime));
Jeff Brown96307042012-07-27 15:51:34 -07001211 pw.println(" mRecentLightSamples=" + mRecentLightSamples);
Jeff Brown4f0e9692012-10-18 16:14:16 -07001212 pw.println(" mRecentShortTermAverageLux=" + mRecentShortTermAverageLux);
1213 pw.println(" mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
Jeff Browne941b1e2012-10-22 16:50:25 -07001214 pw.println(" mDebounceLuxDirection=" + mDebounceLuxDirection);
1215 pw.println(" mDebounceLuxTime=" + TimeUtils.formatUptime(mDebounceLuxTime));
Jeff Brown96307042012-07-27 15:51:34 -07001216 pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
1217 pw.println(" mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
Jeff Brown330560f2012-08-21 22:10:57 -07001218 pw.println(" mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
Jeff Brownaa202a62012-08-21 22:14:26 -07001219 pw.println(" mTwilight.getCurrentState()=" + mTwilight.getCurrentState());
Jeff Brown96307042012-07-27 15:51:34 -07001220
1221 if (mElectronBeamOnAnimator != null) {
1222 pw.println(" mElectronBeamOnAnimator.isStarted()=" +
1223 mElectronBeamOnAnimator.isStarted());
1224 }
1225 if (mElectronBeamOffAnimator != null) {
1226 pw.println(" mElectronBeamOffAnimator.isStarted()=" +
1227 mElectronBeamOffAnimator.isStarted());
1228 }
1229
1230 if (mPowerState != null) {
1231 mPowerState.dump(pw);
1232 }
1233 }
1234
1235 private static String proximityToString(int state) {
1236 switch (state) {
1237 case PROXIMITY_UNKNOWN:
1238 return "Unknown";
1239 case PROXIMITY_NEGATIVE:
1240 return "Negative";
1241 case PROXIMITY_POSITIVE:
1242 return "Positive";
1243 default:
1244 return Integer.toString(state);
1245 }
1246 }
1247
1248 private static boolean wantScreenOn(int state) {
1249 switch (state) {
1250 case DisplayPowerRequest.SCREEN_STATE_BRIGHT:
1251 case DisplayPowerRequest.SCREEN_STATE_DIM:
1252 return true;
1253 }
1254 return false;
1255 }
1256
1257 /**
1258 * Asynchronous callbacks from the power controller to the power manager service.
1259 */
1260 public interface Callbacks {
1261 void onStateChanged();
Jeff Brown93cbbb22012-10-04 13:18:36 -07001262 void onProximityPositive();
Jeff Brown96307042012-07-27 15:51:34 -07001263 void onProximityNegative();
1264 }
1265
1266 private final class DisplayControllerHandler extends Handler {
1267 public DisplayControllerHandler(Looper looper) {
Jeff Browna2910d02012-08-25 12:29:46 -07001268 super(looper, null, true /*async*/);
Jeff Brown96307042012-07-27 15:51:34 -07001269 }
1270
1271 @Override
1272 public void handleMessage(Message msg) {
1273 switch (msg.what) {
1274 case MSG_UPDATE_POWER_STATE:
1275 updatePowerState();
1276 break;
1277
1278 case MSG_PROXIMITY_SENSOR_DEBOUNCED:
1279 debounceProximitySensor();
1280 break;
1281
1282 case MSG_LIGHT_SENSOR_DEBOUNCED:
1283 debounceLightSensor();
1284 break;
1285 }
1286 }
1287 }
1288
1289 private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
1290 @Override
1291 public void onSensorChanged(SensorEvent event) {
1292 if (mProximitySensorEnabled) {
1293 final long time = SystemClock.uptimeMillis();
1294 final float distance = event.values[0];
1295 boolean positive = distance >= 0.0f && distance < mProximityThreshold;
1296 handleProximitySensorEvent(time, positive);
1297 }
1298 }
1299
1300 @Override
1301 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1302 // Not used.
1303 }
1304 };
1305
1306 private final SensorEventListener mLightSensorListener = new SensorEventListener() {
1307 @Override
1308 public void onSensorChanged(SensorEvent event) {
1309 if (mLightSensorEnabled) {
1310 final long time = SystemClock.uptimeMillis();
1311 final float lux = event.values[0];
1312 handleLightSensorEvent(time, lux);
1313 }
1314 }
1315
1316 @Override
1317 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1318 // Not used.
1319 }
1320 };
Jeff Brownaa202a62012-08-21 22:14:26 -07001321
1322 private final TwilightService.TwilightListener mTwilightListener =
1323 new TwilightService.TwilightListener() {
1324 @Override
1325 public void onTwilightStateChanged() {
1326 mTwilightChanged = true;
1327 updatePowerState();
1328 }
1329 };
Jeff Brown96307042012-07-27 15:51:34 -07001330}