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