DisplayPowerController.java revision 01ee6f6cf7de9fb98fc3a88509b43416caa71040
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        // Initialize screen state for battery stats.
549        try {
550            mBatteryStats.noteScreenState(mPowerState.getScreenState());
551            mBatteryStats.noteScreenBrightness(mPowerState.getScreenBrightness());
552        } catch (RemoteException ex) {
553            // same process
554        }
555    }
556
557    private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
558        @Override
559        public void onAnimationStart(Animator animation) {
560        }
561        @Override
562        public void onAnimationEnd(Animator animation) {
563            sendUpdatePowerState();
564        }
565        @Override
566        public void onAnimationRepeat(Animator animation) {
567        }
568        @Override
569        public void onAnimationCancel(Animator animation) {
570        }
571    };
572
573    private void updatePowerState() {
574        // Update the power state request.
575        final boolean mustNotify;
576        boolean mustInitialize = false;
577        boolean updateAutoBrightness = mTwilightChanged;
578        boolean wasDimOrDoze = false;
579        mTwilightChanged = false;
580
581        synchronized (mLock) {
582            mPendingUpdatePowerStateLocked = false;
583            if (mPendingRequestLocked == null) {
584                return; // wait until first actual power request
585            }
586
587            if (mPowerRequest == null) {
588                mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
589                mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
590                mPendingWaitForNegativeProximityLocked = false;
591                mPendingRequestChangedLocked = false;
592                mustInitialize = true;
593            } else if (mPendingRequestChangedLocked) {
594                if (mPowerRequest.screenAutoBrightnessAdjustment
595                        != mPendingRequestLocked.screenAutoBrightnessAdjustment) {
596                    updateAutoBrightness = true;
597                }
598                wasDimOrDoze = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM
599                        || mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE);
600                mPowerRequest.copyFrom(mPendingRequestLocked);
601                mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
602                mPendingWaitForNegativeProximityLocked = false;
603                mPendingRequestChangedLocked = false;
604                mDisplayReadyLocked = false;
605            }
606
607            mustNotify = !mDisplayReadyLocked;
608        }
609
610        // Initialize things the first time the power state is changed.
611        if (mustInitialize) {
612            initialize();
613        }
614
615        // Apply the proximity sensor.
616        if (mProximitySensor != null) {
617            if (mPowerRequest.useProximitySensor
618                    && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
619                setProximitySensorEnabled(true);
620                if (!mScreenOffBecauseOfProximity
621                        && mProximity == PROXIMITY_POSITIVE) {
622                    mScreenOffBecauseOfProximity = true;
623                    sendOnProximityPositiveWithWakelock();
624                }
625            } else if (mWaitingForNegativeProximity
626                    && mScreenOffBecauseOfProximity
627                    && mProximity == PROXIMITY_POSITIVE
628                    && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
629                setProximitySensorEnabled(true);
630            } else {
631                setProximitySensorEnabled(false);
632                mWaitingForNegativeProximity = false;
633            }
634            if (mScreenOffBecauseOfProximity
635                    && mProximity != PROXIMITY_POSITIVE) {
636                mScreenOffBecauseOfProximity = false;
637                sendOnProximityNegativeWithWakelock();
638            }
639        } else {
640            mWaitingForNegativeProximity = false;
641        }
642
643        // Turn on the light sensor if needed.
644        if (mLightSensor != null) {
645            setLightSensorEnabled(mPowerRequest.wantLightSensorEnabled(),
646                    updateAutoBrightness);
647        }
648
649        // Set the screen brightness.
650        if (mPowerRequest.wantScreenOnAny()) {
651            int target;
652            boolean slow;
653            if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) {
654                // Use current auto-brightness value.
655                target = mScreenAutoBrightness;
656                slow = mUsingScreenAutoBrightness;
657                mUsingScreenAutoBrightness = true;
658            } else {
659                // Light sensor is disabled or not ready yet.
660                // Use the current brightness setting from the request, which is expected
661                // provide a nominal default value for the case where auto-brightness
662                // is not ready yet.
663                target = mPowerRequest.screenBrightness;
664                slow = false;
665                mUsingScreenAutoBrightness = false;
666            }
667            if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE) {
668                // Dim quickly to the doze state.
669                target = mScreenBrightnessDozeConfig;
670                slow = false;
671            } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
672                // Dim quickly by at least some minimum amount.
673                target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
674                        mScreenBrightnessDimConfig);
675                slow = false;
676            } else if (wasDimOrDoze) {
677                // Brighten quickly.
678                slow = false;
679            }
680            animateScreenBrightness(clampScreenBrightness(target),
681                    slow ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
682        } else {
683            // Screen is off.  Don't bother changing the brightness.
684            mUsingScreenAutoBrightness = false;
685        }
686
687        // Animate the screen on or off unless blocked.
688        if (mScreenOffBecauseOfProximity) {
689            // Screen off due to proximity.
690            setScreenState(Display.STATE_OFF);
691            unblockScreenOn();
692        } else if (mPowerRequest.wantScreenOnAny()) {
693            // Want screen on.
694            // Wait for previous off animation to complete beforehand.
695            // It is relatively short but if we cancel it and switch to the
696            // on animation immediately then the results are pretty ugly.
697            if (!mElectronBeamOffAnimator.isStarted()) {
698                // Turn the screen on.  The contents of the screen may not yet
699                // be visible if the electron beam has not been dismissed because
700                // its last frame of animation is solid black.
701                setScreenState(mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE
702                        ? Display.STATE_DOZING : Display.STATE_ON);
703
704                if (mPowerRequest.blockScreenOn
705                        && mPowerState.getElectronBeamLevel() == 0.0f) {
706                    blockScreenOn();
707                } else {
708                    unblockScreenOn();
709                    if (USE_ELECTRON_BEAM_ON_ANIMATION) {
710                        if (!mElectronBeamOnAnimator.isStarted()) {
711                            if (mPowerState.getElectronBeamLevel() == 1.0f) {
712                                mPowerState.dismissElectronBeam();
713                            } else if (mPowerState.prepareElectronBeam(
714                                    mElectronBeamFadesConfig ?
715                                            ElectronBeam.MODE_FADE :
716                                                    ElectronBeam.MODE_WARM_UP)) {
717                                mElectronBeamOnAnimator.start();
718                            } else {
719                                mElectronBeamOnAnimator.end();
720                            }
721                        }
722                    } else {
723                        mPowerState.setElectronBeamLevel(1.0f);
724                        mPowerState.dismissElectronBeam();
725                    }
726                }
727            }
728        } else {
729            // Want screen off.
730            // Wait for previous on animation to complete beforehand.
731            unblockScreenOn();
732            if (!mElectronBeamOnAnimator.isStarted()) {
733                if (!mElectronBeamOffAnimator.isStarted()) {
734                    if (mPowerState.getElectronBeamLevel() == 0.0f) {
735                        setScreenState(Display.STATE_OFF);
736                    } else if (mPowerState.prepareElectronBeam(
737                            mElectronBeamFadesConfig ?
738                                    ElectronBeam.MODE_FADE :
739                                            ElectronBeam.MODE_COOL_DOWN)
740                            && mPowerState.getScreenState() != Display.STATE_OFF) {
741                        mElectronBeamOffAnimator.start();
742                    } else {
743                        mElectronBeamOffAnimator.end();
744                    }
745                }
746            }
747        }
748
749        // Report whether the display is ready for use.
750        // We mostly care about the screen state here, ignoring brightness changes
751        // which will be handled asynchronously.
752        if (mustNotify
753                && !mScreenOnWasBlocked
754                && !mElectronBeamOnAnimator.isStarted()
755                && !mElectronBeamOffAnimator.isStarted()
756                && mPowerState.waitUntilClean(mCleanListener)) {
757            synchronized (mLock) {
758                if (!mPendingRequestChangedLocked) {
759                    mDisplayReadyLocked = true;
760
761                    if (DEBUG) {
762                        Slog.d(TAG, "Display ready!");
763                    }
764                }
765            }
766            sendOnStateChangedWithWakelock();
767        }
768    }
769
770    private void blockScreenOn() {
771        if (!mScreenOnWasBlocked) {
772            mScreenOnWasBlocked = true;
773            mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
774            if (DEBUG) {
775                Slog.d(TAG, "Blocked screen on.");
776            }
777        }
778    }
779
780    private void unblockScreenOn() {
781        if (mScreenOnWasBlocked) {
782            mScreenOnWasBlocked = false;
783            long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
784            if (delay > 1000 || DEBUG) {
785                Slog.d(TAG, "Unblocked screen on after " + delay + " ms");
786            }
787        }
788    }
789
790    private void setScreenState(int state) {
791        if (mPowerState.getScreenState() != state) {
792            mPowerState.setScreenState(state);
793            try {
794                mBatteryStats.noteScreenState(state);
795            } catch (RemoteException ex) {
796                // same process
797            }
798        }
799    }
800
801    private int clampScreenBrightness(int value) {
802        return clamp(value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
803    }
804
805    private static int clampAbsoluteBrightness(int value) {
806        return clamp(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
807    }
808
809    private static int clamp(int value, int min, int max) {
810        if (value <= min) {
811            return min;
812        }
813        if (value >= max) {
814            return max;
815        }
816        return value;
817    }
818
819    private static float normalizeAbsoluteBrightness(int value) {
820        return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
821    }
822
823    private void animateScreenBrightness(int target, int rate) {
824        if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
825            try {
826                mBatteryStats.noteScreenBrightness(target);
827            } catch (RemoteException ex) {
828                // same process
829            }
830        }
831    }
832
833    private final Runnable mCleanListener = new Runnable() {
834        @Override
835        public void run() {
836            sendUpdatePowerState();
837        }
838    };
839
840    private void setProximitySensorEnabled(boolean enable) {
841        if (enable) {
842            if (!mProximitySensorEnabled) {
843                // Register the listener.
844                // Proximity sensor state already cleared initially.
845                mProximitySensorEnabled = true;
846                mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
847                        SensorManager.SENSOR_DELAY_NORMAL, mHandler);
848            }
849        } else {
850            if (mProximitySensorEnabled) {
851                // Unregister the listener.
852                // Clear the proximity sensor state for next time.
853                mProximitySensorEnabled = false;
854                mProximity = PROXIMITY_UNKNOWN;
855                mPendingProximity = PROXIMITY_UNKNOWN;
856                mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
857                mSensorManager.unregisterListener(mProximitySensorListener);
858                clearPendingProximityDebounceTime(); // release wake lock (must be last)
859            }
860        }
861    }
862
863    private void handleProximitySensorEvent(long time, boolean positive) {
864        if (mProximitySensorEnabled) {
865            if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
866                return; // no change
867            }
868            if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
869                return; // no change
870            }
871
872            // Only accept a proximity sensor reading if it remains
873            // stable for the entire debounce delay.  We hold a wake lock while
874            // debouncing the sensor.
875            mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
876            if (positive) {
877                mPendingProximity = PROXIMITY_POSITIVE;
878                setPendingProximityDebounceTime(
879                        time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); // acquire wake lock
880            } else {
881                mPendingProximity = PROXIMITY_NEGATIVE;
882                setPendingProximityDebounceTime(
883                        time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); // acquire wake lock
884            }
885
886            // Debounce the new sensor reading.
887            debounceProximitySensor();
888        }
889    }
890
891    private void debounceProximitySensor() {
892        if (mProximitySensorEnabled
893                && mPendingProximity != PROXIMITY_UNKNOWN
894                && mPendingProximityDebounceTime >= 0) {
895            final long now = SystemClock.uptimeMillis();
896            if (mPendingProximityDebounceTime <= now) {
897                // Sensor reading accepted.  Apply the change then release the wake lock.
898                mProximity = mPendingProximity;
899                updatePowerState();
900                clearPendingProximityDebounceTime(); // release wake lock (must be last)
901            } else {
902                // Need to wait a little longer.
903                // Debounce again later.  We continue holding a wake lock while waiting.
904                Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
905                msg.setAsynchronous(true);
906                mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
907            }
908        }
909    }
910
911    private void clearPendingProximityDebounceTime() {
912        if (mPendingProximityDebounceTime >= 0) {
913            mPendingProximityDebounceTime = -1;
914            mCallbacks.releaseSuspendBlocker(); // release wake lock
915        }
916    }
917
918    private void setPendingProximityDebounceTime(long debounceTime) {
919        if (mPendingProximityDebounceTime < 0) {
920            mCallbacks.acquireSuspendBlocker(); // acquire wake lock
921        }
922        mPendingProximityDebounceTime = debounceTime;
923    }
924
925    private void setLightSensorEnabled(boolean enable, boolean updateAutoBrightness) {
926        if (enable) {
927            if (!mLightSensorEnabled) {
928                updateAutoBrightness = true;
929                mLightSensorEnabled = true;
930                mLightSensorEnableTime = SystemClock.uptimeMillis();
931                mSensorManager.registerListener(mLightSensorListener, mLightSensor,
932                        LIGHT_SENSOR_RATE_MILLIS * 1000, mHandler);
933            }
934        } else {
935            if (mLightSensorEnabled) {
936                mLightSensorEnabled = false;
937                mAmbientLuxValid = false;
938                mRecentLightSamples = 0;
939                mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
940                mSensorManager.unregisterListener(mLightSensorListener);
941            }
942        }
943        if (updateAutoBrightness) {
944            updateAutoBrightness(false);
945        }
946    }
947
948    private void handleLightSensorEvent(long time, float lux) {
949        mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
950
951        applyLightSensorMeasurement(time, lux);
952        updateAmbientLux(time);
953    }
954
955    private void applyLightSensorMeasurement(long time, float lux) {
956        // Update our filters.
957        mRecentLightSamples += 1;
958        if (mRecentLightSamples == 1) {
959            mRecentShortTermAverageLux = lux;
960            mRecentLongTermAverageLux = lux;
961        } else {
962            final long timeDelta = time - mLastObservedLuxTime;
963            mRecentShortTermAverageLux += (lux - mRecentShortTermAverageLux)
964                    * timeDelta / (SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
965            mRecentLongTermAverageLux += (lux - mRecentLongTermAverageLux)
966                    * timeDelta / (LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
967        }
968
969        // Remember this sample value.
970        mLastObservedLux = lux;
971        mLastObservedLuxTime = time;
972    }
973
974    private void setAmbientLux(float lux) {
975        mAmbientLux = lux;
976        mBrighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
977        mDarkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
978    }
979
980    private void updateAmbientLux(long time) {
981        // If the light sensor was just turned on then immediately update our initial
982        // estimate of the current ambient light level.
983        if (!mAmbientLuxValid) {
984            final long timeWhenSensorWarmedUp =
985                mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
986            if (time < timeWhenSensorWarmedUp) {
987                mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED,
988                        timeWhenSensorWarmedUp);
989                return;
990            }
991            setAmbientLux(mRecentShortTermAverageLux);
992            mAmbientLuxValid = true;
993            mDebounceLuxDirection = 0;
994            mDebounceLuxTime = time;
995            if (DEBUG) {
996                Slog.d(TAG, "updateAmbientLux: Initializing: "
997                        + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
998                        + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
999                        + ", mAmbientLux=" + mAmbientLux);
1000            }
1001            updateAutoBrightness(true);
1002        } else if (mRecentShortTermAverageLux > mBrighteningLuxThreshold
1003                && mRecentLongTermAverageLux > mBrighteningLuxThreshold) {
1004            // The ambient environment appears to be brightening.
1005            if (mDebounceLuxDirection <= 0) {
1006                mDebounceLuxDirection = 1;
1007                mDebounceLuxTime = time;
1008                if (DEBUG) {
1009                    Slog.d(TAG, "updateAmbientLux: Possibly brightened, waiting for "
1010                            + BRIGHTENING_LIGHT_DEBOUNCE + " ms: "
1011                            + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
1012                            + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
1013                            + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
1014                            + ", mAmbientLux=" + mAmbientLux);
1015                }
1016            }
1017            long debounceTime = mDebounceLuxTime + BRIGHTENING_LIGHT_DEBOUNCE;
1018            if (time < debounceTime) {
1019                mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
1020                return;
1021            }
1022            setAmbientLux(mRecentShortTermAverageLux);
1023            if (DEBUG) {
1024                Slog.d(TAG, "updateAmbientLux: Brightened: "
1025                        + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
1026                        + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
1027                        + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
1028                        + ", mAmbientLux=" + mAmbientLux);
1029            }
1030            updateAutoBrightness(true);
1031        } else if (mRecentShortTermAverageLux < mDarkeningLuxThreshold
1032                && mRecentLongTermAverageLux < mDarkeningLuxThreshold) {
1033            // The ambient environment appears to be darkening.
1034            if (mDebounceLuxDirection >= 0) {
1035                mDebounceLuxDirection = -1;
1036                mDebounceLuxTime = time;
1037                if (DEBUG) {
1038                    Slog.d(TAG, "updateAmbientLux: Possibly darkened, waiting for "
1039                            + DARKENING_LIGHT_DEBOUNCE + " ms: "
1040                            + "mDarkeningLuxThreshold=" + mDarkeningLuxThreshold
1041                            + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
1042                            + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
1043                            + ", mAmbientLux=" + mAmbientLux);
1044                }
1045            }
1046            long debounceTime = mDebounceLuxTime + DARKENING_LIGHT_DEBOUNCE;
1047            if (time < debounceTime) {
1048                mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
1049                return;
1050            }
1051            // Be conservative about reducing the brightness, only reduce it a little bit
1052            // at a time to avoid having to bump it up again soon.
1053            setAmbientLux(Math.max(mRecentShortTermAverageLux, mRecentLongTermAverageLux));
1054            if (DEBUG) {
1055                Slog.d(TAG, "updateAmbientLux: Darkened: "
1056                        + "mDarkeningLuxThreshold=" + mDarkeningLuxThreshold
1057                        + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
1058                        + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
1059                        + ", mAmbientLux=" + mAmbientLux);
1060            }
1061            updateAutoBrightness(true);
1062        } else if (mDebounceLuxDirection != 0) {
1063            // No change or change is within the hysteresis thresholds.
1064            mDebounceLuxDirection = 0;
1065            mDebounceLuxTime = time;
1066            if (DEBUG) {
1067                Slog.d(TAG, "updateAmbientLux: Canceled debounce: "
1068                        + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
1069                        + ", mDarkeningLuxThreshold=" + mDarkeningLuxThreshold
1070                        + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
1071                        + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
1072                        + ", mAmbientLux=" + mAmbientLux);
1073            }
1074        }
1075
1076        // Now that we've done all of that, we haven't yet posted a debounce
1077        // message. So consider the case where current lux is beyond the
1078        // threshold. It's possible that the light sensor may not report values
1079        // if the light level does not change, so we need to occasionally
1080        // synthesize sensor readings in order to make sure the brightness is
1081        // adjusted accordingly. Note these thresholds may have changed since
1082        // we entered the function because we called setAmbientLux and
1083        // updateAutoBrightness along the way.
1084        if (mLastObservedLux > mBrighteningLuxThreshold
1085                || mLastObservedLux < mDarkeningLuxThreshold) {
1086            mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED,
1087                    time + SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS);
1088        }
1089    }
1090
1091    private void debounceLightSensor() {
1092        if (mLightSensorEnabled) {
1093            long time = SystemClock.uptimeMillis();
1094            if (time >= mLastObservedLuxTime + SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS) {
1095                if (DEBUG) {
1096                    Slog.d(TAG, "debounceLightSensor: Synthesizing light sensor measurement "
1097                            + "after " + (time - mLastObservedLuxTime) + " ms.");
1098                }
1099                applyLightSensorMeasurement(time, mLastObservedLux);
1100            }
1101            updateAmbientLux(time);
1102        }
1103    }
1104
1105    private void updateAutoBrightness(boolean sendUpdate) {
1106        if (!mAmbientLuxValid) {
1107            return;
1108        }
1109
1110        float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);
1111        float gamma = 1.0f;
1112
1113        if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
1114                && mPowerRequest.screenAutoBrightnessAdjustment != 0.0f) {
1115            final float adjGamma = FloatMath.pow(SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA,
1116                    Math.min(1.0f, Math.max(-1.0f,
1117                            -mPowerRequest.screenAutoBrightnessAdjustment)));
1118            gamma *= adjGamma;
1119            if (DEBUG) {
1120                Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma);
1121            }
1122        }
1123
1124        if (USE_TWILIGHT_ADJUSTMENT) {
1125            TwilightState state = mTwilight.getCurrentState();
1126            if (state != null && state.isNight()) {
1127                final long now = System.currentTimeMillis();
1128                final float earlyGamma =
1129                        getTwilightGamma(now, state.getYesterdaySunset(), state.getTodaySunrise());
1130                final float lateGamma =
1131                        getTwilightGamma(now, state.getTodaySunset(), state.getTomorrowSunrise());
1132                gamma *= earlyGamma * lateGamma;
1133                if (DEBUG) {
1134                    Slog.d(TAG, "updateAutoBrightness: earlyGamma=" + earlyGamma
1135                            + ", lateGamma=" + lateGamma);
1136                }
1137            }
1138        }
1139
1140        if (gamma != 1.0f) {
1141            final float in = value;
1142            value = FloatMath.pow(value, gamma);
1143            if (DEBUG) {
1144                Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma
1145                        + ", in=" + in + ", out=" + value);
1146            }
1147        }
1148
1149        int newScreenAutoBrightness = clampScreenBrightness(
1150                Math.round(value * PowerManager.BRIGHTNESS_ON));
1151        if (mScreenAutoBrightness != newScreenAutoBrightness) {
1152            if (DEBUG) {
1153                Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
1154                        + mScreenAutoBrightness + ", newScreenAutoBrightness="
1155                        + newScreenAutoBrightness);
1156            }
1157
1158            mScreenAutoBrightness = newScreenAutoBrightness;
1159            mLastScreenAutoBrightnessGamma = gamma;
1160            if (sendUpdate) {
1161                sendUpdatePowerState();
1162            }
1163        }
1164    }
1165
1166    private static float getTwilightGamma(long now, long lastSunset, long nextSunrise) {
1167        if (lastSunset < 0 || nextSunrise < 0
1168                || now < lastSunset || now > nextSunrise) {
1169            return 1.0f;
1170        }
1171
1172        if (now < lastSunset + TWILIGHT_ADJUSTMENT_TIME) {
1173            return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
1174                    (float)(now - lastSunset) / TWILIGHT_ADJUSTMENT_TIME);
1175        }
1176
1177        if (now > nextSunrise - TWILIGHT_ADJUSTMENT_TIME) {
1178            return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
1179                    (float)(nextSunrise - now) / TWILIGHT_ADJUSTMENT_TIME);
1180        }
1181
1182        return TWILIGHT_ADJUSTMENT_MAX_GAMMA;
1183    }
1184
1185    private static float lerp(float x, float y, float alpha) {
1186        return x + (y - x) * alpha;
1187    }
1188
1189    private void sendOnStateChangedWithWakelock() {
1190        mCallbacks.acquireSuspendBlocker();
1191        mHandler.post(mOnStateChangedRunnable);
1192    }
1193
1194    private final Runnable mOnStateChangedRunnable = new Runnable() {
1195        @Override
1196        public void run() {
1197            mCallbacks.onStateChanged();
1198            mCallbacks.releaseSuspendBlocker();
1199        }
1200    };
1201
1202    private void sendOnProximityPositiveWithWakelock() {
1203        mCallbacks.acquireSuspendBlocker();
1204        mHandler.post(mOnProximityPositiveRunnable);
1205    }
1206
1207    private final Runnable mOnProximityPositiveRunnable = new Runnable() {
1208        @Override
1209        public void run() {
1210            mCallbacks.onProximityPositive();
1211            mCallbacks.releaseSuspendBlocker();
1212        }
1213    };
1214
1215    private void sendOnProximityNegativeWithWakelock() {
1216        mCallbacks.acquireSuspendBlocker();
1217        mHandler.post(mOnProximityNegativeRunnable);
1218    }
1219
1220    private final Runnable mOnProximityNegativeRunnable = new Runnable() {
1221        @Override
1222        public void run() {
1223            mCallbacks.onProximityNegative();
1224            mCallbacks.releaseSuspendBlocker();
1225        }
1226    };
1227
1228    public void dump(final PrintWriter pw) {
1229        synchronized (mLock) {
1230            pw.println();
1231            pw.println("Display Power Controller Locked State:");
1232            pw.println("  mDisplayReadyLocked=" + mDisplayReadyLocked);
1233            pw.println("  mPendingRequestLocked=" + mPendingRequestLocked);
1234            pw.println("  mPendingRequestChangedLocked=" + mPendingRequestChangedLocked);
1235            pw.println("  mPendingWaitForNegativeProximityLocked="
1236                    + mPendingWaitForNegativeProximityLocked);
1237            pw.println("  mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked);
1238        }
1239
1240        pw.println();
1241        pw.println("Display Power Controller Configuration:");
1242        pw.println("  mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
1243        pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
1244        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
1245        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
1246        pw.println("  mUseSoftwareAutoBrightnessConfig="
1247                + mUseSoftwareAutoBrightnessConfig);
1248        pw.println("  mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline);
1249        pw.println("  mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
1250
1251        mHandler.runWithScissors(new Runnable() {
1252            @Override
1253            public void run() {
1254                dumpLocal(pw);
1255            }
1256        }, 1000);
1257    }
1258
1259    private void dumpLocal(PrintWriter pw) {
1260        pw.println();
1261        pw.println("Display Power Controller Thread State:");
1262        pw.println("  mPowerRequest=" + mPowerRequest);
1263        pw.println("  mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
1264
1265        pw.println("  mProximitySensor=" + mProximitySensor);
1266        pw.println("  mProximitySensorEnabled=" + mProximitySensorEnabled);
1267        pw.println("  mProximityThreshold=" + mProximityThreshold);
1268        pw.println("  mProximity=" + proximityToString(mProximity));
1269        pw.println("  mPendingProximity=" + proximityToString(mPendingProximity));
1270        pw.println("  mPendingProximityDebounceTime="
1271                + TimeUtils.formatUptime(mPendingProximityDebounceTime));
1272        pw.println("  mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
1273
1274        pw.println("  mLightSensor=" + mLightSensor);
1275        pw.println("  mLightSensorEnabled=" + mLightSensorEnabled);
1276        pw.println("  mLightSensorEnableTime="
1277                + TimeUtils.formatUptime(mLightSensorEnableTime));
1278        pw.println("  mAmbientLux=" + mAmbientLux);
1279        pw.println("  mAmbientLuxValid=" + mAmbientLuxValid);
1280        pw.println("  mLastObservedLux=" + mLastObservedLux);
1281        pw.println("  mLastObservedLuxTime="
1282                + TimeUtils.formatUptime(mLastObservedLuxTime));
1283        pw.println("  mRecentLightSamples=" + mRecentLightSamples);
1284        pw.println("  mRecentShortTermAverageLux=" + mRecentShortTermAverageLux);
1285        pw.println("  mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
1286        pw.println("  mDebounceLuxDirection=" + mDebounceLuxDirection);
1287        pw.println("  mDebounceLuxTime=" + TimeUtils.formatUptime(mDebounceLuxTime));
1288        pw.println("  mScreenAutoBrightness=" + mScreenAutoBrightness);
1289        pw.println("  mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
1290        pw.println("  mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
1291        pw.println("  mTwilight.getCurrentState()=" + mTwilight.getCurrentState());
1292
1293        if (mElectronBeamOnAnimator != null) {
1294            pw.println("  mElectronBeamOnAnimator.isStarted()=" +
1295                    mElectronBeamOnAnimator.isStarted());
1296        }
1297        if (mElectronBeamOffAnimator != null) {
1298            pw.println("  mElectronBeamOffAnimator.isStarted()=" +
1299                    mElectronBeamOffAnimator.isStarted());
1300        }
1301
1302        if (mPowerState != null) {
1303            mPowerState.dump(pw);
1304        }
1305    }
1306
1307    private static String proximityToString(int state) {
1308        switch (state) {
1309            case PROXIMITY_UNKNOWN:
1310                return "Unknown";
1311            case PROXIMITY_NEGATIVE:
1312                return "Negative";
1313            case PROXIMITY_POSITIVE:
1314                return "Positive";
1315            default:
1316                return Integer.toString(state);
1317        }
1318    }
1319
1320    private final class DisplayControllerHandler extends Handler {
1321        public DisplayControllerHandler(Looper looper) {
1322            super(looper, null, true /*async*/);
1323        }
1324
1325        @Override
1326        public void handleMessage(Message msg) {
1327            switch (msg.what) {
1328                case MSG_UPDATE_POWER_STATE:
1329                    updatePowerState();
1330                    break;
1331
1332                case MSG_PROXIMITY_SENSOR_DEBOUNCED:
1333                    debounceProximitySensor();
1334                    break;
1335
1336                case MSG_LIGHT_SENSOR_DEBOUNCED:
1337                    debounceLightSensor();
1338                    break;
1339            }
1340        }
1341    }
1342
1343    private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
1344        @Override
1345        public void onSensorChanged(SensorEvent event) {
1346            if (mProximitySensorEnabled) {
1347                final long time = SystemClock.uptimeMillis();
1348                final float distance = event.values[0];
1349                boolean positive = distance >= 0.0f && distance < mProximityThreshold;
1350                handleProximitySensorEvent(time, positive);
1351            }
1352        }
1353
1354        @Override
1355        public void onAccuracyChanged(Sensor sensor, int accuracy) {
1356            // Not used.
1357        }
1358    };
1359
1360    private final SensorEventListener mLightSensorListener = new SensorEventListener() {
1361        @Override
1362        public void onSensorChanged(SensorEvent event) {
1363            if (mLightSensorEnabled) {
1364                final long time = SystemClock.uptimeMillis();
1365                final float lux = event.values[0];
1366                handleLightSensorEvent(time, lux);
1367            }
1368        }
1369
1370        @Override
1371        public void onAccuracyChanged(Sensor sensor, int accuracy) {
1372            // Not used.
1373        }
1374    };
1375
1376    private final TwilightListener mTwilightListener = new TwilightListener() {
1377        @Override
1378        public void onTwilightStateChanged() {
1379            mTwilightChanged = true;
1380            updatePowerState();
1381        }
1382    };
1383}
1384