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