DisplayPowerController.java revision 6da87ab684f104baa836138ca5153eb2d6c1f929
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.display;
18
19import com.android.internal.app.IBatteryStats;
20import com.android.server.LocalServices;
21import com.android.server.am.BatteryStatsService;
22import com.android.server.lights.LightsManager;
23
24import android.animation.Animator;
25import android.animation.ObjectAnimator;
26import android.content.Context;
27import android.content.res.Resources;
28import android.hardware.Sensor;
29import android.hardware.SensorEvent;
30import android.hardware.SensorEventListener;
31import android.hardware.SensorManager;
32import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
33import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
34import android.os.Handler;
35import android.os.Looper;
36import android.os.Message;
37import android.os.PowerManager;
38import android.os.RemoteException;
39import android.os.SystemClock;
40import android.text.format.DateUtils;
41import android.util.MathUtils;
42import android.util.Slog;
43import android.util.Spline;
44import android.util.TimeUtils;
45import android.view.Display;
46
47import java.io.PrintWriter;
48
49/**
50 * Controls the power state of the display.
51 *
52 * Handles the proximity sensor, light sensor, and animations between states
53 * including the screen off animation.
54 *
55 * This component acts independently of the rest of the power manager service.
56 * In particular, it does not share any state and it only communicates
57 * via asynchronous callbacks to inform the power manager that something has
58 * changed.
59 *
60 * Everything this class does internally is serialized on its handler although
61 * it may be accessed by other threads from the outside.
62 *
63 * Note that the power manager service guarantees that it will hold a suspend
64 * blocker as long as the display is not ready.  So most of the work done here
65 * does not need to worry about holding a suspend blocker unless it happens
66 * independently of the display ready signal.
67 *
68 * For debugging, you can make the electron beam and brightness animations run
69 * slower by changing the "animator duration scale" option in Development Settings.
70 */
71final class DisplayPowerController implements AutomaticBrightnessController.Callbacks {
72    private static final String TAG = "DisplayPowerController";
73
74    private static boolean DEBUG = false;
75    private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
76
77    // If true, uses the electron beam on animation.
78    // We might want to turn this off if we cannot get a guarantee that the screen
79    // actually turns on and starts showing new content after the call to set the
80    // screen state returns.  Playing the animation can also be somewhat slow.
81    private static final boolean USE_ELECTRON_BEAM_ON_ANIMATION = false;
82
83
84    // The minimum reduction in brightness when dimmed.
85    private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
86
87    private static final int ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS = 250;
88    private static final int ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS = 400;
89
90    private static final int MSG_UPDATE_POWER_STATE = 1;
91    private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
92
93    private static final int PROXIMITY_UNKNOWN = -1;
94    private static final int PROXIMITY_NEGATIVE = 0;
95    private static final int PROXIMITY_POSITIVE = 1;
96
97    // Proximity sensor debounce delay in milliseconds for positive or negative transitions.
98    private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
99    private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 250;
100
101    // Trigger proximity if distance is less than 5 cm.
102    private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
103
104    // Brightness animation ramp rate in brightness units per second.
105    private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
106    private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
107
108    private final Object mLock = new Object();
109
110    // Our handler.
111    private final DisplayControllerHandler mHandler;
112
113    // Asynchronous callbacks into the power manager service.
114    // Only invoked from the handler thread while no locks are held.
115    private final DisplayPowerCallbacks mCallbacks;
116
117    // Battery stats.
118    private final IBatteryStats mBatteryStats;
119
120    // The lights service.
121    private final LightsManager mLights;
122
123    // The sensor manager.
124    private final SensorManager mSensorManager;
125
126    // The display blanker.
127    private final DisplayBlanker mBlanker;
128
129    // The proximity sensor, or null if not available or needed.
130    private Sensor mProximitySensor;
131
132    // The doze screen brightness.
133    private final int mScreenBrightnessDozeConfig;
134
135    // The dim screen brightness.
136    private final int mScreenBrightnessDimConfig;
137
138    // The minimum allowed brightness.
139    private final int mScreenBrightnessRangeMinimum;
140
141    // The maximum allowed brightness.
142    private final int mScreenBrightnessRangeMaximum;
143
144    // True if auto-brightness should be used.
145    private boolean mUseSoftwareAutoBrightnessConfig;
146
147    // True if we should fade the screen while turning it off, false if we should play
148    // a stylish electron beam animation instead.
149    private boolean mElectronBeamFadesConfig;
150
151    // The pending power request.
152    // Initially null until the first call to requestPowerState.
153    // Guarded by mLock.
154    private DisplayPowerRequest mPendingRequestLocked;
155
156    // True if a request has been made to wait for the proximity sensor to go negative.
157    // Guarded by mLock.
158    private boolean mPendingWaitForNegativeProximityLocked;
159
160    // True if the pending power request or wait for negative proximity flag
161    // has been changed since the last update occurred.
162    // Guarded by mLock.
163    private boolean mPendingRequestChangedLocked;
164
165    // Set to true when the important parts of the pending power request have been applied.
166    // The important parts are mainly the screen state.  Brightness changes may occur
167    // concurrently.
168    // Guarded by mLock.
169    private boolean mDisplayReadyLocked;
170
171    // Set to true if a power state update is required.
172    // Guarded by mLock.
173    private boolean mPendingUpdatePowerStateLocked;
174
175    /* The following state must only be accessed by the handler thread. */
176
177    // The currently requested power state.
178    // The power controller will progressively update its internal state to match
179    // the requested power state.  Initially null until the first update.
180    private DisplayPowerRequest mPowerRequest;
181
182    // The current power state.
183    // Must only be accessed on the handler thread.
184    private DisplayPowerState mPowerState;
185
186    // True if the device should wait for negative proximity sensor before
187    // waking up the screen.  This is set to false as soon as a negative
188    // proximity sensor measurement is observed or when the device is forced to
189    // go to sleep by the user.  While true, the screen remains off.
190    private boolean mWaitingForNegativeProximity;
191
192    // The actual proximity sensor threshold value.
193    private float mProximityThreshold;
194
195    // Set to true if the proximity sensor listener has been registered
196    // with the sensor manager.
197    private boolean mProximitySensorEnabled;
198
199    // The debounced proximity sensor state.
200    private int mProximity = PROXIMITY_UNKNOWN;
201
202    // The raw non-debounced proximity sensor state.
203    private int mPendingProximity = PROXIMITY_UNKNOWN;
204    private long mPendingProximityDebounceTime = -1; // -1 if fully debounced
205
206    // True if the screen was turned off because of the proximity sensor.
207    // When the screen turns on again, we report user activity to the power manager.
208    private boolean mScreenOffBecauseOfProximity;
209
210    // True if the screen on is being blocked.
211    private boolean mScreenOnWasBlocked;
212
213    // The elapsed real time when the screen on was blocked.
214    private long mScreenOnBlockStartRealTime;
215
216    // True if the screen auto-brightness value is actually being used to
217    // set the display brightness.
218    private boolean mUsingScreenAutoBrightness;
219
220    // The controller for the automatic brightness level.
221    private AutomaticBrightnessController mAutomaticBrightnessController;
222
223    // Animators.
224    private ObjectAnimator mElectronBeamOnAnimator;
225    private ObjectAnimator mElectronBeamOffAnimator;
226    private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
227
228    /**
229     * Creates the display power controller.
230     */
231    public DisplayPowerController(Context context,
232            DisplayPowerCallbacks callbacks, Handler handler,
233            SensorManager sensorManager, DisplayBlanker blanker) {
234        mHandler = new DisplayControllerHandler(handler.getLooper());
235        mCallbacks = callbacks;
236
237        mBatteryStats = BatteryStatsService.getService();
238        mLights = LocalServices.getService(LightsManager.class);
239        mSensorManager = sensorManager;
240        mBlanker = blanker;
241
242        final Resources resources = context.getResources();
243
244        mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger(
245                com.android.internal.R.integer.config_screenBrightnessDoze));
246
247        mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
248                com.android.internal.R.integer.config_screenBrightnessDim));
249
250        int screenBrightnessRangeMinimum = clampAbsoluteBrightness(Math.min(resources.getInteger(
251                com.android.internal.R.integer.config_screenBrightnessSettingMinimum),
252                mScreenBrightnessDimConfig));
253
254        mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
255
256        mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
257                com.android.internal.R.bool.config_automatic_brightness_available);
258        if (mUseSoftwareAutoBrightnessConfig) {
259            int[] lux = resources.getIntArray(
260                    com.android.internal.R.array.config_autoBrightnessLevels);
261            int[] screenBrightness = resources.getIntArray(
262                    com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
263            int lightSensorWarmUpTimeConfig = resources.getInteger(
264                    com.android.internal.R.integer.config_lightSensorWarmupTime);
265
266            Spline screenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
267            if (screenAutoBrightnessSpline == null) {
268                Slog.e(TAG, "Error in config.xml.  config_autoBrightnessLcdBacklightValues "
269                        + "(size " + screenBrightness.length + ") "
270                        + "must be monotic and have exactly one more entry than "
271                        + "config_autoBrightnessLevels (size " + lux.length + ") "
272                        + "which must be strictly increasing.  "
273                        + "Auto-brightness will be disabled.");
274                mUseSoftwareAutoBrightnessConfig = false;
275            } else {
276                if (screenBrightness[0] < screenBrightnessRangeMinimum) {
277                    screenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightness[0]);
278                }
279                mAutomaticBrightnessController = new AutomaticBrightnessController(this,
280                        handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
281                        lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
282                        mScreenBrightnessRangeMaximum);
283            }
284        }
285
286        mScreenBrightnessRangeMinimum = screenBrightnessRangeMinimum;
287
288        mElectronBeamFadesConfig = resources.getBoolean(
289                com.android.internal.R.bool.config_animateScreenLights);
290
291        if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
292            mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
293            if (mProximitySensor != null) {
294                mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
295                        TYPICAL_PROXIMITY_THRESHOLD);
296            }
297        }
298
299    }
300
301    /**
302     * Returns true if the proximity sensor screen-off function is available.
303     */
304    public boolean isProximitySensorAvailable() {
305        return mProximitySensor != null;
306    }
307
308    /**
309     * Requests a new power state.
310     * The controller makes a copy of the provided object and then
311     * begins adjusting the power state to match what was requested.
312     *
313     * @param request The requested power state.
314     * @param waitForNegativeProximity If true, issues a request to wait for
315     * negative proximity before turning the screen back on, assuming the screen
316     * was turned off by the proximity sensor.
317     * @return True if display is ready, false if there are important changes that must
318     * be made asynchronously (such as turning the screen on), in which case the caller
319     * should grab a wake lock, watch for {@link Callbacks#onStateChanged()} then try
320     * the request again later until the state converges.
321     */
322    public boolean requestPowerState(DisplayPowerRequest request,
323            boolean waitForNegativeProximity) {
324        if (DEBUG) {
325            Slog.d(TAG, "requestPowerState: "
326                    + request + ", waitForNegativeProximity=" + waitForNegativeProximity);
327        }
328
329        synchronized (mLock) {
330            boolean changed = false;
331
332            if (waitForNegativeProximity
333                    && !mPendingWaitForNegativeProximityLocked) {
334                mPendingWaitForNegativeProximityLocked = true;
335                changed = true;
336            }
337
338            if (mPendingRequestLocked == null) {
339                mPendingRequestLocked = new DisplayPowerRequest(request);
340                changed = true;
341            } else if (!mPendingRequestLocked.equals(request)) {
342                mPendingRequestLocked.copyFrom(request);
343                changed = true;
344            }
345
346            if (changed) {
347                mDisplayReadyLocked = false;
348            }
349
350            if (changed && !mPendingRequestChangedLocked) {
351                mPendingRequestChangedLocked = true;
352                sendUpdatePowerStateLocked();
353            }
354
355            return mDisplayReadyLocked;
356        }
357    }
358
359    private void sendUpdatePowerState() {
360        synchronized (mLock) {
361            sendUpdatePowerStateLocked();
362        }
363    }
364
365    private void sendUpdatePowerStateLocked() {
366        if (!mPendingUpdatePowerStateLocked) {
367            mPendingUpdatePowerStateLocked = true;
368            Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
369            msg.setAsynchronous(true);
370            mHandler.sendMessage(msg);
371        }
372    }
373
374    private void initialize() {
375        // Initialize the power state object for the default display.
376        // In the future, we might manage multiple displays independently.
377        mPowerState = new DisplayPowerState(mBlanker,
378                mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
379                new ElectronBeam(Display.DEFAULT_DISPLAY));
380
381        mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
382                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
383        mElectronBeamOnAnimator.setDuration(ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS);
384        mElectronBeamOnAnimator.addListener(mAnimatorListener);
385
386        mElectronBeamOffAnimator = ObjectAnimator.ofFloat(
387                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 1.0f, 0.0f);
388        mElectronBeamOffAnimator.setDuration(ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS);
389        mElectronBeamOffAnimator.addListener(mAnimatorListener);
390
391        mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
392                mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
393
394        // Initialize screen state for battery stats.
395        try {
396            mBatteryStats.noteScreenState(mPowerState.getScreenState());
397            mBatteryStats.noteScreenBrightness(mPowerState.getScreenBrightness());
398        } catch (RemoteException ex) {
399            // same process
400        }
401    }
402
403    private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
404        @Override
405        public void onAnimationStart(Animator animation) {
406        }
407        @Override
408        public void onAnimationEnd(Animator animation) {
409            sendUpdatePowerState();
410        }
411        @Override
412        public void onAnimationRepeat(Animator animation) {
413        }
414        @Override
415        public void onAnimationCancel(Animator animation) {
416        }
417    };
418
419    private void updatePowerState() {
420        // Update the power state request.
421        final boolean mustNotify;
422        boolean mustInitialize = false;
423        boolean wasDimOrDoze = false;
424        boolean autoBrightnessAdjustmentChanged = false;
425
426        synchronized (mLock) {
427            mPendingUpdatePowerStateLocked = false;
428            if (mPendingRequestLocked == null) {
429                return; // wait until first actual power request
430            }
431
432            if (mPowerRequest == null) {
433                mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
434                mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
435                mPendingWaitForNegativeProximityLocked = false;
436                mPendingRequestChangedLocked = false;
437                mustInitialize = true;
438            } else if (mPendingRequestChangedLocked) {
439                wasDimOrDoze = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM
440                        || mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE);
441                autoBrightnessAdjustmentChanged = (mPowerRequest.screenAutoBrightnessAdjustment
442                        != mPendingRequestLocked.screenAutoBrightnessAdjustment);
443                mPowerRequest.copyFrom(mPendingRequestLocked);
444                mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
445                mPendingWaitForNegativeProximityLocked = false;
446                mPendingRequestChangedLocked = false;
447                mDisplayReadyLocked = false;
448            }
449
450            mustNotify = !mDisplayReadyLocked;
451        }
452
453        // Initialize things the first time the power state is changed.
454        if (mustInitialize) {
455            initialize();
456        }
457
458        // Apply the proximity sensor.
459        if (mProximitySensor != null) {
460            if (mPowerRequest.useProximitySensor
461                    && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
462                setProximitySensorEnabled(true);
463                if (!mScreenOffBecauseOfProximity
464                        && mProximity == PROXIMITY_POSITIVE) {
465                    mScreenOffBecauseOfProximity = true;
466                    sendOnProximityPositiveWithWakelock();
467                }
468            } else if (mWaitingForNegativeProximity
469                    && mScreenOffBecauseOfProximity
470                    && mProximity == PROXIMITY_POSITIVE
471                    && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
472                setProximitySensorEnabled(true);
473            } else {
474                setProximitySensorEnabled(false);
475                mWaitingForNegativeProximity = false;
476            }
477            if (mScreenOffBecauseOfProximity
478                    && mProximity != PROXIMITY_POSITIVE) {
479                mScreenOffBecauseOfProximity = false;
480                sendOnProximityNegativeWithWakelock();
481            }
482        } else {
483            mWaitingForNegativeProximity = false;
484        }
485
486        // Turn on the light sensor if needed.
487        if (mAutomaticBrightnessController != null) {
488            mAutomaticBrightnessController.updatePowerState(mPowerRequest);
489        }
490
491        // Set the screen brightness.
492        if (mPowerRequest.wantScreenOnAny()) {
493            int target;
494            boolean slow;
495            int screenAutoBrightness = mAutomaticBrightnessController != null ?
496                    mAutomaticBrightnessController.getAutomaticScreenBrightness() : -1;
497            if (screenAutoBrightness >= 0 && mPowerRequest.useAutoBrightness) {
498                // Use current auto-brightness value.
499                target = screenAutoBrightness;
500                slow = mUsingScreenAutoBrightness && !autoBrightnessAdjustmentChanged;
501                mUsingScreenAutoBrightness = true;
502            } else {
503                // Light sensor is disabled or not ready yet.
504                // Use the current brightness setting from the request, which is expected
505                // provide a nominal default value for the case where auto-brightness
506                // is not ready yet.
507                target = mPowerRequest.screenBrightness;
508                slow = false;
509                mUsingScreenAutoBrightness = false;
510            }
511            if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE) {
512                // Dim quickly to the doze state.
513                target = mScreenBrightnessDozeConfig;
514                slow = false;
515            } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
516                // Dim quickly by at least some minimum amount.
517                target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
518                        mScreenBrightnessDimConfig);
519                slow = false;
520            } else if (wasDimOrDoze) {
521                // Brighten quickly.
522                slow = false;
523            }
524            // If low power mode is enabled, brightness level
525            // would be scaled down to half
526            if (mPowerRequest.lowPowerMode) {
527                target = target/2;
528            }
529            animateScreenBrightness(clampScreenBrightness(target),
530                    slow ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
531        } else {
532            // Screen is off.  Don't bother changing the brightness.
533            mUsingScreenAutoBrightness = false;
534        }
535
536        // Animate the screen on or off unless blocked.
537        if (mScreenOffBecauseOfProximity) {
538            // Screen off due to proximity.
539            setScreenState(Display.STATE_OFF);
540            unblockScreenOn();
541        } else if (mPowerRequest.wantScreenOnAny()) {
542            // Want screen on.
543            // Wait for previous off animation to complete beforehand.
544            // It is relatively short but if we cancel it and switch to the
545            // on animation immediately then the results are pretty ugly.
546            if (!mElectronBeamOffAnimator.isStarted()) {
547                // Turn the screen on.  The contents of the screen may not yet
548                // be visible if the electron beam has not been dismissed because
549                // its last frame of animation is solid black.
550                setScreenState(mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE
551                        ? Display.STATE_DOZING : Display.STATE_ON);
552
553                if (mPowerRequest.blockScreenOn
554                        && mPowerState.getElectronBeamLevel() == 0.0f) {
555                    blockScreenOn();
556                } else {
557                    unblockScreenOn();
558                    if (USE_ELECTRON_BEAM_ON_ANIMATION) {
559                        if (!mElectronBeamOnAnimator.isStarted()) {
560                            if (mPowerState.getElectronBeamLevel() == 1.0f) {
561                                mPowerState.dismissElectronBeam();
562                            } else if (mPowerState.prepareElectronBeam(
563                                    mElectronBeamFadesConfig ?
564                                            ElectronBeam.MODE_FADE :
565                                                    ElectronBeam.MODE_WARM_UP)) {
566                                mElectronBeamOnAnimator.start();
567                            } else {
568                                mElectronBeamOnAnimator.end();
569                            }
570                        }
571                    } else {
572                        mPowerState.setElectronBeamLevel(1.0f);
573                        mPowerState.dismissElectronBeam();
574                    }
575                }
576            }
577        } else {
578            // Want screen off.
579            // Wait for previous on animation to complete beforehand.
580            unblockScreenOn();
581            if (!mElectronBeamOnAnimator.isStarted()) {
582                if (!mElectronBeamOffAnimator.isStarted()) {
583                    if (mPowerState.getElectronBeamLevel() == 0.0f) {
584                        setScreenState(Display.STATE_OFF);
585                    } else if (mPowerState.prepareElectronBeam(
586                            mElectronBeamFadesConfig ?
587                                    ElectronBeam.MODE_FADE :
588                                            ElectronBeam.MODE_COOL_DOWN)
589                            && mPowerState.getScreenState() != Display.STATE_OFF) {
590                        mElectronBeamOffAnimator.start();
591                    } else {
592                        mElectronBeamOffAnimator.end();
593                    }
594                }
595            }
596        }
597
598        // Report whether the display is ready for use.
599        // We mostly care about the screen state here, ignoring brightness changes
600        // which will be handled asynchronously.
601        if (mustNotify
602                && !mScreenOnWasBlocked
603                && !mElectronBeamOnAnimator.isStarted()
604                && !mElectronBeamOffAnimator.isStarted()
605                && mPowerState.waitUntilClean(mCleanListener)) {
606            synchronized (mLock) {
607                if (!mPendingRequestChangedLocked) {
608                    mDisplayReadyLocked = true;
609
610                    if (DEBUG) {
611                        Slog.d(TAG, "Display ready!");
612                    }
613                }
614            }
615            sendOnStateChangedWithWakelock();
616        }
617    }
618
619    @Override
620    public void updateBrightness() {
621        sendUpdatePowerState();
622    }
623
624    private void blockScreenOn() {
625        if (!mScreenOnWasBlocked) {
626            mScreenOnWasBlocked = true;
627            mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
628            if (DEBUG) {
629                Slog.d(TAG, "Blocked screen on.");
630            }
631        }
632    }
633
634    private void unblockScreenOn() {
635        if (mScreenOnWasBlocked) {
636            mScreenOnWasBlocked = false;
637            long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
638            if (delay > 1000 || DEBUG) {
639                Slog.d(TAG, "Unblocked screen on after " + delay + " ms");
640            }
641        }
642    }
643
644    private void setScreenState(int state) {
645        if (mPowerState.getScreenState() != state) {
646            mPowerState.setScreenState(state);
647            try {
648                mBatteryStats.noteScreenState(state);
649            } catch (RemoteException ex) {
650                // same process
651            }
652        }
653    }
654
655    private int clampScreenBrightness(int value) {
656        return MathUtils.constrain(
657                value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
658    }
659
660    private void animateScreenBrightness(int target, int rate) {
661        if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
662            try {
663                mBatteryStats.noteScreenBrightness(target);
664            } catch (RemoteException ex) {
665                // same process
666            }
667        }
668    }
669
670    private final Runnable mCleanListener = new Runnable() {
671        @Override
672        public void run() {
673            sendUpdatePowerState();
674        }
675    };
676
677    private void setProximitySensorEnabled(boolean enable) {
678        if (enable) {
679            if (!mProximitySensorEnabled) {
680                // Register the listener.
681                // Proximity sensor state already cleared initially.
682                mProximitySensorEnabled = true;
683                mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
684                        SensorManager.SENSOR_DELAY_NORMAL, mHandler);
685            }
686        } else {
687            if (mProximitySensorEnabled) {
688                // Unregister the listener.
689                // Clear the proximity sensor state for next time.
690                mProximitySensorEnabled = false;
691                mProximity = PROXIMITY_UNKNOWN;
692                mPendingProximity = PROXIMITY_UNKNOWN;
693                mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
694                mSensorManager.unregisterListener(mProximitySensorListener);
695                clearPendingProximityDebounceTime(); // release wake lock (must be last)
696            }
697        }
698    }
699
700    private void handleProximitySensorEvent(long time, boolean positive) {
701        if (mProximitySensorEnabled) {
702            if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
703                return; // no change
704            }
705            if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
706                return; // no change
707            }
708
709            // Only accept a proximity sensor reading if it remains
710            // stable for the entire debounce delay.  We hold a wake lock while
711            // debouncing the sensor.
712            mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
713            if (positive) {
714                mPendingProximity = PROXIMITY_POSITIVE;
715                setPendingProximityDebounceTime(
716                        time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); // acquire wake lock
717            } else {
718                mPendingProximity = PROXIMITY_NEGATIVE;
719                setPendingProximityDebounceTime(
720                        time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); // acquire wake lock
721            }
722
723            // Debounce the new sensor reading.
724            debounceProximitySensor();
725        }
726    }
727
728    private void debounceProximitySensor() {
729        if (mProximitySensorEnabled
730                && mPendingProximity != PROXIMITY_UNKNOWN
731                && mPendingProximityDebounceTime >= 0) {
732            final long now = SystemClock.uptimeMillis();
733            if (mPendingProximityDebounceTime <= now) {
734                // Sensor reading accepted.  Apply the change then release the wake lock.
735                mProximity = mPendingProximity;
736                updatePowerState();
737                clearPendingProximityDebounceTime(); // release wake lock (must be last)
738            } else {
739                // Need to wait a little longer.
740                // Debounce again later.  We continue holding a wake lock while waiting.
741                Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
742                msg.setAsynchronous(true);
743                mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
744            }
745        }
746    }
747
748    private void clearPendingProximityDebounceTime() {
749        if (mPendingProximityDebounceTime >= 0) {
750            mPendingProximityDebounceTime = -1;
751            mCallbacks.releaseSuspendBlocker(); // release wake lock
752        }
753    }
754
755    private void setPendingProximityDebounceTime(long debounceTime) {
756        if (mPendingProximityDebounceTime < 0) {
757            mCallbacks.acquireSuspendBlocker(); // acquire wake lock
758        }
759        mPendingProximityDebounceTime = debounceTime;
760    }
761
762    private void sendOnStateChangedWithWakelock() {
763        mCallbacks.acquireSuspendBlocker();
764        mHandler.post(mOnStateChangedRunnable);
765    }
766
767    private final Runnable mOnStateChangedRunnable = new Runnable() {
768        @Override
769        public void run() {
770            mCallbacks.onStateChanged();
771            mCallbacks.releaseSuspendBlocker();
772        }
773    };
774
775    private void sendOnProximityPositiveWithWakelock() {
776        mCallbacks.acquireSuspendBlocker();
777        mHandler.post(mOnProximityPositiveRunnable);
778    }
779
780    private final Runnable mOnProximityPositiveRunnable = new Runnable() {
781        @Override
782        public void run() {
783            mCallbacks.onProximityPositive();
784            mCallbacks.releaseSuspendBlocker();
785        }
786    };
787
788    private void sendOnProximityNegativeWithWakelock() {
789        mCallbacks.acquireSuspendBlocker();
790        mHandler.post(mOnProximityNegativeRunnable);
791    }
792
793    private final Runnable mOnProximityNegativeRunnable = new Runnable() {
794        @Override
795        public void run() {
796            mCallbacks.onProximityNegative();
797            mCallbacks.releaseSuspendBlocker();
798        }
799    };
800
801    public void dump(final PrintWriter pw) {
802        synchronized (mLock) {
803            pw.println();
804            pw.println("Display Power Controller Locked State:");
805            pw.println("  mDisplayReadyLocked=" + mDisplayReadyLocked);
806            pw.println("  mPendingRequestLocked=" + mPendingRequestLocked);
807            pw.println("  mPendingRequestChangedLocked=" + mPendingRequestChangedLocked);
808            pw.println("  mPendingWaitForNegativeProximityLocked="
809                    + mPendingWaitForNegativeProximityLocked);
810            pw.println("  mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked);
811        }
812
813        pw.println();
814        pw.println("Display Power Controller Configuration:");
815        pw.println("  mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
816        pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
817        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
818        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
819        pw.println("  mUseSoftwareAutoBrightnessConfig="
820                + mUseSoftwareAutoBrightnessConfig);
821
822        mHandler.runWithScissors(new Runnable() {
823            @Override
824            public void run() {
825                dumpLocal(pw);
826            }
827        }, 1000);
828    }
829
830    private void dumpLocal(PrintWriter pw) {
831        pw.println();
832        pw.println("Display Power Controller Thread State:");
833        pw.println("  mPowerRequest=" + mPowerRequest);
834        pw.println("  mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
835
836        pw.println("  mProximitySensor=" + mProximitySensor);
837        pw.println("  mProximitySensorEnabled=" + mProximitySensorEnabled);
838        pw.println("  mProximityThreshold=" + mProximityThreshold);
839        pw.println("  mProximity=" + proximityToString(mProximity));
840        pw.println("  mPendingProximity=" + proximityToString(mPendingProximity));
841        pw.println("  mPendingProximityDebounceTime="
842                + TimeUtils.formatUptime(mPendingProximityDebounceTime));
843        pw.println("  mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
844        pw.println("  mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
845
846        if (mElectronBeamOnAnimator != null) {
847            pw.println("  mElectronBeamOnAnimator.isStarted()=" +
848                    mElectronBeamOnAnimator.isStarted());
849        }
850        if (mElectronBeamOffAnimator != null) {
851            pw.println("  mElectronBeamOffAnimator.isStarted()=" +
852                    mElectronBeamOffAnimator.isStarted());
853        }
854
855        if (mPowerState != null) {
856            mPowerState.dump(pw);
857        }
858
859        if (mAutomaticBrightnessController != null) {
860            mAutomaticBrightnessController.dump(pw);
861        }
862
863    }
864
865    private static String proximityToString(int state) {
866        switch (state) {
867            case PROXIMITY_UNKNOWN:
868                return "Unknown";
869            case PROXIMITY_NEGATIVE:
870                return "Negative";
871            case PROXIMITY_POSITIVE:
872                return "Positive";
873            default:
874                return Integer.toString(state);
875        }
876    }
877
878    private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
879        try {
880            final int n = brightness.length;
881            float[] x = new float[n];
882            float[] y = new float[n];
883            y[0] = normalizeAbsoluteBrightness(brightness[0]);
884            for (int i = 1; i < n; i++) {
885                x[i] = lux[i - 1];
886                y[i] = normalizeAbsoluteBrightness(brightness[i]);
887            }
888
889            Spline spline = Spline.createMonotoneCubicSpline(x, y);
890            if (DEBUG) {
891                Slog.d(TAG, "Auto-brightness spline: " + spline);
892                for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
893                    Slog.d(TAG, String.format("  %7.1f: %7.1f", v, spline.interpolate(v)));
894                }
895            }
896            return spline;
897        } catch (IllegalArgumentException ex) {
898            Slog.e(TAG, "Could not create auto-brightness spline.", ex);
899            return null;
900        }
901    }
902
903    private static float normalizeAbsoluteBrightness(int value) {
904        return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
905    }
906
907    private static int clampAbsoluteBrightness(int value) {
908        return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
909    }
910
911    private final class DisplayControllerHandler extends Handler {
912        public DisplayControllerHandler(Looper looper) {
913            super(looper, null, true /*async*/);
914        }
915
916        @Override
917        public void handleMessage(Message msg) {
918            switch (msg.what) {
919                case MSG_UPDATE_POWER_STATE:
920                    updatePowerState();
921                    break;
922
923                case MSG_PROXIMITY_SENSOR_DEBOUNCED:
924                    debounceProximitySensor();
925                    break;
926            }
927        }
928    }
929
930    private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
931        @Override
932        public void onSensorChanged(SensorEvent event) {
933            if (mProximitySensorEnabled) {
934                final long time = SystemClock.uptimeMillis();
935                final float distance = event.values[0];
936                boolean positive = distance >= 0.0f && distance < mProximityThreshold;
937                handleProximitySensorEvent(time, positive);
938            }
939        }
940
941        @Override
942        public void onAccuracyChanged(Sensor sensor, int accuracy) {
943            // Not used.
944        }
945    };
946}
947