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