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