DisplayPowerController.java revision 037c33eae74bee2774897d969d48947f9abe254f
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;
23import com.android.server.twilight.TwilightListener;
24import com.android.server.twilight.TwilightManager;
25import com.android.server.twilight.TwilightState;
26
27import android.animation.Animator;
28import android.animation.ObjectAnimator;
29import android.content.Context;
30import android.content.res.Resources;
31import android.hardware.Sensor;
32import android.hardware.SensorEvent;
33import android.hardware.SensorEventListener;
34import android.hardware.SensorManager;
35import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
36import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
37import android.os.Handler;
38import android.os.Looper;
39import android.os.Message;
40import android.os.PowerManager;
41import android.os.RemoteException;
42import android.os.SystemClock;
43import android.text.format.DateUtils;
44import android.util.FloatMath;
45import android.util.Slog;
46import android.util.Spline;
47import android.util.TimeUtils;
48import android.view.Display;
49
50import java.io.PrintWriter;
51
52/**
53 * Controls the power state of the display.
54 *
55 * Handles the proximity sensor, light sensor, and animations between states
56 * including the screen off animation.
57 *
58 * This component acts independently of the rest of the power manager service.
59 * In particular, it does not share any state and it only communicates
60 * via asynchronous callbacks to inform the power manager that something has
61 * changed.
62 *
63 * Everything this class does internally is serialized on its handler although
64 * it may be accessed by other threads from the outside.
65 *
66 * Note that the power manager service guarantees that it will hold a suspend
67 * blocker as long as the display is not ready.  So most of the work done here
68 * does not need to worry about holding a suspend blocker unless it happens
69 * independently of the display ready signal.
70 *
71 * For debugging, you can make the electron beam and brightness animations run
72 * slower by changing the "animator duration scale" option in Development Settings.
73 */
74final class DisplayPowerController {
75    private static final String TAG = "DisplayPowerController";
76
77    private static boolean DEBUG = false;
78    private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
79    private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
80
81    // If true, uses the electron beam on animation.
82    // We might want to turn this off if we cannot get a guarantee that the screen
83    // actually turns on and starts showing new content after the call to set the
84    // screen state returns.  Playing the animation can also be somewhat slow.
85    private static final boolean USE_ELECTRON_BEAM_ON_ANIMATION = false;
86
87    // If true, enables the use of the screen auto-brightness adjustment setting.
88    private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT =
89            PowerManager.useScreenAutoBrightnessAdjustmentFeature();
90
91    // The maximum range of gamma adjustment possible using the screen
92    // auto-brightness adjustment setting.
93    private static final float SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA = 3.0f;
94
95    // The minimum reduction in brightness when dimmed.
96    private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
97
98    // If true, enables the use of the current time as an auto-brightness adjustment.
99    // The basic idea here is to expand the dynamic range of auto-brightness
100    // when it is especially dark outside.  The light sensor tends to perform
101    // poorly at low light levels so we compensate for it by making an
102    // assumption about the environment.
103    private static final boolean USE_TWILIGHT_ADJUSTMENT =
104            PowerManager.useTwilightAdjustmentFeature();
105
106    // Specifies the maximum magnitude of the time of day adjustment.
107    private static final float TWILIGHT_ADJUSTMENT_MAX_GAMMA = 1.5f;
108
109    // The amount of time after or before sunrise over which to start adjusting
110    // the gamma.  We want the change to happen gradually so that it is below the
111    // threshold of perceptibility and so that the adjustment has maximum effect
112    // well after dusk.
113    private static final long TWILIGHT_ADJUSTMENT_TIME = DateUtils.HOUR_IN_MILLIS * 2;
114
115    private static final int ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS = 250;
116    private static final int ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS = 400;
117
118    private static final int MSG_UPDATE_POWER_STATE = 1;
119    private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
120    private static final int MSG_LIGHT_SENSOR_DEBOUNCED = 3;
121
122    private static final int PROXIMITY_UNKNOWN = -1;
123    private static final int PROXIMITY_NEGATIVE = 0;
124    private static final int PROXIMITY_POSITIVE = 1;
125
126    // Proximity sensor debounce delay in milliseconds for positive or negative transitions.
127    private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
128    private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 250;
129
130    // Trigger proximity if distance is less than 5 cm.
131    private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
132
133    // Light sensor event rate in milliseconds.
134    private static final int LIGHT_SENSOR_RATE_MILLIS = 1000;
135
136    // A rate for generating synthetic light sensor events in the case where the light
137    // sensor hasn't reported any new data in a while and we need it to update the
138    // debounce filter.  We only synthesize light sensor measurements when needed.
139    private static final int SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS =
140            LIGHT_SENSOR_RATE_MILLIS * 2;
141
142    // Brightness animation ramp rate in brightness units per second.
143    private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
144    private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
145
146    // IIR filter time constants in milliseconds for computing two moving averages of
147    // the light samples.  One is a long-term average and the other is a short-term average.
148    // We can use these filters to assess trends in ambient brightness.
149    // The short term average gives us a filtered but relatively low latency measurement.
150    // The long term average informs us about the overall trend.
151    private static final long SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 1000;
152    private static final long LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 5000;
153
154    // Stability requirements in milliseconds for accepting a new brightness
155    // level.  This is used for debouncing the light sensor.  Different constants
156    // are used to debounce the light sensor when adapting to brighter or darker environments.
157    // This parameter controls how quickly brightness changes occur in response to
158    // an observed change in light level that exceeds the hysteresis threshold.
159    private static final long BRIGHTENING_LIGHT_DEBOUNCE = 4000;
160    private static final long DARKENING_LIGHT_DEBOUNCE = 8000;
161
162    // Hysteresis constraints for brightening or darkening.
163    // The recent lux must have changed by at least this fraction relative to the
164    // current ambient lux before a change will be considered.
165    private static final float BRIGHTENING_LIGHT_HYSTERESIS = 0.10f;
166    private static final float DARKENING_LIGHT_HYSTERESIS = 0.20f;
167
168    private final Object mLock = new Object();
169
170    // Our handler.
171    private final DisplayControllerHandler mHandler;
172
173    // Asynchronous callbacks into the power manager service.
174    // Only invoked from the handler thread while no locks are held.
175    private final DisplayPowerCallbacks mCallbacks;
176
177    // Battery stats.
178    private final IBatteryStats mBatteryStats;
179
180    // The lights service.
181    private final LightsManager mLights;
182
183    // The twilight service.
184    private final TwilightManager mTwilight;
185
186    // The sensor manager.
187    private final SensorManager mSensorManager;
188
189    // The display blanker.
190    private final DisplayBlanker mBlanker;
191
192    // The proximity sensor, or null if not available or needed.
193    private Sensor mProximitySensor;
194
195    // The light sensor, or null if not available or needed.
196    private Sensor mLightSensor;
197
198    // The doze screen brightness.
199    private final int mScreenBrightnessDozeConfig;
200
201    // The dim screen brightness.
202    private final int mScreenBrightnessDimConfig;
203
204    // The minimum allowed brightness.
205    private final int mScreenBrightnessRangeMinimum;
206
207    // The maximum allowed brightness.
208    private final int mScreenBrightnessRangeMaximum;
209
210    // True if auto-brightness should be used.
211    private boolean mUseSoftwareAutoBrightnessConfig;
212
213    // The auto-brightness spline adjustment.
214    // The brightness values have been scaled to a range of 0..1.
215    private Spline mScreenAutoBrightnessSpline;
216
217    // Amount of time to delay auto-brightness after screen on while waiting for
218    // the light sensor to warm-up in milliseconds.
219    // May be 0 if no warm-up is required.
220    private int mLightSensorWarmUpTimeConfig;
221
222    // True if we should fade the screen while turning it off, false if we should play
223    // a stylish electron beam animation instead.
224    private boolean mElectronBeamFadesConfig;
225
226    // The pending power request.
227    // Initially null until the first call to requestPowerState.
228    // Guarded by mLock.
229    private DisplayPowerRequest mPendingRequestLocked;
230
231    // True if a request has been made to wait for the proximity sensor to go negative.
232    // Guarded by mLock.
233    private boolean mPendingWaitForNegativeProximityLocked;
234
235    // True if the pending power request or wait for negative proximity flag
236    // has been changed since the last update occurred.
237    // Guarded by mLock.
238    private boolean mPendingRequestChangedLocked;
239
240    // Set to true when the important parts of the pending power request have been applied.
241    // The important parts are mainly the screen state.  Brightness changes may occur
242    // concurrently.
243    // Guarded by mLock.
244    private boolean mDisplayReadyLocked;
245
246    // Set to true if a power state update is required.
247    // Guarded by mLock.
248    private boolean mPendingUpdatePowerStateLocked;
249
250    /* The following state must only be accessed by the handler thread. */
251
252    // The currently requested power state.
253    // The power controller will progressively update its internal state to match
254    // the requested power state.  Initially null until the first update.
255    private DisplayPowerRequest mPowerRequest;
256
257    // The current power state.
258    // Must only be accessed on the handler thread.
259    private DisplayPowerState mPowerState;
260
261    // True if the device should wait for negative proximity sensor before
262    // waking up the screen.  This is set to false as soon as a negative
263    // proximity sensor measurement is observed or when the device is forced to
264    // go to sleep by the user.  While true, the screen remains off.
265    private boolean mWaitingForNegativeProximity;
266
267    // The actual proximity sensor threshold value.
268    private float mProximityThreshold;
269
270    // Set to true if the proximity sensor listener has been registered
271    // with the sensor manager.
272    private boolean mProximitySensorEnabled;
273
274    // The debounced proximity sensor state.
275    private int mProximity = PROXIMITY_UNKNOWN;
276
277    // The raw non-debounced proximity sensor state.
278    private int mPendingProximity = PROXIMITY_UNKNOWN;
279    private long mPendingProximityDebounceTime = -1; // -1 if fully debounced
280
281    // True if the screen was turned off because of the proximity sensor.
282    // When the screen turns on again, we report user activity to the power manager.
283    private boolean mScreenOffBecauseOfProximity;
284
285    // True if the screen on is being blocked.
286    private boolean mScreenOnWasBlocked;
287
288    // The elapsed real time when the screen on was blocked.
289    private long mScreenOnBlockStartRealTime;
290
291    // Set to true if the light sensor is enabled.
292    private boolean mLightSensorEnabled;
293
294    // The time when the light sensor was enabled.
295    private long mLightSensorEnableTime;
296
297    // The currently accepted nominal ambient light level.
298    private float mAmbientLux;
299
300    // True if mAmbientLux holds a valid value.
301    private boolean mAmbientLuxValid;
302
303    // The ambient light level threshold at which to brighten or darken the screen.
304    private float mBrighteningLuxThreshold;
305    private float mDarkeningLuxThreshold;
306
307    // The most recent light sample.
308    private float mLastObservedLux;
309
310    // The time of the most light recent sample.
311    private long mLastObservedLuxTime;
312
313    // The number of light samples collected since the light sensor was enabled.
314    private int mRecentLightSamples;
315
316    // The long-term and short-term filtered light measurements.
317    private float mRecentShortTermAverageLux;
318    private float mRecentLongTermAverageLux;
319
320    // The direction in which the average lux is moving relative to the current ambient lux.
321    //    0 if not changing or within hysteresis threshold.
322    //    1 if brightening beyond hysteresis threshold.
323    //   -1 if darkening beyond hysteresis threshold.
324    private int mDebounceLuxDirection;
325
326    // The time when the average lux last changed direction.
327    private long mDebounceLuxTime;
328
329    // The screen brightness level that has been chosen by the auto-brightness
330    // algorithm.  The actual brightness should ramp towards this value.
331    // We preserve this value even when we stop using the light sensor so
332    // that we can quickly revert to the previous auto-brightness level
333    // while the light sensor warms up.
334    // Use -1 if there is no current auto-brightness value available.
335    private int mScreenAutoBrightness = -1;
336
337    // The last screen auto-brightness gamma.  (For printing in dump() only.)
338    private float mLastScreenAutoBrightnessGamma = 1.0f;
339
340    // True if the screen auto-brightness value is actually being used to
341    // set the display brightness.
342    private boolean mUsingScreenAutoBrightness;
343
344    // Animators.
345    private ObjectAnimator mElectronBeamOnAnimator;
346    private ObjectAnimator mElectronBeamOffAnimator;
347    private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
348
349    // Twilight changed.  We might recalculate auto-brightness values.
350    private boolean mTwilightChanged;
351
352    /**
353     * Creates the display power controller.
354     */
355    public DisplayPowerController(Context context,
356            DisplayPowerCallbacks callbacks, Handler handler,
357            SensorManager sensorManager, DisplayBlanker blanker) {
358        mHandler = new DisplayControllerHandler(handler.getLooper());
359        mCallbacks = callbacks;
360
361        mBatteryStats = BatteryStatsService.getService();
362        mLights = LocalServices.getService(LightsManager.class);
363        mTwilight = LocalServices.getService(TwilightManager.class);
364        mSensorManager = sensorManager;
365        mBlanker = blanker;
366
367        final Resources resources = context.getResources();
368
369        mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger(
370                com.android.internal.R.integer.config_screenBrightnessDoze));
371
372        mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
373                com.android.internal.R.integer.config_screenBrightnessDim));
374
375        int screenBrightnessMinimum = Math.min(resources.getInteger(
376                com.android.internal.R.integer.config_screenBrightnessSettingMinimum),
377                mScreenBrightnessDimConfig);
378
379        mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
380                com.android.internal.R.bool.config_automatic_brightness_available);
381        if (mUseSoftwareAutoBrightnessConfig) {
382            int[] lux = resources.getIntArray(
383                    com.android.internal.R.array.config_autoBrightnessLevels);
384            int[] screenBrightness = resources.getIntArray(
385                    com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
386
387            mScreenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
388            if (mScreenAutoBrightnessSpline == null) {
389                Slog.e(TAG, "Error in config.xml.  config_autoBrightnessLcdBacklightValues "
390                        + "(size " + screenBrightness.length + ") "
391                        + "must be monotic and have exactly one more entry than "
392                        + "config_autoBrightnessLevels (size " + lux.length + ") "
393                        + "which must be strictly increasing.  "
394                        + "Auto-brightness will be disabled.");
395                mUseSoftwareAutoBrightnessConfig = false;
396            } else {
397                if (screenBrightness[0] < screenBrightnessMinimum) {
398                    screenBrightnessMinimum = screenBrightness[0];
399                }
400            }
401
402            mLightSensorWarmUpTimeConfig = resources.getInteger(
403                    com.android.internal.R.integer.config_lightSensorWarmupTime);
404        }
405
406        mScreenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightnessMinimum);
407        mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
408
409        mElectronBeamFadesConfig = resources.getBoolean(
410                com.android.internal.R.bool.config_animateScreenLights);
411
412        if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
413            mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
414            if (mProximitySensor != null) {
415                mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
416                        TYPICAL_PROXIMITY_THRESHOLD);
417            }
418        }
419
420        if (mUseSoftwareAutoBrightnessConfig
421                && !DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
422            mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
423        }
424
425        if (mUseSoftwareAutoBrightnessConfig && USE_TWILIGHT_ADJUSTMENT) {
426            mTwilight.registerListener(mTwilightListener, mHandler);
427        }
428    }
429
430    private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
431        try {
432            final int n = brightness.length;
433            float[] x = new float[n];
434            float[] y = new float[n];
435            y[0] = normalizeAbsoluteBrightness(brightness[0]);
436            for (int i = 1; i < n; i++) {
437                x[i] = lux[i - 1];
438                y[i] = normalizeAbsoluteBrightness(brightness[i]);
439            }
440
441            Spline spline = Spline.createMonotoneCubicSpline(x, y);
442            if (DEBUG) {
443                Slog.d(TAG, "Auto-brightness spline: " + spline);
444                for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
445                    Slog.d(TAG, String.format("  %7.1f: %7.1f", v, spline.interpolate(v)));
446                }
447            }
448            return spline;
449        } catch (IllegalArgumentException ex) {
450            Slog.e(TAG, "Could not create auto-brightness spline.", ex);
451            return null;
452        }
453    }
454
455    /**
456     * Returns true if the proximity sensor screen-off function is available.
457     */
458    public boolean isProximitySensorAvailable() {
459        return mProximitySensor != null;
460    }
461
462    /**
463     * Requests a new power state.
464     * The controller makes a copy of the provided object and then
465     * begins adjusting the power state to match what was requested.
466     *
467     * @param request The requested power state.
468     * @param waitForNegativeProximity If true, issues a request to wait for
469     * negative proximity before turning the screen back on, assuming the screen
470     * was turned off by the proximity sensor.
471     * @return True if display is ready, false if there are important changes that must
472     * be made asynchronously (such as turning the screen on), in which case the caller
473     * should grab a wake lock, watch for {@link Callbacks#onStateChanged()} then try
474     * the request again later until the state converges.
475     */
476    public boolean requestPowerState(DisplayPowerRequest request,
477            boolean waitForNegativeProximity) {
478        if (DEBUG) {
479            Slog.d(TAG, "requestPowerState: "
480                    + request + ", waitForNegativeProximity=" + waitForNegativeProximity);
481        }
482
483        synchronized (mLock) {
484            boolean changed = false;
485
486            if (waitForNegativeProximity
487                    && !mPendingWaitForNegativeProximityLocked) {
488                mPendingWaitForNegativeProximityLocked = true;
489                changed = true;
490            }
491
492            if (mPendingRequestLocked == null) {
493                mPendingRequestLocked = new DisplayPowerRequest(request);
494                changed = true;
495            } else if (!mPendingRequestLocked.equals(request)) {
496                mPendingRequestLocked.copyFrom(request);
497                changed = true;
498            }
499
500            if (changed) {
501                mDisplayReadyLocked = false;
502            }
503
504            if (changed && !mPendingRequestChangedLocked) {
505                mPendingRequestChangedLocked = true;
506                sendUpdatePowerStateLocked();
507            }
508
509            return mDisplayReadyLocked;
510        }
511    }
512
513    private void sendUpdatePowerState() {
514        synchronized (mLock) {
515            sendUpdatePowerStateLocked();
516        }
517    }
518
519    private void sendUpdatePowerStateLocked() {
520        if (!mPendingUpdatePowerStateLocked) {
521            mPendingUpdatePowerStateLocked = true;
522            Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
523            msg.setAsynchronous(true);
524            mHandler.sendMessage(msg);
525        }
526    }
527
528    private void initialize() {
529        // Initialize the power state object for the default display.
530        // In the future, we might manage multiple displays independently.
531        mPowerState = new DisplayPowerState(mBlanker,
532                mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
533                new ElectronBeam(Display.DEFAULT_DISPLAY));
534
535        mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
536                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
537        mElectronBeamOnAnimator.setDuration(ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS);
538        mElectronBeamOnAnimator.addListener(mAnimatorListener);
539
540        mElectronBeamOffAnimator = ObjectAnimator.ofFloat(
541                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 1.0f, 0.0f);
542        mElectronBeamOffAnimator.setDuration(ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS);
543        mElectronBeamOffAnimator.addListener(mAnimatorListener);
544
545        mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
546                mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
547    }
548
549    private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
550        @Override
551        public void onAnimationStart(Animator animation) {
552        }
553        @Override
554        public void onAnimationEnd(Animator animation) {
555            sendUpdatePowerState();
556        }
557        @Override
558        public void onAnimationRepeat(Animator animation) {
559        }
560        @Override
561        public void onAnimationCancel(Animator animation) {
562        }
563    };
564
565    private void updatePowerState() {
566        // Update the power state request.
567        final boolean mustNotify;
568        boolean mustInitialize = false;
569        boolean updateAutoBrightness = mTwilightChanged;
570        boolean wasDimOrDoze = false;
571        mTwilightChanged = false;
572
573        synchronized (mLock) {
574            mPendingUpdatePowerStateLocked = false;
575            if (mPendingRequestLocked == null) {
576                return; // wait until first actual power request
577            }
578
579            if (mPowerRequest == null) {
580                mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
581                mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
582                mPendingWaitForNegativeProximityLocked = false;
583                mPendingRequestChangedLocked = false;
584                mustInitialize = true;
585            } else if (mPendingRequestChangedLocked) {
586                if (mPowerRequest.screenAutoBrightnessAdjustment
587                        != mPendingRequestLocked.screenAutoBrightnessAdjustment) {
588                    updateAutoBrightness = true;
589                }
590                wasDimOrDoze = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM
591                        || mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE);
592                mPowerRequest.copyFrom(mPendingRequestLocked);
593                mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
594                mPendingWaitForNegativeProximityLocked = false;
595                mPendingRequestChangedLocked = false;
596                mDisplayReadyLocked = false;
597            }
598
599            mustNotify = !mDisplayReadyLocked;
600        }
601
602        // Initialize things the first time the power state is changed.
603        if (mustInitialize) {
604            initialize();
605        }
606
607        // Apply the proximity sensor.
608        if (mProximitySensor != null) {
609            if (mPowerRequest.useProximitySensor
610                    && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
611                setProximitySensorEnabled(true);
612                if (!mScreenOffBecauseOfProximity
613                        && mProximity == PROXIMITY_POSITIVE) {
614                    mScreenOffBecauseOfProximity = true;
615                    sendOnProximityPositiveWithWakelock();
616                }
617            } else if (mWaitingForNegativeProximity
618                    && mScreenOffBecauseOfProximity
619                    && mProximity == PROXIMITY_POSITIVE
620                    && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
621                setProximitySensorEnabled(true);
622            } else {
623                setProximitySensorEnabled(false);
624                mWaitingForNegativeProximity = false;
625            }
626            if (mScreenOffBecauseOfProximity
627                    && mProximity != PROXIMITY_POSITIVE) {
628                mScreenOffBecauseOfProximity = false;
629                sendOnProximityNegativeWithWakelock();
630            }
631        } else {
632            mWaitingForNegativeProximity = false;
633        }
634
635        // Turn on the light sensor if needed.
636        if (mLightSensor != null) {
637            setLightSensorEnabled(mPowerRequest.wantLightSensorEnabled(),
638                    updateAutoBrightness);
639        }
640
641        // Set the screen brightness.
642        if (mPowerRequest.wantScreenOnAny()) {
643            int target;
644            boolean slow;
645            if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) {
646                // Use current auto-brightness value.
647                target = mScreenAutoBrightness;
648                slow = mUsingScreenAutoBrightness;
649                mUsingScreenAutoBrightness = true;
650            } else {
651                // Light sensor is disabled or not ready yet.
652                // Use the current brightness setting from the request, which is expected
653                // provide a nominal default value for the case where auto-brightness
654                // is not ready yet.
655                target = mPowerRequest.screenBrightness;
656                slow = false;
657                mUsingScreenAutoBrightness = false;
658            }
659            if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE) {
660                // Dim quickly to the doze state.
661                target = mScreenBrightnessDozeConfig;
662                slow = false;
663            } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
664                // Dim quickly by at least some minimum amount.
665                target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
666                        mScreenBrightnessDimConfig);
667                slow = false;
668            } else if (wasDimOrDoze) {
669                // Brighten quickly.
670                slow = false;
671            }
672            animateScreenBrightness(clampScreenBrightness(target),
673                    slow ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
674        } else {
675            // Screen is off.  Don't bother changing the brightness.
676            mUsingScreenAutoBrightness = false;
677        }
678
679        // Animate the screen on or off unless blocked.
680        if (mScreenOffBecauseOfProximity) {
681            // Screen off due to proximity.
682            setScreenState(Display.STATE_OFF);
683            unblockScreenOn();
684        } else if (mPowerRequest.wantScreenOnAny()) {
685            // Want screen on.
686            // Wait for previous off animation to complete beforehand.
687            // It is relatively short but if we cancel it and switch to the
688            // on animation immediately then the results are pretty ugly.
689            if (!mElectronBeamOffAnimator.isStarted()) {
690                // Turn the screen on.  The contents of the screen may not yet
691                // be visible if the electron beam has not been dismissed because
692                // its last frame of animation is solid black.
693                setScreenState(mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE
694                        ? Display.STATE_DOZING : Display.STATE_ON);
695
696                if (mPowerRequest.blockScreenOn
697                        && mPowerState.getElectronBeamLevel() == 0.0f) {
698                    blockScreenOn();
699                } else {
700                    unblockScreenOn();
701                    if (USE_ELECTRON_BEAM_ON_ANIMATION) {
702                        if (!mElectronBeamOnAnimator.isStarted()) {
703                            if (mPowerState.getElectronBeamLevel() == 1.0f) {
704                                mPowerState.dismissElectronBeam();
705                            } else if (mPowerState.prepareElectronBeam(
706                                    mElectronBeamFadesConfig ?
707                                            ElectronBeam.MODE_FADE :
708                                                    ElectronBeam.MODE_WARM_UP)) {
709                                mElectronBeamOnAnimator.start();
710                            } else {
711                                mElectronBeamOnAnimator.end();
712                            }
713                        }
714                    } else {
715                        mPowerState.setElectronBeamLevel(1.0f);
716                        mPowerState.dismissElectronBeam();
717                    }
718                }
719            }
720        } else {
721            // Want screen off.
722            // Wait for previous on animation to complete beforehand.
723            unblockScreenOn();
724            if (!mElectronBeamOnAnimator.isStarted()) {
725                if (!mElectronBeamOffAnimator.isStarted()) {
726                    if (mPowerState.getElectronBeamLevel() == 0.0f) {
727                        setScreenState(Display.STATE_OFF);
728                    } else if (mPowerState.prepareElectronBeam(
729                            mElectronBeamFadesConfig ?
730                                    ElectronBeam.MODE_FADE :
731                                            ElectronBeam.MODE_COOL_DOWN)
732                            && mPowerState.getScreenState() != Display.STATE_OFF) {
733                        mElectronBeamOffAnimator.start();
734                    } else {
735                        mElectronBeamOffAnimator.end();
736                    }
737                }
738            }
739        }
740
741        // Report whether the display is ready for use.
742        // We mostly care about the screen state here, ignoring brightness changes
743        // which will be handled asynchronously.
744        if (mustNotify
745                && !mScreenOnWasBlocked
746                && !mElectronBeamOnAnimator.isStarted()
747                && !mElectronBeamOffAnimator.isStarted()
748                && mPowerState.waitUntilClean(mCleanListener)) {
749            synchronized (mLock) {
750                if (!mPendingRequestChangedLocked) {
751                    mDisplayReadyLocked = true;
752
753                    if (DEBUG) {
754                        Slog.d(TAG, "Display ready!");
755                    }
756                }
757            }
758            sendOnStateChangedWithWakelock();
759        }
760    }
761
762    private void blockScreenOn() {
763        if (!mScreenOnWasBlocked) {
764            mScreenOnWasBlocked = true;
765            mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
766            if (DEBUG) {
767                Slog.d(TAG, "Blocked screen on.");
768            }
769        }
770    }
771
772    private void unblockScreenOn() {
773        if (mScreenOnWasBlocked) {
774            mScreenOnWasBlocked = false;
775            long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
776            if (delay > 1000 || DEBUG) {
777                Slog.d(TAG, "Unblocked screen on after " + delay + " ms");
778            }
779        }
780    }
781
782    private void setScreenState(int state) {
783        if (mPowerState.getScreenState() != state) {
784            mPowerState.setScreenState(state);
785            try {
786                if (state != Display.STATE_OFF) {
787                    mBatteryStats.noteScreenOn();
788                } else {
789                    mBatteryStats.noteScreenOff();
790                }
791            } catch (RemoteException ex) {
792                // same process
793            }
794        }
795    }
796
797    private int clampScreenBrightness(int value) {
798        return clamp(value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
799    }
800
801    private static int clampAbsoluteBrightness(int value) {
802        return clamp(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
803    }
804
805    private static int clamp(int value, int min, int max) {
806        if (value <= min) {
807            return min;
808        }
809        if (value >= max) {
810            return max;
811        }
812        return value;
813    }
814
815    private static float normalizeAbsoluteBrightness(int value) {
816        return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
817    }
818
819    private void animateScreenBrightness(int target, int rate) {
820        if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
821            try {
822                mBatteryStats.noteScreenBrightness(target);
823            } catch (RemoteException ex) {
824                // same process
825            }
826        }
827    }
828
829    private final Runnable mCleanListener = new Runnable() {
830        @Override
831        public void run() {
832            sendUpdatePowerState();
833        }
834    };
835
836    private void setProximitySensorEnabled(boolean enable) {
837        if (enable) {
838            if (!mProximitySensorEnabled) {
839                // Register the listener.
840                // Proximity sensor state already cleared initially.
841                mProximitySensorEnabled = true;
842                mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
843                        SensorManager.SENSOR_DELAY_NORMAL, mHandler);
844            }
845        } else {
846            if (mProximitySensorEnabled) {
847                // Unregister the listener.
848                // Clear the proximity sensor state for next time.
849                mProximitySensorEnabled = false;
850                mProximity = PROXIMITY_UNKNOWN;
851                mPendingProximity = PROXIMITY_UNKNOWN;
852                mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
853                mSensorManager.unregisterListener(mProximitySensorListener);
854                clearPendingProximityDebounceTime(); // release wake lock (must be last)
855            }
856        }
857    }
858
859    private void handleProximitySensorEvent(long time, boolean positive) {
860        if (mProximitySensorEnabled) {
861            if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
862                return; // no change
863            }
864            if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
865                return; // no change
866            }
867
868            // Only accept a proximity sensor reading if it remains
869            // stable for the entire debounce delay.  We hold a wake lock while
870            // debouncing the sensor.
871            mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
872            if (positive) {
873                mPendingProximity = PROXIMITY_POSITIVE;
874                setPendingProximityDebounceTime(
875                        time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); // acquire wake lock
876            } else {
877                mPendingProximity = PROXIMITY_NEGATIVE;
878                setPendingProximityDebounceTime(
879                        time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); // acquire wake lock
880            }
881
882            // Debounce the new sensor reading.
883            debounceProximitySensor();
884        }
885    }
886
887    private void debounceProximitySensor() {
888        if (mProximitySensorEnabled
889                && mPendingProximity != PROXIMITY_UNKNOWN
890                && mPendingProximityDebounceTime >= 0) {
891            final long now = SystemClock.uptimeMillis();
892            if (mPendingProximityDebounceTime <= now) {
893                // Sensor reading accepted.  Apply the change then release the wake lock.
894                mProximity = mPendingProximity;
895                updatePowerState();
896                clearPendingProximityDebounceTime(); // release wake lock (must be last)
897            } else {
898                // Need to wait a little longer.
899                // Debounce again later.  We continue holding a wake lock while waiting.
900                Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
901                msg.setAsynchronous(true);
902                mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
903            }
904        }
905    }
906
907    private void clearPendingProximityDebounceTime() {
908        if (mPendingProximityDebounceTime >= 0) {
909            mPendingProximityDebounceTime = -1;
910            mCallbacks.releaseSuspendBlocker(); // release wake lock
911        }
912    }
913
914    private void setPendingProximityDebounceTime(long debounceTime) {
915        if (mPendingProximityDebounceTime < 0) {
916            mCallbacks.acquireSuspendBlocker(); // acquire wake lock
917        }
918        mPendingProximityDebounceTime = debounceTime;
919    }
920
921    private void setLightSensorEnabled(boolean enable, boolean updateAutoBrightness) {
922        if (enable) {
923            if (!mLightSensorEnabled) {
924                updateAutoBrightness = true;
925                mLightSensorEnabled = true;
926                mLightSensorEnableTime = SystemClock.uptimeMillis();
927                mSensorManager.registerListener(mLightSensorListener, mLightSensor,
928                        LIGHT_SENSOR_RATE_MILLIS * 1000, mHandler);
929            }
930        } else {
931            if (mLightSensorEnabled) {
932                mLightSensorEnabled = false;
933                mAmbientLuxValid = false;
934                mRecentLightSamples = 0;
935                mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
936                mSensorManager.unregisterListener(mLightSensorListener);
937            }
938        }
939        if (updateAutoBrightness) {
940            updateAutoBrightness(false);
941        }
942    }
943
944    private void handleLightSensorEvent(long time, float lux) {
945        mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
946
947        applyLightSensorMeasurement(time, lux);
948        updateAmbientLux(time);
949    }
950
951    private void applyLightSensorMeasurement(long time, float lux) {
952        // Update our filters.
953        mRecentLightSamples += 1;
954        if (mRecentLightSamples == 1) {
955            mRecentShortTermAverageLux = lux;
956            mRecentLongTermAverageLux = lux;
957        } else {
958            final long timeDelta = time - mLastObservedLuxTime;
959            mRecentShortTermAverageLux += (lux - mRecentShortTermAverageLux)
960                    * timeDelta / (SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
961            mRecentLongTermAverageLux += (lux - mRecentLongTermAverageLux)
962                    * timeDelta / (LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
963        }
964
965        // Remember this sample value.
966        mLastObservedLux = lux;
967        mLastObservedLuxTime = time;
968    }
969
970    private void setAmbientLux(float lux) {
971        mAmbientLux = lux;
972        mBrighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
973        mDarkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
974    }
975
976    private void updateAmbientLux(long time) {
977        // If the light sensor was just turned on then immediately update our initial
978        // estimate of the current ambient light level.
979        if (!mAmbientLuxValid) {
980            final long timeWhenSensorWarmedUp =
981                mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
982            if (time < timeWhenSensorWarmedUp) {
983                mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED,
984                        timeWhenSensorWarmedUp);
985                return;
986            }
987            setAmbientLux(mRecentShortTermAverageLux);
988            mAmbientLuxValid = true;
989            mDebounceLuxDirection = 0;
990            mDebounceLuxTime = time;
991            if (DEBUG) {
992                Slog.d(TAG, "updateAmbientLux: Initializing: "
993                        + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
994                        + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
995                        + ", mAmbientLux=" + mAmbientLux);
996            }
997            updateAutoBrightness(true);
998        } else if (mRecentShortTermAverageLux > mBrighteningLuxThreshold
999                && mRecentLongTermAverageLux > mBrighteningLuxThreshold) {
1000            // The ambient environment appears to be brightening.
1001            if (mDebounceLuxDirection <= 0) {
1002                mDebounceLuxDirection = 1;
1003                mDebounceLuxTime = time;
1004                if (DEBUG) {
1005                    Slog.d(TAG, "updateAmbientLux: Possibly brightened, waiting for "
1006                            + BRIGHTENING_LIGHT_DEBOUNCE + " ms: "
1007                            + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
1008                            + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
1009                            + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
1010                            + ", mAmbientLux=" + mAmbientLux);
1011                }
1012            }
1013            long debounceTime = mDebounceLuxTime + BRIGHTENING_LIGHT_DEBOUNCE;
1014            if (time < debounceTime) {
1015                mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
1016                return;
1017            }
1018            setAmbientLux(mRecentShortTermAverageLux);
1019            if (DEBUG) {
1020                Slog.d(TAG, "updateAmbientLux: Brightened: "
1021                        + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
1022                        + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
1023                        + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
1024                        + ", mAmbientLux=" + mAmbientLux);
1025            }
1026            updateAutoBrightness(true);
1027        } else if (mRecentShortTermAverageLux < mDarkeningLuxThreshold
1028                && mRecentLongTermAverageLux < mDarkeningLuxThreshold) {
1029            // The ambient environment appears to be darkening.
1030            if (mDebounceLuxDirection >= 0) {
1031                mDebounceLuxDirection = -1;
1032                mDebounceLuxTime = time;
1033                if (DEBUG) {
1034                    Slog.d(TAG, "updateAmbientLux: Possibly darkened, waiting for "
1035                            + DARKENING_LIGHT_DEBOUNCE + " ms: "
1036                            + "mDarkeningLuxThreshold=" + mDarkeningLuxThreshold
1037                            + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
1038                            + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
1039                            + ", mAmbientLux=" + mAmbientLux);
1040                }
1041            }
1042            long debounceTime = mDebounceLuxTime + DARKENING_LIGHT_DEBOUNCE;
1043            if (time < debounceTime) {
1044                mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
1045                return;
1046            }
1047            // Be conservative about reducing the brightness, only reduce it a little bit
1048            // at a time to avoid having to bump it up again soon.
1049            setAmbientLux(Math.max(mRecentShortTermAverageLux, mRecentLongTermAverageLux));
1050            if (DEBUG) {
1051                Slog.d(TAG, "updateAmbientLux: Darkened: "
1052                        + "mDarkeningLuxThreshold=" + mDarkeningLuxThreshold
1053                        + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
1054                        + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
1055                        + ", mAmbientLux=" + mAmbientLux);
1056            }
1057            updateAutoBrightness(true);
1058        } else if (mDebounceLuxDirection != 0) {
1059            // No change or change is within the hysteresis thresholds.
1060            mDebounceLuxDirection = 0;
1061            mDebounceLuxTime = time;
1062            if (DEBUG) {
1063                Slog.d(TAG, "updateAmbientLux: Canceled debounce: "
1064                        + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
1065                        + ", mDarkeningLuxThreshold=" + mDarkeningLuxThreshold
1066                        + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
1067                        + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
1068                        + ", mAmbientLux=" + mAmbientLux);
1069            }
1070        }
1071
1072        // Now that we've done all of that, we haven't yet posted a debounce
1073        // message. So consider the case where current lux is beyond the
1074        // threshold. It's possible that the light sensor may not report values
1075        // if the light level does not change, so we need to occasionally
1076        // synthesize sensor readings in order to make sure the brightness is
1077        // adjusted accordingly. Note these thresholds may have changed since
1078        // we entered the function because we called setAmbientLux and
1079        // updateAutoBrightness along the way.
1080        if (mLastObservedLux > mBrighteningLuxThreshold
1081                || mLastObservedLux < mDarkeningLuxThreshold) {
1082            mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED,
1083                    time + SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS);
1084        }
1085    }
1086
1087    private void debounceLightSensor() {
1088        if (mLightSensorEnabled) {
1089            long time = SystemClock.uptimeMillis();
1090            if (time >= mLastObservedLuxTime + SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS) {
1091                if (DEBUG) {
1092                    Slog.d(TAG, "debounceLightSensor: Synthesizing light sensor measurement "
1093                            + "after " + (time - mLastObservedLuxTime) + " ms.");
1094                }
1095                applyLightSensorMeasurement(time, mLastObservedLux);
1096            }
1097            updateAmbientLux(time);
1098        }
1099    }
1100
1101    private void updateAutoBrightness(boolean sendUpdate) {
1102        if (!mAmbientLuxValid) {
1103            return;
1104        }
1105
1106        float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);
1107        float gamma = 1.0f;
1108
1109        if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
1110                && mPowerRequest.screenAutoBrightnessAdjustment != 0.0f) {
1111            final float adjGamma = FloatMath.pow(SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA,
1112                    Math.min(1.0f, Math.max(-1.0f,
1113                            -mPowerRequest.screenAutoBrightnessAdjustment)));
1114            gamma *= adjGamma;
1115            if (DEBUG) {
1116                Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma);
1117            }
1118        }
1119
1120        if (USE_TWILIGHT_ADJUSTMENT) {
1121            TwilightState state = mTwilight.getCurrentState();
1122            if (state != null && state.isNight()) {
1123                final long now = System.currentTimeMillis();
1124                final float earlyGamma =
1125                        getTwilightGamma(now, state.getYesterdaySunset(), state.getTodaySunrise());
1126                final float lateGamma =
1127                        getTwilightGamma(now, state.getTodaySunset(), state.getTomorrowSunrise());
1128                gamma *= earlyGamma * lateGamma;
1129                if (DEBUG) {
1130                    Slog.d(TAG, "updateAutoBrightness: earlyGamma=" + earlyGamma
1131                            + ", lateGamma=" + lateGamma);
1132                }
1133            }
1134        }
1135
1136        if (gamma != 1.0f) {
1137            final float in = value;
1138            value = FloatMath.pow(value, gamma);
1139            if (DEBUG) {
1140                Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma
1141                        + ", in=" + in + ", out=" + value);
1142            }
1143        }
1144
1145        int newScreenAutoBrightness = clampScreenBrightness(
1146                Math.round(value * PowerManager.BRIGHTNESS_ON));
1147        if (mScreenAutoBrightness != newScreenAutoBrightness) {
1148            if (DEBUG) {
1149                Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
1150                        + mScreenAutoBrightness + ", newScreenAutoBrightness="
1151                        + newScreenAutoBrightness);
1152            }
1153
1154            mScreenAutoBrightness = newScreenAutoBrightness;
1155            mLastScreenAutoBrightnessGamma = gamma;
1156            if (sendUpdate) {
1157                sendUpdatePowerState();
1158            }
1159        }
1160    }
1161
1162    private static float getTwilightGamma(long now, long lastSunset, long nextSunrise) {
1163        if (lastSunset < 0 || nextSunrise < 0
1164                || now < lastSunset || now > nextSunrise) {
1165            return 1.0f;
1166        }
1167
1168        if (now < lastSunset + TWILIGHT_ADJUSTMENT_TIME) {
1169            return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
1170                    (float)(now - lastSunset) / TWILIGHT_ADJUSTMENT_TIME);
1171        }
1172
1173        if (now > nextSunrise - TWILIGHT_ADJUSTMENT_TIME) {
1174            return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
1175                    (float)(nextSunrise - now) / TWILIGHT_ADJUSTMENT_TIME);
1176        }
1177
1178        return TWILIGHT_ADJUSTMENT_MAX_GAMMA;
1179    }
1180
1181    private static float lerp(float x, float y, float alpha) {
1182        return x + (y - x) * alpha;
1183    }
1184
1185    private void sendOnStateChangedWithWakelock() {
1186        mCallbacks.acquireSuspendBlocker();
1187        mHandler.post(mOnStateChangedRunnable);
1188    }
1189
1190    private final Runnable mOnStateChangedRunnable = new Runnable() {
1191        @Override
1192        public void run() {
1193            mCallbacks.onStateChanged();
1194            mCallbacks.releaseSuspendBlocker();
1195        }
1196    };
1197
1198    private void sendOnProximityPositiveWithWakelock() {
1199        mCallbacks.acquireSuspendBlocker();
1200        mHandler.post(mOnProximityPositiveRunnable);
1201    }
1202
1203    private final Runnable mOnProximityPositiveRunnable = new Runnable() {
1204        @Override
1205        public void run() {
1206            mCallbacks.onProximityPositive();
1207            mCallbacks.releaseSuspendBlocker();
1208        }
1209    };
1210
1211    private void sendOnProximityNegativeWithWakelock() {
1212        mCallbacks.acquireSuspendBlocker();
1213        mHandler.post(mOnProximityNegativeRunnable);
1214    }
1215
1216    private final Runnable mOnProximityNegativeRunnable = new Runnable() {
1217        @Override
1218        public void run() {
1219            mCallbacks.onProximityNegative();
1220            mCallbacks.releaseSuspendBlocker();
1221        }
1222    };
1223
1224    public void dump(final PrintWriter pw) {
1225        synchronized (mLock) {
1226            pw.println();
1227            pw.println("Display Power Controller Locked State:");
1228            pw.println("  mDisplayReadyLocked=" + mDisplayReadyLocked);
1229            pw.println("  mPendingRequestLocked=" + mPendingRequestLocked);
1230            pw.println("  mPendingRequestChangedLocked=" + mPendingRequestChangedLocked);
1231            pw.println("  mPendingWaitForNegativeProximityLocked="
1232                    + mPendingWaitForNegativeProximityLocked);
1233            pw.println("  mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked);
1234        }
1235
1236        pw.println();
1237        pw.println("Display Power Controller Configuration:");
1238        pw.println("  mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
1239        pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
1240        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
1241        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
1242        pw.println("  mUseSoftwareAutoBrightnessConfig="
1243                + mUseSoftwareAutoBrightnessConfig);
1244        pw.println("  mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline);
1245        pw.println("  mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
1246
1247        mHandler.runWithScissors(new Runnable() {
1248            @Override
1249            public void run() {
1250                dumpLocal(pw);
1251            }
1252        }, 1000);
1253    }
1254
1255    private void dumpLocal(PrintWriter pw) {
1256        pw.println();
1257        pw.println("Display Power Controller Thread State:");
1258        pw.println("  mPowerRequest=" + mPowerRequest);
1259        pw.println("  mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
1260
1261        pw.println("  mProximitySensor=" + mProximitySensor);
1262        pw.println("  mProximitySensorEnabled=" + mProximitySensorEnabled);
1263        pw.println("  mProximityThreshold=" + mProximityThreshold);
1264        pw.println("  mProximity=" + proximityToString(mProximity));
1265        pw.println("  mPendingProximity=" + proximityToString(mPendingProximity));
1266        pw.println("  mPendingProximityDebounceTime="
1267                + TimeUtils.formatUptime(mPendingProximityDebounceTime));
1268        pw.println("  mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
1269
1270        pw.println("  mLightSensor=" + mLightSensor);
1271        pw.println("  mLightSensorEnabled=" + mLightSensorEnabled);
1272        pw.println("  mLightSensorEnableTime="
1273                + TimeUtils.formatUptime(mLightSensorEnableTime));
1274        pw.println("  mAmbientLux=" + mAmbientLux);
1275        pw.println("  mAmbientLuxValid=" + mAmbientLuxValid);
1276        pw.println("  mLastObservedLux=" + mLastObservedLux);
1277        pw.println("  mLastObservedLuxTime="
1278                + TimeUtils.formatUptime(mLastObservedLuxTime));
1279        pw.println("  mRecentLightSamples=" + mRecentLightSamples);
1280        pw.println("  mRecentShortTermAverageLux=" + mRecentShortTermAverageLux);
1281        pw.println("  mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
1282        pw.println("  mDebounceLuxDirection=" + mDebounceLuxDirection);
1283        pw.println("  mDebounceLuxTime=" + TimeUtils.formatUptime(mDebounceLuxTime));
1284        pw.println("  mScreenAutoBrightness=" + mScreenAutoBrightness);
1285        pw.println("  mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
1286        pw.println("  mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
1287        pw.println("  mTwilight.getCurrentState()=" + mTwilight.getCurrentState());
1288
1289        if (mElectronBeamOnAnimator != null) {
1290            pw.println("  mElectronBeamOnAnimator.isStarted()=" +
1291                    mElectronBeamOnAnimator.isStarted());
1292        }
1293        if (mElectronBeamOffAnimator != null) {
1294            pw.println("  mElectronBeamOffAnimator.isStarted()=" +
1295                    mElectronBeamOffAnimator.isStarted());
1296        }
1297
1298        if (mPowerState != null) {
1299            mPowerState.dump(pw);
1300        }
1301    }
1302
1303    private static String proximityToString(int state) {
1304        switch (state) {
1305            case PROXIMITY_UNKNOWN:
1306                return "Unknown";
1307            case PROXIMITY_NEGATIVE:
1308                return "Negative";
1309            case PROXIMITY_POSITIVE:
1310                return "Positive";
1311            default:
1312                return Integer.toString(state);
1313        }
1314    }
1315
1316    private final class DisplayControllerHandler extends Handler {
1317        public DisplayControllerHandler(Looper looper) {
1318            super(looper, null, true /*async*/);
1319        }
1320
1321        @Override
1322        public void handleMessage(Message msg) {
1323            switch (msg.what) {
1324                case MSG_UPDATE_POWER_STATE:
1325                    updatePowerState();
1326                    break;
1327
1328                case MSG_PROXIMITY_SENSOR_DEBOUNCED:
1329                    debounceProximitySensor();
1330                    break;
1331
1332                case MSG_LIGHT_SENSOR_DEBOUNCED:
1333                    debounceLightSensor();
1334                    break;
1335            }
1336        }
1337    }
1338
1339    private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
1340        @Override
1341        public void onSensorChanged(SensorEvent event) {
1342            if (mProximitySensorEnabled) {
1343                final long time = SystemClock.uptimeMillis();
1344                final float distance = event.values[0];
1345                boolean positive = distance >= 0.0f && distance < mProximityThreshold;
1346                handleProximitySensorEvent(time, positive);
1347            }
1348        }
1349
1350        @Override
1351        public void onAccuracyChanged(Sensor sensor, int accuracy) {
1352            // Not used.
1353        }
1354    };
1355
1356    private final SensorEventListener mLightSensorListener = new SensorEventListener() {
1357        @Override
1358        public void onSensorChanged(SensorEvent event) {
1359            if (mLightSensorEnabled) {
1360                final long time = SystemClock.uptimeMillis();
1361                final float lux = event.values[0];
1362                handleLightSensorEvent(time, lux);
1363            }
1364        }
1365
1366        @Override
1367        public void onAccuracyChanged(Sensor sensor, int accuracy) {
1368            // Not used.
1369        }
1370    };
1371
1372    private final TwilightListener mTwilightListener = new TwilightListener() {
1373        @Override
1374        public void onTwilightStateChanged() {
1375            mTwilightChanged = true;
1376            updatePowerState();
1377        }
1378    };
1379}
1380