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