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