DisplayPowerController.java revision 606e4e8c98304daf756f7e89d47005573288f72a
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 DisplayPowerCallbacks#onStateChanged()}
353     * then try 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        boolean performScreenOffTransition = false;
501        switch (mPowerRequest.policy) {
502            case DisplayPowerRequest.POLICY_OFF:
503                state = Display.STATE_OFF;
504                performScreenOffTransition = true;
505                break;
506            case DisplayPowerRequest.POLICY_DOZE:
507                if (mPowerRequest.dozeScreenState != Display.STATE_UNKNOWN) {
508                    state = mPowerRequest.dozeScreenState;
509                } else {
510                    state = Display.STATE_DOZE;
511                }
512                brightness = mPowerRequest.dozeScreenBrightness;
513                break;
514            case DisplayPowerRequest.POLICY_DIM:
515            case DisplayPowerRequest.POLICY_BRIGHT:
516            default:
517                state = Display.STATE_ON;
518                break;
519        }
520        assert(state != Display.STATE_UNKNOWN);
521
522        // Apply the proximity sensor.
523        if (mProximitySensor != null) {
524            if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) {
525                setProximitySensorEnabled(true);
526                if (!mScreenOffBecauseOfProximity
527                        && mProximity == PROXIMITY_POSITIVE) {
528                    mScreenOffBecauseOfProximity = true;
529                    sendOnProximityPositiveWithWakelock();
530                }
531            } else if (mWaitingForNegativeProximity
532                    && mScreenOffBecauseOfProximity
533                    && mProximity == PROXIMITY_POSITIVE
534                    && state != Display.STATE_OFF) {
535                setProximitySensorEnabled(true);
536            } else {
537                setProximitySensorEnabled(false);
538                mWaitingForNegativeProximity = false;
539            }
540            if (mScreenOffBecauseOfProximity
541                    && mProximity != PROXIMITY_POSITIVE) {
542                mScreenOffBecauseOfProximity = false;
543                sendOnProximityNegativeWithWakelock();
544            }
545        } else {
546            mWaitingForNegativeProximity = false;
547        }
548        if (mScreenOffBecauseOfProximity) {
549            state = Display.STATE_OFF;
550        }
551
552        // Use zero brightness when screen is off.
553        if (state == Display.STATE_OFF) {
554            brightness = PowerManager.BRIGHTNESS_OFF;
555        }
556
557        // Use default brightness when dozing unless overridden.
558        if (brightness < 0 && (state == Display.STATE_DOZE
559                || state == Display.STATE_DOZE_SUSPEND)) {
560            brightness = mScreenBrightnessDozeConfig;
561        }
562
563        // Configure auto-brightness.
564        boolean autoBrightnessEnabled = false;
565        if (mAutomaticBrightnessController != null) {
566            autoBrightnessEnabled = mPowerRequest.useAutoBrightness
567                    && state == Display.STATE_ON && brightness < 0;
568            mAutomaticBrightnessController.configure(autoBrightnessEnabled,
569                    mPowerRequest.screenAutoBrightnessAdjustment);
570        }
571
572        // Apply auto-brightness.
573        boolean slowChange = false;
574        if (brightness < 0) {
575            if (autoBrightnessEnabled) {
576                brightness = mAutomaticBrightnessController.getAutomaticScreenBrightness();
577            }
578            if (brightness >= 0) {
579                // Use current auto-brightness value and slowly adjust to changes.
580                brightness = clampScreenBrightness(brightness);
581                if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
582                    slowChange = true; // slowly adapt to auto-brightness
583                }
584                mAppliedAutoBrightness = true;
585            } else {
586                mAppliedAutoBrightness = false;
587            }
588        } else {
589            mAppliedAutoBrightness = false;
590        }
591
592        // Apply manual brightness.
593        // Use the current brightness setting from the request, which is expected
594        // provide a nominal default value for the case where auto-brightness
595        // is not ready yet.
596        if (brightness < 0) {
597            brightness = clampScreenBrightness(mPowerRequest.screenBrightness);
598        }
599
600        // Apply dimming by at least some minimum amount when user activity
601        // timeout is about to expire.
602        if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
603            if (brightness > mScreenBrightnessRangeMinimum) {
604                brightness = Math.max(Math.min(brightness - SCREEN_DIM_MINIMUM_REDUCTION,
605                        mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum);
606            }
607            if (!mAppliedDimming) {
608                slowChange = false;
609            }
610            mAppliedDimming = true;
611        }
612
613        // If low power mode is enabled, cut the brightness level by half
614        // as long as it is above the minimum threshold.
615        if (mPowerRequest.lowPowerMode) {
616            if (brightness > mScreenBrightnessRangeMinimum) {
617                brightness = Math.max(brightness / 2, mScreenBrightnessRangeMinimum);
618            }
619            if (!mAppliedLowPower) {
620                slowChange = false;
621            }
622            mAppliedLowPower = true;
623        }
624
625        // Animate the screen brightness when the screen is on.
626        if (state != Display.STATE_OFF) {
627            animateScreenBrightness(brightness, slowChange
628                    ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
629        }
630
631        // Animate the screen state change unless already animating.
632        animateScreenStateChange(state, performScreenOffTransition);
633
634        // Report whether the display is ready for use and all changes have been applied.
635        if (mustNotify
636                && !mScreenOnWasBlocked
637                && !mColorFadeOnAnimator.isStarted()
638                && !mColorFadeOffAnimator.isStarted()
639                && !mScreenBrightnessRampAnimator.isAnimating()
640                && mPowerState.waitUntilClean(mCleanListener)) {
641            synchronized (mLock) {
642                if (!mPendingRequestChangedLocked) {
643                    mDisplayReadyLocked = true;
644
645                    if (DEBUG) {
646                        Slog.d(TAG, "Display ready!");
647                    }
648                }
649            }
650            sendOnStateChangedWithWakelock();
651        }
652    }
653
654    @Override
655    public void updateBrightness() {
656        sendUpdatePowerState();
657    }
658
659    private void blockScreenOn() {
660        if (!mScreenOnWasBlocked) {
661            Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
662            mScreenOnWasBlocked = true;
663            mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
664            Slog.i(TAG, "Blocking screen on until initial contents have been drawn.");
665        }
666    }
667
668    private void unblockScreenOn() {
669        if (mScreenOnWasBlocked) {
670            mScreenOnWasBlocked = false;
671            long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
672            Slog.i(TAG, "Unblocked screen on after " + delay + " ms");
673            Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
674        }
675    }
676
677    private void setScreenState(int state) {
678        if (mPowerState.getScreenState() != state) {
679            mPowerState.setScreenState(state);
680            try {
681                mBatteryStats.noteScreenState(state);
682            } catch (RemoteException ex) {
683                // same process
684            }
685        }
686    }
687
688    private int clampScreenBrightness(int value) {
689        return MathUtils.constrain(
690                value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
691    }
692
693    private void animateScreenBrightness(int target, int rate) {
694        if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
695            try {
696                mBatteryStats.noteScreenBrightness(target);
697            } catch (RemoteException ex) {
698                // same process
699            }
700        }
701    }
702
703    private void animateScreenStateChange(int target, boolean performScreenOffTransition) {
704        // If there is already an animation in progress, don't interfere with it.
705        if (mColorFadeOnAnimator.isStarted()
706                || mColorFadeOffAnimator.isStarted()) {
707            return;
708        }
709
710        // Temporarily block turning the screen on if requested and there is already a
711        // black surface covering the screen.
712        if (mPowerRequest.blockScreenOn
713                && mPowerState.getColorFadeLevel() == 0.0f
714                && target != Display.STATE_OFF) {
715            blockScreenOn();
716            return;
717        }
718
719        if (target == Display.STATE_ON) {
720            // Want screen on.  The contents of the screen may not yet
721            // be visible if the electron beam has not been dismissed because
722            // its last frame of animation is solid black.
723            unblockScreenOn();
724            setScreenState(Display.STATE_ON);
725            if (USE_COLOR_FADE_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {
726                // Perform screen on animation.
727                if (mPowerState.getColorFadeLevel() == 1.0f) {
728                    mPowerState.dismissColorFade();
729                } else if (mPowerState.prepareColorFade(mContext,
730                        mColorFadeFadesConfig ?
731                                ColorFade.MODE_FADE :
732                                        ColorFade.MODE_WARM_UP)) {
733                    mColorFadeOnAnimator.start();
734                } else {
735                    mColorFadeOnAnimator.end();
736                }
737            } else {
738                // Skip screen on animation.
739                mPowerState.setColorFadeLevel(1.0f);
740                mPowerState.dismissColorFade();
741            }
742        } else if (target == Display.STATE_DOZE) {
743            // Want screen dozing.
744            // Wait for brightness animation to complete beforehand when entering doze
745            // from screen on to prevent a perceptible jump because brightness may operate
746            // differently when the display is configured for dozing.
747            if (mScreenBrightnessRampAnimator.isAnimating()
748                    && mPowerState.getScreenState() == Display.STATE_ON) {
749                return;
750            }
751
752            // Set screen state and dismiss the black surface without fanfare.
753            unblockScreenOn();
754            setScreenState(Display.STATE_DOZE);
755            mPowerState.setColorFadeLevel(1.0f);
756            mPowerState.dismissColorFade();
757        } else if (target == Display.STATE_DOZE_SUSPEND) {
758            // Want screen dozing and suspended.
759            // Wait for brightness animation to complete beforehand unless already
760            // suspended because we may not be able to change it after suspension.
761            if (mScreenBrightnessRampAnimator.isAnimating()
762                    && mPowerState.getScreenState() != Display.STATE_DOZE_SUSPEND) {
763                return;
764            }
765
766            // Set screen state and dismiss the black surface without fanfare.
767            unblockScreenOn();
768            setScreenState(Display.STATE_DOZE_SUSPEND);
769            mPowerState.setColorFadeLevel(1.0f);
770            mPowerState.dismissColorFade();
771        } else {
772            // Want screen off.
773            unblockScreenOn();
774            if (mPowerState.getColorFadeLevel() == 0.0f) {
775                // Turn the screen off.
776                // A black surface is already hiding the contents of the screen.
777                setScreenState(Display.STATE_OFF);
778            } else if (performScreenOffTransition
779                    && mPowerState.prepareColorFade(mContext,
780                            mColorFadeFadesConfig ?
781                                    ColorFade.MODE_FADE : ColorFade.MODE_COOL_DOWN)
782                    && mPowerState.getScreenState() != Display.STATE_OFF) {
783                // Perform the screen off animation.
784                mColorFadeOffAnimator.start();
785            } else {
786                // Skip the screen off animation and add a black surface to hide the
787                // contents of the screen.
788                mColorFadeOffAnimator.end();
789            }
790        }
791    }
792
793    private final Runnable mCleanListener = new Runnable() {
794        @Override
795        public void run() {
796            sendUpdatePowerState();
797        }
798    };
799
800    private void setProximitySensorEnabled(boolean enable) {
801        if (enable) {
802            if (!mProximitySensorEnabled) {
803                // Register the listener.
804                // Proximity sensor state already cleared initially.
805                mProximitySensorEnabled = true;
806                mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
807                        SensorManager.SENSOR_DELAY_NORMAL, mHandler);
808            }
809        } else {
810            if (mProximitySensorEnabled) {
811                // Unregister the listener.
812                // Clear the proximity sensor state for next time.
813                mProximitySensorEnabled = false;
814                mProximity = PROXIMITY_UNKNOWN;
815                mPendingProximity = PROXIMITY_UNKNOWN;
816                mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
817                mSensorManager.unregisterListener(mProximitySensorListener);
818                clearPendingProximityDebounceTime(); // release wake lock (must be last)
819            }
820        }
821    }
822
823    private void handleProximitySensorEvent(long time, boolean positive) {
824        if (mProximitySensorEnabled) {
825            if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
826                return; // no change
827            }
828            if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
829                return; // no change
830            }
831
832            // Only accept a proximity sensor reading if it remains
833            // stable for the entire debounce delay.  We hold a wake lock while
834            // debouncing the sensor.
835            mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
836            if (positive) {
837                mPendingProximity = PROXIMITY_POSITIVE;
838                setPendingProximityDebounceTime(
839                        time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); // acquire wake lock
840            } else {
841                mPendingProximity = PROXIMITY_NEGATIVE;
842                setPendingProximityDebounceTime(
843                        time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); // acquire wake lock
844            }
845
846            // Debounce the new sensor reading.
847            debounceProximitySensor();
848        }
849    }
850
851    private void debounceProximitySensor() {
852        if (mProximitySensorEnabled
853                && mPendingProximity != PROXIMITY_UNKNOWN
854                && mPendingProximityDebounceTime >= 0) {
855            final long now = SystemClock.uptimeMillis();
856            if (mPendingProximityDebounceTime <= now) {
857                // Sensor reading accepted.  Apply the change then release the wake lock.
858                mProximity = mPendingProximity;
859                updatePowerState();
860                clearPendingProximityDebounceTime(); // release wake lock (must be last)
861            } else {
862                // Need to wait a little longer.
863                // Debounce again later.  We continue holding a wake lock while waiting.
864                Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
865                msg.setAsynchronous(true);
866                mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
867            }
868        }
869    }
870
871    private void clearPendingProximityDebounceTime() {
872        if (mPendingProximityDebounceTime >= 0) {
873            mPendingProximityDebounceTime = -1;
874            mCallbacks.releaseSuspendBlocker(); // release wake lock
875        }
876    }
877
878    private void setPendingProximityDebounceTime(long debounceTime) {
879        if (mPendingProximityDebounceTime < 0) {
880            mCallbacks.acquireSuspendBlocker(); // acquire wake lock
881        }
882        mPendingProximityDebounceTime = debounceTime;
883    }
884
885    private void sendOnStateChangedWithWakelock() {
886        mCallbacks.acquireSuspendBlocker();
887        mHandler.post(mOnStateChangedRunnable);
888    }
889
890    private final Runnable mOnStateChangedRunnable = new Runnable() {
891        @Override
892        public void run() {
893            mCallbacks.onStateChanged();
894            mCallbacks.releaseSuspendBlocker();
895        }
896    };
897
898    private void sendOnProximityPositiveWithWakelock() {
899        mCallbacks.acquireSuspendBlocker();
900        mHandler.post(mOnProximityPositiveRunnable);
901    }
902
903    private final Runnable mOnProximityPositiveRunnable = new Runnable() {
904        @Override
905        public void run() {
906            mCallbacks.onProximityPositive();
907            mCallbacks.releaseSuspendBlocker();
908        }
909    };
910
911    private void sendOnProximityNegativeWithWakelock() {
912        mCallbacks.acquireSuspendBlocker();
913        mHandler.post(mOnProximityNegativeRunnable);
914    }
915
916    private final Runnable mOnProximityNegativeRunnable = new Runnable() {
917        @Override
918        public void run() {
919            mCallbacks.onProximityNegative();
920            mCallbacks.releaseSuspendBlocker();
921        }
922    };
923
924    public void dump(final PrintWriter pw) {
925        synchronized (mLock) {
926            pw.println();
927            pw.println("Display Power Controller Locked State:");
928            pw.println("  mDisplayReadyLocked=" + mDisplayReadyLocked);
929            pw.println("  mPendingRequestLocked=" + mPendingRequestLocked);
930            pw.println("  mPendingRequestChangedLocked=" + mPendingRequestChangedLocked);
931            pw.println("  mPendingWaitForNegativeProximityLocked="
932                    + mPendingWaitForNegativeProximityLocked);
933            pw.println("  mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked);
934        }
935
936        pw.println();
937        pw.println("Display Power Controller Configuration:");
938        pw.println("  mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
939        pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
940        pw.println("  mScreenBrightnessDarkConfig=" + mScreenBrightnessDarkConfig);
941        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
942        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
943        pw.println("  mUseSoftwareAutoBrightnessConfig=" + mUseSoftwareAutoBrightnessConfig);
944        pw.println("  mColorFadeFadesConfig=" + mColorFadeFadesConfig);
945
946        mHandler.runWithScissors(new Runnable() {
947            @Override
948            public void run() {
949                dumpLocal(pw);
950            }
951        }, 1000);
952    }
953
954    private void dumpLocal(PrintWriter pw) {
955        pw.println();
956        pw.println("Display Power Controller Thread State:");
957        pw.println("  mPowerRequest=" + mPowerRequest);
958        pw.println("  mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
959
960        pw.println("  mProximitySensor=" + mProximitySensor);
961        pw.println("  mProximitySensorEnabled=" + mProximitySensorEnabled);
962        pw.println("  mProximityThreshold=" + mProximityThreshold);
963        pw.println("  mProximity=" + proximityToString(mProximity));
964        pw.println("  mPendingProximity=" + proximityToString(mPendingProximity));
965        pw.println("  mPendingProximityDebounceTime="
966                + TimeUtils.formatUptime(mPendingProximityDebounceTime));
967        pw.println("  mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
968        pw.println("  mAppliedAutoBrightness=" + mAppliedAutoBrightness);
969        pw.println("  mAppliedDimming=" + mAppliedDimming);
970        pw.println("  mAppliedLowPower=" + mAppliedLowPower);
971
972        pw.println("  mScreenBrightnessRampAnimator.isAnimating()=" +
973                mScreenBrightnessRampAnimator.isAnimating());
974
975        if (mColorFadeOnAnimator != null) {
976            pw.println("  mColorFadeOnAnimator.isStarted()=" +
977                    mColorFadeOnAnimator.isStarted());
978        }
979        if (mColorFadeOffAnimator != null) {
980            pw.println("  mColorFadeOffAnimator.isStarted()=" +
981                    mColorFadeOffAnimator.isStarted());
982        }
983
984        if (mPowerState != null) {
985            mPowerState.dump(pw);
986        }
987
988        if (mAutomaticBrightnessController != null) {
989            mAutomaticBrightnessController.dump(pw);
990        }
991
992    }
993
994    private static String proximityToString(int state) {
995        switch (state) {
996            case PROXIMITY_UNKNOWN:
997                return "Unknown";
998            case PROXIMITY_NEGATIVE:
999                return "Negative";
1000            case PROXIMITY_POSITIVE:
1001                return "Positive";
1002            default:
1003                return Integer.toString(state);
1004        }
1005    }
1006
1007    private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
1008        try {
1009            final int n = brightness.length;
1010            float[] x = new float[n];
1011            float[] y = new float[n];
1012            y[0] = normalizeAbsoluteBrightness(brightness[0]);
1013            for (int i = 1; i < n; i++) {
1014                x[i] = lux[i - 1];
1015                y[i] = normalizeAbsoluteBrightness(brightness[i]);
1016            }
1017
1018            Spline spline = Spline.createSpline(x, y);
1019            if (DEBUG) {
1020                Slog.d(TAG, "Auto-brightness spline: " + spline);
1021                for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
1022                    Slog.d(TAG, String.format("  %7.1f: %7.1f", v, spline.interpolate(v)));
1023                }
1024            }
1025            return spline;
1026        } catch (IllegalArgumentException ex) {
1027            Slog.e(TAG, "Could not create auto-brightness spline.", ex);
1028            return null;
1029        }
1030    }
1031
1032    private static float normalizeAbsoluteBrightness(int value) {
1033        return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
1034    }
1035
1036    private static int clampAbsoluteBrightness(int value) {
1037        return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
1038    }
1039
1040    private final class DisplayControllerHandler extends Handler {
1041        public DisplayControllerHandler(Looper looper) {
1042            super(looper, null, true /*async*/);
1043        }
1044
1045        @Override
1046        public void handleMessage(Message msg) {
1047            switch (msg.what) {
1048                case MSG_UPDATE_POWER_STATE:
1049                    updatePowerState();
1050                    break;
1051
1052                case MSG_PROXIMITY_SENSOR_DEBOUNCED:
1053                    debounceProximitySensor();
1054                    break;
1055            }
1056        }
1057    }
1058
1059    private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
1060        @Override
1061        public void onSensorChanged(SensorEvent event) {
1062            if (mProximitySensorEnabled) {
1063                final long time = SystemClock.uptimeMillis();
1064                final float distance = event.values[0];
1065                boolean positive = distance >= 0.0f && distance < mProximityThreshold;
1066                handleProximitySensorEvent(time, positive);
1067            }
1068        }
1069
1070        @Override
1071        public void onAccuracyChanged(Sensor sensor, int accuracy) {
1072            // Not used.
1073        }
1074    };
1075}
1076