DisplayPowerController.java revision 2175e9c366998ed7bd1a4501b94a02f4f49b932c
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        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 on or off unless blocked.
632        if (state == Display.STATE_ON) {
633            // Want screen on.
634            // Wait for previous off animation to complete beforehand.
635            // It is relatively short but if we cancel it and switch to the
636            // on animation immediately then the results are pretty ugly.
637            if (!mColorFadeOffAnimator.isStarted()) {
638                // Turn the screen on.  The contents of the screen may not yet
639                // be visible if the electron beam has not been dismissed because
640                // its last frame of animation is solid black.
641                setScreenState(Display.STATE_ON);
642                if (mPowerRequest.blockScreenOn
643                        && mPowerState.getColorFadeLevel() == 0.0f) {
644                    blockScreenOn();
645                } else {
646                    unblockScreenOn();
647                    if (USE_COLOR_FADE_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {
648                        // Perform screen on animation.
649                        if (!mColorFadeOnAnimator.isStarted()) {
650                            if (mPowerState.getColorFadeLevel() == 1.0f) {
651                                mPowerState.dismissColorFade();
652                            } else if (mPowerState.prepareColorFade(mContext,
653                                    mColorFadeFadesConfig ?
654                                            ColorFade.MODE_FADE :
655                                                    ColorFade.MODE_WARM_UP)) {
656                                mColorFadeOnAnimator.start();
657                            } else {
658                                mColorFadeOnAnimator.end();
659                            }
660                        }
661                    } else {
662                        // Skip screen on animation.
663                        mPowerState.setColorFadeLevel(1.0f);
664                        mPowerState.dismissColorFade();
665                    }
666                }
667            }
668        } else if (state == Display.STATE_DOZE) {
669            // Want screen dozing.
670            // Wait for brightness animation to complete beforehand when entering doze
671            // from screen on.
672            unblockScreenOn();
673            if (!mScreenBrightnessRampAnimator.isAnimating()
674                    || mPowerState.getScreenState() != Display.STATE_ON) {
675                // Set screen state and dismiss the black surface without fanfare.
676                setScreenState(state);
677                mPowerState.setColorFadeLevel(1.0f);
678                mPowerState.dismissColorFade();
679            }
680        } else if (state == Display.STATE_DOZE_SUSPEND) {
681            // Want screen dozing and suspended.
682            // Wait for brightness animation to complete beforehand unless already
683            // suspended because we may not be able to change it after suspension.
684            unblockScreenOn();
685            if (!mScreenBrightnessRampAnimator.isAnimating()
686                    || mPowerState.getScreenState() == Display.STATE_DOZE_SUSPEND) {
687                // Set screen state and dismiss the black surface without fanfare.
688                setScreenState(state);
689                mPowerState.setColorFadeLevel(1.0f);
690                mPowerState.dismissColorFade();
691            }
692        } else {
693            // Want screen off.
694            // Wait for previous on animation to complete beforehand.
695            unblockScreenOn();
696            if (!mColorFadeOnAnimator.isStarted()) {
697                if (performScreenOffTransition) {
698                    // Perform screen off animation.
699                    if (!mColorFadeOffAnimator.isStarted()) {
700                        if (mPowerState.getColorFadeLevel() == 0.0f) {
701                            setScreenState(Display.STATE_OFF);
702                        } else if (mPowerState.prepareColorFade(mContext,
703                                mColorFadeFadesConfig ?
704                                        ColorFade.MODE_FADE :
705                                                ColorFade.MODE_COOL_DOWN)
706                                && mPowerState.getScreenState() != Display.STATE_OFF) {
707                            mColorFadeOffAnimator.start();
708                        } else {
709                            mColorFadeOffAnimator.end();
710                        }
711                    }
712                } else {
713                    // Skip screen off animation.
714                    setScreenState(Display.STATE_OFF);
715                }
716            }
717        }
718
719        // Report whether the display is ready for use.
720        // We mostly care about the screen state here, ignoring brightness changes
721        // which will be handled asynchronously.
722        if (mustNotify
723                && !mScreenOnWasBlocked
724                && !mColorFadeOnAnimator.isStarted()
725                && !mColorFadeOffAnimator.isStarted()
726                && !mScreenBrightnessRampAnimator.isAnimating()
727                && mPowerState.waitUntilClean(mCleanListener)) {
728            synchronized (mLock) {
729                if (!mPendingRequestChangedLocked) {
730                    mDisplayReadyLocked = true;
731
732                    if (DEBUG) {
733                        Slog.d(TAG, "Display ready!");
734                    }
735                }
736            }
737            sendOnStateChangedWithWakelock();
738        }
739    }
740
741    @Override
742    public void updateBrightness() {
743        sendUpdatePowerState();
744    }
745
746    private void blockScreenOn() {
747        if (!mScreenOnWasBlocked) {
748            Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
749            mScreenOnWasBlocked = true;
750            mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
751            Slog.i(TAG, "Blocking screen on until initial contents have been drawn.");
752        }
753    }
754
755    private void unblockScreenOn() {
756        if (mScreenOnWasBlocked) {
757            mScreenOnWasBlocked = false;
758            long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
759            Slog.i(TAG, "Unblocked screen on after " + delay + " ms");
760            Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
761        }
762    }
763
764    private void setScreenState(int state) {
765        if (mPowerState.getScreenState() != state) {
766            mPowerState.setScreenState(state);
767            try {
768                mBatteryStats.noteScreenState(state);
769            } catch (RemoteException ex) {
770                // same process
771            }
772        }
773    }
774
775    private int clampScreenBrightness(int value) {
776        return MathUtils.constrain(
777                value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
778    }
779
780    private void animateScreenBrightness(int target, int rate) {
781        if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
782            try {
783                mBatteryStats.noteScreenBrightness(target);
784            } catch (RemoteException ex) {
785                // same process
786            }
787        }
788    }
789
790    private final Runnable mCleanListener = new Runnable() {
791        @Override
792        public void run() {
793            sendUpdatePowerState();
794        }
795    };
796
797    private void setProximitySensorEnabled(boolean enable) {
798        if (enable) {
799            if (!mProximitySensorEnabled) {
800                // Register the listener.
801                // Proximity sensor state already cleared initially.
802                mProximitySensorEnabled = true;
803                mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
804                        SensorManager.SENSOR_DELAY_NORMAL, mHandler);
805            }
806        } else {
807            if (mProximitySensorEnabled) {
808                // Unregister the listener.
809                // Clear the proximity sensor state for next time.
810                mProximitySensorEnabled = false;
811                mProximity = PROXIMITY_UNKNOWN;
812                mPendingProximity = PROXIMITY_UNKNOWN;
813                mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
814                mSensorManager.unregisterListener(mProximitySensorListener);
815                clearPendingProximityDebounceTime(); // release wake lock (must be last)
816            }
817        }
818    }
819
820    private void handleProximitySensorEvent(long time, boolean positive) {
821        if (mProximitySensorEnabled) {
822            if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
823                return; // no change
824            }
825            if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
826                return; // no change
827            }
828
829            // Only accept a proximity sensor reading if it remains
830            // stable for the entire debounce delay.  We hold a wake lock while
831            // debouncing the sensor.
832            mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
833            if (positive) {
834                mPendingProximity = PROXIMITY_POSITIVE;
835                setPendingProximityDebounceTime(
836                        time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); // acquire wake lock
837            } else {
838                mPendingProximity = PROXIMITY_NEGATIVE;
839                setPendingProximityDebounceTime(
840                        time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); // acquire wake lock
841            }
842
843            // Debounce the new sensor reading.
844            debounceProximitySensor();
845        }
846    }
847
848    private void debounceProximitySensor() {
849        if (mProximitySensorEnabled
850                && mPendingProximity != PROXIMITY_UNKNOWN
851                && mPendingProximityDebounceTime >= 0) {
852            final long now = SystemClock.uptimeMillis();
853            if (mPendingProximityDebounceTime <= now) {
854                // Sensor reading accepted.  Apply the change then release the wake lock.
855                mProximity = mPendingProximity;
856                updatePowerState();
857                clearPendingProximityDebounceTime(); // release wake lock (must be last)
858            } else {
859                // Need to wait a little longer.
860                // Debounce again later.  We continue holding a wake lock while waiting.
861                Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
862                msg.setAsynchronous(true);
863                mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
864            }
865        }
866    }
867
868    private void clearPendingProximityDebounceTime() {
869        if (mPendingProximityDebounceTime >= 0) {
870            mPendingProximityDebounceTime = -1;
871            mCallbacks.releaseSuspendBlocker(); // release wake lock
872        }
873    }
874
875    private void setPendingProximityDebounceTime(long debounceTime) {
876        if (mPendingProximityDebounceTime < 0) {
877            mCallbacks.acquireSuspendBlocker(); // acquire wake lock
878        }
879        mPendingProximityDebounceTime = debounceTime;
880    }
881
882    private void sendOnStateChangedWithWakelock() {
883        mCallbacks.acquireSuspendBlocker();
884        mHandler.post(mOnStateChangedRunnable);
885    }
886
887    private final Runnable mOnStateChangedRunnable = new Runnable() {
888        @Override
889        public void run() {
890            mCallbacks.onStateChanged();
891            mCallbacks.releaseSuspendBlocker();
892        }
893    };
894
895    private void sendOnProximityPositiveWithWakelock() {
896        mCallbacks.acquireSuspendBlocker();
897        mHandler.post(mOnProximityPositiveRunnable);
898    }
899
900    private final Runnable mOnProximityPositiveRunnable = new Runnable() {
901        @Override
902        public void run() {
903            mCallbacks.onProximityPositive();
904            mCallbacks.releaseSuspendBlocker();
905        }
906    };
907
908    private void sendOnProximityNegativeWithWakelock() {
909        mCallbacks.acquireSuspendBlocker();
910        mHandler.post(mOnProximityNegativeRunnable);
911    }
912
913    private final Runnable mOnProximityNegativeRunnable = new Runnable() {
914        @Override
915        public void run() {
916            mCallbacks.onProximityNegative();
917            mCallbacks.releaseSuspendBlocker();
918        }
919    };
920
921    public void dump(final PrintWriter pw) {
922        synchronized (mLock) {
923            pw.println();
924            pw.println("Display Power Controller Locked State:");
925            pw.println("  mDisplayReadyLocked=" + mDisplayReadyLocked);
926            pw.println("  mPendingRequestLocked=" + mPendingRequestLocked);
927            pw.println("  mPendingRequestChangedLocked=" + mPendingRequestChangedLocked);
928            pw.println("  mPendingWaitForNegativeProximityLocked="
929                    + mPendingWaitForNegativeProximityLocked);
930            pw.println("  mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked);
931        }
932
933        pw.println();
934        pw.println("Display Power Controller Configuration:");
935        pw.println("  mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
936        pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
937        pw.println("  mScreenBrightnessDarkConfig=" + mScreenBrightnessDarkConfig);
938        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
939        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
940        pw.println("  mUseSoftwareAutoBrightnessConfig=" + mUseSoftwareAutoBrightnessConfig);
941        pw.println("  mColorFadeFadesConfig=" + mColorFadeFadesConfig);
942
943        mHandler.runWithScissors(new Runnable() {
944            @Override
945            public void run() {
946                dumpLocal(pw);
947            }
948        }, 1000);
949    }
950
951    private void dumpLocal(PrintWriter pw) {
952        pw.println();
953        pw.println("Display Power Controller Thread State:");
954        pw.println("  mPowerRequest=" + mPowerRequest);
955        pw.println("  mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
956
957        pw.println("  mProximitySensor=" + mProximitySensor);
958        pw.println("  mProximitySensorEnabled=" + mProximitySensorEnabled);
959        pw.println("  mProximityThreshold=" + mProximityThreshold);
960        pw.println("  mProximity=" + proximityToString(mProximity));
961        pw.println("  mPendingProximity=" + proximityToString(mPendingProximity));
962        pw.println("  mPendingProximityDebounceTime="
963                + TimeUtils.formatUptime(mPendingProximityDebounceTime));
964        pw.println("  mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
965        pw.println("  mAppliedAutoBrightness=" + mAppliedAutoBrightness);
966        pw.println("  mAppliedDimming=" + mAppliedDimming);
967        pw.println("  mAppliedLowPower=" + mAppliedLowPower);
968
969        pw.println("  mScreenBrightnessRampAnimator.isAnimating()=" +
970                mScreenBrightnessRampAnimator.isAnimating());
971
972        if (mColorFadeOnAnimator != null) {
973            pw.println("  mColorFadeOnAnimator.isStarted()=" +
974                    mColorFadeOnAnimator.isStarted());
975        }
976        if (mColorFadeOffAnimator != null) {
977            pw.println("  mColorFadeOffAnimator.isStarted()=" +
978                    mColorFadeOffAnimator.isStarted());
979        }
980
981        if (mPowerState != null) {
982            mPowerState.dump(pw);
983        }
984
985        if (mAutomaticBrightnessController != null) {
986            mAutomaticBrightnessController.dump(pw);
987        }
988
989    }
990
991    private static String proximityToString(int state) {
992        switch (state) {
993            case PROXIMITY_UNKNOWN:
994                return "Unknown";
995            case PROXIMITY_NEGATIVE:
996                return "Negative";
997            case PROXIMITY_POSITIVE:
998                return "Positive";
999            default:
1000                return Integer.toString(state);
1001        }
1002    }
1003
1004    private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
1005        try {
1006            final int n = brightness.length;
1007            float[] x = new float[n];
1008            float[] y = new float[n];
1009            y[0] = normalizeAbsoluteBrightness(brightness[0]);
1010            for (int i = 1; i < n; i++) {
1011                x[i] = lux[i - 1];
1012                y[i] = normalizeAbsoluteBrightness(brightness[i]);
1013            }
1014
1015            Spline spline = Spline.createSpline(x, y);
1016            if (DEBUG) {
1017                Slog.d(TAG, "Auto-brightness spline: " + spline);
1018                for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
1019                    Slog.d(TAG, String.format("  %7.1f: %7.1f", v, spline.interpolate(v)));
1020                }
1021            }
1022            return spline;
1023        } catch (IllegalArgumentException ex) {
1024            Slog.e(TAG, "Could not create auto-brightness spline.", ex);
1025            return null;
1026        }
1027    }
1028
1029    private static float normalizeAbsoluteBrightness(int value) {
1030        return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
1031    }
1032
1033    private static int clampAbsoluteBrightness(int value) {
1034        return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
1035    }
1036
1037    private final class DisplayControllerHandler extends Handler {
1038        public DisplayControllerHandler(Looper looper) {
1039            super(looper, null, true /*async*/);
1040        }
1041
1042        @Override
1043        public void handleMessage(Message msg) {
1044            switch (msg.what) {
1045                case MSG_UPDATE_POWER_STATE:
1046                    updatePowerState();
1047                    break;
1048
1049                case MSG_PROXIMITY_SENSOR_DEBOUNCED:
1050                    debounceProximitySensor();
1051                    break;
1052            }
1053        }
1054    }
1055
1056    private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
1057        @Override
1058        public void onSensorChanged(SensorEvent event) {
1059            if (mProximitySensorEnabled) {
1060                final long time = SystemClock.uptimeMillis();
1061                final float distance = event.values[0];
1062                boolean positive = distance >= 0.0f && distance < mProximityThreshold;
1063                handleProximitySensorEvent(time, positive);
1064            }
1065        }
1066
1067        @Override
1068        public void onAccuracyChanged(Sensor sensor, int accuracy) {
1069            // Not used.
1070        }
1071    };
1072}
1073