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