DisplayPowerController.java revision 3c584f20ac8fe9378c094ad3b63936bca35954ba
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 = 400;
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    // 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 average light sensor value.
288    private float mLightMeasurement;
289
290    // True if the light sensor measurement is valid.
291    private boolean mLightMeasurementValid;
292
293    // The number of light sensor samples that have been collected since the
294    // last time a light sensor reading was accepted.
295    private int mRecentLightSamples;
296
297    // The moving average of recent light sensor values.
298    private float mRecentLightAverage;
299
300    // True if recent light samples are getting brighter than the previous
301    // stable light measurement.
302    private boolean mRecentLightBrightening;
303
304    // The time constant to use for filtering based on whether the
305    // light appears to be brightening or dimming.
306    private long mRecentLightTimeConstant;
307
308    // The most recent light sample.
309    private float mLastLightSample;
310
311    // The time of the most light recent sample.
312    private long mLastLightSampleTime;
313
314    // The time when we accumulated the first recent light sample into mRecentLightSamples.
315    private long mFirstRecentLightSampleTime;
316
317    // The upcoming debounce light sensor time.
318    // This is only valid when mLightMeasurementValue && mRecentLightSamples >= 1.
319    private long mPendingLightSensorDebounceTime;
320
321    // The screen brightness level that has been chosen by the auto-brightness
322    // algorithm.  The actual brightness should ramp towards this value.
323    // We preserve this value even when we stop using the light sensor so
324    // that we can quickly revert to the previous auto-brightness level
325    // while the light sensor warms up.
326    // Use -1 if there is no current auto-brightness value available.
327    private int mScreenAutoBrightness = -1;
328
329    // The last screen auto-brightness gamma.  (For printing in dump() only.)
330    private float mLastScreenAutoBrightnessGamma = 1.0f;
331
332    // True if the screen auto-brightness value is actually being used to
333    // set the display brightness.
334    private boolean mUsingScreenAutoBrightness;
335
336    // Animators.
337    private ObjectAnimator mElectronBeamOnAnimator;
338    private ObjectAnimator mElectronBeamOffAnimator;
339    private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
340
341    // Twilight changed.  We might recalculate auto-brightness values.
342    private boolean mTwilightChanged;
343
344    /**
345     * Creates the display power controller.
346     */
347    public DisplayPowerController(Looper looper, Context context, Notifier notifier,
348            LightsService lights, TwilightService twilight, SuspendBlocker suspendBlocker,
349            DisplayBlanker displayBlanker,
350            Callbacks callbacks, Handler callbackHandler) {
351        mHandler = new DisplayControllerHandler(looper);
352        mNotifier = notifier;
353        mSuspendBlocker = suspendBlocker;
354        mDisplayBlanker = displayBlanker;
355        mCallbacks = callbacks;
356        mCallbackHandler = callbackHandler;
357
358        mLights = lights;
359        mTwilight = twilight;
360        mSensorManager = new SystemSensorManager(mHandler.getLooper());
361        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
362
363        final Resources resources = context.getResources();
364
365        mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
366                com.android.internal.R.integer.config_screenBrightnessDim));
367
368        int screenBrightnessMinimum = Math.min(resources.getInteger(
369                com.android.internal.R.integer.config_screenBrightnessSettingMinimum),
370                mScreenBrightnessDimConfig);
371
372        mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
373                com.android.internal.R.bool.config_automatic_brightness_available);
374        if (mUseSoftwareAutoBrightnessConfig) {
375            int[] lux = resources.getIntArray(
376                    com.android.internal.R.array.config_autoBrightnessLevels);
377            int[] screenBrightness = resources.getIntArray(
378                    com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
379
380            mScreenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
381            if (mScreenAutoBrightnessSpline == null) {
382                Slog.e(TAG, "Error in config.xml.  config_autoBrightnessLcdBacklightValues "
383                        + "(size " + screenBrightness.length + ") "
384                        + "must be monotic and have exactly one more entry than "
385                        + "config_autoBrightnessLevels (size " + lux.length + ") "
386                        + "which must be strictly increasing.  "
387                        + "Auto-brightness will be disabled.");
388                mUseSoftwareAutoBrightnessConfig = false;
389            } else {
390                if (screenBrightness[0] < screenBrightnessMinimum) {
391                    screenBrightnessMinimum = screenBrightness[0];
392                }
393            }
394
395            mLightSensorWarmUpTimeConfig = resources.getInteger(
396                    com.android.internal.R.integer.config_lightSensorWarmupTime);
397        }
398
399        mScreenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightnessMinimum);
400        mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
401
402        mElectronBeamFadesConfig = resources.getBoolean(
403                com.android.internal.R.bool.config_animateScreenLights);
404
405        if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
406            mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
407            if (mProximitySensor != null) {
408                mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
409                        TYPICAL_PROXIMITY_THRESHOLD);
410            }
411        }
412
413        if (mUseSoftwareAutoBrightnessConfig
414                && !DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
415            mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
416        }
417
418        if (mUseSoftwareAutoBrightnessConfig && USE_TWILIGHT_ADJUSTMENT) {
419            mTwilight.registerListener(mTwilightListener, mHandler);
420        }
421    }
422
423    private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
424        try {
425            final int n = brightness.length;
426            float[] x = new float[n];
427            float[] y = new float[n];
428            y[0] = normalizeAbsoluteBrightness(brightness[0]);
429            for (int i = 1; i < n; i++) {
430                x[i] = lux[i - 1];
431                y[i] = normalizeAbsoluteBrightness(brightness[i]);
432            }
433
434            Spline spline = Spline.createMonotoneCubicSpline(x, y);
435            if (DEBUG) {
436                Slog.d(TAG, "Auto-brightness spline: " + spline);
437                for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
438                    Slog.d(TAG, String.format("  %7.1f: %7.1f", v, spline.interpolate(v)));
439                }
440            }
441            return spline;
442        } catch (IllegalArgumentException ex) {
443            Slog.e(TAG, "Could not create auto-brightness spline.", ex);
444            return null;
445        }
446    }
447
448    /**
449     * Returns true if the proximity sensor screen-off function is available.
450     */
451    public boolean isProximitySensorAvailable() {
452        return mProximitySensor != null;
453    }
454
455    /**
456     * Requests a new power state.
457     * The controller makes a copy of the provided object and then
458     * begins adjusting the power state to match what was requested.
459     *
460     * @param request The requested power state.
461     * @param waitForNegativeProximity If true, issues a request to wait for
462     * negative proximity before turning the screen back on, assuming the screen
463     * was turned off by the proximity sensor.
464     * @return True if display is ready, false if there are important changes that must
465     * be made asynchronously (such as turning the screen on), in which case the caller
466     * should grab a wake lock, watch for {@link Callbacks#onStateChanged()} then try
467     * the request again later until the state converges.
468     */
469    public boolean requestPowerState(DisplayPowerRequest request,
470            boolean waitForNegativeProximity) {
471        if (DEBUG) {
472            Slog.d(TAG, "requestPowerState: "
473                    + request + ", waitForNegativeProximity=" + waitForNegativeProximity);
474        }
475
476        synchronized (mLock) {
477            boolean changed = false;
478
479            if (waitForNegativeProximity
480                    && !mPendingWaitForNegativeProximityLocked) {
481                mPendingWaitForNegativeProximityLocked = true;
482                changed = true;
483            }
484
485            if (mPendingRequestLocked == null) {
486                mPendingRequestLocked = new DisplayPowerRequest(request);
487                changed = true;
488            } else if (!mPendingRequestLocked.equals(request)) {
489                mPendingRequestLocked.copyFrom(request);
490                changed = true;
491            }
492
493            if (changed) {
494                mDisplayReadyLocked = false;
495            }
496
497            if (changed && !mPendingRequestChangedLocked) {
498                mPendingRequestChangedLocked = true;
499                sendUpdatePowerStateLocked();
500            }
501
502            return mDisplayReadyLocked;
503        }
504    }
505
506    private void sendUpdatePowerState() {
507        synchronized (mLock) {
508            sendUpdatePowerStateLocked();
509        }
510    }
511
512    private void sendUpdatePowerStateLocked() {
513        if (!mPendingUpdatePowerStateLocked) {
514            mPendingUpdatePowerStateLocked = true;
515            Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
516            msg.setAsynchronous(true);
517            mHandler.sendMessage(msg);
518        }
519    }
520
521    private void initialize() {
522        final Executor executor = AsyncTask.THREAD_POOL_EXECUTOR;
523        Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
524        mPowerState = new DisplayPowerState(
525                new ElectronBeam(display),
526                new PhotonicModulator(executor,
527                        mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT),
528                        mSuspendBlocker),
529                mDisplayBlanker);
530
531        mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
532                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
533        mElectronBeamOnAnimator.setDuration(ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS);
534        mElectronBeamOnAnimator.addListener(mAnimatorListener);
535
536        mElectronBeamOffAnimator = ObjectAnimator.ofFloat(
537                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 1.0f, 0.0f);
538        mElectronBeamOffAnimator.setDuration(ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS);
539        mElectronBeamOffAnimator.addListener(mAnimatorListener);
540
541        mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
542                mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
543    }
544
545    private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
546        @Override
547        public void onAnimationStart(Animator animation) {
548        }
549        @Override
550        public void onAnimationEnd(Animator animation) {
551            sendUpdatePowerState();
552        }
553        @Override
554        public void onAnimationRepeat(Animator animation) {
555        }
556        @Override
557        public void onAnimationCancel(Animator animation) {
558        }
559    };
560
561    private void updatePowerState() {
562        // Update the power state request.
563        final boolean mustNotify;
564        boolean mustInitialize = false;
565        boolean updateAutoBrightness = mTwilightChanged;
566        mTwilightChanged = false;
567
568        synchronized (mLock) {
569            mPendingUpdatePowerStateLocked = false;
570            if (mPendingRequestLocked == null) {
571                return; // wait until first actual power request
572            }
573
574            if (mPowerRequest == null) {
575                mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
576                mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
577                mPendingWaitForNegativeProximityLocked = false;
578                mPendingRequestChangedLocked = false;
579                mustInitialize = true;
580            } else if (mPendingRequestChangedLocked) {
581                if (mPowerRequest.screenAutoBrightnessAdjustment
582                        != mPendingRequestLocked.screenAutoBrightnessAdjustment) {
583                    updateAutoBrightness = true;
584                }
585                mPowerRequest.copyFrom(mPendingRequestLocked);
586                mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
587                mPendingWaitForNegativeProximityLocked = false;
588                mPendingRequestChangedLocked = false;
589                mDisplayReadyLocked = false;
590            }
591
592            mustNotify = !mDisplayReadyLocked;
593        }
594
595        // Initialize things the first time the power state is changed.
596        if (mustInitialize) {
597            initialize();
598        }
599
600        // Apply the proximity sensor.
601        if (mProximitySensor != null) {
602            if (mPowerRequest.useProximitySensor
603                    && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
604                setProximitySensorEnabled(true);
605                if (!mScreenOffBecauseOfProximity
606                        && mProximity == PROXIMITY_POSITIVE) {
607                    mScreenOffBecauseOfProximity = true;
608                    sendOnProximityPositive();
609                    setScreenOn(false);
610                }
611            } else if (mWaitingForNegativeProximity
612                    && mScreenOffBecauseOfProximity
613                    && mProximity == PROXIMITY_POSITIVE
614                    && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
615                setProximitySensorEnabled(true);
616            } else {
617                setProximitySensorEnabled(false);
618                mWaitingForNegativeProximity = false;
619            }
620            if (mScreenOffBecauseOfProximity
621                    && mProximity != PROXIMITY_POSITIVE) {
622                mScreenOffBecauseOfProximity = false;
623                sendOnProximityNegative();
624            }
625        } else {
626            mWaitingForNegativeProximity = false;
627        }
628
629        // Turn on the light sensor if needed.
630        if (mLightSensor != null) {
631            setLightSensorEnabled(mPowerRequest.useAutoBrightness
632                    && wantScreenOn(mPowerRequest.screenState), updateAutoBrightness);
633        }
634
635        // Set the screen brightness.
636        if (wantScreenOn(mPowerRequest.screenState)) {
637            int target;
638            boolean slow;
639            if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) {
640                // Use current auto-brightness value.
641                target = mScreenAutoBrightness;
642                slow = mUsingScreenAutoBrightness;
643                mUsingScreenAutoBrightness = true;
644            } else {
645                // Light sensor is disabled or not ready yet.
646                // Use the current brightness setting from the request, which is expected
647                // provide a nominal default value for the case where auto-brightness
648                // is not ready yet.
649                target = mPowerRequest.screenBrightness;
650                slow = false;
651                mUsingScreenAutoBrightness = false;
652            }
653            if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
654                // Screen is dimmed.  Sets an upper bound on everything else.
655                target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
656                        mScreenBrightnessDimConfig);
657                slow = false;
658            }
659            animateScreenBrightness(clampScreenBrightness(target),
660                    slow ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
661        } else {
662            // Screen is off.  Don't bother changing the brightness.
663            mUsingScreenAutoBrightness = false;
664        }
665
666        // Animate the screen on or off.
667        if (!mScreenOffBecauseOfProximity) {
668            if (wantScreenOn(mPowerRequest.screenState)) {
669                // Want screen on.
670                // Wait for previous off animation to complete beforehand.
671                // It is relatively short but if we cancel it and switch to the
672                // on animation immediately then the results are pretty ugly.
673                if (!mElectronBeamOffAnimator.isStarted()) {
674                    // Turn the screen on.  The contents of the screen may not yet
675                    // be visible if the electron beam has not been dismissed because
676                    // its last frame of animation is solid black.
677                    setScreenOn(true);
678
679                    if (mPowerRequest.blockScreenOn
680                            && mPowerState.getElectronBeamLevel() == 0.0f) {
681                        blockScreenOn();
682                    } else {
683                        unblockScreenOn();
684                        if (USE_ELECTRON_BEAM_ON_ANIMATION) {
685                            if (!mElectronBeamOnAnimator.isStarted()) {
686                                if (mPowerState.getElectronBeamLevel() == 1.0f) {
687                                    mPowerState.dismissElectronBeam();
688                                } else if (mPowerState.prepareElectronBeam(
689                                        mElectronBeamFadesConfig ?
690                                                ElectronBeam.MODE_FADE :
691                                                        ElectronBeam.MODE_WARM_UP)) {
692                                    mElectronBeamOnAnimator.start();
693                                } else {
694                                    mElectronBeamOnAnimator.end();
695                                }
696                            }
697                        } else {
698                            mPowerState.setElectronBeamLevel(1.0f);
699                            mPowerState.dismissElectronBeam();
700                        }
701                    }
702                }
703            } else {
704                // Want screen off.
705                // Wait for previous on animation to complete beforehand.
706                if (!mElectronBeamOnAnimator.isStarted()) {
707                    if (!mElectronBeamOffAnimator.isStarted()) {
708                        if (mPowerState.getElectronBeamLevel() == 0.0f) {
709                            setScreenOn(false);
710                        } else if (mPowerState.prepareElectronBeam(
711                                mElectronBeamFadesConfig ?
712                                        ElectronBeam.MODE_FADE :
713                                                ElectronBeam.MODE_COOL_DOWN)
714                                && mPowerState.isScreenOn()) {
715                            mElectronBeamOffAnimator.start();
716                        } else {
717                            mElectronBeamOffAnimator.end();
718                        }
719                    }
720                }
721            }
722        }
723
724        // Report whether the display is ready for use.
725        // We mostly care about the screen state here, ignoring brightness changes
726        // which will be handled asynchronously.
727        if (mustNotify
728                && !mScreenOnWasBlocked
729                && !mElectronBeamOnAnimator.isStarted()
730                && !mElectronBeamOffAnimator.isStarted()
731                && mPowerState.waitUntilClean(mCleanListener)) {
732            synchronized (mLock) {
733                if (!mPendingRequestChangedLocked) {
734                    mDisplayReadyLocked = true;
735
736                    if (DEBUG) {
737                        Slog.d(TAG, "Display ready!");
738                    }
739                }
740            }
741            sendOnStateChanged();
742        }
743    }
744
745    private void blockScreenOn() {
746        if (!mScreenOnWasBlocked) {
747            mScreenOnWasBlocked = true;
748            if (DEBUG) {
749                Slog.d(TAG, "Blocked screen on.");
750                mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
751            }
752        }
753    }
754
755    private void unblockScreenOn() {
756        if (mScreenOnWasBlocked) {
757            mScreenOnWasBlocked = false;
758            if (DEBUG) {
759                Slog.d(TAG, "Unblocked screen on after " +
760                        (SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime) + " ms");
761            }
762        }
763    }
764
765    private void setScreenOn(boolean on) {
766        if (!mPowerState.isScreenOn() == on) {
767            mPowerState.setScreenOn(on);
768            if (on) {
769                mNotifier.onScreenOn();
770            } else {
771                mNotifier.onScreenOff();
772            }
773        }
774    }
775
776    private int clampScreenBrightness(int value) {
777        return clamp(value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
778    }
779
780    private static int clampAbsoluteBrightness(int value) {
781        return clamp(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
782    }
783
784    private static int clamp(int value, int min, int max) {
785        if (value <= min) {
786            return min;
787        }
788        if (value >= max) {
789            return max;
790        }
791        return value;
792    }
793
794    private static float normalizeAbsoluteBrightness(int value) {
795        return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
796    }
797
798    private void animateScreenBrightness(int target, int rate) {
799        if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
800            mNotifier.onScreenBrightness(target);
801        }
802    }
803
804    private final Runnable mCleanListener = new Runnable() {
805        @Override
806        public void run() {
807            sendUpdatePowerState();
808        }
809    };
810
811    private void setProximitySensorEnabled(boolean enable) {
812        if (enable) {
813            if (!mProximitySensorEnabled) {
814                mProximitySensorEnabled = true;
815                mPendingProximity = PROXIMITY_UNKNOWN;
816                mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
817                        SensorManager.SENSOR_DELAY_NORMAL, mHandler);
818            }
819        } else {
820            if (mProximitySensorEnabled) {
821                mProximitySensorEnabled = false;
822                mProximity = PROXIMITY_UNKNOWN;
823                mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
824                mSensorManager.unregisterListener(mProximitySensorListener);
825            }
826        }
827    }
828
829    private void handleProximitySensorEvent(long time, boolean positive) {
830        if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
831            return; // no change
832        }
833        if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
834            return; // no change
835        }
836
837        // Only accept a proximity sensor reading if it remains
838        // stable for the entire debounce delay.
839        mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
840        if (positive) {
841            mPendingProximity = PROXIMITY_POSITIVE;
842            mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY;
843        } else {
844            mPendingProximity = PROXIMITY_NEGATIVE;
845            mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY;
846        }
847        debounceProximitySensor();
848    }
849
850    private void debounceProximitySensor() {
851        if (mPendingProximity != PROXIMITY_UNKNOWN) {
852            final long now = SystemClock.uptimeMillis();
853            if (mPendingProximityDebounceTime <= now) {
854                mProximity = mPendingProximity;
855                sendUpdatePowerState();
856            } else {
857                Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
858                msg.setAsynchronous(true);
859                mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
860            }
861        }
862    }
863
864    private void setLightSensorEnabled(boolean enable, boolean updateAutoBrightness) {
865        if (enable) {
866            if (!mLightSensorEnabled) {
867                updateAutoBrightness = true;
868                mLightSensorEnabled = true;
869                mLightSensorEnableTime = SystemClock.uptimeMillis();
870                mSensorManager.registerListener(mLightSensorListener, mLightSensor,
871                        LIGHT_SENSOR_RATE, mHandler);
872            }
873        } else {
874            if (mLightSensorEnabled) {
875                mLightSensorEnabled = false;
876                mLightMeasurementValid = false;
877                mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
878                mSensorManager.unregisterListener(mLightSensorListener);
879            }
880        }
881        if (updateAutoBrightness) {
882            updateAutoBrightness(false);
883        }
884    }
885
886    private void handleLightSensorEvent(long time, float lux) {
887        // Take the first few readings during the warm-up period and apply them
888        // immediately without debouncing.
889        if (!mLightMeasurementValid
890                || (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) {
891            mLightMeasurement = lux;
892            mLightMeasurementValid = true;
893            mRecentLightSamples = 0;
894            updateAutoBrightness(true);
895        }
896
897        // Update our moving average.
898        if (lux != mLightMeasurement && (mRecentLightSamples == 0
899                || (lux < mLightMeasurement && mRecentLightBrightening)
900                || (lux > mLightMeasurement && !mRecentLightBrightening))) {
901            // If the newest light sample doesn't seem to be going in the
902            // same general direction as recent samples, then start over.
903            setRecentLight(time, lux, lux > mLightMeasurement);
904        } else if (mRecentLightSamples >= 1) {
905            // Add the newest light sample to the moving average.
906            accumulateRecentLight(time, lux);
907        }
908        if (DEBUG) {
909            Slog.d(TAG, "handleLightSensorEvent: lux=" + lux
910                    + ", mLightMeasurementValid=" + mLightMeasurementValid
911                    + ", mLightMeasurement=" + mLightMeasurement
912                    + ", mRecentLightSamples=" + mRecentLightSamples
913                    + ", mRecentLightAverage=" + mRecentLightAverage
914                    + ", mRecentLightBrightening=" + mRecentLightBrightening
915                    + ", mRecentLightTimeConstant=" + mRecentLightTimeConstant
916                    + ", mFirstRecentLightSampleTime="
917                            + TimeUtils.formatUptime(mFirstRecentLightSampleTime)
918                    + ", mPendingLightSensorDebounceTime="
919                            + TimeUtils.formatUptime(mPendingLightSensorDebounceTime));
920        }
921
922        // Debounce.
923        mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
924        debounceLightSensor();
925    }
926
927    private void setRecentLight(long time, float lux, boolean brightening) {
928        mRecentLightBrightening = brightening;
929        mRecentLightTimeConstant = brightening ?
930                BRIGHTENING_LIGHT_TIME_CONSTANT : DIMMING_LIGHT_TIME_CONSTANT;
931        mRecentLightSamples = 1;
932        mRecentLightAverage = lux;
933        mLastLightSample = lux;
934        mLastLightSampleTime = time;
935        mFirstRecentLightSampleTime = time;
936        mPendingLightSensorDebounceTime = time + (brightening ?
937                BRIGHTENING_LIGHT_DEBOUNCE : DIMMING_LIGHT_DEBOUNCE);
938    }
939
940    private void accumulateRecentLight(long time, float lux) {
941        final long timeDelta = time - mLastLightSampleTime;
942        mRecentLightSamples += 1;
943        mRecentLightAverage += (lux - mRecentLightAverage) *
944                timeDelta / (mRecentLightTimeConstant + timeDelta);
945        mLastLightSample = lux;
946        mLastLightSampleTime = time;
947    }
948
949    private void debounceLightSensor() {
950        if (mLightMeasurementValid && mRecentLightSamples >= 1) {
951            final long now = SystemClock.uptimeMillis();
952            if (mPendingLightSensorDebounceTime <= now) {
953                accumulateRecentLight(now, mLastLightSample);
954                mLightMeasurement = mRecentLightAverage;
955
956                if (DEBUG) {
957                    Slog.d(TAG, "debounceLightSensor: Accepted new measurement "
958                            + mLightMeasurement + " after "
959                            + (now - mFirstRecentLightSampleTime) + " ms based on "
960                            + mRecentLightSamples + " recent samples.");
961                }
962
963                updateAutoBrightness(true);
964
965                // Now that we have debounced the light sensor data, we have the
966                // option of either leaving the sensor in a debounced state or
967                // restarting the debounce cycle by setting mRecentLightSamples to 0.
968                //
969                // If we leave the sensor debounced, then new average light measurements
970                // may be accepted immediately as long as they are trending in the same
971                // direction as they were before.  If the measurements start
972                // jittering or trending in the opposite direction then the debounce
973                // cycle will automatically be restarted.  The benefit is that the
974                // auto-brightness control can be more responsive to changes over a
975                // broad range.
976                //
977                // For now, we choose to be more responsive and leave the following line
978                // commented out.
979                //
980                // mRecentLightSamples = 0;
981            } else {
982                Message msg = mHandler.obtainMessage(MSG_LIGHT_SENSOR_DEBOUNCED);
983                msg.setAsynchronous(true);
984                mHandler.sendMessageAtTime(msg, mPendingLightSensorDebounceTime);
985            }
986        }
987    }
988
989    private void updateAutoBrightness(boolean sendUpdate) {
990        if (!mLightMeasurementValid) {
991            return;
992        }
993
994        float value = mScreenAutoBrightnessSpline.interpolate(mLightMeasurement);
995        float gamma = 1.0f;
996
997        if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
998                && mPowerRequest.screenAutoBrightnessAdjustment != 0.0f) {
999            final float adjGamma = FloatMath.pow(SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA,
1000                    Math.min(1.0f, Math.max(-1.0f,
1001                            -mPowerRequest.screenAutoBrightnessAdjustment)));
1002            gamma *= adjGamma;
1003            if (DEBUG) {
1004                Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma);
1005            }
1006        }
1007
1008        if (USE_TWILIGHT_ADJUSTMENT) {
1009            TwilightState state = mTwilight.getCurrentState();
1010            if (state != null && state.isNight()) {
1011                final long now = System.currentTimeMillis();
1012                final float earlyGamma =
1013                        getTwilightGamma(now, state.getYesterdaySunset(), state.getTodaySunrise());
1014                final float lateGamma =
1015                        getTwilightGamma(now, state.getTodaySunset(), state.getTomorrowSunrise());
1016                gamma *= earlyGamma * lateGamma;
1017                if (DEBUG) {
1018                    Slog.d(TAG, "updateAutoBrightness: earlyGamma=" + earlyGamma
1019                            + ", lateGamma=" + lateGamma);
1020                }
1021            }
1022        }
1023
1024        if (gamma != 1.0f) {
1025            final float in = value;
1026            value = FloatMath.pow(value, gamma);
1027            if (DEBUG) {
1028                Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma
1029                        + ", in=" + in + ", out=" + value);
1030            }
1031        }
1032
1033        int newScreenAutoBrightness = clampScreenBrightness(
1034                (int)Math.round(value * PowerManager.BRIGHTNESS_ON));
1035        if (mScreenAutoBrightness != newScreenAutoBrightness) {
1036            if (DEBUG) {
1037                Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
1038                        + mScreenAutoBrightness + ", newScreenAutoBrightness="
1039                        + newScreenAutoBrightness);
1040            }
1041
1042            mScreenAutoBrightness = newScreenAutoBrightness;
1043            mLastScreenAutoBrightnessGamma = gamma;
1044            if (sendUpdate) {
1045                sendUpdatePowerState();
1046            }
1047        }
1048    }
1049
1050    private static float getTwilightGamma(long now, long lastSunset, long nextSunrise) {
1051        if (lastSunset < 0 || nextSunrise < 0
1052                || now < lastSunset || now > nextSunrise) {
1053            return 1.0f;
1054        }
1055
1056        if (now < lastSunset + TWILIGHT_ADJUSTMENT_TIME) {
1057            return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
1058                    (float)(now - lastSunset) / TWILIGHT_ADJUSTMENT_TIME);
1059        }
1060
1061        if (now > nextSunrise - TWILIGHT_ADJUSTMENT_TIME) {
1062            return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
1063                    (float)(nextSunrise - now) / TWILIGHT_ADJUSTMENT_TIME);
1064        }
1065
1066        return TWILIGHT_ADJUSTMENT_MAX_GAMMA;
1067    }
1068
1069    private static float lerp(float x, float y, float alpha) {
1070        return x + (y - x) * alpha;
1071    }
1072
1073    private void sendOnStateChanged() {
1074        mCallbackHandler.post(mOnStateChangedRunnable);
1075    }
1076
1077    private final Runnable mOnStateChangedRunnable = new Runnable() {
1078        @Override
1079        public void run() {
1080            mCallbacks.onStateChanged();
1081        }
1082    };
1083
1084    private void sendOnProximityPositive() {
1085        mCallbackHandler.post(mOnProximityPositiveRunnable);
1086    }
1087
1088    private final Runnable mOnProximityPositiveRunnable = new Runnable() {
1089        @Override
1090        public void run() {
1091            mCallbacks.onProximityPositive();
1092        }
1093    };
1094
1095    private void sendOnProximityNegative() {
1096        mCallbackHandler.post(mOnProximityNegativeRunnable);
1097    }
1098
1099    private final Runnable mOnProximityNegativeRunnable = new Runnable() {
1100        @Override
1101        public void run() {
1102            mCallbacks.onProximityNegative();
1103        }
1104    };
1105
1106    public void dump(final PrintWriter pw) {
1107        synchronized (mLock) {
1108            pw.println();
1109            pw.println("Display Controller Locked State:");
1110            pw.println("  mDisplayReadyLocked=" + mDisplayReadyLocked);
1111            pw.println("  mPendingRequestLocked=" + mPendingRequestLocked);
1112            pw.println("  mPendingRequestChangedLocked=" + mPendingRequestChangedLocked);
1113            pw.println("  mPendingWaitForNegativeProximityLocked="
1114                    + mPendingWaitForNegativeProximityLocked);
1115            pw.println("  mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked);
1116        }
1117
1118        pw.println();
1119        pw.println("Display Controller Configuration:");
1120        pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
1121        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
1122        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
1123        pw.println("  mUseSoftwareAutoBrightnessConfig="
1124                + mUseSoftwareAutoBrightnessConfig);
1125        pw.println("  mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline);
1126        pw.println("  mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
1127
1128        mHandler.runWithScissors(new Runnable() {
1129            @Override
1130            public void run() {
1131                dumpLocal(pw);
1132            }
1133        }, 1000);
1134    }
1135
1136    private void dumpLocal(PrintWriter pw) {
1137        pw.println();
1138        pw.println("Display Controller Thread State:");
1139        pw.println("  mPowerRequest=" + mPowerRequest);
1140        pw.println("  mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
1141
1142        pw.println("  mProximitySensor=" + mProximitySensor);
1143        pw.println("  mProximitySensorEnabled=" + mProximitySensorEnabled);
1144        pw.println("  mProximityThreshold=" + mProximityThreshold);
1145        pw.println("  mProximity=" + proximityToString(mProximity));
1146        pw.println("  mPendingProximity=" + proximityToString(mPendingProximity));
1147        pw.println("  mPendingProximityDebounceTime="
1148                + TimeUtils.formatUptime(mPendingProximityDebounceTime));
1149        pw.println("  mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
1150
1151        pw.println("  mLightSensor=" + mLightSensor);
1152        pw.println("  mLightSensorEnabled=" + mLightSensorEnabled);
1153        pw.println("  mLightSensorEnableTime="
1154                + TimeUtils.formatUptime(mLightSensorEnableTime));
1155        pw.println("  mLightMeasurement=" + mLightMeasurement);
1156        pw.println("  mLightMeasurementValid=" + mLightMeasurementValid);
1157        pw.println("  mLastLightSample=" + mLastLightSample);
1158        pw.println("  mLastLightSampleTime="
1159                + TimeUtils.formatUptime(mLastLightSampleTime));
1160        pw.println("  mRecentLightSamples=" + mRecentLightSamples);
1161        pw.println("  mRecentLightAverage=" + mRecentLightAverage);
1162        pw.println("  mRecentLightBrightening=" + mRecentLightBrightening);
1163        pw.println("  mRecentLightTimeConstant=" + mRecentLightTimeConstant);
1164        pw.println("  mFirstRecentLightSampleTime="
1165                + TimeUtils.formatUptime(mFirstRecentLightSampleTime));
1166        pw.println("  mPendingLightSensorDebounceTime="
1167                + TimeUtils.formatUptime(mPendingLightSensorDebounceTime));
1168        pw.println("  mScreenAutoBrightness=" + mScreenAutoBrightness);
1169        pw.println("  mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
1170        pw.println("  mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
1171        pw.println("  mTwilight.getCurrentState()=" + mTwilight.getCurrentState());
1172
1173        if (mElectronBeamOnAnimator != null) {
1174            pw.println("  mElectronBeamOnAnimator.isStarted()=" +
1175                    mElectronBeamOnAnimator.isStarted());
1176        }
1177        if (mElectronBeamOffAnimator != null) {
1178            pw.println("  mElectronBeamOffAnimator.isStarted()=" +
1179                    mElectronBeamOffAnimator.isStarted());
1180        }
1181
1182        if (mPowerState != null) {
1183            mPowerState.dump(pw);
1184        }
1185    }
1186
1187    private static String proximityToString(int state) {
1188        switch (state) {
1189            case PROXIMITY_UNKNOWN:
1190                return "Unknown";
1191            case PROXIMITY_NEGATIVE:
1192                return "Negative";
1193            case PROXIMITY_POSITIVE:
1194                return "Positive";
1195            default:
1196                return Integer.toString(state);
1197        }
1198    }
1199
1200    private static boolean wantScreenOn(int state) {
1201        switch (state) {
1202            case DisplayPowerRequest.SCREEN_STATE_BRIGHT:
1203            case DisplayPowerRequest.SCREEN_STATE_DIM:
1204                return true;
1205        }
1206        return false;
1207    }
1208
1209    /**
1210     * Asynchronous callbacks from the power controller to the power manager service.
1211     */
1212    public interface Callbacks {
1213        void onStateChanged();
1214        void onProximityPositive();
1215        void onProximityNegative();
1216    }
1217
1218    private final class DisplayControllerHandler extends Handler {
1219        public DisplayControllerHandler(Looper looper) {
1220            super(looper, null, true /*async*/);
1221        }
1222
1223        @Override
1224        public void handleMessage(Message msg) {
1225            switch (msg.what) {
1226                case MSG_UPDATE_POWER_STATE:
1227                    updatePowerState();
1228                    break;
1229
1230                case MSG_PROXIMITY_SENSOR_DEBOUNCED:
1231                    debounceProximitySensor();
1232                    break;
1233
1234                case MSG_LIGHT_SENSOR_DEBOUNCED:
1235                    debounceLightSensor();
1236                    break;
1237            }
1238        }
1239    }
1240
1241    private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
1242        @Override
1243        public void onSensorChanged(SensorEvent event) {
1244            if (mProximitySensorEnabled) {
1245                final long time = SystemClock.uptimeMillis();
1246                final float distance = event.values[0];
1247                boolean positive = distance >= 0.0f && distance < mProximityThreshold;
1248                handleProximitySensorEvent(time, positive);
1249            }
1250        }
1251
1252        @Override
1253        public void onAccuracyChanged(Sensor sensor, int accuracy) {
1254            // Not used.
1255        }
1256    };
1257
1258    private final SensorEventListener mLightSensorListener = new SensorEventListener() {
1259        @Override
1260        public void onSensorChanged(SensorEvent event) {
1261            if (mLightSensorEnabled) {
1262                final long time = SystemClock.uptimeMillis();
1263                final float lux = event.values[0];
1264                handleLightSensorEvent(time, lux);
1265            }
1266        }
1267
1268        @Override
1269        public void onAccuracyChanged(Sensor sensor, int accuracy) {
1270            // Not used.
1271        }
1272    };
1273
1274    private final TwilightService.TwilightListener mTwilightListener =
1275            new TwilightService.TwilightListener() {
1276        @Override
1277        public void onTwilightStateChanged() {
1278            mTwilightChanged = true;
1279            updatePowerState();
1280        }
1281    };
1282}
1283