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