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