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