DisplayPowerController.java revision 0839adb25c6d1a9f4e06fc5a098ffd03c67dbe99
1/*
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.display;
18
19import com.android.internal.app.IBatteryStats;
20import com.android.server.LocalServices;
21import com.android.server.am.BatteryStatsService;
22import com.android.server.lights.LightsManager;
23
24import android.animation.Animator;
25import android.animation.ObjectAnimator;
26import android.content.Context;
27import android.content.res.Resources;
28import android.hardware.Sensor;
29import android.hardware.SensorEvent;
30import android.hardware.SensorEventListener;
31import android.hardware.SensorManager;
32import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
33import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
34import android.os.Handler;
35import android.os.Looper;
36import android.os.Message;
37import android.os.PowerManager;
38import android.os.RemoteException;
39import android.os.SystemClock;
40import android.text.format.DateUtils;
41import android.util.MathUtils;
42import android.util.Slog;
43import android.util.Spline;
44import android.util.TimeUtils;
45import android.view.Display;
46
47import java.io.PrintWriter;
48
49/**
50 * Controls the power state of the display.
51 *
52 * Handles the proximity sensor, light sensor, and animations between states
53 * including the screen off animation.
54 *
55 * This component acts independently of the rest of the power manager service.
56 * In particular, it does not share any state and it only communicates
57 * via asynchronous callbacks to inform the power manager that something has
58 * changed.
59 *
60 * Everything this class does internally is serialized on its handler although
61 * it may be accessed by other threads from the outside.
62 *
63 * Note that the power manager service guarantees that it will hold a suspend
64 * blocker as long as the display is not ready.  So most of the work done here
65 * does not need to worry about holding a suspend blocker unless it happens
66 * independently of the display ready signal.
67   *
68 * For debugging, you can make the electron beam and brightness animations run
69 * slower by changing the "animator duration scale" option in Development Settings.
70 */
71final class DisplayPowerController implements AutomaticBrightnessController.Callbacks {
72    private static final String TAG = "DisplayPowerController";
73
74    private static boolean DEBUG = false;
75    private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
76
77    // If true, uses the electron beam on animation.
78    // We might want to turn this off if we cannot get a guarantee that the screen
79    // actually turns on and starts showing new content after the call to set the
80    // screen state returns.  Playing the animation can also be somewhat slow.
81    private static final boolean USE_COLOR_FADE_ON_ANIMATION = false;
82
83
84    // The minimum reduction in brightness when dimmed.
85    private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
86
87    private static final int COLOR_FADE_ON_ANIMATION_DURATION_MILLIS = 250;
88    private static final int COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS = 600;
89
90    private static final int MSG_UPDATE_POWER_STATE = 1;
91    private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
92
93    private static final int PROXIMITY_UNKNOWN = -1;
94    private static final int PROXIMITY_NEGATIVE = 0;
95    private static final int PROXIMITY_POSITIVE = 1;
96
97    // Proximity sensor debounce delay in milliseconds for positive or negative transitions.
98    private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
99    private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 250;
100
101    // Trigger proximity if distance is less than 5 cm.
102    private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
103
104    // Brightness animation ramp rate in brightness units per second.
105    private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
106    private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
107
108    private final Object mLock = new Object();
109
110    private final Context mContext;
111
112    // Our handler.
113    private final DisplayControllerHandler mHandler;
114
115    // Asynchronous callbacks into the power manager service.
116    // Only invoked from the handler thread while no locks are held.
117    private final DisplayPowerCallbacks mCallbacks;
118
119    // Battery stats.
120    private final IBatteryStats mBatteryStats;
121
122    // The lights service.
123    private final LightsManager mLights;
124
125    // The sensor manager.
126    private final SensorManager mSensorManager;
127
128    // The display blanker.
129    private final DisplayBlanker mBlanker;
130
131    // The proximity sensor, or null if not available or needed.
132    private Sensor mProximitySensor;
133
134    // The doze screen brightness.
135    private final int mScreenBrightnessDozeConfig;
136
137    // The dim screen brightness.
138    private final int mScreenBrightnessDimConfig;
139
140    // The minimum allowed brightness.
141    private final int mScreenBrightnessRangeMinimum;
142
143    // The maximum allowed brightness.
144    private final int mScreenBrightnessRangeMaximum;
145
146    // True if auto-brightness should be used.
147    private boolean mUseSoftwareAutoBrightnessConfig;
148
149    // True if we should fade the screen while turning it off, false if we should play
150    // a stylish electron beam animation instead.
151    private boolean mColorFadeFadesConfig;
152
153    // The pending power request.
154    // Initially null until the first call to requestPowerState.
155    // Guarded by mLock.
156    private DisplayPowerRequest mPendingRequestLocked;
157
158    // True if a request has been made to wait for the proximity sensor to go negative.
159    // Guarded by mLock.
160    private boolean mPendingWaitForNegativeProximityLocked;
161
162    // True if the pending power request or wait for negative proximity flag
163    // has been changed since the last update occurred.
164    // Guarded by mLock.
165    private boolean mPendingRequestChangedLocked;
166
167    // Set to true when the important parts of the pending power request have been applied.
168    // The important parts are mainly the screen state.  Brightness changes may occur
169    // concurrently.
170    // Guarded by mLock.
171    private boolean mDisplayReadyLocked;
172
173    // Set to true if a power state update is required.
174    // Guarded by mLock.
175    private boolean mPendingUpdatePowerStateLocked;
176
177    /* The following state must only be accessed by the handler thread. */
178
179    // The currently requested power state.
180    // The power controller will progressively update its internal state to match
181    // the requested power state.  Initially null until the first update.
182    private DisplayPowerRequest mPowerRequest;
183
184    // The current power state.
185    // Must only be accessed on the handler thread.
186    private DisplayPowerState mPowerState;
187
188    // True if the device should wait for negative proximity sensor before
189    // waking up the screen.  This is set to false as soon as a negative
190    // proximity sensor measurement is observed or when the device is forced to
191    // go to sleep by the user.  While true, the screen remains off.
192    private boolean mWaitingForNegativeProximity;
193
194    // The actual proximity sensor threshold value.
195    private float mProximityThreshold;
196
197    // Set to true if the proximity sensor listener has been registered
198    // with the sensor manager.
199    private boolean mProximitySensorEnabled;
200
201    // The debounced proximity sensor state.
202    private int mProximity = PROXIMITY_UNKNOWN;
203
204    // The raw non-debounced proximity sensor state.
205    private int mPendingProximity = PROXIMITY_UNKNOWN;
206    private long mPendingProximityDebounceTime = -1; // -1 if fully debounced
207
208    // True if the screen was turned off because of the proximity sensor.
209    // When the screen turns on again, we report user activity to the power manager.
210    private boolean mScreenOffBecauseOfProximity;
211
212    // True if the screen on is being blocked.
213    private boolean mScreenOnWasBlocked;
214
215    // The elapsed real time when the screen on was blocked.
216    private long mScreenOnBlockStartRealTime;
217
218    // Remembers whether certain kinds of brightness adjustments
219    // were recently applied so that we can decide how to transition.
220    private boolean mAppliedAutoBrightness;
221    private boolean mAppliedDimming;
222    private boolean mAppliedLowPower;
223
224    // The controller for the automatic brightness level.
225    private AutomaticBrightnessController mAutomaticBrightnessController;
226
227    // Animators.
228    private ObjectAnimator mColorFadeOnAnimator;
229    private ObjectAnimator mColorFadeOffAnimator;
230    private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
231
232    /**
233     * Creates the display power controller.
234     */
235    public DisplayPowerController(Context context,
236            DisplayPowerCallbacks callbacks, Handler handler,
237            SensorManager sensorManager, DisplayBlanker blanker) {
238        mHandler = new DisplayControllerHandler(handler.getLooper());
239        mCallbacks = callbacks;
240
241        mBatteryStats = BatteryStatsService.getService();
242        mLights = LocalServices.getService(LightsManager.class);
243        mSensorManager = sensorManager;
244        mBlanker = blanker;
245        mContext = context;
246
247        final Resources resources = context.getResources();
248
249        mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger(
250                com.android.internal.R.integer.config_screenBrightnessDoze));
251
252        mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
253                com.android.internal.R.integer.config_screenBrightnessDim));
254
255        int screenBrightnessRangeMinimum = clampAbsoluteBrightness(Math.min(resources.getInteger(
256                com.android.internal.R.integer.config_screenBrightnessSettingMinimum),
257                mScreenBrightnessDimConfig));
258
259        mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
260
261        mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
262                com.android.internal.R.bool.config_automatic_brightness_available);
263        if (mUseSoftwareAutoBrightnessConfig) {
264            int[] lux = resources.getIntArray(
265                    com.android.internal.R.array.config_autoBrightnessLevels);
266            int[] screenBrightness = resources.getIntArray(
267                    com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
268            int lightSensorWarmUpTimeConfig = resources.getInteger(
269                    com.android.internal.R.integer.config_lightSensorWarmupTime);
270
271            Spline screenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
272            if (screenAutoBrightnessSpline == null) {
273                Slog.e(TAG, "Error in config.xml.  config_autoBrightnessLcdBacklightValues "
274                        + "(size " + screenBrightness.length + ") "
275                        + "must be monotic and have exactly one more entry than "
276                        + "config_autoBrightnessLevels (size " + lux.length + ") "
277                        + "which must be strictly increasing.  "
278                        + "Auto-brightness will be disabled.");
279                mUseSoftwareAutoBrightnessConfig = false;
280            } else {
281                if (screenBrightness[0] < screenBrightnessRangeMinimum) {
282                    screenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightness[0]);
283                }
284                mAutomaticBrightnessController = new AutomaticBrightnessController(this,
285                        handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
286                        lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
287                        mScreenBrightnessRangeMaximum);
288            }
289        }
290
291        mScreenBrightnessRangeMinimum = screenBrightnessRangeMinimum;
292
293        mColorFadeFadesConfig = resources.getBoolean(
294                com.android.internal.R.bool.config_animateScreenLights);
295
296        if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
297            mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
298            if (mProximitySensor != null) {
299                mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
300                        TYPICAL_PROXIMITY_THRESHOLD);
301            }
302        }
303
304    }
305
306    /**
307     * Returns true if the proximity sensor screen-off function is available.
308     */
309    public boolean isProximitySensorAvailable() {
310        return mProximitySensor != null;
311    }
312
313    /**
314     * Requests a new power state.
315     * The controller makes a copy of the provided object and then
316     * begins adjusting the power state to match what was requested.
317     *
318     * @param request The requested power state.
319     * @param waitForNegativeProximity If true, issues a request to wait for
320     * negative proximity before turning the screen back on, assuming the screen
321     * was turned off by the proximity sensor.
322     * @return True if display is ready, false if there are important changes that must
323     * be made asynchronously (such as turning the screen on), in which case the caller
324     * should grab a wake lock, watch for {@link Callbacks#onStateChanged()} then try
325     * the request again later until the state converges.
326     */
327    public boolean requestPowerState(DisplayPowerRequest request,
328            boolean waitForNegativeProximity) {
329        if (DEBUG) {
330            Slog.d(TAG, "requestPowerState: "
331                    + request + ", waitForNegativeProximity=" + waitForNegativeProximity);
332        }
333
334        synchronized (mLock) {
335            boolean changed = false;
336
337            if (waitForNegativeProximity
338                    && !mPendingWaitForNegativeProximityLocked) {
339                mPendingWaitForNegativeProximityLocked = true;
340                changed = true;
341            }
342
343            if (mPendingRequestLocked == null) {
344                mPendingRequestLocked = new DisplayPowerRequest(request);
345                changed = true;
346            } else if (!mPendingRequestLocked.equals(request)) {
347                mPendingRequestLocked.copyFrom(request);
348                changed = true;
349            }
350
351            if (changed) {
352                mDisplayReadyLocked = false;
353            }
354
355            if (changed && !mPendingRequestChangedLocked) {
356                mPendingRequestChangedLocked = true;
357                sendUpdatePowerStateLocked();
358            }
359
360            return mDisplayReadyLocked;
361        }
362    }
363
364    private void sendUpdatePowerState() {
365        synchronized (mLock) {
366            sendUpdatePowerStateLocked();
367        }
368    }
369
370    private void sendUpdatePowerStateLocked() {
371        if (!mPendingUpdatePowerStateLocked) {
372            mPendingUpdatePowerStateLocked = true;
373            Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
374            msg.setAsynchronous(true);
375            mHandler.sendMessage(msg);
376        }
377    }
378
379    private void initialize() {
380        // Initialize the power state object for the default display.
381        // In the future, we might manage multiple displays independently.
382        mPowerState = new DisplayPowerState(mBlanker,
383                mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
384                new ColorFade(Display.DEFAULT_DISPLAY));
385
386        mColorFadeOnAnimator = ObjectAnimator.ofFloat(
387                mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 0.0f, 1.0f);
388        mColorFadeOnAnimator.setDuration(COLOR_FADE_ON_ANIMATION_DURATION_MILLIS);
389        mColorFadeOnAnimator.addListener(mAnimatorListener);
390
391        mColorFadeOffAnimator = ObjectAnimator.ofFloat(
392                mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 1.0f, 0.0f);
393        mColorFadeOffAnimator.setDuration(COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS);
394        mColorFadeOffAnimator.addListener(mAnimatorListener);
395
396        mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
397                mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
398        mScreenBrightnessRampAnimator.setListener(mRampAnimatorListener);
399
400        // Initialize screen state for battery stats.
401        try {
402            mBatteryStats.noteScreenState(mPowerState.getScreenState());
403            mBatteryStats.noteScreenBrightness(mPowerState.getScreenBrightness());
404        } catch (RemoteException ex) {
405            // same process
406        }
407    }
408
409    private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
410        @Override
411        public void onAnimationStart(Animator animation) {
412        }
413        @Override
414        public void onAnimationEnd(Animator animation) {
415            sendUpdatePowerState();
416        }
417        @Override
418        public void onAnimationRepeat(Animator animation) {
419        }
420        @Override
421        public void onAnimationCancel(Animator animation) {
422        }
423    };
424
425    private final RampAnimator.Listener mRampAnimatorListener = new RampAnimator.Listener() {
426        @Override
427        public void onAnimationEnd() {
428            sendUpdatePowerState();
429        }
430    };
431
432    private void updatePowerState() {
433        // Update the power state request.
434        final boolean mustNotify;
435        boolean mustInitialize = false;
436        boolean autoBrightnessAdjustmentChanged = false;
437
438        synchronized (mLock) {
439            mPendingUpdatePowerStateLocked = false;
440            if (mPendingRequestLocked == null) {
441                return; // wait until first actual power request
442            }
443
444            if (mPowerRequest == null) {
445                mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
446                mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
447                mPendingWaitForNegativeProximityLocked = false;
448                mPendingRequestChangedLocked = false;
449                mustInitialize = true;
450            } else if (mPendingRequestChangedLocked) {
451                autoBrightnessAdjustmentChanged = (mPowerRequest.screenAutoBrightnessAdjustment
452                        != mPendingRequestLocked.screenAutoBrightnessAdjustment);
453                mPowerRequest.copyFrom(mPendingRequestLocked);
454                mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
455                mPendingWaitForNegativeProximityLocked = false;
456                mPendingRequestChangedLocked = false;
457                mDisplayReadyLocked = false;
458            }
459
460            mustNotify = !mDisplayReadyLocked;
461        }
462
463        // Initialize things the first time the power state is changed.
464        if (mustInitialize) {
465            initialize();
466        }
467
468        // Compute the basic display state using the policy.
469        // We might override this below based on other factors.
470        int state;
471        int brightness = PowerManager.BRIGHTNESS_DEFAULT;
472        switch (mPowerRequest.policy) {
473            case DisplayPowerRequest.POLICY_OFF:
474                state = Display.STATE_OFF;
475                break;
476            case DisplayPowerRequest.POLICY_DOZE:
477                if (mPowerRequest.dozeScreenState != Display.STATE_UNKNOWN) {
478                    state = mPowerRequest.dozeScreenState;
479                } else {
480                    state = Display.STATE_DOZE;
481                }
482                brightness = mPowerRequest.dozeScreenBrightness;
483                break;
484            case DisplayPowerRequest.POLICY_DIM:
485            case DisplayPowerRequest.POLICY_BRIGHT:
486            default:
487                state = Display.STATE_ON;
488                break;
489        }
490
491        // Apply the proximity sensor.
492        if (mProximitySensor != null) {
493            if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) {
494                setProximitySensorEnabled(true);
495                if (!mScreenOffBecauseOfProximity
496                        && mProximity == PROXIMITY_POSITIVE) {
497                    mScreenOffBecauseOfProximity = true;
498                    sendOnProximityPositiveWithWakelock();
499                }
500            } else if (mWaitingForNegativeProximity
501                    && mScreenOffBecauseOfProximity
502                    && mProximity == PROXIMITY_POSITIVE
503                    && state != Display.STATE_OFF) {
504                setProximitySensorEnabled(true);
505            } else {
506                setProximitySensorEnabled(false);
507                mWaitingForNegativeProximity = false;
508            }
509            if (mScreenOffBecauseOfProximity
510                    && mProximity != PROXIMITY_POSITIVE) {
511                mScreenOffBecauseOfProximity = false;
512                sendOnProximityNegativeWithWakelock();
513            }
514        } else {
515            mWaitingForNegativeProximity = false;
516        }
517        if (mScreenOffBecauseOfProximity) {
518            state = Display.STATE_OFF;
519        }
520
521        // Use zero brightness when screen is off.
522        if (state == Display.STATE_OFF) {
523            brightness = PowerManager.BRIGHTNESS_OFF;
524        }
525
526        // Use default brightness when dozing unless overridden.
527        if (brightness < 0 && (state == Display.STATE_DOZE
528                || state == Display.STATE_DOZE_SUSPEND)) {
529            brightness = mScreenBrightnessDozeConfig;
530        }
531
532        // Configure auto-brightness.
533        boolean autoBrightnessEnabled = false;
534        if (mAutomaticBrightnessController != null) {
535            autoBrightnessEnabled = mPowerRequest.useAutoBrightness
536                    && state == Display.STATE_ON && brightness < 0;
537            mAutomaticBrightnessController.configure(autoBrightnessEnabled,
538                    mPowerRequest.screenAutoBrightnessAdjustment);
539        }
540
541        // Apply auto-brightness.
542        boolean slowChange = false;
543        if (brightness < 0) {
544            if (autoBrightnessEnabled) {
545                brightness = mAutomaticBrightnessController.getAutomaticScreenBrightness();
546            }
547            if (brightness >= 0) {
548                // Use current auto-brightness value and slowly adjust to changes.
549                brightness = clampScreenBrightness(brightness);
550                if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
551                    slowChange = true; // slowly adapt to auto-brightness
552                }
553                mAppliedAutoBrightness = true;
554            } else {
555                mAppliedAutoBrightness = false;
556            }
557        } else {
558            mAppliedAutoBrightness = false;
559        }
560
561        // Apply manual brightness.
562        // Use the current brightness setting from the request, which is expected
563        // provide a nominal default value for the case where auto-brightness
564        // is not ready yet.
565        if (brightness < 0) {
566            brightness = clampScreenBrightness(mPowerRequest.screenBrightness);
567        }
568
569        // Apply dimming by at least some minimum amount when user activity
570        // timeout is about to expire.
571        if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
572            if (brightness > mScreenBrightnessRangeMinimum) {
573                brightness = Math.max(Math.min(brightness - SCREEN_DIM_MINIMUM_REDUCTION,
574                        mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum);
575            }
576            if (!mAppliedDimming) {
577                slowChange = false;
578            }
579            mAppliedDimming = true;
580        }
581
582        // If low power mode is enabled, cut the brightness level by half
583        // as long as it is above the minimum threshold.
584        if (mPowerRequest.lowPowerMode) {
585            if (brightness > mScreenBrightnessRangeMinimum) {
586                brightness = Math.max(brightness / 2, mScreenBrightnessRangeMinimum);
587            }
588            if (!mAppliedLowPower) {
589                slowChange = false;
590            }
591            mAppliedLowPower = true;
592        }
593
594        // Animate the screen brightness when the screen is on.
595        if (state != Display.STATE_OFF) {
596            animateScreenBrightness(brightness, slowChange
597                    ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
598        }
599
600        // Animate the screen on or off unless blocked.
601        if (state == Display.STATE_ON) {
602            // Want screen on.
603            // Wait for previous off animation to complete beforehand.
604            // It is relatively short but if we cancel it and switch to the
605            // on animation immediately then the results are pretty ugly.
606            if (!mColorFadeOffAnimator.isStarted()) {
607                // Turn the screen on.  The contents of the screen may not yet
608                // be visible if the electron beam has not been dismissed because
609                // its last frame of animation is solid black.
610                setScreenState(Display.STATE_ON);
611                if (mPowerRequest.blockScreenOn
612                        && mPowerState.getColorFadeLevel() == 0.0f) {
613                    blockScreenOn();
614                } else {
615                    unblockScreenOn();
616                    if (USE_COLOR_FADE_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {
617                        // Perform screen on animation.
618                        if (!mColorFadeOnAnimator.isStarted()) {
619                            if (mPowerState.getColorFadeLevel() == 1.0f) {
620                                mPowerState.dismissColorFade();
621                            } else if (mPowerState.prepareColorFade(mContext,
622                                    mColorFadeFadesConfig ?
623                                            ColorFade.MODE_FADE :
624                                                    ColorFade.MODE_WARM_UP)) {
625                                mColorFadeOnAnimator.start();
626                            } else {
627                                mColorFadeOnAnimator.end();
628                            }
629                        }
630                    } else {
631                        // Skip screen on animation.
632                        mPowerState.setColorFadeLevel(1.0f);
633                        mPowerState.dismissColorFade();
634                    }
635                }
636            }
637        } else if (state == Display.STATE_DOZE) {
638            // Want screen dozing.
639            // Wait for brightness animation to complete beforehand when entering doze
640            // from screen on.
641            unblockScreenOn();
642            if (!mScreenBrightnessRampAnimator.isAnimating()
643                    || mPowerState.getScreenState() != Display.STATE_ON) {
644                // Set screen state and dismiss the black surface without fanfare.
645                setScreenState(state);
646                mPowerState.setColorFadeLevel(1.0f);
647                mPowerState.dismissColorFade();
648            }
649        } else if (state == Display.STATE_DOZE_SUSPEND) {
650            // Want screen dozing and suspended.
651            // Wait for brightness animation to complete beforehand unless already
652            // suspended because we may not be able to change it after suspension.
653            unblockScreenOn();
654            if (!mScreenBrightnessRampAnimator.isAnimating()
655                    || mPowerState.getScreenState() == Display.STATE_DOZE_SUSPEND) {
656                // Set screen state and dismiss the black surface without fanfare.
657                setScreenState(state);
658                mPowerState.setColorFadeLevel(1.0f);
659                mPowerState.dismissColorFade();
660            }
661        } else {
662            // Want screen off.
663            // Wait for previous on animation to complete beforehand.
664            unblockScreenOn();
665            if (!mColorFadeOnAnimator.isStarted()) {
666                if (mPowerRequest.policy == DisplayPowerRequest.POLICY_OFF) {
667                    // Perform screen off animation.
668                    if (!mColorFadeOffAnimator.isStarted()) {
669                        if (mPowerState.getColorFadeLevel() == 0.0f) {
670                            setScreenState(Display.STATE_OFF);
671                        } else if (mPowerState.prepareColorFade(mContext,
672                                mColorFadeFadesConfig ?
673                                        ColorFade.MODE_FADE :
674                                                ColorFade.MODE_COOL_DOWN)
675                                && mPowerState.getScreenState() != Display.STATE_OFF) {
676                            mColorFadeOffAnimator.start();
677                        } else {
678                            mColorFadeOffAnimator.end();
679                        }
680                    }
681                } else {
682                    // Skip screen off animation.
683                    setScreenState(Display.STATE_OFF);
684                }
685            }
686        }
687
688        // Report whether the display is ready for use.
689        // We mostly care about the screen state here, ignoring brightness changes
690        // which will be handled asynchronously.
691        if (mustNotify
692                && !mScreenOnWasBlocked
693                && !mColorFadeOnAnimator.isStarted()
694                && !mColorFadeOffAnimator.isStarted()
695                && !mScreenBrightnessRampAnimator.isAnimating()
696                && mPowerState.waitUntilClean(mCleanListener)) {
697            synchronized (mLock) {
698                if (!mPendingRequestChangedLocked) {
699                    mDisplayReadyLocked = true;
700
701                    if (DEBUG) {
702                        Slog.d(TAG, "Display ready!");
703                    }
704                }
705            }
706            sendOnStateChangedWithWakelock();
707        }
708    }
709
710    @Override
711    public void updateBrightness() {
712        sendUpdatePowerState();
713    }
714
715    private void blockScreenOn() {
716        if (!mScreenOnWasBlocked) {
717            mScreenOnWasBlocked = true;
718            mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
719            if (DEBUG) {
720                Slog.d(TAG, "Blocked screen on.");
721            }
722        }
723    }
724
725    private void unblockScreenOn() {
726        if (mScreenOnWasBlocked) {
727            mScreenOnWasBlocked = false;
728            long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
729            if (delay > 1000 || DEBUG) {
730                Slog.d(TAG, "Unblocked screen on after " + delay + " ms");
731            }
732        }
733    }
734
735    private void setScreenState(int state) {
736        if (mPowerState.getScreenState() != state) {
737            mPowerState.setScreenState(state);
738            try {
739                mBatteryStats.noteScreenState(state);
740            } catch (RemoteException ex) {
741                // same process
742            }
743        }
744    }
745
746    private int clampScreenBrightness(int value) {
747        return MathUtils.constrain(
748                value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
749    }
750
751    private void animateScreenBrightness(int target, int rate) {
752        if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
753            try {
754                mBatteryStats.noteScreenBrightness(target);
755            } catch (RemoteException ex) {
756                // same process
757            }
758        }
759    }
760
761    private final Runnable mCleanListener = new Runnable() {
762        @Override
763        public void run() {
764            sendUpdatePowerState();
765        }
766    };
767
768    private void setProximitySensorEnabled(boolean enable) {
769        if (enable) {
770            if (!mProximitySensorEnabled) {
771                // Register the listener.
772                // Proximity sensor state already cleared initially.
773                mProximitySensorEnabled = true;
774                mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
775                        SensorManager.SENSOR_DELAY_NORMAL, mHandler);
776            }
777        } else {
778            if (mProximitySensorEnabled) {
779                // Unregister the listener.
780                // Clear the proximity sensor state for next time.
781                mProximitySensorEnabled = false;
782                mProximity = PROXIMITY_UNKNOWN;
783                mPendingProximity = PROXIMITY_UNKNOWN;
784                mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
785                mSensorManager.unregisterListener(mProximitySensorListener);
786                clearPendingProximityDebounceTime(); // release wake lock (must be last)
787            }
788        }
789    }
790
791    private void handleProximitySensorEvent(long time, boolean positive) {
792        if (mProximitySensorEnabled) {
793            if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
794                return; // no change
795            }
796            if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
797                return; // no change
798            }
799
800            // Only accept a proximity sensor reading if it remains
801            // stable for the entire debounce delay.  We hold a wake lock while
802            // debouncing the sensor.
803            mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
804            if (positive) {
805                mPendingProximity = PROXIMITY_POSITIVE;
806                setPendingProximityDebounceTime(
807                        time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); // acquire wake lock
808            } else {
809                mPendingProximity = PROXIMITY_NEGATIVE;
810                setPendingProximityDebounceTime(
811                        time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); // acquire wake lock
812            }
813
814            // Debounce the new sensor reading.
815            debounceProximitySensor();
816        }
817    }
818
819    private void debounceProximitySensor() {
820        if (mProximitySensorEnabled
821                && mPendingProximity != PROXIMITY_UNKNOWN
822                && mPendingProximityDebounceTime >= 0) {
823            final long now = SystemClock.uptimeMillis();
824            if (mPendingProximityDebounceTime <= now) {
825                // Sensor reading accepted.  Apply the change then release the wake lock.
826                mProximity = mPendingProximity;
827                updatePowerState();
828                clearPendingProximityDebounceTime(); // release wake lock (must be last)
829            } else {
830                // Need to wait a little longer.
831                // Debounce again later.  We continue holding a wake lock while waiting.
832                Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
833                msg.setAsynchronous(true);
834                mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
835            }
836        }
837    }
838
839    private void clearPendingProximityDebounceTime() {
840        if (mPendingProximityDebounceTime >= 0) {
841            mPendingProximityDebounceTime = -1;
842            mCallbacks.releaseSuspendBlocker(); // release wake lock
843        }
844    }
845
846    private void setPendingProximityDebounceTime(long debounceTime) {
847        if (mPendingProximityDebounceTime < 0) {
848            mCallbacks.acquireSuspendBlocker(); // acquire wake lock
849        }
850        mPendingProximityDebounceTime = debounceTime;
851    }
852
853    private void sendOnStateChangedWithWakelock() {
854        mCallbacks.acquireSuspendBlocker();
855        mHandler.post(mOnStateChangedRunnable);
856    }
857
858    private final Runnable mOnStateChangedRunnable = new Runnable() {
859        @Override
860        public void run() {
861            mCallbacks.onStateChanged();
862            mCallbacks.releaseSuspendBlocker();
863        }
864    };
865
866    private void sendOnProximityPositiveWithWakelock() {
867        mCallbacks.acquireSuspendBlocker();
868        mHandler.post(mOnProximityPositiveRunnable);
869    }
870
871    private final Runnable mOnProximityPositiveRunnable = new Runnable() {
872        @Override
873        public void run() {
874            mCallbacks.onProximityPositive();
875            mCallbacks.releaseSuspendBlocker();
876        }
877    };
878
879    private void sendOnProximityNegativeWithWakelock() {
880        mCallbacks.acquireSuspendBlocker();
881        mHandler.post(mOnProximityNegativeRunnable);
882    }
883
884    private final Runnable mOnProximityNegativeRunnable = new Runnable() {
885        @Override
886        public void run() {
887            mCallbacks.onProximityNegative();
888            mCallbacks.releaseSuspendBlocker();
889        }
890    };
891
892    public void dump(final PrintWriter pw) {
893        synchronized (mLock) {
894            pw.println();
895            pw.println("Display Power Controller Locked State:");
896            pw.println("  mDisplayReadyLocked=" + mDisplayReadyLocked);
897            pw.println("  mPendingRequestLocked=" + mPendingRequestLocked);
898            pw.println("  mPendingRequestChangedLocked=" + mPendingRequestChangedLocked);
899            pw.println("  mPendingWaitForNegativeProximityLocked="
900                    + mPendingWaitForNegativeProximityLocked);
901            pw.println("  mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked);
902        }
903
904        pw.println();
905        pw.println("Display Power Controller Configuration:");
906        pw.println("  mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
907        pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
908        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
909        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
910        pw.println("  mUseSoftwareAutoBrightnessConfig="
911                + mUseSoftwareAutoBrightnessConfig);
912
913        mHandler.runWithScissors(new Runnable() {
914            @Override
915            public void run() {
916                dumpLocal(pw);
917            }
918        }, 1000);
919    }
920
921    private void dumpLocal(PrintWriter pw) {
922        pw.println();
923        pw.println("Display Power Controller Thread State:");
924        pw.println("  mPowerRequest=" + mPowerRequest);
925        pw.println("  mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
926
927        pw.println("  mProximitySensor=" + mProximitySensor);
928        pw.println("  mProximitySensorEnabled=" + mProximitySensorEnabled);
929        pw.println("  mProximityThreshold=" + mProximityThreshold);
930        pw.println("  mProximity=" + proximityToString(mProximity));
931        pw.println("  mPendingProximity=" + proximityToString(mPendingProximity));
932        pw.println("  mPendingProximityDebounceTime="
933                + TimeUtils.formatUptime(mPendingProximityDebounceTime));
934        pw.println("  mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
935        pw.println("  mAppliedAutoBrightness=" + mAppliedAutoBrightness);
936        pw.println("  mAppliedDimming=" + mAppliedDimming);
937        pw.println("  mAppliedLowPower=" + mAppliedLowPower);
938
939        pw.println("  mScreenBrightnessRampAnimator.isAnimating()=" +
940                mScreenBrightnessRampAnimator.isAnimating());
941
942        if (mColorFadeOnAnimator != null) {
943            pw.println("  mColorFadeOnAnimator.isStarted()=" +
944                    mColorFadeOnAnimator.isStarted());
945        }
946        if (mColorFadeOffAnimator != null) {
947            pw.println("  mColorFadeOffAnimator.isStarted()=" +
948                    mColorFadeOffAnimator.isStarted());
949        }
950
951        if (mPowerState != null) {
952            mPowerState.dump(pw);
953        }
954
955        if (mAutomaticBrightnessController != null) {
956            mAutomaticBrightnessController.dump(pw);
957        }
958
959    }
960
961    private static String proximityToString(int state) {
962        switch (state) {
963            case PROXIMITY_UNKNOWN:
964                return "Unknown";
965            case PROXIMITY_NEGATIVE:
966                return "Negative";
967            case PROXIMITY_POSITIVE:
968                return "Positive";
969            default:
970                return Integer.toString(state);
971        }
972    }
973
974    private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
975        try {
976            final int n = brightness.length;
977            float[] x = new float[n];
978            float[] y = new float[n];
979            y[0] = normalizeAbsoluteBrightness(brightness[0]);
980            for (int i = 1; i < n; i++) {
981                x[i] = lux[i - 1];
982                y[i] = normalizeAbsoluteBrightness(brightness[i]);
983            }
984
985            Spline spline = Spline.createMonotoneCubicSpline(x, y);
986            if (DEBUG) {
987                Slog.d(TAG, "Auto-brightness spline: " + spline);
988                for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
989                    Slog.d(TAG, String.format("  %7.1f: %7.1f", v, spline.interpolate(v)));
990                }
991            }
992            return spline;
993        } catch (IllegalArgumentException ex) {
994            Slog.e(TAG, "Could not create auto-brightness spline.", ex);
995            return null;
996        }
997    }
998
999    private static float normalizeAbsoluteBrightness(int value) {
1000        return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
1001    }
1002
1003    private static int clampAbsoluteBrightness(int value) {
1004        return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
1005    }
1006
1007    private final class DisplayControllerHandler extends Handler {
1008        public DisplayControllerHandler(Looper looper) {
1009            super(looper, null, true /*async*/);
1010        }
1011
1012        @Override
1013        public void handleMessage(Message msg) {
1014            switch (msg.what) {
1015                case MSG_UPDATE_POWER_STATE:
1016                    updatePowerState();
1017                    break;
1018
1019                case MSG_PROXIMITY_SENSOR_DEBOUNCED:
1020                    debounceProximitySensor();
1021                    break;
1022            }
1023        }
1024    }
1025
1026    private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
1027        @Override
1028        public void onSensorChanged(SensorEvent event) {
1029            if (mProximitySensorEnabled) {
1030                final long time = SystemClock.uptimeMillis();
1031                final float distance = event.values[0];
1032                boolean positive = distance >= 0.0f && distance < mProximityThreshold;
1033                handleProximitySensorEvent(time, positive);
1034            }
1035        }
1036
1037        @Override
1038        public void onAccuracyChanged(Sensor sensor, int accuracy) {
1039            // Not used.
1040        }
1041    };
1042}
1043