2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.display;
19 import com.android.internal.app.IBatteryStats;
20 import com.android.server.LocalServices;
21 import com.android.server.am.BatteryStatsService;
22 import com.android.server.lights.LightsManager;
24 import android.animation.Animator;
25 import android.animation.ObjectAnimator;
26 import android.content.Context;
27 import android.content.res.Resources;
28 import android.hardware.Sensor;
29 import android.hardware.SensorEvent;
30 import android.hardware.SensorEventListener;
31 import android.hardware.SensorManager;
32 import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
33 import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
34 import android.os.Handler;
35 import android.os.Looper;
36 import android.os.Message;
37 import android.os.PowerManager;
38 import android.os.RemoteException;
39 import android.os.SystemClock;
40 import android.os.Trace;
41 import android.util.MathUtils;
42 import android.util.Slog;
43 import android.util.Spline;
44 import android.util.TimeUtils;
45 import android.view.Display;
46 import android.view.WindowManagerPolicy;
48 import java.io.PrintWriter;
51 * Controls the power state of the display.
53 * Handles the proximity sensor, light sensor, and animations between states
54 * including the screen off animation.
56 * This component acts independently of the rest of the power manager service.
57 * In particular, it does not share any state and it only communicates
58 * via asynchronous callbacks to inform the power manager that something has
61 * Everything this class does internally is serialized on its handler although
62 * it may be accessed by other threads from the outside.
64 * Note that the power manager service guarantees that it will hold a suspend
65 * blocker as long as the display is not ready. So most of the work done here
66 * does not need to worry about holding a suspend blocker unless it happens
67 * independently of the display ready signal.
69 * For debugging, you can make the color fade and brightness animations run
70 * slower by changing the "animator duration scale" option in Development Settings.
72 final class DisplayPowerController implements AutomaticBrightnessController.Callbacks {
73 private static final String TAG = "DisplayPowerController";
75 private static boolean DEBUG = false;
76 private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
78 private static final String SCREEN_ON_BLOCKED_TRACE_NAME = "Screen on blocked";
80 // If true, uses the color fade on animation.
81 // We might want to turn this off if we cannot get a guarantee that the screen
82 // actually turns on and starts showing new content after the call to set the
83 // screen state returns. Playing the animation can also be somewhat slow.
84 private static final boolean USE_COLOR_FADE_ON_ANIMATION = false;
86 // The minimum reduction in brightness when dimmed.
87 private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
89 private static final int COLOR_FADE_ON_ANIMATION_DURATION_MILLIS = 250;
90 private static final int COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS = 400;
92 private static final int MSG_UPDATE_POWER_STATE = 1;
93 private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
94 private static final int MSG_SCREEN_ON_UNBLOCKED = 3;
96 private static final int PROXIMITY_UNKNOWN = -1;
97 private static final int PROXIMITY_NEGATIVE = 0;
98 private static final int PROXIMITY_POSITIVE = 1;
100 // Proximity sensor debounce delay in milliseconds for positive or negative transitions.
101 private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
102 private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 250;
104 // Trigger proximity if distance is less than 5 cm.
105 private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
107 // Brightness animation ramp rate in brightness units per second.
108 private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
109 private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
111 private final Object mLock = new Object();
113 private final Context mContext;
116 private final DisplayControllerHandler mHandler;
118 // Asynchronous callbacks into the power manager service.
119 // Only invoked from the handler thread while no locks are held.
120 private final DisplayPowerCallbacks mCallbacks;
123 private final IBatteryStats mBatteryStats;
125 // The lights service.
126 private final LightsManager mLights;
128 // The sensor manager.
129 private final SensorManager mSensorManager;
131 // The window manager policy.
132 private final WindowManagerPolicy mWindowManagerPolicy;
134 // The display blanker.
135 private final DisplayBlanker mBlanker;
137 // The proximity sensor, or null if not available or needed.
138 private Sensor mProximitySensor;
140 // The doze screen brightness.
141 private final int mScreenBrightnessDozeConfig;
143 // The dim screen brightness.
144 private final int mScreenBrightnessDimConfig;
146 // The minimum screen brightness to use in a very dark room.
147 private final int mScreenBrightnessDarkConfig;
149 // The minimum allowed brightness.
150 private final int mScreenBrightnessRangeMinimum;
152 // The maximum allowed brightness.
153 private final int mScreenBrightnessRangeMaximum;
155 // True if auto-brightness should be used.
156 private boolean mUseSoftwareAutoBrightnessConfig;
158 // True if we should fade the screen while turning it off, false if we should play
159 // a stylish color fade animation instead.
160 private boolean mColorFadeFadesConfig;
162 // The pending power request.
163 // Initially null until the first call to requestPowerState.
165 private DisplayPowerRequest mPendingRequestLocked;
167 // True if a request has been made to wait for the proximity sensor to go negative.
169 private boolean mPendingWaitForNegativeProximityLocked;
171 // True if the pending power request or wait for negative proximity flag
172 // has been changed since the last update occurred.
174 private boolean mPendingRequestChangedLocked;
176 // Set to true when the important parts of the pending power request have been applied.
177 // The important parts are mainly the screen state. Brightness changes may occur
180 private boolean mDisplayReadyLocked;
182 // Set to true if a power state update is required.
184 private boolean mPendingUpdatePowerStateLocked;
186 /* The following state must only be accessed by the handler thread. */
188 // The currently requested power state.
189 // The power controller will progressively update its internal state to match
190 // the requested power state. Initially null until the first update.
191 private DisplayPowerRequest mPowerRequest;
193 // The current power state.
194 // Must only be accessed on the handler thread.
195 private DisplayPowerState mPowerState;
197 // True if the device should wait for negative proximity sensor before
198 // waking up the screen. This is set to false as soon as a negative
199 // proximity sensor measurement is observed or when the device is forced to
200 // go to sleep by the user. While true, the screen remains off.
201 private boolean mWaitingForNegativeProximity;
203 // The actual proximity sensor threshold value.
204 private float mProximityThreshold;
206 // Set to true if the proximity sensor listener has been registered
207 // with the sensor manager.
208 private boolean mProximitySensorEnabled;
210 // The debounced proximity sensor state.
211 private int mProximity = PROXIMITY_UNKNOWN;
213 // The raw non-debounced proximity sensor state.
214 private int mPendingProximity = PROXIMITY_UNKNOWN;
215 private long mPendingProximityDebounceTime = -1; // -1 if fully debounced
217 // True if the screen was turned off because of the proximity sensor.
218 // When the screen turns on again, we report user activity to the power manager.
219 private boolean mScreenOffBecauseOfProximity;
221 // The currently active screen on unblocker. This field is non-null whenever
222 // we are waiting for a callback to release it and unblock the screen.
223 private ScreenOnUnblocker mPendingScreenOnUnblocker;
225 // True if we were in the process of turning off the screen.
226 // This allows us to recover more gracefully from situations where we abort
227 // turning off the screen.
228 private boolean mPendingScreenOff;
230 // True if we have unfinished business and are holding a suspend blocker.
231 private boolean mUnfinishedBusiness;
233 // The elapsed real time when the screen on was blocked.
234 private long mScreenOnBlockStartRealTime;
236 // Remembers whether certain kinds of brightness adjustments
237 // were recently applied so that we can decide how to transition.
238 private boolean mAppliedAutoBrightness;
239 private boolean mAppliedDimming;
240 private boolean mAppliedLowPower;
242 // The controller for the automatic brightness level.
243 private AutomaticBrightnessController mAutomaticBrightnessController;
246 private ObjectAnimator mColorFadeOnAnimator;
247 private ObjectAnimator mColorFadeOffAnimator;
248 private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
251 * Creates the display power controller.
253 public DisplayPowerController(Context context,
254 DisplayPowerCallbacks callbacks, Handler handler,
255 SensorManager sensorManager, DisplayBlanker blanker) {
256 mHandler = new DisplayControllerHandler(handler.getLooper());
257 mCallbacks = callbacks;
259 mBatteryStats = BatteryStatsService.getService();
260 mLights = LocalServices.getService(LightsManager.class);
261 mSensorManager = sensorManager;
262 mWindowManagerPolicy = LocalServices.getService(WindowManagerPolicy.class);
266 final Resources resources = context.getResources();
267 final int screenBrightnessSettingMinimum = clampAbsoluteBrightness(resources.getInteger(
268 com.android.internal.R.integer.config_screenBrightnessSettingMinimum));
270 mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger(
271 com.android.internal.R.integer.config_screenBrightnessDoze));
273 mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
274 com.android.internal.R.integer.config_screenBrightnessDim));
276 mScreenBrightnessDarkConfig = clampAbsoluteBrightness(resources.getInteger(
277 com.android.internal.R.integer.config_screenBrightnessDark));
278 if (mScreenBrightnessDarkConfig > mScreenBrightnessDimConfig) {
279 Slog.w(TAG, "Expected config_screenBrightnessDark ("
280 + mScreenBrightnessDarkConfig + ") to be less than or equal to "
281 + "config_screenBrightnessDim (" + mScreenBrightnessDimConfig + ").");
283 if (mScreenBrightnessDarkConfig > mScreenBrightnessDimConfig) {
284 Slog.w(TAG, "Expected config_screenBrightnessDark ("
285 + mScreenBrightnessDarkConfig + ") to be less than or equal to "
286 + "config_screenBrightnessSettingMinimum ("
287 + screenBrightnessSettingMinimum + ").");
290 int screenBrightnessRangeMinimum = Math.min(Math.min(
291 screenBrightnessSettingMinimum, mScreenBrightnessDimConfig),
292 mScreenBrightnessDarkConfig);
294 mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
296 mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
297 com.android.internal.R.bool.config_automatic_brightness_available);
298 if (mUseSoftwareAutoBrightnessConfig) {
299 int[] lux = resources.getIntArray(
300 com.android.internal.R.array.config_autoBrightnessLevels);
301 int[] screenBrightness = resources.getIntArray(
302 com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
303 int lightSensorWarmUpTimeConfig = resources.getInteger(
304 com.android.internal.R.integer.config_lightSensorWarmupTime);
306 Spline screenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
307 if (screenAutoBrightnessSpline == null) {
308 Slog.e(TAG, "Error in config.xml. config_autoBrightnessLcdBacklightValues "
309 + "(size " + screenBrightness.length + ") "
310 + "must be monotic and have exactly one more entry than "
311 + "config_autoBrightnessLevels (size " + lux.length + ") "
312 + "which must be strictly increasing. "
313 + "Auto-brightness will be disabled.");
314 mUseSoftwareAutoBrightnessConfig = false;
316 int bottom = clampAbsoluteBrightness(screenBrightness[0]);
317 if (mScreenBrightnessDarkConfig > bottom) {
318 Slog.w(TAG, "config_screenBrightnessDark (" + mScreenBrightnessDarkConfig
319 + ") should be less than or equal to the first value of "
320 + "config_autoBrightnessLcdBacklightValues ("
323 if (bottom < screenBrightnessRangeMinimum) {
324 screenBrightnessRangeMinimum = bottom;
326 mAutomaticBrightnessController = new AutomaticBrightnessController(this,
327 handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
328 lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
329 mScreenBrightnessRangeMaximum);
333 mScreenBrightnessRangeMinimum = screenBrightnessRangeMinimum;
335 mColorFadeFadesConfig = resources.getBoolean(
336 com.android.internal.R.bool.config_animateScreenLights);
338 if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
339 mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
340 if (mProximitySensor != null) {
341 mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
342 TYPICAL_PROXIMITY_THRESHOLD);
349 * Returns true if the proximity sensor screen-off function is available.
351 public boolean isProximitySensorAvailable() {
352 return mProximitySensor != null;
356 * Requests a new power state.
357 * The controller makes a copy of the provided object and then
358 * begins adjusting the power state to match what was requested.
360 * @param request The requested power state.
361 * @param waitForNegativeProximity If true, issues a request to wait for
362 * negative proximity before turning the screen back on, assuming the screen
363 * was turned off by the proximity sensor.
364 * @return True if display is ready, false if there are important changes that must
365 * be made asynchronously (such as turning the screen on), in which case the caller
366 * should grab a wake lock, watch for {@link DisplayPowerCallbacks#onStateChanged()}
367 * then try the request again later until the state converges.
369 public boolean requestPowerState(DisplayPowerRequest request,
370 boolean waitForNegativeProximity) {
372 Slog.d(TAG, "requestPowerState: "
373 + request + ", waitForNegativeProximity=" + waitForNegativeProximity);
376 synchronized (mLock) {
377 boolean changed = false;
379 if (waitForNegativeProximity
380 && !mPendingWaitForNegativeProximityLocked) {
381 mPendingWaitForNegativeProximityLocked = true;
385 if (mPendingRequestLocked == null) {
386 mPendingRequestLocked = new DisplayPowerRequest(request);
388 } else if (!mPendingRequestLocked.equals(request)) {
389 mPendingRequestLocked.copyFrom(request);
394 mDisplayReadyLocked = false;
397 if (changed && !mPendingRequestChangedLocked) {
398 mPendingRequestChangedLocked = true;
399 sendUpdatePowerStateLocked();
402 return mDisplayReadyLocked;
406 private void sendUpdatePowerState() {
407 synchronized (mLock) {
408 sendUpdatePowerStateLocked();
412 private void sendUpdatePowerStateLocked() {
413 if (!mPendingUpdatePowerStateLocked) {
414 mPendingUpdatePowerStateLocked = true;
415 Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
416 msg.setAsynchronous(true);
417 mHandler.sendMessage(msg);
421 private void initialize() {
422 // Initialize the power state object for the default display.
423 // In the future, we might manage multiple displays independently.
424 mPowerState = new DisplayPowerState(mBlanker,
425 mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
426 new ColorFade(Display.DEFAULT_DISPLAY));
428 mColorFadeOnAnimator = ObjectAnimator.ofFloat(
429 mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 0.0f, 1.0f);
430 mColorFadeOnAnimator.setDuration(COLOR_FADE_ON_ANIMATION_DURATION_MILLIS);
431 mColorFadeOnAnimator.addListener(mAnimatorListener);
433 mColorFadeOffAnimator = ObjectAnimator.ofFloat(
434 mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 1.0f, 0.0f);
435 mColorFadeOffAnimator.setDuration(COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS);
436 mColorFadeOffAnimator.addListener(mAnimatorListener);
438 mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
439 mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
440 mScreenBrightnessRampAnimator.setListener(mRampAnimatorListener);
442 // Initialize screen state for battery stats.
444 mBatteryStats.noteScreenState(mPowerState.getScreenState());
445 mBatteryStats.noteScreenBrightness(mPowerState.getScreenBrightness());
446 } catch (RemoteException ex) {
451 private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
453 public void onAnimationStart(Animator animation) {
456 public void onAnimationEnd(Animator animation) {
457 sendUpdatePowerState();
460 public void onAnimationRepeat(Animator animation) {
463 public void onAnimationCancel(Animator animation) {
467 private final RampAnimator.Listener mRampAnimatorListener = new RampAnimator.Listener() {
469 public void onAnimationEnd() {
470 sendUpdatePowerState();
474 private void updatePowerState() {
475 // Update the power state request.
476 final boolean mustNotify;
477 boolean mustInitialize = false;
478 boolean autoBrightnessAdjustmentChanged = false;
480 synchronized (mLock) {
481 mPendingUpdatePowerStateLocked = false;
482 if (mPendingRequestLocked == null) {
483 return; // wait until first actual power request
486 if (mPowerRequest == null) {
487 mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
488 mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
489 mPendingWaitForNegativeProximityLocked = false;
490 mPendingRequestChangedLocked = false;
491 mustInitialize = true;
492 } else if (mPendingRequestChangedLocked) {
493 autoBrightnessAdjustmentChanged = (mPowerRequest.screenAutoBrightnessAdjustment
494 != mPendingRequestLocked.screenAutoBrightnessAdjustment);
495 mPowerRequest.copyFrom(mPendingRequestLocked);
496 mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
497 mPendingWaitForNegativeProximityLocked = false;
498 mPendingRequestChangedLocked = false;
499 mDisplayReadyLocked = false;
502 mustNotify = !mDisplayReadyLocked;
505 // Initialize things the first time the power state is changed.
506 if (mustInitialize) {
510 // Compute the basic display state using the policy.
511 // We might override this below based on other factors.
513 int brightness = PowerManager.BRIGHTNESS_DEFAULT;
514 boolean performScreenOffTransition = false;
515 switch (mPowerRequest.policy) {
516 case DisplayPowerRequest.POLICY_OFF:
517 state = Display.STATE_OFF;
518 performScreenOffTransition = true;
520 case DisplayPowerRequest.POLICY_DOZE:
521 if (mPowerRequest.dozeScreenState != Display.STATE_UNKNOWN) {
522 state = mPowerRequest.dozeScreenState;
524 state = Display.STATE_DOZE;
526 brightness = mPowerRequest.dozeScreenBrightness;
528 case DisplayPowerRequest.POLICY_DIM:
529 case DisplayPowerRequest.POLICY_BRIGHT:
531 state = Display.STATE_ON;
534 assert(state != Display.STATE_UNKNOWN);
536 // Apply the proximity sensor.
537 if (mProximitySensor != null) {
538 if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) {
539 setProximitySensorEnabled(true);
540 if (!mScreenOffBecauseOfProximity
541 && mProximity == PROXIMITY_POSITIVE) {
542 mScreenOffBecauseOfProximity = true;
543 sendOnProximityPositiveWithWakelock();
545 } else if (mWaitingForNegativeProximity
546 && mScreenOffBecauseOfProximity
547 && mProximity == PROXIMITY_POSITIVE
548 && state != Display.STATE_OFF) {
549 setProximitySensorEnabled(true);
551 setProximitySensorEnabled(false);
552 mWaitingForNegativeProximity = false;
554 if (mScreenOffBecauseOfProximity
555 && mProximity != PROXIMITY_POSITIVE) {
556 mScreenOffBecauseOfProximity = false;
557 sendOnProximityNegativeWithWakelock();
560 mWaitingForNegativeProximity = false;
562 if (mScreenOffBecauseOfProximity) {
563 state = Display.STATE_OFF;
566 // Animate the screen state change unless already animating.
567 // The transition may be deferred, so after this point we will use the
568 // actual state instead of the desired one.
569 animateScreenStateChange(state, performScreenOffTransition);
570 state = mPowerState.getScreenState();
572 // Use zero brightness when screen is off.
573 if (state == Display.STATE_OFF) {
574 brightness = PowerManager.BRIGHTNESS_OFF;
577 // Use default brightness when dozing unless overridden.
578 if (brightness < 0 && (state == Display.STATE_DOZE
579 || state == Display.STATE_DOZE_SUSPEND)) {
580 brightness = mScreenBrightnessDozeConfig;
583 // Configure auto-brightness.
584 boolean autoBrightnessEnabled = false;
585 if (mAutomaticBrightnessController != null) {
586 autoBrightnessEnabled = mPowerRequest.useAutoBrightness
587 && state == Display.STATE_ON && brightness < 0;
588 mAutomaticBrightnessController.configure(autoBrightnessEnabled,
589 mPowerRequest.screenAutoBrightnessAdjustment);
592 // Apply auto-brightness.
593 boolean slowChange = false;
594 if (brightness < 0) {
595 if (autoBrightnessEnabled) {
596 brightness = mAutomaticBrightnessController.getAutomaticScreenBrightness();
598 if (brightness >= 0) {
599 // Use current auto-brightness value and slowly adjust to changes.
600 brightness = clampScreenBrightness(brightness);
601 if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
602 slowChange = true; // slowly adapt to auto-brightness
604 mAppliedAutoBrightness = true;
606 mAppliedAutoBrightness = false;
609 mAppliedAutoBrightness = false;
612 // Apply manual brightness.
613 // Use the current brightness setting from the request, which is expected
614 // provide a nominal default value for the case where auto-brightness
616 if (brightness < 0) {
617 brightness = clampScreenBrightness(mPowerRequest.screenBrightness);
620 // Apply dimming by at least some minimum amount when user activity
621 // timeout is about to expire.
622 if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
623 if (brightness > mScreenBrightnessRangeMinimum) {
624 brightness = Math.max(Math.min(brightness - SCREEN_DIM_MINIMUM_REDUCTION,
625 mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum);
627 if (!mAppliedDimming) {
630 mAppliedDimming = true;
633 // If low power mode is enabled, cut the brightness level by half
634 // as long as it is above the minimum threshold.
635 if (mPowerRequest.lowPowerMode) {
636 if (brightness > mScreenBrightnessRangeMinimum) {
637 brightness = Math.max(brightness / 2, mScreenBrightnessRangeMinimum);
639 if (!mAppliedLowPower) {
642 mAppliedLowPower = true;
645 // Animate the screen brightness when the screen is on or dozing.
646 // Skip the animation when the screen is off or suspended.
647 if (state == Display.STATE_ON || state == Display.STATE_DOZE) {
648 animateScreenBrightness(brightness,
649 slowChange ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
651 animateScreenBrightness(brightness, 0);
654 // Determine whether the display is ready for use in the newly requested state.
655 // Note that we do not wait for the brightness ramp animation to complete before
656 // reporting the display is ready because we only need to ensure the screen is in the
657 // right power state even as it continues to converge on the desired brightness.
658 final boolean ready = mPendingScreenOnUnblocker == null
659 && !mColorFadeOnAnimator.isStarted()
660 && !mColorFadeOffAnimator.isStarted()
661 && mPowerState.waitUntilClean(mCleanListener);
662 final boolean finished = ready
663 && !mScreenBrightnessRampAnimator.isAnimating();
665 // Grab a wake lock if we have unfinished business.
666 if (!finished && !mUnfinishedBusiness) {
668 Slog.d(TAG, "Unfinished business...");
670 mCallbacks.acquireSuspendBlocker();
671 mUnfinishedBusiness = true;
674 // Notify the power manager when ready.
675 if (ready && mustNotify) {
676 // Send state change.
677 synchronized (mLock) {
678 if (!mPendingRequestChangedLocked) {
679 mDisplayReadyLocked = true;
682 Slog.d(TAG, "Display ready!");
686 sendOnStateChangedWithWakelock();
689 // Release the wake lock when we have no unfinished business.
690 if (finished && mUnfinishedBusiness) {
692 Slog.d(TAG, "Finished business...");
694 mUnfinishedBusiness = false;
695 mCallbacks.releaseSuspendBlocker();
700 public void updateBrightness() {
701 sendUpdatePowerState();
704 private void blockScreenOn() {
705 if (mPendingScreenOnUnblocker == null) {
706 Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
707 mPendingScreenOnUnblocker = new ScreenOnUnblocker();
708 mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
709 Slog.i(TAG, "Blocking screen on until initial contents have been drawn.");
713 private void unblockScreenOn() {
714 if (mPendingScreenOnUnblocker != null) {
715 mPendingScreenOnUnblocker = null;
716 long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
717 Slog.i(TAG, "Unblocked screen on after " + delay + " ms");
718 Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
722 private boolean setScreenState(int state) {
723 if (mPowerState.getScreenState() != state) {
724 final boolean wasOn = (mPowerState.getScreenState() != Display.STATE_OFF);
725 mPowerState.setScreenState(state);
727 // Tell battery stats about the transition.
729 mBatteryStats.noteScreenState(state);
730 } catch (RemoteException ex) {
734 // Tell the window manager what's happening.
735 // Temporarily block turning the screen on until the window manager is ready
736 // by leaving a black surface covering the screen. This surface is essentially
737 // the final state of the color fade animation.
738 boolean isOn = (state != Display.STATE_OFF);
739 if (wasOn && !isOn) {
741 mWindowManagerPolicy.screenTurnedOff();
742 } else if (!wasOn && isOn) {
743 if (mPowerState.getColorFadeLevel() == 0.0f) {
748 mWindowManagerPolicy.screenTurningOn(mPendingScreenOnUnblocker);
751 return mPendingScreenOnUnblocker == null;
754 private int clampScreenBrightness(int value) {
755 return MathUtils.constrain(
756 value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
759 private void animateScreenBrightness(int target, int rate) {
761 Slog.d(TAG, "Animating brightness: target=" + target +", rate=" + rate);
763 if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
765 mBatteryStats.noteScreenBrightness(target);
766 } catch (RemoteException ex) {
772 private void animateScreenStateChange(int target, boolean performScreenOffTransition) {
773 // If there is already an animation in progress, don't interfere with it.
774 if (mColorFadeOnAnimator.isStarted()
775 || mColorFadeOffAnimator.isStarted()) {
779 // If we were in the process of turning off the screen but didn't quite
780 // finish. Then finish up now to prevent a jarring transition back
781 // to screen on if we skipped blocking screen on as usual.
782 if (mPendingScreenOff && target != Display.STATE_OFF) {
783 setScreenState(Display.STATE_OFF);
784 mPendingScreenOff = false;
787 if (target == Display.STATE_ON) {
788 // Want screen on. The contents of the screen may not yet
789 // be visible if the color fade has not been dismissed because
790 // its last frame of animation is solid black.
791 if (!setScreenState(Display.STATE_ON)) {
792 return; // screen on blocked
794 if (USE_COLOR_FADE_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {
795 // Perform screen on animation.
796 if (mPowerState.getColorFadeLevel() == 1.0f) {
797 mPowerState.dismissColorFade();
798 } else if (mPowerState.prepareColorFade(mContext,
799 mColorFadeFadesConfig ?
800 ColorFade.MODE_FADE :
801 ColorFade.MODE_WARM_UP)) {
802 mColorFadeOnAnimator.start();
804 mColorFadeOnAnimator.end();
807 // Skip screen on animation.
808 mPowerState.setColorFadeLevel(1.0f);
809 mPowerState.dismissColorFade();
811 } else if (target == Display.STATE_DOZE) {
812 // Want screen dozing.
813 // Wait for brightness animation to complete beforehand when entering doze
814 // from screen on to prevent a perceptible jump because brightness may operate
815 // differently when the display is configured for dozing.
816 if (mScreenBrightnessRampAnimator.isAnimating()
817 && mPowerState.getScreenState() == Display.STATE_ON) {
822 if (!setScreenState(Display.STATE_DOZE)) {
823 return; // screen on blocked
826 // Dismiss the black surface without fanfare.
827 mPowerState.setColorFadeLevel(1.0f);
828 mPowerState.dismissColorFade();
829 } else if (target == Display.STATE_DOZE_SUSPEND) {
830 // Want screen dozing and suspended.
831 // Wait for brightness animation to complete beforehand unless already
832 // suspended because we may not be able to change it after suspension.
833 if (mScreenBrightnessRampAnimator.isAnimating()
834 && mPowerState.getScreenState() != Display.STATE_DOZE_SUSPEND) {
838 // If not already suspending, temporarily set the state to doze until the
839 // screen on is unblocked, then suspend.
840 if (mPowerState.getScreenState() != Display.STATE_DOZE_SUSPEND) {
841 if (!setScreenState(Display.STATE_DOZE)) {
842 return; // screen on blocked
844 setScreenState(Display.STATE_DOZE_SUSPEND); // already on so can't block
847 // Dismiss the black surface without fanfare.
848 mPowerState.setColorFadeLevel(1.0f);
849 mPowerState.dismissColorFade();
852 mPendingScreenOff = true;
853 if (mPowerState.getColorFadeLevel() == 0.0f) {
854 // Turn the screen off.
855 // A black surface is already hiding the contents of the screen.
856 setScreenState(Display.STATE_OFF);
857 mPendingScreenOff = false;
858 } else if (performScreenOffTransition
859 && mPowerState.prepareColorFade(mContext,
860 mColorFadeFadesConfig ?
861 ColorFade.MODE_FADE : ColorFade.MODE_COOL_DOWN)
862 && mPowerState.getScreenState() != Display.STATE_OFF) {
863 // Perform the screen off animation.
864 mColorFadeOffAnimator.start();
866 // Skip the screen off animation and add a black surface to hide the
867 // contents of the screen.
868 mColorFadeOffAnimator.end();
873 private final Runnable mCleanListener = new Runnable() {
876 sendUpdatePowerState();
880 private void setProximitySensorEnabled(boolean enable) {
882 if (!mProximitySensorEnabled) {
883 // Register the listener.
884 // Proximity sensor state already cleared initially.
885 mProximitySensorEnabled = true;
886 mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
887 SensorManager.SENSOR_DELAY_NORMAL, mHandler);
890 if (mProximitySensorEnabled) {
891 // Unregister the listener.
892 // Clear the proximity sensor state for next time.
893 mProximitySensorEnabled = false;
894 mProximity = PROXIMITY_UNKNOWN;
895 mPendingProximity = PROXIMITY_UNKNOWN;
896 mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
897 mSensorManager.unregisterListener(mProximitySensorListener);
898 clearPendingProximityDebounceTime(); // release wake lock (must be last)
903 private void handleProximitySensorEvent(long time, boolean positive) {
904 if (mProximitySensorEnabled) {
905 if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
908 if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
912 // Only accept a proximity sensor reading if it remains
913 // stable for the entire debounce delay. We hold a wake lock while
914 // debouncing the sensor.
915 mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
917 mPendingProximity = PROXIMITY_POSITIVE;
918 setPendingProximityDebounceTime(
919 time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); // acquire wake lock
921 mPendingProximity = PROXIMITY_NEGATIVE;
922 setPendingProximityDebounceTime(
923 time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); // acquire wake lock
926 // Debounce the new sensor reading.
927 debounceProximitySensor();
931 private void debounceProximitySensor() {
932 if (mProximitySensorEnabled
933 && mPendingProximity != PROXIMITY_UNKNOWN
934 && mPendingProximityDebounceTime >= 0) {
935 final long now = SystemClock.uptimeMillis();
936 if (mPendingProximityDebounceTime <= now) {
937 // Sensor reading accepted. Apply the change then release the wake lock.
938 mProximity = mPendingProximity;
940 clearPendingProximityDebounceTime(); // release wake lock (must be last)
942 // Need to wait a little longer.
943 // Debounce again later. We continue holding a wake lock while waiting.
944 Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
945 msg.setAsynchronous(true);
946 mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
951 private void clearPendingProximityDebounceTime() {
952 if (mPendingProximityDebounceTime >= 0) {
953 mPendingProximityDebounceTime = -1;
954 mCallbacks.releaseSuspendBlocker(); // release wake lock
958 private void setPendingProximityDebounceTime(long debounceTime) {
959 if (mPendingProximityDebounceTime < 0) {
960 mCallbacks.acquireSuspendBlocker(); // acquire wake lock
962 mPendingProximityDebounceTime = debounceTime;
965 private void sendOnStateChangedWithWakelock() {
966 mCallbacks.acquireSuspendBlocker();
967 mHandler.post(mOnStateChangedRunnable);
970 private final Runnable mOnStateChangedRunnable = new Runnable() {
973 mCallbacks.onStateChanged();
974 mCallbacks.releaseSuspendBlocker();
978 private void sendOnProximityPositiveWithWakelock() {
979 mCallbacks.acquireSuspendBlocker();
980 mHandler.post(mOnProximityPositiveRunnable);
983 private final Runnable mOnProximityPositiveRunnable = new Runnable() {
986 mCallbacks.onProximityPositive();
987 mCallbacks.releaseSuspendBlocker();
991 private void sendOnProximityNegativeWithWakelock() {
992 mCallbacks.acquireSuspendBlocker();
993 mHandler.post(mOnProximityNegativeRunnable);
996 private final Runnable mOnProximityNegativeRunnable = new Runnable() {
999 mCallbacks.onProximityNegative();
1000 mCallbacks.releaseSuspendBlocker();
1004 public void dump(final PrintWriter pw) {
1005 synchronized (mLock) {
1007 pw.println("Display Power Controller Locked State:");
1008 pw.println(" mDisplayReadyLocked=" + mDisplayReadyLocked);
1009 pw.println(" mPendingRequestLocked=" + mPendingRequestLocked);
1010 pw.println(" mPendingRequestChangedLocked=" + mPendingRequestChangedLocked);
1011 pw.println(" mPendingWaitForNegativeProximityLocked="
1012 + mPendingWaitForNegativeProximityLocked);
1013 pw.println(" mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked);
1017 pw.println("Display Power Controller Configuration:");
1018 pw.println(" mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
1019 pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
1020 pw.println(" mScreenBrightnessDarkConfig=" + mScreenBrightnessDarkConfig);
1021 pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
1022 pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
1023 pw.println(" mUseSoftwareAutoBrightnessConfig=" + mUseSoftwareAutoBrightnessConfig);
1024 pw.println(" mColorFadeFadesConfig=" + mColorFadeFadesConfig);
1026 mHandler.runWithScissors(new Runnable() {
1034 private void dumpLocal(PrintWriter pw) {
1036 pw.println("Display Power Controller Thread State:");
1037 pw.println(" mPowerRequest=" + mPowerRequest);
1038 pw.println(" mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
1040 pw.println(" mProximitySensor=" + mProximitySensor);
1041 pw.println(" mProximitySensorEnabled=" + mProximitySensorEnabled);
1042 pw.println(" mProximityThreshold=" + mProximityThreshold);
1043 pw.println(" mProximity=" + proximityToString(mProximity));
1044 pw.println(" mPendingProximity=" + proximityToString(mPendingProximity));
1045 pw.println(" mPendingProximityDebounceTime="
1046 + TimeUtils.formatUptime(mPendingProximityDebounceTime));
1047 pw.println(" mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
1048 pw.println(" mAppliedAutoBrightness=" + mAppliedAutoBrightness);
1049 pw.println(" mAppliedDimming=" + mAppliedDimming);
1050 pw.println(" mAppliedLowPower=" + mAppliedLowPower);
1051 pw.println(" mPendingScreenOnUnblocker=" + mPendingScreenOnUnblocker);
1052 pw.println(" mPendingScreenOff=" + mPendingScreenOff);
1054 pw.println(" mScreenBrightnessRampAnimator.isAnimating()=" +
1055 mScreenBrightnessRampAnimator.isAnimating());
1057 if (mColorFadeOnAnimator != null) {
1058 pw.println(" mColorFadeOnAnimator.isStarted()=" +
1059 mColorFadeOnAnimator.isStarted());
1061 if (mColorFadeOffAnimator != null) {
1062 pw.println(" mColorFadeOffAnimator.isStarted()=" +
1063 mColorFadeOffAnimator.isStarted());
1066 if (mPowerState != null) {
1067 mPowerState.dump(pw);
1070 if (mAutomaticBrightnessController != null) {
1071 mAutomaticBrightnessController.dump(pw);
1076 private static String proximityToString(int state) {
1078 case PROXIMITY_UNKNOWN:
1080 case PROXIMITY_NEGATIVE:
1082 case PROXIMITY_POSITIVE:
1085 return Integer.toString(state);
1089 private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
1091 final int n = brightness.length;
1092 float[] x = new float[n];
1093 float[] y = new float[n];
1094 y[0] = normalizeAbsoluteBrightness(brightness[0]);
1095 for (int i = 1; i < n; i++) {
1097 y[i] = normalizeAbsoluteBrightness(brightness[i]);
1100 Spline spline = Spline.createSpline(x, y);
1102 Slog.d(TAG, "Auto-brightness spline: " + spline);
1103 for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
1104 Slog.d(TAG, String.format(" %7.1f: %7.1f", v, spline.interpolate(v)));
1108 } catch (IllegalArgumentException ex) {
1109 Slog.e(TAG, "Could not create auto-brightness spline.", ex);
1114 private static float normalizeAbsoluteBrightness(int value) {
1115 return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
1118 private static int clampAbsoluteBrightness(int value) {
1119 return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
1122 private final class DisplayControllerHandler extends Handler {
1123 public DisplayControllerHandler(Looper looper) {
1124 super(looper, null, true /*async*/);
1128 public void handleMessage(Message msg) {
1130 case MSG_UPDATE_POWER_STATE:
1134 case MSG_PROXIMITY_SENSOR_DEBOUNCED:
1135 debounceProximitySensor();
1138 case MSG_SCREEN_ON_UNBLOCKED:
1139 if (mPendingScreenOnUnblocker == msg.obj) {
1148 private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
1150 public void onSensorChanged(SensorEvent event) {
1151 if (mProximitySensorEnabled) {
1152 final long time = SystemClock.uptimeMillis();
1153 final float distance = event.values[0];
1154 boolean positive = distance >= 0.0f && distance < mProximityThreshold;
1155 handleProximitySensorEvent(time, positive);
1160 public void onAccuracyChanged(Sensor sensor, int accuracy) {
1165 private final class ScreenOnUnblocker implements WindowManagerPolicy.ScreenOnListener {
1167 public void onScreenOn() {
1168 Message msg = mHandler.obtainMessage(MSG_SCREEN_ON_UNBLOCKED, this);
1169 msg.setAsynchronous(true);
1170 mHandler.sendMessage(msg);