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