DisplayPowerController.java revision 0c9a62dc8db7b39d5236aba70f14d4e99d38a194
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.os.Trace;
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    private static final String SCREEN_ON_BLOCKED_TRACE_NAME = "Screen on blocked";
78
79    // If true, uses the electron beam on animation.
80    // We might want to turn this off if we cannot get a guarantee that the screen
81    // actually turns on and starts showing new content after the call to set the
82    // screen state returns.  Playing the animation can also be somewhat slow.
83    private static final boolean USE_COLOR_FADE_ON_ANIMATION = false;
84
85
86    // The minimum reduction in brightness when dimmed.
87    private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
88
89    private static final int COLOR_FADE_ON_ANIMATION_DURATION_MILLIS = 250;
90    private static final int COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS = 400;
91
92    private static final int MSG_UPDATE_POWER_STATE = 1;
93    private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
94
95    private static final int PROXIMITY_UNKNOWN = -1;
96    private static final int PROXIMITY_NEGATIVE = 0;
97    private static final int PROXIMITY_POSITIVE = 1;
98
99    // Proximity sensor debounce delay in milliseconds for positive or negative transitions.
100    private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
101    private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 250;
102
103    // Trigger proximity if distance is less than 5 cm.
104    private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
105
106    // Brightness animation ramp rate in brightness units per second.
107    private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
108    private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
109
110    private final Object mLock = new Object();
111
112    private final Context mContext;
113
114    // Our handler.
115    private final DisplayControllerHandler mHandler;
116
117    // Asynchronous callbacks into the power manager service.
118    // Only invoked from the handler thread while no locks are held.
119    private final DisplayPowerCallbacks mCallbacks;
120
121    // Battery stats.
122    private final IBatteryStats mBatteryStats;
123
124    // The lights service.
125    private final LightsManager mLights;
126
127    // The sensor manager.
128    private final SensorManager mSensorManager;
129
130    // The display blanker.
131    private final DisplayBlanker mBlanker;
132
133    // The proximity sensor, or null if not available or needed.
134    private Sensor mProximitySensor;
135
136    // The doze screen brightness.
137    private final int mScreenBrightnessDozeConfig;
138
139    // The dim screen brightness.
140    private final int mScreenBrightnessDimConfig;
141
142    // The minimum allowed brightness.
143    private final int mScreenBrightnessRangeMinimum;
144
145    // The maximum allowed brightness.
146    private final int mScreenBrightnessRangeMaximum;
147
148    // True if auto-brightness should be used.
149    private boolean mUseSoftwareAutoBrightnessConfig;
150
151    // True if we should fade the screen while turning it off, false if we should play
152    // a stylish electron beam animation instead.
153    private boolean mColorFadeFadesConfig;
154
155    // The pending power request.
156    // Initially null until the first call to requestPowerState.
157    // Guarded by mLock.
158    private DisplayPowerRequest mPendingRequestLocked;
159
160    // True if a request has been made to wait for the proximity sensor to go negative.
161    // Guarded by mLock.
162    private boolean mPendingWaitForNegativeProximityLocked;
163
164    // True if the pending power request or wait for negative proximity flag
165    // has been changed since the last update occurred.
166    // Guarded by mLock.
167    private boolean mPendingRequestChangedLocked;
168
169    // Set to true when the important parts of the pending power request have been applied.
170    // The important parts are mainly the screen state.  Brightness changes may occur
171    // concurrently.
172    // Guarded by mLock.
173    private boolean mDisplayReadyLocked;
174
175    // Set to true if a power state update is required.
176    // Guarded by mLock.
177    private boolean mPendingUpdatePowerStateLocked;
178
179    /* The following state must only be accessed by the handler thread. */
180
181    // The currently requested power state.
182    // The power controller will progressively update its internal state to match
183    // the requested power state.  Initially null until the first update.
184    private DisplayPowerRequest mPowerRequest;
185
186    // The current power state.
187    // Must only be accessed on the handler thread.
188    private DisplayPowerState mPowerState;
189
190    // True if the device should wait for negative proximity sensor before
191    // waking up the screen.  This is set to false as soon as a negative
192    // proximity sensor measurement is observed or when the device is forced to
193    // go to sleep by the user.  While true, the screen remains off.
194    private boolean mWaitingForNegativeProximity;
195
196    // The actual proximity sensor threshold value.
197    private float mProximityThreshold;
198
199    // Set to true if the proximity sensor listener has been registered
200    // with the sensor manager.
201    private boolean mProximitySensorEnabled;
202
203    // The debounced proximity sensor state.
204    private int mProximity = PROXIMITY_UNKNOWN;
205
206    // The raw non-debounced proximity sensor state.
207    private int mPendingProximity = PROXIMITY_UNKNOWN;
208    private long mPendingProximityDebounceTime = -1; // -1 if fully debounced
209
210    // True if the screen was turned off because of the proximity sensor.
211    // When the screen turns on again, we report user activity to the power manager.
212    private boolean mScreenOffBecauseOfProximity;
213
214    // True if the screen on is being blocked.
215    private boolean mScreenOnWasBlocked;
216
217    // The elapsed real time when the screen on was blocked.
218    private long mScreenOnBlockStartRealTime;
219
220    // Remembers whether certain kinds of brightness adjustments
221    // were recently applied so that we can decide how to transition.
222    private boolean mAppliedAutoBrightness;
223    private boolean mAppliedDimming;
224    private boolean mAppliedLowPower;
225
226    // The controller for the automatic brightness level.
227    private AutomaticBrightnessController mAutomaticBrightnessController;
228
229    // Animators.
230    private ObjectAnimator mColorFadeOnAnimator;
231    private ObjectAnimator mColorFadeOffAnimator;
232    private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
233
234    /**
235     * Creates the display power controller.
236     */
237    public DisplayPowerController(Context context,
238            DisplayPowerCallbacks callbacks, Handler handler,
239            SensorManager sensorManager, DisplayBlanker blanker) {
240        mHandler = new DisplayControllerHandler(handler.getLooper());
241        mCallbacks = callbacks;
242
243        mBatteryStats = BatteryStatsService.getService();
244        mLights = LocalServices.getService(LightsManager.class);
245        mSensorManager = sensorManager;
246        mBlanker = blanker;
247        mContext = context;
248
249        final Resources resources = context.getResources();
250
251        mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger(
252                com.android.internal.R.integer.config_screenBrightnessDoze));
253
254        mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
255                com.android.internal.R.integer.config_screenBrightnessDim));
256
257        int screenBrightnessRangeMinimum = clampAbsoluteBrightness(Math.min(resources.getInteger(
258                com.android.internal.R.integer.config_screenBrightnessSettingMinimum),
259                mScreenBrightnessDimConfig));
260
261        mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
262
263        mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
264                com.android.internal.R.bool.config_automatic_brightness_available);
265        if (mUseSoftwareAutoBrightnessConfig) {
266            int[] lux = resources.getIntArray(
267                    com.android.internal.R.array.config_autoBrightnessLevels);
268            int[] screenBrightness = resources.getIntArray(
269                    com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
270            int lightSensorWarmUpTimeConfig = resources.getInteger(
271                    com.android.internal.R.integer.config_lightSensorWarmupTime);
272
273            Spline screenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
274            if (screenAutoBrightnessSpline == null) {
275                Slog.e(TAG, "Error in config.xml.  config_autoBrightnessLcdBacklightValues "
276                        + "(size " + screenBrightness.length + ") "
277                        + "must be monotic and have exactly one more entry than "
278                        + "config_autoBrightnessLevels (size " + lux.length + ") "
279                        + "which must be strictly increasing.  "
280                        + "Auto-brightness will be disabled.");
281                mUseSoftwareAutoBrightnessConfig = false;
282            } else {
283                if (screenBrightness[0] < screenBrightnessRangeMinimum) {
284                    screenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightness[0]);
285                }
286                mAutomaticBrightnessController = new AutomaticBrightnessController(this,
287                        handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
288                        lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
289                        mScreenBrightnessRangeMaximum);
290            }
291        }
292
293        mScreenBrightnessRangeMinimum = screenBrightnessRangeMinimum;
294
295        mColorFadeFadesConfig = resources.getBoolean(
296                com.android.internal.R.bool.config_animateScreenLights);
297
298        if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
299            mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
300            if (mProximitySensor != null) {
301                mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
302                        TYPICAL_PROXIMITY_THRESHOLD);
303            }
304        }
305
306    }
307
308    /**
309     * Returns true if the proximity sensor screen-off function is available.
310     */
311    public boolean isProximitySensorAvailable() {
312        return mProximitySensor != null;
313    }
314
315    /**
316     * Requests a new power state.
317     * The controller makes a copy of the provided object and then
318     * begins adjusting the power state to match what was requested.
319     *
320     * @param request The requested power state.
321     * @param waitForNegativeProximity If true, issues a request to wait for
322     * negative proximity before turning the screen back on, assuming the screen
323     * was turned off by the proximity sensor.
324     * @return True if display is ready, false if there are important changes that must
325     * be made asynchronously (such as turning the screen on), in which case the caller
326     * should grab a wake lock, watch for {@link Callbacks#onStateChanged()} then try
327     * the request again later until the state converges.
328     */
329    public boolean requestPowerState(DisplayPowerRequest request,
330            boolean waitForNegativeProximity) {
331        if (DEBUG) {
332            Slog.d(TAG, "requestPowerState: "
333                    + request + ", waitForNegativeProximity=" + waitForNegativeProximity);
334        }
335
336        synchronized (mLock) {
337            boolean changed = false;
338
339            if (waitForNegativeProximity
340                    && !mPendingWaitForNegativeProximityLocked) {
341                mPendingWaitForNegativeProximityLocked = true;
342                changed = true;
343            }
344
345            if (mPendingRequestLocked == null) {
346                mPendingRequestLocked = new DisplayPowerRequest(request);
347                changed = true;
348            } else if (!mPendingRequestLocked.equals(request)) {
349                mPendingRequestLocked.copyFrom(request);
350                changed = true;
351            }
352
353            if (changed) {
354                mDisplayReadyLocked = false;
355            }
356
357            if (changed && !mPendingRequestChangedLocked) {
358                mPendingRequestChangedLocked = true;
359                sendUpdatePowerStateLocked();
360            }
361
362            return mDisplayReadyLocked;
363        }
364    }
365
366    private void sendUpdatePowerState() {
367        synchronized (mLock) {
368            sendUpdatePowerStateLocked();
369        }
370    }
371
372    private void sendUpdatePowerStateLocked() {
373        if (!mPendingUpdatePowerStateLocked) {
374            mPendingUpdatePowerStateLocked = true;
375            Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
376            msg.setAsynchronous(true);
377            mHandler.sendMessage(msg);
378        }
379    }
380
381    private void initialize() {
382        // Initialize the power state object for the default display.
383        // In the future, we might manage multiple displays independently.
384        mPowerState = new DisplayPowerState(mBlanker,
385                mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
386                new ColorFade(Display.DEFAULT_DISPLAY));
387
388        mColorFadeOnAnimator = ObjectAnimator.ofFloat(
389                mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 0.0f, 1.0f);
390        mColorFadeOnAnimator.setDuration(COLOR_FADE_ON_ANIMATION_DURATION_MILLIS);
391        mColorFadeOnAnimator.addListener(mAnimatorListener);
392
393        mColorFadeOffAnimator = ObjectAnimator.ofFloat(
394                mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 1.0f, 0.0f);
395        mColorFadeOffAnimator.setDuration(COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS);
396        mColorFadeOffAnimator.addListener(mAnimatorListener);
397
398        mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
399                mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
400        mScreenBrightnessRampAnimator.setListener(mRampAnimatorListener);
401
402        // Initialize screen state for battery stats.
403        try {
404            mBatteryStats.noteScreenState(mPowerState.getScreenState());
405            mBatteryStats.noteScreenBrightness(mPowerState.getScreenBrightness());
406        } catch (RemoteException ex) {
407            // same process
408        }
409    }
410
411    private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
412        @Override
413        public void onAnimationStart(Animator animation) {
414        }
415        @Override
416        public void onAnimationEnd(Animator animation) {
417            sendUpdatePowerState();
418        }
419        @Override
420        public void onAnimationRepeat(Animator animation) {
421        }
422        @Override
423        public void onAnimationCancel(Animator animation) {
424        }
425    };
426
427    private final RampAnimator.Listener mRampAnimatorListener = new RampAnimator.Listener() {
428        @Override
429        public void onAnimationEnd() {
430            sendUpdatePowerState();
431        }
432    };
433
434    private void updatePowerState() {
435        // Update the power state request.
436        final boolean mustNotify;
437        boolean mustInitialize = false;
438        boolean autoBrightnessAdjustmentChanged = false;
439
440        synchronized (mLock) {
441            mPendingUpdatePowerStateLocked = false;
442            if (mPendingRequestLocked == null) {
443                return; // wait until first actual power request
444            }
445
446            if (mPowerRequest == null) {
447                mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
448                mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
449                mPendingWaitForNegativeProximityLocked = false;
450                mPendingRequestChangedLocked = false;
451                mustInitialize = true;
452            } else if (mPendingRequestChangedLocked) {
453                autoBrightnessAdjustmentChanged = (mPowerRequest.screenAutoBrightnessAdjustment
454                        != mPendingRequestLocked.screenAutoBrightnessAdjustment);
455                mPowerRequest.copyFrom(mPendingRequestLocked);
456                mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
457                mPendingWaitForNegativeProximityLocked = false;
458                mPendingRequestChangedLocked = false;
459                mDisplayReadyLocked = false;
460            }
461
462            mustNotify = !mDisplayReadyLocked;
463        }
464
465        // Initialize things the first time the power state is changed.
466        if (mustInitialize) {
467            initialize();
468        }
469
470        // Compute the basic display state using the policy.
471        // We might override this below based on other factors.
472        int state;
473        int brightness = PowerManager.BRIGHTNESS_DEFAULT;
474        switch (mPowerRequest.policy) {
475            case DisplayPowerRequest.POLICY_OFF:
476                state = Display.STATE_OFF;
477                break;
478            case DisplayPowerRequest.POLICY_DOZE:
479                if (mPowerRequest.dozeScreenState != Display.STATE_UNKNOWN) {
480                    state = mPowerRequest.dozeScreenState;
481                } else {
482                    state = Display.STATE_DOZE;
483                }
484                brightness = mPowerRequest.dozeScreenBrightness;
485                break;
486            case DisplayPowerRequest.POLICY_DIM:
487            case DisplayPowerRequest.POLICY_BRIGHT:
488            default:
489                state = Display.STATE_ON;
490                break;
491        }
492
493        // Apply the proximity sensor.
494        if (mProximitySensor != null) {
495            if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) {
496                setProximitySensorEnabled(true);
497                if (!mScreenOffBecauseOfProximity
498                        && mProximity == PROXIMITY_POSITIVE) {
499                    mScreenOffBecauseOfProximity = true;
500                    sendOnProximityPositiveWithWakelock();
501                }
502            } else if (mWaitingForNegativeProximity
503                    && mScreenOffBecauseOfProximity
504                    && mProximity == PROXIMITY_POSITIVE
505                    && state != Display.STATE_OFF) {
506                setProximitySensorEnabled(true);
507            } else {
508                setProximitySensorEnabled(false);
509                mWaitingForNegativeProximity = false;
510            }
511            if (mScreenOffBecauseOfProximity
512                    && mProximity != PROXIMITY_POSITIVE) {
513                mScreenOffBecauseOfProximity = false;
514                sendOnProximityNegativeWithWakelock();
515            }
516        } else {
517            mWaitingForNegativeProximity = false;
518        }
519        if (mScreenOffBecauseOfProximity) {
520            state = Display.STATE_OFF;
521        }
522
523        // Use zero brightness when screen is off.
524        if (state == Display.STATE_OFF) {
525            brightness = PowerManager.BRIGHTNESS_OFF;
526        }
527
528        // Use default brightness when dozing unless overridden.
529        if (brightness < 0 && (state == Display.STATE_DOZE
530                || state == Display.STATE_DOZE_SUSPEND)) {
531            brightness = mScreenBrightnessDozeConfig;
532        }
533
534        // Configure auto-brightness.
535        boolean autoBrightnessEnabled = false;
536        if (mAutomaticBrightnessController != null) {
537            autoBrightnessEnabled = mPowerRequest.useAutoBrightness
538                    && state == Display.STATE_ON && brightness < 0;
539            mAutomaticBrightnessController.configure(autoBrightnessEnabled,
540                    mPowerRequest.screenAutoBrightnessAdjustment);
541        }
542
543        // Apply auto-brightness.
544        boolean slowChange = false;
545        if (brightness < 0) {
546            if (autoBrightnessEnabled) {
547                brightness = mAutomaticBrightnessController.getAutomaticScreenBrightness();
548            }
549            if (brightness >= 0) {
550                // Use current auto-brightness value and slowly adjust to changes.
551                brightness = clampScreenBrightness(brightness);
552                if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
553                    slowChange = true; // slowly adapt to auto-brightness
554                }
555                mAppliedAutoBrightness = true;
556            } else {
557                mAppliedAutoBrightness = false;
558            }
559        } else {
560            mAppliedAutoBrightness = false;
561        }
562
563        // Apply manual brightness.
564        // Use the current brightness setting from the request, which is expected
565        // provide a nominal default value for the case where auto-brightness
566        // is not ready yet.
567        if (brightness < 0) {
568            brightness = clampScreenBrightness(mPowerRequest.screenBrightness);
569        }
570
571        // Apply dimming by at least some minimum amount when user activity
572        // timeout is about to expire.
573        if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
574            if (brightness > mScreenBrightnessRangeMinimum) {
575                brightness = Math.max(Math.min(brightness - SCREEN_DIM_MINIMUM_REDUCTION,
576                        mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum);
577            }
578            if (!mAppliedDimming) {
579                slowChange = false;
580            }
581            mAppliedDimming = true;
582        }
583
584        // If low power mode is enabled, cut the brightness level by half
585        // as long as it is above the minimum threshold.
586        if (mPowerRequest.lowPowerMode) {
587            if (brightness > mScreenBrightnessRangeMinimum) {
588                brightness = Math.max(brightness / 2, mScreenBrightnessRangeMinimum);
589            }
590            if (!mAppliedLowPower) {
591                slowChange = false;
592            }
593            mAppliedLowPower = true;
594        }
595
596        // Animate the screen brightness when the screen is on.
597        if (state != Display.STATE_OFF) {
598            animateScreenBrightness(brightness, slowChange
599                    ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
600        }
601
602        // Animate the screen on or off unless blocked.
603        if (state == Display.STATE_ON) {
604            // Want screen on.
605            // Wait for previous off animation to complete beforehand.
606            // It is relatively short but if we cancel it and switch to the
607            // on animation immediately then the results are pretty ugly.
608            if (!mColorFadeOffAnimator.isStarted()) {
609                // Turn the screen on.  The contents of the screen may not yet
610                // be visible if the electron beam has not been dismissed because
611                // its last frame of animation is solid black.
612                setScreenState(Display.STATE_ON);
613                if (mPowerRequest.blockScreenOn
614                        && mPowerState.getColorFadeLevel() == 0.0f) {
615                    blockScreenOn();
616                } else {
617                    unblockScreenOn();
618                    if (USE_COLOR_FADE_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {
619                        // Perform screen on animation.
620                        if (!mColorFadeOnAnimator.isStarted()) {
621                            if (mPowerState.getColorFadeLevel() == 1.0f) {
622                                mPowerState.dismissColorFade();
623                            } else if (mPowerState.prepareColorFade(mContext,
624                                    mColorFadeFadesConfig ?
625                                            ColorFade.MODE_FADE :
626                                                    ColorFade.MODE_WARM_UP)) {
627                                mColorFadeOnAnimator.start();
628                            } else {
629                                mColorFadeOnAnimator.end();
630                            }
631                        }
632                    } else {
633                        // Skip screen on animation.
634                        mPowerState.setColorFadeLevel(1.0f);
635                        mPowerState.dismissColorFade();
636                    }
637                }
638            }
639        } else if (state == Display.STATE_DOZE) {
640            // Want screen dozing.
641            // Wait for brightness animation to complete beforehand when entering doze
642            // from screen on.
643            unblockScreenOn();
644            if (!mScreenBrightnessRampAnimator.isAnimating()
645                    || mPowerState.getScreenState() != Display.STATE_ON) {
646                // Set screen state and dismiss the black surface without fanfare.
647                setScreenState(state);
648                mPowerState.setColorFadeLevel(1.0f);
649                mPowerState.dismissColorFade();
650            }
651        } else if (state == Display.STATE_DOZE_SUSPEND) {
652            // Want screen dozing and suspended.
653            // Wait for brightness animation to complete beforehand unless already
654            // suspended because we may not be able to change it after suspension.
655            unblockScreenOn();
656            if (!mScreenBrightnessRampAnimator.isAnimating()
657                    || mPowerState.getScreenState() == Display.STATE_DOZE_SUSPEND) {
658                // Set screen state and dismiss the black surface without fanfare.
659                setScreenState(state);
660                mPowerState.setColorFadeLevel(1.0f);
661                mPowerState.dismissColorFade();
662            }
663        } else {
664            // Want screen off.
665            // Wait for previous on animation to complete beforehand.
666            unblockScreenOn();
667            if (!mColorFadeOnAnimator.isStarted()) {
668                if (mPowerRequest.policy == DisplayPowerRequest.POLICY_OFF) {
669                    // Perform screen off animation.
670                    if (!mColorFadeOffAnimator.isStarted()) {
671                        if (mPowerState.getColorFadeLevel() == 0.0f) {
672                            setScreenState(Display.STATE_OFF);
673                        } else if (mPowerState.prepareColorFade(mContext,
674                                mColorFadeFadesConfig ?
675                                        ColorFade.MODE_FADE :
676                                                ColorFade.MODE_COOL_DOWN)
677                                && mPowerState.getScreenState() != Display.STATE_OFF) {
678                            mColorFadeOffAnimator.start();
679                        } else {
680                            mColorFadeOffAnimator.end();
681                        }
682                    }
683                } else {
684                    // Skip screen off animation.
685                    setScreenState(Display.STATE_OFF);
686                }
687            }
688        }
689
690        // Report whether the display is ready for use.
691        // We mostly care about the screen state here, ignoring brightness changes
692        // which will be handled asynchronously.
693        if (mustNotify
694                && !mScreenOnWasBlocked
695                && !mColorFadeOnAnimator.isStarted()
696                && !mColorFadeOffAnimator.isStarted()
697                && !mScreenBrightnessRampAnimator.isAnimating()
698                && mPowerState.waitUntilClean(mCleanListener)) {
699            synchronized (mLock) {
700                if (!mPendingRequestChangedLocked) {
701                    mDisplayReadyLocked = true;
702
703                    if (DEBUG) {
704                        Slog.d(TAG, "Display ready!");
705                    }
706                }
707            }
708            sendOnStateChangedWithWakelock();
709        }
710    }
711
712    @Override
713    public void updateBrightness() {
714        sendUpdatePowerState();
715    }
716
717    private void blockScreenOn() {
718        if (!mScreenOnWasBlocked) {
719            Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
720            mScreenOnWasBlocked = true;
721            mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
722            Slog.i(TAG, "Blocking screen on until initial contents have been drawn.");
723        }
724    }
725
726    private void unblockScreenOn() {
727        if (mScreenOnWasBlocked) {
728            mScreenOnWasBlocked = false;
729            long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
730            Slog.i(TAG, "Unblocked screen on after " + delay + " ms");
731            Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
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