DisplayPowerController.java revision e941b1e27f6aad8a351c3caa3e0ad5f53dbf3707
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.power;
18
19import com.android.server.LightsService;
20import com.android.server.TwilightService;
21import com.android.server.TwilightService.TwilightState;
22
23import android.animation.Animator;
24import android.animation.ObjectAnimator;
25import android.content.Context;
26import android.content.res.Resources;
27import android.hardware.Sensor;
28import android.hardware.SensorEvent;
29import android.hardware.SensorEventListener;
30import android.hardware.SensorManager;
31import android.hardware.SystemSensorManager;
32import android.hardware.display.DisplayManager;
33import android.os.Handler;
34import android.os.Looper;
35import android.os.Message;
36import android.os.PowerManager;
37import android.os.SystemClock;
38import android.text.format.DateUtils;
39import android.util.FloatMath;
40import android.util.Slog;
41import android.util.Spline;
42import android.util.TimeUtils;
43import android.view.Display;
44
45import java.io.PrintWriter;
46
47/**
48 * Controls the power state of the display.
49 *
50 * Handles the proximity sensor, light sensor, and animations between states
51 * including the screen off animation.
52 *
53 * This component acts independently of the rest of the power manager service.
54 * In particular, it does not share any state and it only communicates
55 * via asynchronous callbacks to inform the power manager that something has
56 * changed.
57 *
58 * Everything this class does internally is serialized on its handler although
59 * it may be accessed by other threads from the outside.
60 *
61 * Note that the power manager service guarantees that it will hold a suspend
62 * blocker as long as the display is not ready.  So most of the work done here
63 * does not need to worry about holding a suspend blocker unless it happens
64 * independently of the display ready signal.
65 *
66 * For debugging, you can make the electron beam and brightness animations run
67 * slower by changing the "animator duration scale" option in Development Settings.
68 */
69final class DisplayPowerController {
70    private static final String TAG = "DisplayPowerController";
71
72    private static boolean DEBUG = false;
73    private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
74    private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
75
76    // If true, uses the electron beam on animation.
77    // We might want to turn this off if we cannot get a guarantee that the screen
78    // actually turns on and starts showing new content after the call to set the
79    // screen state returns.  Playing the animation can also be somewhat slow.
80    private static final boolean USE_ELECTRON_BEAM_ON_ANIMATION = false;
81
82    // If true, enables the use of the screen auto-brightness adjustment setting.
83    private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT =
84            PowerManager.useScreenAutoBrightnessAdjustmentFeature();
85
86    // The maximum range of gamma adjustment possible using the screen
87    // auto-brightness adjustment setting.
88    private static final float SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA = 3.0f;
89
90    // The minimum reduction in brightness when dimmed.
91    private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
92
93    // If true, enables the use of the current time as an auto-brightness adjustment.
94    // The basic idea here is to expand the dynamic range of auto-brightness
95    // when it is especially dark outside.  The light sensor tends to perform
96    // poorly at low light levels so we compensate for it by making an
97    // assumption about the environment.
98    private static final boolean USE_TWILIGHT_ADJUSTMENT =
99            PowerManager.useTwilightAdjustmentFeature();
100
101    // Specifies the maximum magnitude of the time of day adjustment.
102    private static final float TWILIGHT_ADJUSTMENT_MAX_GAMMA = 1.5f;
103
104    // The amount of time after or before sunrise over which to start adjusting
105    // the gamma.  We want the change to happen gradually so that it is below the
106    // threshold of perceptibility and so that the adjustment has maximum effect
107    // well after dusk.
108    private static final long TWILIGHT_ADJUSTMENT_TIME = DateUtils.HOUR_IN_MILLIS * 2;
109
110    private static final int ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS = 250;
111    private static final int ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS = 400;
112
113    private static final int MSG_UPDATE_POWER_STATE = 1;
114    private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
115    private static final int MSG_LIGHT_SENSOR_DEBOUNCED = 3;
116
117    private static final int PROXIMITY_UNKNOWN = -1;
118    private static final int PROXIMITY_NEGATIVE = 0;
119    private static final int PROXIMITY_POSITIVE = 1;
120
121    // Proximity sensor debounce delay in milliseconds for positive or negative transitions.
122    private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
123    private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 500;
124
125    // Trigger proximity if distance is less than 5 cm.
126    private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
127
128    // Light sensor event rate in milliseconds.
129    private static final int LIGHT_SENSOR_RATE_MILLIS = 1000;
130
131    // A rate for generating synthetic light sensor events in the case where the light
132    // sensor hasn't reported any new data in a while and we need it to update the
133    // debounce filter.  We only synthesize light sensor measurements when needed.
134    private static final int SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS =
135            LIGHT_SENSOR_RATE_MILLIS * 2;
136
137    // Brightness animation ramp rate in brightness units per second.
138    private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
139    private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
140
141    // IIR filter time constants in milliseconds for computing two moving averages of
142    // the light samples.  One is a long-term average and the other is a short-term average.
143    // We can use these filters to assess trends in ambient brightness.
144    // The short term average gives us a filtered but relatively low latency measurement.
145    // The long term average informs us about the overall trend.
146    private static final long SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 1000;
147    private static final long LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 5000;
148
149    // Stability requirements in milliseconds for accepting a new brightness
150    // level.  This is used for debouncing the light sensor.  Different constants
151    // are used to debounce the light sensor when adapting to brighter or darker environments.
152    // This parameter controls how quickly brightness changes occur in response to
153    // an observed change in light level that exceeds the hysteresis threshold.
154    private static final long BRIGHTENING_LIGHT_DEBOUNCE = 4000;
155    private static final long DARKENING_LIGHT_DEBOUNCE = 8000;
156
157    // Hysteresis constraints for brightening or darkening.
158    // The recent lux must have changed by at least this fraction relative to the
159    // current ambient lux before a change will be considered.
160    private static final float BRIGHTENING_LIGHT_HYSTERESIS = 0.10f;
161    private static final float DARKENING_LIGHT_HYSTERESIS = 0.20f;
162
163    private final Object mLock = new Object();
164
165    // Notifier for sending asynchronous notifications.
166    private final Notifier mNotifier;
167
168    // The display blanker.
169    private final DisplayBlanker mDisplayBlanker;
170
171    // Our handler.
172    private final DisplayControllerHandler mHandler;
173
174    // Asynchronous callbacks into the power manager service.
175    // Only invoked from the handler thread while no locks are held.
176    private final Callbacks mCallbacks;
177    private Handler mCallbackHandler;
178
179    // The lights service.
180    private final LightsService mLights;
181
182    // The twilight service.
183    private final TwilightService mTwilight;
184
185    // The display manager.
186    private final DisplayManager mDisplayManager;
187
188    // The sensor manager.
189    private final SensorManager mSensorManager;
190
191    // The proximity sensor, or null if not available or needed.
192    private Sensor mProximitySensor;
193
194    // The light sensor, or null if not available or needed.
195    private Sensor mLightSensor;
196
197    // The dim screen brightness.
198    private final int mScreenBrightnessDimConfig;
199
200    // The minimum allowed brightness.
201    private final int mScreenBrightnessRangeMinimum;
202
203    // The maximum allowed brightness.
204    private final int mScreenBrightnessRangeMaximum;
205
206    // True if auto-brightness should be used.
207    private boolean mUseSoftwareAutoBrightnessConfig;
208
209    // The auto-brightness spline adjustment.
210    // The brightness values have been scaled to a range of 0..1.
211    private Spline mScreenAutoBrightnessSpline;
212
213    // Amount of time to delay auto-brightness after screen on while waiting for
214    // the light sensor to warm-up in milliseconds.
215    // May be 0 if no warm-up is required.
216    private int mLightSensorWarmUpTimeConfig;
217
218    // True if we should fade the screen while turning it off, false if we should play
219    // a stylish electron beam animation instead.
220    private boolean mElectronBeamFadesConfig;
221
222    // The pending power request.
223    // Initially null until the first call to requestPowerState.
224    // Guarded by mLock.
225    private DisplayPowerRequest mPendingRequestLocked;
226
227    // True if a request has been made to wait for the proximity sensor to go negative.
228    // Guarded by mLock.
229    private boolean mPendingWaitForNegativeProximityLocked;
230
231    // True if the pending power request or wait for negative proximity flag
232    // has been changed since the last update occurred.
233    // Guarded by mLock.
234    private boolean mPendingRequestChangedLocked;
235
236    // Set to true when the important parts of the pending power request have been applied.
237    // The important parts are mainly the screen state.  Brightness changes may occur
238    // concurrently.
239    // Guarded by mLock.
240    private boolean mDisplayReadyLocked;
241
242    // Set to true if a power state update is required.
243    // Guarded by mLock.
244    private boolean mPendingUpdatePowerStateLocked;
245
246    /* The following state must only be accessed by the handler thread. */
247
248    // The currently requested power state.
249    // The power controller will progressively update its internal state to match
250    // the requested power state.  Initially null until the first update.
251    private DisplayPowerRequest mPowerRequest;
252
253    // The current power state.
254    // Must only be accessed on the handler thread.
255    private DisplayPowerState mPowerState;
256
257    // True if the device should wait for negative proximity sensor before
258    // waking up the screen.  This is set to false as soon as a negative
259    // proximity sensor measurement is observed or when the device is forced to
260    // go to sleep by the user.  While true, the screen remains off.
261    private boolean mWaitingForNegativeProximity;
262
263    // The actual proximity sensor threshold value.
264    private float mProximityThreshold;
265
266    // Set to true if the proximity sensor listener has been registered
267    // with the sensor manager.
268    private boolean mProximitySensorEnabled;
269
270    // The debounced proximity sensor state.
271    private int mProximity = PROXIMITY_UNKNOWN;
272
273    // The raw non-debounced proximity sensor state.
274    private int mPendingProximity = PROXIMITY_UNKNOWN;
275    private long mPendingProximityDebounceTime;
276
277    // True if the screen was turned off because of the proximity sensor.
278    // When the screen turns on again, we report user activity to the power manager.
279    private boolean mScreenOffBecauseOfProximity;
280
281    // True if the screen on is being blocked.
282    private boolean mScreenOnWasBlocked;
283
284    // The elapsed real time when the screen on was blocked.
285    private long mScreenOnBlockStartRealTime;
286
287    // Set to true if the light sensor is enabled.
288    private boolean mLightSensorEnabled;
289
290    // The time when the light sensor was enabled.
291    private long mLightSensorEnableTime;
292
293    // The currently accepted nominal ambient light level.
294    private float mAmbientLux;
295
296    // True if mAmbientLux holds a valid value.
297    private boolean mAmbientLuxValid;
298
299    // The most recent light sample.
300    private float mLastObservedLux;
301
302    // The time of the most light recent sample.
303    private long mLastObservedLuxTime;
304
305    // The number of light samples collected since the light sensor was enabled.
306    private int mRecentLightSamples;
307
308    // The long-term and short-term filtered light measurements.
309    private float mRecentShortTermAverageLux;
310    private float mRecentLongTermAverageLux;
311
312    // The direction in which the average lux is moving relative to the current ambient lux.
313    //    0 if not changing or within hysteresis threshold.
314    //    1 if brightening beyond hysteresis threshold.
315    //   -1 if darkening beyond hysteresis threshold.
316    private int mDebounceLuxDirection;
317
318    // The time when the average lux last changed direction.
319    private long mDebounceLuxTime;
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,
349            DisplayBlanker displayBlanker,
350            Callbacks callbacks, Handler callbackHandler) {
351        mHandler = new DisplayControllerHandler(looper);
352        mNotifier = notifier;
353        mDisplayBlanker = displayBlanker;
354        mCallbacks = callbacks;
355        mCallbackHandler = callbackHandler;
356
357        mLights = lights;
358        mTwilight = twilight;
359        mSensorManager = new SystemSensorManager(mHandler.getLooper());
360        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
361
362        final Resources resources = context.getResources();
363
364        mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
365                com.android.internal.R.integer.config_screenBrightnessDim));
366
367        int screenBrightnessMinimum = Math.min(resources.getInteger(
368                com.android.internal.R.integer.config_screenBrightnessSettingMinimum),
369                mScreenBrightnessDimConfig);
370
371        mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
372                com.android.internal.R.bool.config_automatic_brightness_available);
373        if (mUseSoftwareAutoBrightnessConfig) {
374            int[] lux = resources.getIntArray(
375                    com.android.internal.R.array.config_autoBrightnessLevels);
376            int[] screenBrightness = resources.getIntArray(
377                    com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
378
379            mScreenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
380            if (mScreenAutoBrightnessSpline == null) {
381                Slog.e(TAG, "Error in config.xml.  config_autoBrightnessLcdBacklightValues "
382                        + "(size " + screenBrightness.length + ") "
383                        + "must be monotic and have exactly one more entry than "
384                        + "config_autoBrightnessLevels (size " + lux.length + ") "
385                        + "which must be strictly increasing.  "
386                        + "Auto-brightness will be disabled.");
387                mUseSoftwareAutoBrightnessConfig = false;
388            } else {
389                if (screenBrightness[0] < screenBrightnessMinimum) {
390                    screenBrightnessMinimum = screenBrightness[0];
391                }
392            }
393
394            mLightSensorWarmUpTimeConfig = resources.getInteger(
395                    com.android.internal.R.integer.config_lightSensorWarmupTime);
396        }
397
398        mScreenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightnessMinimum);
399        mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
400
401        mElectronBeamFadesConfig = resources.getBoolean(
402                com.android.internal.R.bool.config_animateScreenLights);
403
404        if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
405            mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
406            if (mProximitySensor != null) {
407                mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
408                        TYPICAL_PROXIMITY_THRESHOLD);
409            }
410        }
411
412        if (mUseSoftwareAutoBrightnessConfig
413                && !DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
414            mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
415        }
416
417        if (mUseSoftwareAutoBrightnessConfig && USE_TWILIGHT_ADJUSTMENT) {
418            mTwilight.registerListener(mTwilightListener, mHandler);
419        }
420    }
421
422    private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
423        try {
424            final int n = brightness.length;
425            float[] x = new float[n];
426            float[] y = new float[n];
427            y[0] = normalizeAbsoluteBrightness(brightness[0]);
428            for (int i = 1; i < n; i++) {
429                x[i] = lux[i - 1];
430                y[i] = normalizeAbsoluteBrightness(brightness[i]);
431            }
432
433            Spline spline = Spline.createMonotoneCubicSpline(x, y);
434            if (DEBUG) {
435                Slog.d(TAG, "Auto-brightness spline: " + spline);
436                for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
437                    Slog.d(TAG, String.format("  %7.1f: %7.1f", v, spline.interpolate(v)));
438                }
439            }
440            return spline;
441        } catch (IllegalArgumentException ex) {
442            Slog.e(TAG, "Could not create auto-brightness spline.", ex);
443            return null;
444        }
445    }
446
447    /**
448     * Returns true if the proximity sensor screen-off function is available.
449     */
450    public boolean isProximitySensorAvailable() {
451        return mProximitySensor != null;
452    }
453
454    /**
455     * Requests a new power state.
456     * The controller makes a copy of the provided object and then
457     * begins adjusting the power state to match what was requested.
458     *
459     * @param request The requested power state.
460     * @param waitForNegativeProximity If true, issues a request to wait for
461     * negative proximity before turning the screen back on, assuming the screen
462     * was turned off by the proximity sensor.
463     * @return True if display is ready, false if there are important changes that must
464     * be made asynchronously (such as turning the screen on), in which case the caller
465     * should grab a wake lock, watch for {@link Callbacks#onStateChanged()} then try
466     * the request again later until the state converges.
467     */
468    public boolean requestPowerState(DisplayPowerRequest request,
469            boolean waitForNegativeProximity) {
470        if (DEBUG) {
471            Slog.d(TAG, "requestPowerState: "
472                    + request + ", waitForNegativeProximity=" + waitForNegativeProximity);
473        }
474
475        synchronized (mLock) {
476            boolean changed = false;
477
478            if (waitForNegativeProximity
479                    && !mPendingWaitForNegativeProximityLocked) {
480                mPendingWaitForNegativeProximityLocked = true;
481                changed = true;
482            }
483
484            if (mPendingRequestLocked == null) {
485                mPendingRequestLocked = new DisplayPowerRequest(request);
486                changed = true;
487            } else if (!mPendingRequestLocked.equals(request)) {
488                mPendingRequestLocked.copyFrom(request);
489                changed = true;
490            }
491
492            if (changed) {
493                mDisplayReadyLocked = false;
494            }
495
496            if (changed && !mPendingRequestChangedLocked) {
497                mPendingRequestChangedLocked = true;
498                sendUpdatePowerStateLocked();
499            }
500
501            return mDisplayReadyLocked;
502        }
503    }
504
505    private void sendUpdatePowerState() {
506        synchronized (mLock) {
507            sendUpdatePowerStateLocked();
508        }
509    }
510
511    private void sendUpdatePowerStateLocked() {
512        if (!mPendingUpdatePowerStateLocked) {
513            mPendingUpdatePowerStateLocked = true;
514            Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
515            msg.setAsynchronous(true);
516            mHandler.sendMessage(msg);
517        }
518    }
519
520    private void initialize() {
521        Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
522        mPowerState = new DisplayPowerState(
523                new ElectronBeam(display), mDisplayBlanker,
524                mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT));
525
526        mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
527                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
528        mElectronBeamOnAnimator.setDuration(ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS);
529        mElectronBeamOnAnimator.addListener(mAnimatorListener);
530
531        mElectronBeamOffAnimator = ObjectAnimator.ofFloat(
532                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 1.0f, 0.0f);
533        mElectronBeamOffAnimator.setDuration(ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS);
534        mElectronBeamOffAnimator.addListener(mAnimatorListener);
535
536        mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
537                mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
538    }
539
540    private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
541        @Override
542        public void onAnimationStart(Animator animation) {
543        }
544        @Override
545        public void onAnimationEnd(Animator animation) {
546            sendUpdatePowerState();
547        }
548        @Override
549        public void onAnimationRepeat(Animator animation) {
550        }
551        @Override
552        public void onAnimationCancel(Animator animation) {
553        }
554    };
555
556    private void updatePowerState() {
557        // Update the power state request.
558        final boolean mustNotify;
559        boolean mustInitialize = false;
560        boolean updateAutoBrightness = mTwilightChanged;
561        boolean wasDim = false;
562        mTwilightChanged = false;
563
564        synchronized (mLock) {
565            mPendingUpdatePowerStateLocked = false;
566            if (mPendingRequestLocked == null) {
567                return; // wait until first actual power request
568            }
569
570            if (mPowerRequest == null) {
571                mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
572                mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
573                mPendingWaitForNegativeProximityLocked = false;
574                mPendingRequestChangedLocked = false;
575                mustInitialize = true;
576            } else if (mPendingRequestChangedLocked) {
577                if (mPowerRequest.screenAutoBrightnessAdjustment
578                        != mPendingRequestLocked.screenAutoBrightnessAdjustment) {
579                    updateAutoBrightness = true;
580                }
581                wasDim = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM);
582                mPowerRequest.copyFrom(mPendingRequestLocked);
583                mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
584                mPendingWaitForNegativeProximityLocked = false;
585                mPendingRequestChangedLocked = false;
586                mDisplayReadyLocked = false;
587            }
588
589            mustNotify = !mDisplayReadyLocked;
590        }
591
592        // Initialize things the first time the power state is changed.
593        if (mustInitialize) {
594            initialize();
595        }
596
597        // Apply the proximity sensor.
598        if (mProximitySensor != null) {
599            if (mPowerRequest.useProximitySensor
600                    && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
601                setProximitySensorEnabled(true);
602                if (!mScreenOffBecauseOfProximity
603                        && mProximity == PROXIMITY_POSITIVE) {
604                    mScreenOffBecauseOfProximity = true;
605                    sendOnProximityPositive();
606                    setScreenOn(false);
607                }
608            } else if (mWaitingForNegativeProximity
609                    && mScreenOffBecauseOfProximity
610                    && mProximity == PROXIMITY_POSITIVE
611                    && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
612                setProximitySensorEnabled(true);
613            } else {
614                setProximitySensorEnabled(false);
615                mWaitingForNegativeProximity = false;
616            }
617            if (mScreenOffBecauseOfProximity
618                    && mProximity != PROXIMITY_POSITIVE) {
619                mScreenOffBecauseOfProximity = false;
620                sendOnProximityNegative();
621            }
622        } else {
623            mWaitingForNegativeProximity = false;
624        }
625
626        // Turn on the light sensor if needed.
627        if (mLightSensor != null) {
628            setLightSensorEnabled(mPowerRequest.useAutoBrightness
629                    && wantScreenOn(mPowerRequest.screenState), updateAutoBrightness);
630        }
631
632        // Set the screen brightness.
633        if (wantScreenOn(mPowerRequest.screenState)) {
634            int target;
635            boolean slow;
636            if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) {
637                // Use current auto-brightness value.
638                target = mScreenAutoBrightness;
639                slow = mUsingScreenAutoBrightness;
640                mUsingScreenAutoBrightness = true;
641            } else {
642                // Light sensor is disabled or not ready yet.
643                // Use the current brightness setting from the request, which is expected
644                // provide a nominal default value for the case where auto-brightness
645                // is not ready yet.
646                target = mPowerRequest.screenBrightness;
647                slow = false;
648                mUsingScreenAutoBrightness = false;
649            }
650            if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
651                // Dim slowly by at least some minimum amount.
652                target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
653                        mScreenBrightnessDimConfig);
654                slow = true;
655            } else if (wasDim) {
656                // Brighten quickly.
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_MILLIS * 1000, mHandler);
872            }
873        } else {
874            if (mLightSensorEnabled) {
875                mLightSensorEnabled = false;
876                mAmbientLuxValid = false;
877                mRecentLightSamples = 0;
878                mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
879                mSensorManager.unregisterListener(mLightSensorListener);
880            }
881        }
882        if (updateAutoBrightness) {
883            updateAutoBrightness(false);
884        }
885    }
886
887    private void handleLightSensorEvent(long time, float lux) {
888        mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
889
890        applyLightSensorMeasurement(time, lux);
891        updateAmbientLux(time);
892    }
893
894    private void applyLightSensorMeasurement(long time, float lux) {
895        // Update our filters.
896        mRecentLightSamples += 1;
897        if (mRecentLightSamples == 1) {
898            mRecentShortTermAverageLux = lux;
899            mRecentLongTermAverageLux = lux;
900        } else {
901            final long timeDelta = time - mLastObservedLuxTime;
902            mRecentShortTermAverageLux += (lux - mRecentShortTermAverageLux)
903                    * timeDelta / (SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
904            mRecentLongTermAverageLux += (lux - mRecentLongTermAverageLux)
905                    * timeDelta / (LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
906        }
907
908        // Remember this sample value.
909        mLastObservedLux = lux;
910        mLastObservedLuxTime = time;
911    }
912
913    private void updateAmbientLux(long time) {
914        // If the light sensor was just turned on then immediately update our initial
915        // estimate of the current ambient light level.
916        if (!mAmbientLuxValid
917                || (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) {
918            mAmbientLux = mRecentShortTermAverageLux;
919            mAmbientLuxValid = true;
920            mDebounceLuxDirection = 0;
921            mDebounceLuxTime = time;
922            if (DEBUG) {
923                Slog.d(TAG, "updateAmbientLux: Initializing: "
924                        + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
925                        + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
926                        + ", mAmbientLux=" + mAmbientLux);
927            }
928            updateAutoBrightness(true);
929            return;
930        }
931
932        // Determine whether the ambient environment appears to be brightening.
933        float brighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
934        if (mRecentShortTermAverageLux > brighteningLuxThreshold
935                && mRecentLongTermAverageLux > brighteningLuxThreshold) {
936            if (mDebounceLuxDirection <= 0) {
937                mDebounceLuxDirection = 1;
938                mDebounceLuxTime = time;
939                if (DEBUG) {
940                    Slog.d(TAG, "updateAmbientLux: Possibly brightened, waiting for "
941                            + BRIGHTENING_LIGHT_DEBOUNCE + " ms: "
942                            + "brighteningLuxThreshold=" + brighteningLuxThreshold
943                            + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
944                            + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
945                            + ", mAmbientLux=" + mAmbientLux);
946                }
947            }
948            long debounceTime = mDebounceLuxTime + BRIGHTENING_LIGHT_DEBOUNCE;
949            if (time >= debounceTime) {
950                mAmbientLux = mRecentShortTermAverageLux;
951                if (DEBUG) {
952                    Slog.d(TAG, "updateAmbientLux: Brightened: "
953                            + "brighteningLuxThreshold=" + brighteningLuxThreshold
954                            + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
955                            + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
956                            + ", mAmbientLux=" + mAmbientLux);
957                }
958                updateAutoBrightness(true);
959            } else {
960                mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
961            }
962            return;
963        }
964
965        // Determine whether the ambient environment appears to be darkening.
966        float darkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
967        if (mRecentShortTermAverageLux < darkeningLuxThreshold
968                && mRecentLongTermAverageLux < darkeningLuxThreshold) {
969            if (mDebounceLuxDirection >= 0) {
970                mDebounceLuxDirection = -1;
971                mDebounceLuxTime = time;
972                if (DEBUG) {
973                    Slog.d(TAG, "updateAmbientLux: Possibly darkened, waiting for "
974                            + DARKENING_LIGHT_DEBOUNCE + " ms: "
975                            + "darkeningLuxThreshold=" + darkeningLuxThreshold
976                            + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
977                            + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
978                            + ", mAmbientLux=" + mAmbientLux);
979                }
980            }
981            long debounceTime = mDebounceLuxTime + DARKENING_LIGHT_DEBOUNCE;
982            if (time >= debounceTime) {
983                // Be conservative about reducing the brightness, only reduce it a little bit
984                // at a time to avoid having to bump it up again soon.
985                mAmbientLux = Math.max(mRecentShortTermAverageLux, mRecentLongTermAverageLux);
986                if (DEBUG) {
987                    Slog.d(TAG, "updateAmbientLux: Darkened: "
988                            + "darkeningLuxThreshold=" + darkeningLuxThreshold
989                            + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
990                            + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
991                            + ", mAmbientLux=" + mAmbientLux);
992                }
993                updateAutoBrightness(true);
994            } else {
995                mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
996            }
997            return;
998        }
999
1000        // No change or change is within the hysteresis thresholds.
1001        if (mDebounceLuxDirection != 0) {
1002            mDebounceLuxDirection = 0;
1003            mDebounceLuxTime = time;
1004            if (DEBUG) {
1005                Slog.d(TAG, "updateAmbientLux: Canceled debounce: "
1006                        + "brighteningLuxThreshold=" + brighteningLuxThreshold
1007                        + ", darkeningLuxThreshold=" + darkeningLuxThreshold
1008                        + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
1009                        + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
1010                        + ", mAmbientLux=" + mAmbientLux);
1011            }
1012        }
1013
1014        // If the light level does not change, then the sensor may not report
1015        // a new value.  This can cause problems for the auto-brightness algorithm
1016        // because the filters might not be updated.  To work around it, we want to
1017        // make sure to update the filters whenever the observed light level could
1018        // possibly exceed one of the hysteresis thresholds.
1019        if (mLastObservedLux > brighteningLuxThreshold
1020                || mLastObservedLux < darkeningLuxThreshold) {
1021            mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED,
1022                    time + SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS);
1023        }
1024    }
1025
1026    private void debounceLightSensor() {
1027        if (mLightSensorEnabled) {
1028            long time = SystemClock.uptimeMillis();
1029            if (time >= mLastObservedLuxTime + SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS) {
1030                if (DEBUG) {
1031                    Slog.d(TAG, "debounceLightSensor: Synthesizing light sensor measurement "
1032                            + "after " + (time - mLastObservedLuxTime) + " ms.");
1033                }
1034                applyLightSensorMeasurement(time, mLastObservedLux);
1035            }
1036            updateAmbientLux(time);
1037        }
1038    }
1039
1040    private void updateAutoBrightness(boolean sendUpdate) {
1041        if (!mAmbientLuxValid) {
1042            return;
1043        }
1044
1045        float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);
1046        float gamma = 1.0f;
1047
1048        if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
1049                && mPowerRequest.screenAutoBrightnessAdjustment != 0.0f) {
1050            final float adjGamma = FloatMath.pow(SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA,
1051                    Math.min(1.0f, Math.max(-1.0f,
1052                            -mPowerRequest.screenAutoBrightnessAdjustment)));
1053            gamma *= adjGamma;
1054            if (DEBUG) {
1055                Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma);
1056            }
1057        }
1058
1059        if (USE_TWILIGHT_ADJUSTMENT) {
1060            TwilightState state = mTwilight.getCurrentState();
1061            if (state != null && state.isNight()) {
1062                final long now = System.currentTimeMillis();
1063                final float earlyGamma =
1064                        getTwilightGamma(now, state.getYesterdaySunset(), state.getTodaySunrise());
1065                final float lateGamma =
1066                        getTwilightGamma(now, state.getTodaySunset(), state.getTomorrowSunrise());
1067                gamma *= earlyGamma * lateGamma;
1068                if (DEBUG) {
1069                    Slog.d(TAG, "updateAutoBrightness: earlyGamma=" + earlyGamma
1070                            + ", lateGamma=" + lateGamma);
1071                }
1072            }
1073        }
1074
1075        if (gamma != 1.0f) {
1076            final float in = value;
1077            value = FloatMath.pow(value, gamma);
1078            if (DEBUG) {
1079                Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma
1080                        + ", in=" + in + ", out=" + value);
1081            }
1082        }
1083
1084        int newScreenAutoBrightness = clampScreenBrightness(
1085                Math.round(value * PowerManager.BRIGHTNESS_ON));
1086        if (mScreenAutoBrightness != newScreenAutoBrightness) {
1087            if (DEBUG) {
1088                Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
1089                        + mScreenAutoBrightness + ", newScreenAutoBrightness="
1090                        + newScreenAutoBrightness);
1091            }
1092
1093            mScreenAutoBrightness = newScreenAutoBrightness;
1094            mLastScreenAutoBrightnessGamma = gamma;
1095            if (sendUpdate) {
1096                sendUpdatePowerState();
1097            }
1098        }
1099    }
1100
1101    private static float getTwilightGamma(long now, long lastSunset, long nextSunrise) {
1102        if (lastSunset < 0 || nextSunrise < 0
1103                || now < lastSunset || now > nextSunrise) {
1104            return 1.0f;
1105        }
1106
1107        if (now < lastSunset + TWILIGHT_ADJUSTMENT_TIME) {
1108            return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
1109                    (float)(now - lastSunset) / TWILIGHT_ADJUSTMENT_TIME);
1110        }
1111
1112        if (now > nextSunrise - TWILIGHT_ADJUSTMENT_TIME) {
1113            return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
1114                    (float)(nextSunrise - now) / TWILIGHT_ADJUSTMENT_TIME);
1115        }
1116
1117        return TWILIGHT_ADJUSTMENT_MAX_GAMMA;
1118    }
1119
1120    private static float lerp(float x, float y, float alpha) {
1121        return x + (y - x) * alpha;
1122    }
1123
1124    private void sendOnStateChanged() {
1125        mCallbackHandler.post(mOnStateChangedRunnable);
1126    }
1127
1128    private final Runnable mOnStateChangedRunnable = new Runnable() {
1129        @Override
1130        public void run() {
1131            mCallbacks.onStateChanged();
1132        }
1133    };
1134
1135    private void sendOnProximityPositive() {
1136        mCallbackHandler.post(mOnProximityPositiveRunnable);
1137    }
1138
1139    private final Runnable mOnProximityPositiveRunnable = new Runnable() {
1140        @Override
1141        public void run() {
1142            mCallbacks.onProximityPositive();
1143        }
1144    };
1145
1146    private void sendOnProximityNegative() {
1147        mCallbackHandler.post(mOnProximityNegativeRunnable);
1148    }
1149
1150    private final Runnable mOnProximityNegativeRunnable = new Runnable() {
1151        @Override
1152        public void run() {
1153            mCallbacks.onProximityNegative();
1154        }
1155    };
1156
1157    public void dump(final PrintWriter pw) {
1158        synchronized (mLock) {
1159            pw.println();
1160            pw.println("Display Controller Locked State:");
1161            pw.println("  mDisplayReadyLocked=" + mDisplayReadyLocked);
1162            pw.println("  mPendingRequestLocked=" + mPendingRequestLocked);
1163            pw.println("  mPendingRequestChangedLocked=" + mPendingRequestChangedLocked);
1164            pw.println("  mPendingWaitForNegativeProximityLocked="
1165                    + mPendingWaitForNegativeProximityLocked);
1166            pw.println("  mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked);
1167        }
1168
1169        pw.println();
1170        pw.println("Display Controller Configuration:");
1171        pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
1172        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
1173        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
1174        pw.println("  mUseSoftwareAutoBrightnessConfig="
1175                + mUseSoftwareAutoBrightnessConfig);
1176        pw.println("  mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline);
1177        pw.println("  mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
1178
1179        mHandler.runWithScissors(new Runnable() {
1180            @Override
1181            public void run() {
1182                dumpLocal(pw);
1183            }
1184        }, 1000);
1185    }
1186
1187    private void dumpLocal(PrintWriter pw) {
1188        pw.println();
1189        pw.println("Display Controller Thread State:");
1190        pw.println("  mPowerRequest=" + mPowerRequest);
1191        pw.println("  mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
1192
1193        pw.println("  mProximitySensor=" + mProximitySensor);
1194        pw.println("  mProximitySensorEnabled=" + mProximitySensorEnabled);
1195        pw.println("  mProximityThreshold=" + mProximityThreshold);
1196        pw.println("  mProximity=" + proximityToString(mProximity));
1197        pw.println("  mPendingProximity=" + proximityToString(mPendingProximity));
1198        pw.println("  mPendingProximityDebounceTime="
1199                + TimeUtils.formatUptime(mPendingProximityDebounceTime));
1200        pw.println("  mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
1201
1202        pw.println("  mLightSensor=" + mLightSensor);
1203        pw.println("  mLightSensorEnabled=" + mLightSensorEnabled);
1204        pw.println("  mLightSensorEnableTime="
1205                + TimeUtils.formatUptime(mLightSensorEnableTime));
1206        pw.println("  mAmbientLux=" + mAmbientLux);
1207        pw.println("  mAmbientLuxValid=" + mAmbientLuxValid);
1208        pw.println("  mLastObservedLux=" + mLastObservedLux);
1209        pw.println("  mLastObservedLuxTime="
1210                + TimeUtils.formatUptime(mLastObservedLuxTime));
1211        pw.println("  mRecentLightSamples=" + mRecentLightSamples);
1212        pw.println("  mRecentShortTermAverageLux=" + mRecentShortTermAverageLux);
1213        pw.println("  mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
1214        pw.println("  mDebounceLuxDirection=" + mDebounceLuxDirection);
1215        pw.println("  mDebounceLuxTime=" + TimeUtils.formatUptime(mDebounceLuxTime));
1216        pw.println("  mScreenAutoBrightness=" + mScreenAutoBrightness);
1217        pw.println("  mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
1218        pw.println("  mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
1219        pw.println("  mTwilight.getCurrentState()=" + mTwilight.getCurrentState());
1220
1221        if (mElectronBeamOnAnimator != null) {
1222            pw.println("  mElectronBeamOnAnimator.isStarted()=" +
1223                    mElectronBeamOnAnimator.isStarted());
1224        }
1225        if (mElectronBeamOffAnimator != null) {
1226            pw.println("  mElectronBeamOffAnimator.isStarted()=" +
1227                    mElectronBeamOffAnimator.isStarted());
1228        }
1229
1230        if (mPowerState != null) {
1231            mPowerState.dump(pw);
1232        }
1233    }
1234
1235    private static String proximityToString(int state) {
1236        switch (state) {
1237            case PROXIMITY_UNKNOWN:
1238                return "Unknown";
1239            case PROXIMITY_NEGATIVE:
1240                return "Negative";
1241            case PROXIMITY_POSITIVE:
1242                return "Positive";
1243            default:
1244                return Integer.toString(state);
1245        }
1246    }
1247
1248    private static boolean wantScreenOn(int state) {
1249        switch (state) {
1250            case DisplayPowerRequest.SCREEN_STATE_BRIGHT:
1251            case DisplayPowerRequest.SCREEN_STATE_DIM:
1252                return true;
1253        }
1254        return false;
1255    }
1256
1257    /**
1258     * Asynchronous callbacks from the power controller to the power manager service.
1259     */
1260    public interface Callbacks {
1261        void onStateChanged();
1262        void onProximityPositive();
1263        void onProximityNegative();
1264    }
1265
1266    private final class DisplayControllerHandler extends Handler {
1267        public DisplayControllerHandler(Looper looper) {
1268            super(looper, null, true /*async*/);
1269        }
1270
1271        @Override
1272        public void handleMessage(Message msg) {
1273            switch (msg.what) {
1274                case MSG_UPDATE_POWER_STATE:
1275                    updatePowerState();
1276                    break;
1277
1278                case MSG_PROXIMITY_SENSOR_DEBOUNCED:
1279                    debounceProximitySensor();
1280                    break;
1281
1282                case MSG_LIGHT_SENSOR_DEBOUNCED:
1283                    debounceLightSensor();
1284                    break;
1285            }
1286        }
1287    }
1288
1289    private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
1290        @Override
1291        public void onSensorChanged(SensorEvent event) {
1292            if (mProximitySensorEnabled) {
1293                final long time = SystemClock.uptimeMillis();
1294                final float distance = event.values[0];
1295                boolean positive = distance >= 0.0f && distance < mProximityThreshold;
1296                handleProximitySensorEvent(time, positive);
1297            }
1298        }
1299
1300        @Override
1301        public void onAccuracyChanged(Sensor sensor, int accuracy) {
1302            // Not used.
1303        }
1304    };
1305
1306    private final SensorEventListener mLightSensorListener = new SensorEventListener() {
1307        @Override
1308        public void onSensorChanged(SensorEvent event) {
1309            if (mLightSensorEnabled) {
1310                final long time = SystemClock.uptimeMillis();
1311                final float lux = event.values[0];
1312                handleLightSensorEvent(time, lux);
1313            }
1314        }
1315
1316        @Override
1317        public void onAccuracyChanged(Sensor sensor, int accuracy) {
1318            // Not used.
1319        }
1320    };
1321
1322    private final TwilightService.TwilightListener mTwilightListener =
1323            new TwilightService.TwilightListener() {
1324        @Override
1325        public void onTwilightStateChanged() {
1326            mTwilightChanged = true;
1327            updatePowerState();
1328        }
1329    };
1330}
1331