DisplayPowerController.java revision 5c8ea084e609ecce17a038eb6b09fe118a81d700
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    // Remembers whether certain kinds of brightness adjustments
217    // were recently applied so that we can decide how to transition.
218    private boolean mAppliedAutoBrightness;
219    private boolean mAppliedDimming;
220    private boolean mAppliedLowPower;
221
222    // The controller for the automatic brightness level.
223    private AutomaticBrightnessController mAutomaticBrightnessController;
224
225    // Animators.
226    private ObjectAnimator mElectronBeamOnAnimator;
227    private ObjectAnimator mElectronBeamOffAnimator;
228    private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
229
230    /**
231     * Creates the display power controller.
232     */
233    public DisplayPowerController(Context context,
234            DisplayPowerCallbacks callbacks, Handler handler,
235            SensorManager sensorManager, DisplayBlanker blanker) {
236        mHandler = new DisplayControllerHandler(handler.getLooper());
237        mCallbacks = callbacks;
238
239        mBatteryStats = BatteryStatsService.getService();
240        mLights = LocalServices.getService(LightsManager.class);
241        mSensorManager = sensorManager;
242        mBlanker = blanker;
243
244        final Resources resources = context.getResources();
245
246        mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger(
247                com.android.internal.R.integer.config_screenBrightnessDoze));
248
249        mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
250                com.android.internal.R.integer.config_screenBrightnessDim));
251
252        int screenBrightnessRangeMinimum = clampAbsoluteBrightness(Math.min(resources.getInteger(
253                com.android.internal.R.integer.config_screenBrightnessSettingMinimum),
254                mScreenBrightnessDimConfig));
255
256        mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
257
258        mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
259                com.android.internal.R.bool.config_automatic_brightness_available);
260        if (mUseSoftwareAutoBrightnessConfig) {
261            int[] lux = resources.getIntArray(
262                    com.android.internal.R.array.config_autoBrightnessLevels);
263            int[] screenBrightness = resources.getIntArray(
264                    com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
265            int lightSensorWarmUpTimeConfig = resources.getInteger(
266                    com.android.internal.R.integer.config_lightSensorWarmupTime);
267
268            Spline screenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
269            if (screenAutoBrightnessSpline == null) {
270                Slog.e(TAG, "Error in config.xml.  config_autoBrightnessLcdBacklightValues "
271                        + "(size " + screenBrightness.length + ") "
272                        + "must be monotic and have exactly one more entry than "
273                        + "config_autoBrightnessLevels (size " + lux.length + ") "
274                        + "which must be strictly increasing.  "
275                        + "Auto-brightness will be disabled.");
276                mUseSoftwareAutoBrightnessConfig = false;
277            } else {
278                if (screenBrightness[0] < screenBrightnessRangeMinimum) {
279                    screenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightness[0]);
280                }
281                mAutomaticBrightnessController = new AutomaticBrightnessController(this,
282                        handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
283                        lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
284                        mScreenBrightnessRangeMaximum);
285            }
286        }
287
288        mScreenBrightnessRangeMinimum = screenBrightnessRangeMinimum;
289
290        mElectronBeamFadesConfig = resources.getBoolean(
291                com.android.internal.R.bool.config_animateScreenLights);
292
293        if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
294            mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
295            if (mProximitySensor != null) {
296                mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
297                        TYPICAL_PROXIMITY_THRESHOLD);
298            }
299        }
300
301    }
302
303    /**
304     * Returns true if the proximity sensor screen-off function is available.
305     */
306    public boolean isProximitySensorAvailable() {
307        return mProximitySensor != null;
308    }
309
310    /**
311     * Requests a new power state.
312     * The controller makes a copy of the provided object and then
313     * begins adjusting the power state to match what was requested.
314     *
315     * @param request The requested power state.
316     * @param waitForNegativeProximity If true, issues a request to wait for
317     * negative proximity before turning the screen back on, assuming the screen
318     * was turned off by the proximity sensor.
319     * @return True if display is ready, false if there are important changes that must
320     * be made asynchronously (such as turning the screen on), in which case the caller
321     * should grab a wake lock, watch for {@link Callbacks#onStateChanged()} then try
322     * the request again later until the state converges.
323     */
324    public boolean requestPowerState(DisplayPowerRequest request,
325            boolean waitForNegativeProximity) {
326        if (DEBUG) {
327            Slog.d(TAG, "requestPowerState: "
328                    + request + ", waitForNegativeProximity=" + waitForNegativeProximity);
329        }
330
331        synchronized (mLock) {
332            boolean changed = false;
333
334            if (waitForNegativeProximity
335                    && !mPendingWaitForNegativeProximityLocked) {
336                mPendingWaitForNegativeProximityLocked = true;
337                changed = true;
338            }
339
340            if (mPendingRequestLocked == null) {
341                mPendingRequestLocked = new DisplayPowerRequest(request);
342                changed = true;
343            } else if (!mPendingRequestLocked.equals(request)) {
344                mPendingRequestLocked.copyFrom(request);
345                changed = true;
346            }
347
348            if (changed) {
349                mDisplayReadyLocked = false;
350            }
351
352            if (changed && !mPendingRequestChangedLocked) {
353                mPendingRequestChangedLocked = true;
354                sendUpdatePowerStateLocked();
355            }
356
357            return mDisplayReadyLocked;
358        }
359    }
360
361    private void sendUpdatePowerState() {
362        synchronized (mLock) {
363            sendUpdatePowerStateLocked();
364        }
365    }
366
367    private void sendUpdatePowerStateLocked() {
368        if (!mPendingUpdatePowerStateLocked) {
369            mPendingUpdatePowerStateLocked = true;
370            Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
371            msg.setAsynchronous(true);
372            mHandler.sendMessage(msg);
373        }
374    }
375
376    private void initialize() {
377        // Initialize the power state object for the default display.
378        // In the future, we might manage multiple displays independently.
379        mPowerState = new DisplayPowerState(mBlanker,
380                mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
381                new ElectronBeam(Display.DEFAULT_DISPLAY));
382
383        mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
384                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
385        mElectronBeamOnAnimator.setDuration(ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS);
386        mElectronBeamOnAnimator.addListener(mAnimatorListener);
387
388        mElectronBeamOffAnimator = ObjectAnimator.ofFloat(
389                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 1.0f, 0.0f);
390        mElectronBeamOffAnimator.setDuration(ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS);
391        mElectronBeamOffAnimator.addListener(mAnimatorListener);
392
393        mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
394                mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
395        mScreenBrightnessRampAnimator.setListener(mRampAnimatorListener);
396
397        // Initialize screen state for battery stats.
398        try {
399            mBatteryStats.noteScreenState(mPowerState.getScreenState());
400            mBatteryStats.noteScreenBrightness(mPowerState.getScreenBrightness());
401        } catch (RemoteException ex) {
402            // same process
403        }
404    }
405
406    private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
407        @Override
408        public void onAnimationStart(Animator animation) {
409        }
410        @Override
411        public void onAnimationEnd(Animator animation) {
412            sendUpdatePowerState();
413        }
414        @Override
415        public void onAnimationRepeat(Animator animation) {
416        }
417        @Override
418        public void onAnimationCancel(Animator animation) {
419        }
420    };
421
422    private final RampAnimator.Listener mRampAnimatorListener = new RampAnimator.Listener() {
423        @Override
424        public void onAnimationEnd() {
425            sendUpdatePowerState();
426        }
427    };
428
429    private void updatePowerState() {
430        // Update the power state request.
431        final boolean mustNotify;
432        boolean mustInitialize = false;
433        boolean autoBrightnessAdjustmentChanged = false;
434
435        synchronized (mLock) {
436            mPendingUpdatePowerStateLocked = false;
437            if (mPendingRequestLocked == null) {
438                return; // wait until first actual power request
439            }
440
441            if (mPowerRequest == null) {
442                mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
443                mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
444                mPendingWaitForNegativeProximityLocked = false;
445                mPendingRequestChangedLocked = false;
446                mustInitialize = true;
447            } else if (mPendingRequestChangedLocked) {
448                autoBrightnessAdjustmentChanged = (mPowerRequest.screenAutoBrightnessAdjustment
449                        != mPendingRequestLocked.screenAutoBrightnessAdjustment);
450                mPowerRequest.copyFrom(mPendingRequestLocked);
451                mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
452                mPendingWaitForNegativeProximityLocked = false;
453                mPendingRequestChangedLocked = false;
454                mDisplayReadyLocked = false;
455            }
456
457            mustNotify = !mDisplayReadyLocked;
458        }
459
460        // Initialize things the first time the power state is changed.
461        if (mustInitialize) {
462            initialize();
463        }
464
465        // Compute the basic display state using the policy.
466        // We might override this below based on other factors.
467        int state;
468        int brightness = PowerManager.BRIGHTNESS_DEFAULT;
469        switch (mPowerRequest.policy) {
470            case DisplayPowerRequest.POLICY_OFF:
471                state = Display.STATE_OFF;
472                break;
473            case DisplayPowerRequest.POLICY_DOZE:
474                if (mPowerRequest.dozeScreenState != Display.STATE_UNKNOWN) {
475                    state = mPowerRequest.dozeScreenState;
476                } else {
477                    state = Display.STATE_DOZE;
478                }
479                brightness = mPowerRequest.dozeScreenBrightness;
480                break;
481            case DisplayPowerRequest.POLICY_DIM:
482            case DisplayPowerRequest.POLICY_BRIGHT:
483            default:
484                state = Display.STATE_ON;
485                break;
486        }
487
488        // Apply the proximity sensor.
489        if (mProximitySensor != null) {
490            if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) {
491                setProximitySensorEnabled(true);
492                if (!mScreenOffBecauseOfProximity
493                        && mProximity == PROXIMITY_POSITIVE) {
494                    mScreenOffBecauseOfProximity = true;
495                    sendOnProximityPositiveWithWakelock();
496                }
497            } else if (mWaitingForNegativeProximity
498                    && mScreenOffBecauseOfProximity
499                    && mProximity == PROXIMITY_POSITIVE
500                    && state != Display.STATE_OFF) {
501                setProximitySensorEnabled(true);
502            } else {
503                setProximitySensorEnabled(false);
504                mWaitingForNegativeProximity = false;
505            }
506            if (mScreenOffBecauseOfProximity
507                    && mProximity != PROXIMITY_POSITIVE) {
508                mScreenOffBecauseOfProximity = false;
509                sendOnProximityNegativeWithWakelock();
510            }
511        } else {
512            mWaitingForNegativeProximity = false;
513        }
514        if (mScreenOffBecauseOfProximity) {
515            state = Display.STATE_OFF;
516        }
517
518        // Use zero brightness when screen is off.
519        if (state == Display.STATE_OFF) {
520            brightness = PowerManager.BRIGHTNESS_OFF;
521        }
522
523        // Use default brightness when dozing unless overridden.
524        if (brightness < 0 && (state == Display.STATE_DOZE
525                || state == Display.STATE_DOZE_SUSPEND)) {
526            brightness = mScreenBrightnessDozeConfig;
527        }
528
529        // Configure auto-brightness.
530        boolean autoBrightnessEnabled = false;
531        if (mAutomaticBrightnessController != null) {
532            autoBrightnessEnabled = mPowerRequest.useAutoBrightness
533                    && state == Display.STATE_ON && brightness < 0;
534            mAutomaticBrightnessController.configure(autoBrightnessEnabled,
535                    mPowerRequest.screenAutoBrightnessAdjustment);
536        }
537
538        // Apply auto-brightness.
539        boolean slowChange = false;
540        if (brightness < 0) {
541            if (autoBrightnessEnabled) {
542                brightness = mAutomaticBrightnessController.getAutomaticScreenBrightness();
543            }
544            if (brightness >= 0) {
545                // Use current auto-brightness value and slowly adjust to changes.
546                brightness = clampScreenBrightness(brightness);
547                if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
548                    slowChange = true; // slowly adapt to auto-brightness
549                }
550                mAppliedAutoBrightness = true;
551            } else {
552                mAppliedAutoBrightness = false;
553            }
554        } else {
555            mAppliedAutoBrightness = false;
556        }
557
558        // Apply manual brightness.
559        // Use the current brightness setting from the request, which is expected
560        // provide a nominal default value for the case where auto-brightness
561        // is not ready yet.
562        if (brightness < 0) {
563            brightness = clampScreenBrightness(mPowerRequest.screenBrightness);
564        }
565
566        // Apply dimming by at least some minimum amount when user activity
567        // timeout is about to expire.
568        if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
569            if (brightness > mScreenBrightnessRangeMinimum) {
570                brightness = Math.max(Math.min(brightness - SCREEN_DIM_MINIMUM_REDUCTION,
571                        mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum);
572            }
573            if (!mAppliedDimming) {
574                slowChange = false;
575            }
576            mAppliedDimming = true;
577        }
578
579        // If low power mode is enabled, cut the brightness level by half
580        // as long as it is above the minimum threshold.
581        if (mPowerRequest.lowPowerMode) {
582            if (brightness > mScreenBrightnessRangeMinimum) {
583                brightness = Math.max(brightness / 2, mScreenBrightnessRangeMinimum);
584            }
585            if (!mAppliedLowPower) {
586                slowChange = false;
587            }
588            mAppliedLowPower = true;
589        }
590
591        // Animate the screen brightness when the screen is on.
592        if (state != Display.STATE_OFF) {
593            animateScreenBrightness(brightness, slowChange
594                    ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
595        }
596
597        // Animate the screen on or off unless blocked.
598        if (state == Display.STATE_ON) {
599            // Want screen on.
600            // Wait for previous off animation to complete beforehand.
601            // It is relatively short but if we cancel it and switch to the
602            // on animation immediately then the results are pretty ugly.
603            if (!mElectronBeamOffAnimator.isStarted()) {
604                // Turn the screen on.  The contents of the screen may not yet
605                // be visible if the electron beam has not been dismissed because
606                // its last frame of animation is solid black.
607                setScreenState(Display.STATE_ON);
608                if (mPowerRequest.blockScreenOn
609                        && mPowerState.getElectronBeamLevel() == 0.0f) {
610                    blockScreenOn();
611                } else {
612                    unblockScreenOn();
613                    if (USE_ELECTRON_BEAM_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {
614                        // Perform screen on animation.
615                        if (!mElectronBeamOnAnimator.isStarted()) {
616                            if (mPowerState.getElectronBeamLevel() == 1.0f) {
617                                mPowerState.dismissElectronBeam();
618                            } else if (mPowerState.prepareElectronBeam(
619                                    mElectronBeamFadesConfig ?
620                                            ElectronBeam.MODE_FADE :
621                                                    ElectronBeam.MODE_WARM_UP)) {
622                                mElectronBeamOnAnimator.start();
623                            } else {
624                                mElectronBeamOnAnimator.end();
625                            }
626                        }
627                    } else {
628                        // Skip screen on animation.
629                        mPowerState.setElectronBeamLevel(1.0f);
630                        mPowerState.dismissElectronBeam();
631                    }
632                }
633            }
634        } else if (state == Display.STATE_DOZE) {
635            // Want screen dozing.
636            // Wait for brightness animation to complete beforehand when entering doze
637            // from screen on.
638            unblockScreenOn();
639            if (!mScreenBrightnessRampAnimator.isAnimating()
640                    || mPowerState.getScreenState() != Display.STATE_ON) {
641                // Set screen state and dismiss the black surface without fanfare.
642                setScreenState(state);
643                mPowerState.setElectronBeamLevel(1.0f);
644                mPowerState.dismissElectronBeam();
645            }
646        } else if (state == Display.STATE_DOZE_SUSPEND) {
647            // Want screen dozing and suspended.
648            // Wait for brightness animation to complete beforehand unless already
649            // suspended because we may not be able to change it after suspension.
650            unblockScreenOn();
651            if (!mScreenBrightnessRampAnimator.isAnimating()
652                    || mPowerState.getScreenState() == Display.STATE_DOZE_SUSPEND) {
653                // Set screen state and dismiss the black surface without fanfare.
654                setScreenState(state);
655                mPowerState.setElectronBeamLevel(1.0f);
656                mPowerState.dismissElectronBeam();
657            }
658        } else {
659            // Want screen off.
660            // Wait for previous on animation to complete beforehand.
661            unblockScreenOn();
662            if (!mElectronBeamOnAnimator.isStarted()) {
663                if (mPowerRequest.policy == DisplayPowerRequest.POLICY_OFF) {
664                    // Perform screen off animation.
665                    if (!mElectronBeamOffAnimator.isStarted()) {
666                        if (mPowerState.getElectronBeamLevel() == 0.0f) {
667                            setScreenState(Display.STATE_OFF);
668                        } else if (mPowerState.prepareElectronBeam(
669                                mElectronBeamFadesConfig ?
670                                        ElectronBeam.MODE_FADE :
671                                                ElectronBeam.MODE_COOL_DOWN)
672                                && mPowerState.getScreenState() != Display.STATE_OFF) {
673                            mElectronBeamOffAnimator.start();
674                        } else {
675                            mElectronBeamOffAnimator.end();
676                        }
677                    }
678                } else {
679                    // Skip screen off animation.
680                    setScreenState(Display.STATE_OFF);
681                }
682            }
683        }
684
685        // Report whether the display is ready for use.
686        // We mostly care about the screen state here, ignoring brightness changes
687        // which will be handled asynchronously.
688        if (mustNotify
689                && !mScreenOnWasBlocked
690                && !mElectronBeamOnAnimator.isStarted()
691                && !mElectronBeamOffAnimator.isStarted()
692                && !mScreenBrightnessRampAnimator.isAnimating()
693                && mPowerState.waitUntilClean(mCleanListener)) {
694            synchronized (mLock) {
695                if (!mPendingRequestChangedLocked) {
696                    mDisplayReadyLocked = true;
697
698                    if (DEBUG) {
699                        Slog.d(TAG, "Display ready!");
700                    }
701                }
702            }
703            sendOnStateChangedWithWakelock();
704        }
705    }
706
707    @Override
708    public void updateBrightness() {
709        sendUpdatePowerState();
710    }
711
712    private void blockScreenOn() {
713        if (!mScreenOnWasBlocked) {
714            mScreenOnWasBlocked = true;
715            mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
716            if (DEBUG) {
717                Slog.d(TAG, "Blocked screen on.");
718            }
719        }
720    }
721
722    private void unblockScreenOn() {
723        if (mScreenOnWasBlocked) {
724            mScreenOnWasBlocked = false;
725            long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
726            if (delay > 1000 || DEBUG) {
727                Slog.d(TAG, "Unblocked screen on after " + delay + " ms");
728            }
729        }
730    }
731
732    private void setScreenState(int state) {
733        if (mPowerState.getScreenState() != state) {
734            mPowerState.setScreenState(state);
735            try {
736                mBatteryStats.noteScreenState(state);
737            } catch (RemoteException ex) {
738                // same process
739            }
740        }
741    }
742
743    private int clampScreenBrightness(int value) {
744        return MathUtils.constrain(
745                value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
746    }
747
748    private void animateScreenBrightness(int target, int rate) {
749        if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
750            try {
751                mBatteryStats.noteScreenBrightness(target);
752            } catch (RemoteException ex) {
753                // same process
754            }
755        }
756    }
757
758    private final Runnable mCleanListener = new Runnable() {
759        @Override
760        public void run() {
761            sendUpdatePowerState();
762        }
763    };
764
765    private void setProximitySensorEnabled(boolean enable) {
766        if (enable) {
767            if (!mProximitySensorEnabled) {
768                // Register the listener.
769                // Proximity sensor state already cleared initially.
770                mProximitySensorEnabled = true;
771                mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
772                        SensorManager.SENSOR_DELAY_NORMAL, mHandler);
773            }
774        } else {
775            if (mProximitySensorEnabled) {
776                // Unregister the listener.
777                // Clear the proximity sensor state for next time.
778                mProximitySensorEnabled = false;
779                mProximity = PROXIMITY_UNKNOWN;
780                mPendingProximity = PROXIMITY_UNKNOWN;
781                mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
782                mSensorManager.unregisterListener(mProximitySensorListener);
783                clearPendingProximityDebounceTime(); // release wake lock (must be last)
784            }
785        }
786    }
787
788    private void handleProximitySensorEvent(long time, boolean positive) {
789        if (mProximitySensorEnabled) {
790            if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
791                return; // no change
792            }
793            if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
794                return; // no change
795            }
796
797            // Only accept a proximity sensor reading if it remains
798            // stable for the entire debounce delay.  We hold a wake lock while
799            // debouncing the sensor.
800            mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
801            if (positive) {
802                mPendingProximity = PROXIMITY_POSITIVE;
803                setPendingProximityDebounceTime(
804                        time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); // acquire wake lock
805            } else {
806                mPendingProximity = PROXIMITY_NEGATIVE;
807                setPendingProximityDebounceTime(
808                        time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); // acquire wake lock
809            }
810
811            // Debounce the new sensor reading.
812            debounceProximitySensor();
813        }
814    }
815
816    private void debounceProximitySensor() {
817        if (mProximitySensorEnabled
818                && mPendingProximity != PROXIMITY_UNKNOWN
819                && mPendingProximityDebounceTime >= 0) {
820            final long now = SystemClock.uptimeMillis();
821            if (mPendingProximityDebounceTime <= now) {
822                // Sensor reading accepted.  Apply the change then release the wake lock.
823                mProximity = mPendingProximity;
824                updatePowerState();
825                clearPendingProximityDebounceTime(); // release wake lock (must be last)
826            } else {
827                // Need to wait a little longer.
828                // Debounce again later.  We continue holding a wake lock while waiting.
829                Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
830                msg.setAsynchronous(true);
831                mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
832            }
833        }
834    }
835
836    private void clearPendingProximityDebounceTime() {
837        if (mPendingProximityDebounceTime >= 0) {
838            mPendingProximityDebounceTime = -1;
839            mCallbacks.releaseSuspendBlocker(); // release wake lock
840        }
841    }
842
843    private void setPendingProximityDebounceTime(long debounceTime) {
844        if (mPendingProximityDebounceTime < 0) {
845            mCallbacks.acquireSuspendBlocker(); // acquire wake lock
846        }
847        mPendingProximityDebounceTime = debounceTime;
848    }
849
850    private void sendOnStateChangedWithWakelock() {
851        mCallbacks.acquireSuspendBlocker();
852        mHandler.post(mOnStateChangedRunnable);
853    }
854
855    private final Runnable mOnStateChangedRunnable = new Runnable() {
856        @Override
857        public void run() {
858            mCallbacks.onStateChanged();
859            mCallbacks.releaseSuspendBlocker();
860        }
861    };
862
863    private void sendOnProximityPositiveWithWakelock() {
864        mCallbacks.acquireSuspendBlocker();
865        mHandler.post(mOnProximityPositiveRunnable);
866    }
867
868    private final Runnable mOnProximityPositiveRunnable = new Runnable() {
869        @Override
870        public void run() {
871            mCallbacks.onProximityPositive();
872            mCallbacks.releaseSuspendBlocker();
873        }
874    };
875
876    private void sendOnProximityNegativeWithWakelock() {
877        mCallbacks.acquireSuspendBlocker();
878        mHandler.post(mOnProximityNegativeRunnable);
879    }
880
881    private final Runnable mOnProximityNegativeRunnable = new Runnable() {
882        @Override
883        public void run() {
884            mCallbacks.onProximityNegative();
885            mCallbacks.releaseSuspendBlocker();
886        }
887    };
888
889    public void dump(final PrintWriter pw) {
890        synchronized (mLock) {
891            pw.println();
892            pw.println("Display Power Controller Locked State:");
893            pw.println("  mDisplayReadyLocked=" + mDisplayReadyLocked);
894            pw.println("  mPendingRequestLocked=" + mPendingRequestLocked);
895            pw.println("  mPendingRequestChangedLocked=" + mPendingRequestChangedLocked);
896            pw.println("  mPendingWaitForNegativeProximityLocked="
897                    + mPendingWaitForNegativeProximityLocked);
898            pw.println("  mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked);
899        }
900
901        pw.println();
902        pw.println("Display Power Controller Configuration:");
903        pw.println("  mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
904        pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
905        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
906        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
907        pw.println("  mUseSoftwareAutoBrightnessConfig="
908                + mUseSoftwareAutoBrightnessConfig);
909
910        mHandler.runWithScissors(new Runnable() {
911            @Override
912            public void run() {
913                dumpLocal(pw);
914            }
915        }, 1000);
916    }
917
918    private void dumpLocal(PrintWriter pw) {
919        pw.println();
920        pw.println("Display Power Controller Thread State:");
921        pw.println("  mPowerRequest=" + mPowerRequest);
922        pw.println("  mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
923
924        pw.println("  mProximitySensor=" + mProximitySensor);
925        pw.println("  mProximitySensorEnabled=" + mProximitySensorEnabled);
926        pw.println("  mProximityThreshold=" + mProximityThreshold);
927        pw.println("  mProximity=" + proximityToString(mProximity));
928        pw.println("  mPendingProximity=" + proximityToString(mPendingProximity));
929        pw.println("  mPendingProximityDebounceTime="
930                + TimeUtils.formatUptime(mPendingProximityDebounceTime));
931        pw.println("  mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
932        pw.println("  mAppliedAutoBrightness=" + mAppliedAutoBrightness);
933        pw.println("  mAppliedDimming=" + mAppliedDimming);
934        pw.println("  mAppliedLowPower=" + mAppliedLowPower);
935
936        pw.println("  mScreenBrightnessRampAnimator.isAnimating()=" +
937                mScreenBrightnessRampAnimator.isAnimating());
938
939        if (mElectronBeamOnAnimator != null) {
940            pw.println("  mElectronBeamOnAnimator.isStarted()=" +
941                    mElectronBeamOnAnimator.isStarted());
942        }
943        if (mElectronBeamOffAnimator != null) {
944            pw.println("  mElectronBeamOffAnimator.isStarted()=" +
945                    mElectronBeamOffAnimator.isStarted());
946        }
947
948        if (mPowerState != null) {
949            mPowerState.dump(pw);
950        }
951
952        if (mAutomaticBrightnessController != null) {
953            mAutomaticBrightnessController.dump(pw);
954        }
955
956    }
957
958    private static String proximityToString(int state) {
959        switch (state) {
960            case PROXIMITY_UNKNOWN:
961                return "Unknown";
962            case PROXIMITY_NEGATIVE:
963                return "Negative";
964            case PROXIMITY_POSITIVE:
965                return "Positive";
966            default:
967                return Integer.toString(state);
968        }
969    }
970
971    private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
972        try {
973            final int n = brightness.length;
974            float[] x = new float[n];
975            float[] y = new float[n];
976            y[0] = normalizeAbsoluteBrightness(brightness[0]);
977            for (int i = 1; i < n; i++) {
978                x[i] = lux[i - 1];
979                y[i] = normalizeAbsoluteBrightness(brightness[i]);
980            }
981
982            Spline spline = Spline.createMonotoneCubicSpline(x, y);
983            if (DEBUG) {
984                Slog.d(TAG, "Auto-brightness spline: " + spline);
985                for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
986                    Slog.d(TAG, String.format("  %7.1f: %7.1f", v, spline.interpolate(v)));
987                }
988            }
989            return spline;
990        } catch (IllegalArgumentException ex) {
991            Slog.e(TAG, "Could not create auto-brightness spline.", ex);
992            return null;
993        }
994    }
995
996    private static float normalizeAbsoluteBrightness(int value) {
997        return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
998    }
999
1000    private static int clampAbsoluteBrightness(int value) {
1001        return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
1002    }
1003
1004    private final class DisplayControllerHandler extends Handler {
1005        public DisplayControllerHandler(Looper looper) {
1006            super(looper, null, true /*async*/);
1007        }
1008
1009        @Override
1010        public void handleMessage(Message msg) {
1011            switch (msg.what) {
1012                case MSG_UPDATE_POWER_STATE:
1013                    updatePowerState();
1014                    break;
1015
1016                case MSG_PROXIMITY_SENSOR_DEBOUNCED:
1017                    debounceProximitySensor();
1018                    break;
1019            }
1020        }
1021    }
1022
1023    private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
1024        @Override
1025        public void onSensorChanged(SensorEvent event) {
1026            if (mProximitySensorEnabled) {
1027                final long time = SystemClock.uptimeMillis();
1028                final float distance = event.values[0];
1029                boolean positive = distance >= 0.0f && distance < mProximityThreshold;
1030                handleProximitySensorEvent(time, positive);
1031            }
1032        }
1033
1034        @Override
1035        public void onAccuracyChanged(Sensor sensor, int accuracy) {
1036            // Not used.
1037        }
1038    };
1039}
1040