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