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