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