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