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