DisplayPowerController.java revision 3ee549ca2404067bb8b2fcbaa741ec118c76bf3e
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.os.Trace;
41import android.util.MathUtils;
42import android.util.Slog;
43import android.util.Spline;
44import android.util.TimeUtils;
45import android.view.Display;
46import android.view.WindowManagerPolicy;
47
48import java.io.PrintWriter;
49
50/**
51 * Controls the power state of the display.
52 *
53 * Handles the proximity sensor, light sensor, and animations between states
54 * including the screen off animation.
55 *
56 * This component acts independently of the rest of the power manager service.
57 * In particular, it does not share any state and it only communicates
58 * via asynchronous callbacks to inform the power manager that something has
59 * changed.
60 *
61 * Everything this class does internally is serialized on its handler although
62 * it may be accessed by other threads from the outside.
63 *
64 * Note that the power manager service guarantees that it will hold a suspend
65 * blocker as long as the display is not ready.  So most of the work done here
66 * does not need to worry about holding a suspend blocker unless it happens
67 * independently of the display ready signal.
68   *
69 * For debugging, you can make the color fade and brightness animations run
70 * slower by changing the "animator duration scale" option in Development Settings.
71 */
72final class DisplayPowerController implements AutomaticBrightnessController.Callbacks {
73    private static final String TAG = "DisplayPowerController";
74
75    private static boolean DEBUG = false;
76    private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
77
78    private static final String SCREEN_ON_BLOCKED_TRACE_NAME = "Screen on blocked";
79
80    // If true, uses the color fade on animation.
81    // We might want to turn this off if we cannot get a guarantee that the screen
82    // actually turns on and starts showing new content after the call to set the
83    // screen state returns.  Playing the animation can also be somewhat slow.
84    private static final boolean USE_COLOR_FADE_ON_ANIMATION = false;
85
86    // The minimum reduction in brightness when dimmed.
87    private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
88
89    private static final int COLOR_FADE_ON_ANIMATION_DURATION_MILLIS = 250;
90    private static final int COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS = 400;
91
92    private static final int MSG_UPDATE_POWER_STATE = 1;
93    private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
94    private static final int MSG_SCREEN_ON_UNBLOCKED = 3;
95
96    private static final int PROXIMITY_UNKNOWN = -1;
97    private static final int PROXIMITY_NEGATIVE = 0;
98    private static final int PROXIMITY_POSITIVE = 1;
99
100    // Proximity sensor debounce delay in milliseconds for positive or negative transitions.
101    private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
102    private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 250;
103
104    // Trigger proximity if distance is less than 5 cm.
105    private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
106
107    // Brightness animation ramp rate in brightness units per second.
108    private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
109    private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
110
111    private final Object mLock = new Object();
112
113    private final Context mContext;
114
115    // Our handler.
116    private final DisplayControllerHandler mHandler;
117
118    // Asynchronous callbacks into the power manager service.
119    // Only invoked from the handler thread while no locks are held.
120    private final DisplayPowerCallbacks mCallbacks;
121
122    // Battery stats.
123    private final IBatteryStats mBatteryStats;
124
125    // The lights service.
126    private final LightsManager mLights;
127
128    // The sensor manager.
129    private final SensorManager mSensorManager;
130
131    // The window manager policy.
132    private final WindowManagerPolicy mWindowManagerPolicy;
133
134    // The display blanker.
135    private final DisplayBlanker mBlanker;
136
137    // The proximity sensor, or null if not available or needed.
138    private Sensor mProximitySensor;
139
140    // The doze screen brightness.
141    private final int mScreenBrightnessDozeConfig;
142
143    // The dim screen brightness.
144    private final int mScreenBrightnessDimConfig;
145
146    // The minimum screen brightness to use in a very dark room.
147    private final int mScreenBrightnessDarkConfig;
148
149    // The minimum allowed brightness.
150    private final int mScreenBrightnessRangeMinimum;
151
152    // The maximum allowed brightness.
153    private final int mScreenBrightnessRangeMaximum;
154
155    // True if auto-brightness should be used.
156    private boolean mUseSoftwareAutoBrightnessConfig;
157
158    // True if we should fade the screen while turning it off, false if we should play
159    // a stylish color fade animation instead.
160    private boolean mColorFadeFadesConfig;
161
162    // The pending power request.
163    // Initially null until the first call to requestPowerState.
164    // Guarded by mLock.
165    private DisplayPowerRequest mPendingRequestLocked;
166
167    // True if a request has been made to wait for the proximity sensor to go negative.
168    // Guarded by mLock.
169    private boolean mPendingWaitForNegativeProximityLocked;
170
171    // True if the pending power request or wait for negative proximity flag
172    // has been changed since the last update occurred.
173    // Guarded by mLock.
174    private boolean mPendingRequestChangedLocked;
175
176    // Set to true when the important parts of the pending power request have been applied.
177    // The important parts are mainly the screen state.  Brightness changes may occur
178    // concurrently.
179    // Guarded by mLock.
180    private boolean mDisplayReadyLocked;
181
182    // Set to true if a power state update is required.
183    // Guarded by mLock.
184    private boolean mPendingUpdatePowerStateLocked;
185
186    /* The following state must only be accessed by the handler thread. */
187
188    // The currently requested power state.
189    // The power controller will progressively update its internal state to match
190    // the requested power state.  Initially null until the first update.
191    private DisplayPowerRequest mPowerRequest;
192
193    // The current power state.
194    // Must only be accessed on the handler thread.
195    private DisplayPowerState mPowerState;
196
197    // True if the device should wait for negative proximity sensor before
198    // waking up the screen.  This is set to false as soon as a negative
199    // proximity sensor measurement is observed or when the device is forced to
200    // go to sleep by the user.  While true, the screen remains off.
201    private boolean mWaitingForNegativeProximity;
202
203    // The actual proximity sensor threshold value.
204    private float mProximityThreshold;
205
206    // Set to true if the proximity sensor listener has been registered
207    // with the sensor manager.
208    private boolean mProximitySensorEnabled;
209
210    // The debounced proximity sensor state.
211    private int mProximity = PROXIMITY_UNKNOWN;
212
213    // The raw non-debounced proximity sensor state.
214    private int mPendingProximity = PROXIMITY_UNKNOWN;
215    private long mPendingProximityDebounceTime = -1; // -1 if fully debounced
216
217    // True if the screen was turned off because of the proximity sensor.
218    // When the screen turns on again, we report user activity to the power manager.
219    private boolean mScreenOffBecauseOfProximity;
220
221    // The currently active screen on unblocker.  This field is non-null whenever
222    // we are waiting for a callback to release it and unblock the screen.
223    private ScreenOnUnblocker mPendingScreenOnUnblocker;
224
225    // True if we were in the process of turning off the screen.
226    // This allows us to recover more gracefully from situations where we abort
227    // turning off the screen.
228    private boolean mPendingScreenOff;
229
230    // The elapsed real time when the screen on was blocked.
231    private long mScreenOnBlockStartRealTime;
232
233    // Remembers whether certain kinds of brightness adjustments
234    // were recently applied so that we can decide how to transition.
235    private boolean mAppliedAutoBrightness;
236    private boolean mAppliedDimming;
237    private boolean mAppliedLowPower;
238
239    // The controller for the automatic brightness level.
240    private AutomaticBrightnessController mAutomaticBrightnessController;
241
242    // Animators.
243    private ObjectAnimator mColorFadeOnAnimator;
244    private ObjectAnimator mColorFadeOffAnimator;
245    private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
246
247    /**
248     * Creates the display power controller.
249     */
250    public DisplayPowerController(Context context,
251            DisplayPowerCallbacks callbacks, Handler handler,
252            SensorManager sensorManager, DisplayBlanker blanker) {
253        mHandler = new DisplayControllerHandler(handler.getLooper());
254        mCallbacks = callbacks;
255
256        mBatteryStats = BatteryStatsService.getService();
257        mLights = LocalServices.getService(LightsManager.class);
258        mSensorManager = sensorManager;
259        mWindowManagerPolicy = LocalServices.getService(WindowManagerPolicy.class);
260        mBlanker = blanker;
261        mContext = context;
262
263        final Resources resources = context.getResources();
264        final int screenBrightnessSettingMinimum = clampAbsoluteBrightness(resources.getInteger(
265                com.android.internal.R.integer.config_screenBrightnessSettingMinimum));
266
267        mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger(
268                com.android.internal.R.integer.config_screenBrightnessDoze));
269
270        mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
271                com.android.internal.R.integer.config_screenBrightnessDim));
272
273        mScreenBrightnessDarkConfig = clampAbsoluteBrightness(resources.getInteger(
274                com.android.internal.R.integer.config_screenBrightnessDark));
275        if (mScreenBrightnessDarkConfig > mScreenBrightnessDimConfig) {
276            Slog.w(TAG, "Expected config_screenBrightnessDark ("
277                    + mScreenBrightnessDarkConfig + ") to be less than or equal to "
278                    + "config_screenBrightnessDim (" + mScreenBrightnessDimConfig + ").");
279        }
280        if (mScreenBrightnessDarkConfig > mScreenBrightnessDimConfig) {
281            Slog.w(TAG, "Expected config_screenBrightnessDark ("
282                    + mScreenBrightnessDarkConfig + ") to be less than or equal to "
283                    + "config_screenBrightnessSettingMinimum ("
284                    + screenBrightnessSettingMinimum + ").");
285        }
286
287        int screenBrightnessRangeMinimum = Math.min(Math.min(
288                screenBrightnessSettingMinimum, mScreenBrightnessDimConfig),
289                mScreenBrightnessDarkConfig);
290
291        mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
292
293        mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
294                com.android.internal.R.bool.config_automatic_brightness_available);
295        if (mUseSoftwareAutoBrightnessConfig) {
296            int[] lux = resources.getIntArray(
297                    com.android.internal.R.array.config_autoBrightnessLevels);
298            int[] screenBrightness = resources.getIntArray(
299                    com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
300            int lightSensorWarmUpTimeConfig = resources.getInteger(
301                    com.android.internal.R.integer.config_lightSensorWarmupTime);
302
303            Spline screenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
304            if (screenAutoBrightnessSpline == null) {
305                Slog.e(TAG, "Error in config.xml.  config_autoBrightnessLcdBacklightValues "
306                        + "(size " + screenBrightness.length + ") "
307                        + "must be monotic and have exactly one more entry than "
308                        + "config_autoBrightnessLevels (size " + lux.length + ") "
309                        + "which must be strictly increasing.  "
310                        + "Auto-brightness will be disabled.");
311                mUseSoftwareAutoBrightnessConfig = false;
312            } else {
313                int bottom = clampAbsoluteBrightness(screenBrightness[0]);
314                if (mScreenBrightnessDarkConfig > bottom) {
315                    Slog.w(TAG, "config_screenBrightnessDark (" + mScreenBrightnessDarkConfig
316                            + ") should be less than or equal to the first value of "
317                            + "config_autoBrightnessLcdBacklightValues ("
318                            + bottom + ").");
319                }
320                if (bottom < screenBrightnessRangeMinimum) {
321                    screenBrightnessRangeMinimum = bottom;
322                }
323                mAutomaticBrightnessController = new AutomaticBrightnessController(this,
324                        handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
325                        lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
326                        mScreenBrightnessRangeMaximum);
327            }
328        }
329
330        mScreenBrightnessRangeMinimum = screenBrightnessRangeMinimum;
331
332        mColorFadeFadesConfig = resources.getBoolean(
333                com.android.internal.R.bool.config_animateScreenLights);
334
335        if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
336            mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
337            if (mProximitySensor != null) {
338                mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
339                        TYPICAL_PROXIMITY_THRESHOLD);
340            }
341        }
342
343    }
344
345    /**
346     * Returns true if the proximity sensor screen-off function is available.
347     */
348    public boolean isProximitySensorAvailable() {
349        return mProximitySensor != null;
350    }
351
352    /**
353     * Requests a new power state.
354     * The controller makes a copy of the provided object and then
355     * begins adjusting the power state to match what was requested.
356     *
357     * @param request The requested power state.
358     * @param waitForNegativeProximity If true, issues a request to wait for
359     * negative proximity before turning the screen back on, assuming the screen
360     * was turned off by the proximity sensor.
361     * @return True if display is ready, false if there are important changes that must
362     * be made asynchronously (such as turning the screen on), in which case the caller
363     * should grab a wake lock, watch for {@link DisplayPowerCallbacks#onStateChanged()}
364     * then try the request again later until the state converges.
365     */
366    public boolean requestPowerState(DisplayPowerRequest request,
367            boolean waitForNegativeProximity) {
368        if (DEBUG) {
369            Slog.d(TAG, "requestPowerState: "
370                    + request + ", waitForNegativeProximity=" + waitForNegativeProximity);
371        }
372
373        synchronized (mLock) {
374            boolean changed = false;
375
376            if (waitForNegativeProximity
377                    && !mPendingWaitForNegativeProximityLocked) {
378                mPendingWaitForNegativeProximityLocked = true;
379                changed = true;
380            }
381
382            if (mPendingRequestLocked == null) {
383                mPendingRequestLocked = new DisplayPowerRequest(request);
384                changed = true;
385            } else if (!mPendingRequestLocked.equals(request)) {
386                mPendingRequestLocked.copyFrom(request);
387                changed = true;
388            }
389
390            if (changed) {
391                mDisplayReadyLocked = false;
392            }
393
394            if (changed && !mPendingRequestChangedLocked) {
395                mPendingRequestChangedLocked = true;
396                sendUpdatePowerStateLocked();
397            }
398
399            return mDisplayReadyLocked;
400        }
401    }
402
403    private void sendUpdatePowerState() {
404        synchronized (mLock) {
405            sendUpdatePowerStateLocked();
406        }
407    }
408
409    private void sendUpdatePowerStateLocked() {
410        if (!mPendingUpdatePowerStateLocked) {
411            mPendingUpdatePowerStateLocked = true;
412            Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
413            msg.setAsynchronous(true);
414            mHandler.sendMessage(msg);
415        }
416    }
417
418    private void initialize() {
419        // Initialize the power state object for the default display.
420        // In the future, we might manage multiple displays independently.
421        mPowerState = new DisplayPowerState(mBlanker,
422                mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
423                new ColorFade(Display.DEFAULT_DISPLAY));
424
425        mColorFadeOnAnimator = ObjectAnimator.ofFloat(
426                mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 0.0f, 1.0f);
427        mColorFadeOnAnimator.setDuration(COLOR_FADE_ON_ANIMATION_DURATION_MILLIS);
428        mColorFadeOnAnimator.addListener(mAnimatorListener);
429
430        mColorFadeOffAnimator = ObjectAnimator.ofFloat(
431                mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 1.0f, 0.0f);
432        mColorFadeOffAnimator.setDuration(COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS);
433        mColorFadeOffAnimator.addListener(mAnimatorListener);
434
435        mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
436                mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
437        mScreenBrightnessRampAnimator.setListener(mRampAnimatorListener);
438
439        // Initialize screen state for battery stats.
440        try {
441            mBatteryStats.noteScreenState(mPowerState.getScreenState());
442            mBatteryStats.noteScreenBrightness(mPowerState.getScreenBrightness());
443        } catch (RemoteException ex) {
444            // same process
445        }
446    }
447
448    private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
449        @Override
450        public void onAnimationStart(Animator animation) {
451        }
452        @Override
453        public void onAnimationEnd(Animator animation) {
454            sendUpdatePowerState();
455        }
456        @Override
457        public void onAnimationRepeat(Animator animation) {
458        }
459        @Override
460        public void onAnimationCancel(Animator animation) {
461        }
462    };
463
464    private final RampAnimator.Listener mRampAnimatorListener = new RampAnimator.Listener() {
465        @Override
466        public void onAnimationEnd() {
467            sendUpdatePowerState();
468        }
469    };
470
471    private void updatePowerState() {
472        // Update the power state request.
473        final boolean mustNotify;
474        boolean mustInitialize = false;
475        boolean autoBrightnessAdjustmentChanged = false;
476
477        synchronized (mLock) {
478            mPendingUpdatePowerStateLocked = false;
479            if (mPendingRequestLocked == null) {
480                return; // wait until first actual power request
481            }
482
483            if (mPowerRequest == null) {
484                mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
485                mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
486                mPendingWaitForNegativeProximityLocked = false;
487                mPendingRequestChangedLocked = false;
488                mustInitialize = true;
489            } else if (mPendingRequestChangedLocked) {
490                autoBrightnessAdjustmentChanged = (mPowerRequest.screenAutoBrightnessAdjustment
491                        != mPendingRequestLocked.screenAutoBrightnessAdjustment);
492                mPowerRequest.copyFrom(mPendingRequestLocked);
493                mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
494                mPendingWaitForNegativeProximityLocked = false;
495                mPendingRequestChangedLocked = false;
496                mDisplayReadyLocked = false;
497            }
498
499            mustNotify = !mDisplayReadyLocked;
500        }
501
502        // Initialize things the first time the power state is changed.
503        if (mustInitialize) {
504            initialize();
505        }
506
507        // Compute the basic display state using the policy.
508        // We might override this below based on other factors.
509        int state;
510        int brightness = PowerManager.BRIGHTNESS_DEFAULT;
511        boolean performScreenOffTransition = false;
512        switch (mPowerRequest.policy) {
513            case DisplayPowerRequest.POLICY_OFF:
514                state = Display.STATE_OFF;
515                performScreenOffTransition = true;
516                break;
517            case DisplayPowerRequest.POLICY_DOZE:
518                if (mPowerRequest.dozeScreenState != Display.STATE_UNKNOWN) {
519                    state = mPowerRequest.dozeScreenState;
520                } else {
521                    state = Display.STATE_DOZE;
522                }
523                brightness = mPowerRequest.dozeScreenBrightness;
524                break;
525            case DisplayPowerRequest.POLICY_DIM:
526            case DisplayPowerRequest.POLICY_BRIGHT:
527            default:
528                state = Display.STATE_ON;
529                break;
530        }
531        assert(state != Display.STATE_UNKNOWN);
532
533        // Apply the proximity sensor.
534        if (mProximitySensor != null) {
535            if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) {
536                setProximitySensorEnabled(true);
537                if (!mScreenOffBecauseOfProximity
538                        && mProximity == PROXIMITY_POSITIVE) {
539                    mScreenOffBecauseOfProximity = true;
540                    sendOnProximityPositiveWithWakelock();
541                }
542            } else if (mWaitingForNegativeProximity
543                    && mScreenOffBecauseOfProximity
544                    && mProximity == PROXIMITY_POSITIVE
545                    && state != Display.STATE_OFF) {
546                setProximitySensorEnabled(true);
547            } else {
548                setProximitySensorEnabled(false);
549                mWaitingForNegativeProximity = false;
550            }
551            if (mScreenOffBecauseOfProximity
552                    && mProximity != PROXIMITY_POSITIVE) {
553                mScreenOffBecauseOfProximity = false;
554                sendOnProximityNegativeWithWakelock();
555            }
556        } else {
557            mWaitingForNegativeProximity = false;
558        }
559        if (mScreenOffBecauseOfProximity) {
560            state = Display.STATE_OFF;
561        }
562
563        // Use zero brightness when screen is off.
564        if (state == Display.STATE_OFF) {
565            brightness = PowerManager.BRIGHTNESS_OFF;
566        }
567
568        // Use default brightness when dozing unless overridden.
569        if (brightness < 0 && (state == Display.STATE_DOZE
570                || state == Display.STATE_DOZE_SUSPEND)) {
571            brightness = mScreenBrightnessDozeConfig;
572        }
573
574        // Configure auto-brightness.
575        boolean autoBrightnessEnabled = false;
576        if (mAutomaticBrightnessController != null) {
577            autoBrightnessEnabled = mPowerRequest.useAutoBrightness
578                    && state == Display.STATE_ON && brightness < 0;
579            mAutomaticBrightnessController.configure(autoBrightnessEnabled,
580                    mPowerRequest.screenAutoBrightnessAdjustment);
581        }
582
583        // Apply auto-brightness.
584        boolean slowChange = false;
585        if (brightness < 0) {
586            if (autoBrightnessEnabled) {
587                brightness = mAutomaticBrightnessController.getAutomaticScreenBrightness();
588            }
589            if (brightness >= 0) {
590                // Use current auto-brightness value and slowly adjust to changes.
591                brightness = clampScreenBrightness(brightness);
592                if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
593                    slowChange = true; // slowly adapt to auto-brightness
594                }
595                mAppliedAutoBrightness = true;
596            } else {
597                mAppliedAutoBrightness = false;
598            }
599        } else {
600            mAppliedAutoBrightness = false;
601        }
602
603        // Apply manual brightness.
604        // Use the current brightness setting from the request, which is expected
605        // provide a nominal default value for the case where auto-brightness
606        // is not ready yet.
607        if (brightness < 0) {
608            brightness = clampScreenBrightness(mPowerRequest.screenBrightness);
609        }
610
611        // Apply dimming by at least some minimum amount when user activity
612        // timeout is about to expire.
613        if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
614            if (brightness > mScreenBrightnessRangeMinimum) {
615                brightness = Math.max(Math.min(brightness - SCREEN_DIM_MINIMUM_REDUCTION,
616                        mScreenBrightnessDimConfig), mScreenBrightnessRangeMinimum);
617            }
618            if (!mAppliedDimming) {
619                slowChange = false;
620            }
621            mAppliedDimming = true;
622        }
623
624        // If low power mode is enabled, cut the brightness level by half
625        // as long as it is above the minimum threshold.
626        if (mPowerRequest.lowPowerMode) {
627            if (brightness > mScreenBrightnessRangeMinimum) {
628                brightness = Math.max(brightness / 2, mScreenBrightnessRangeMinimum);
629            }
630            if (!mAppliedLowPower) {
631                slowChange = false;
632            }
633            mAppliedLowPower = true;
634        }
635
636        // Animate the screen brightness when the screen is on.
637        if (state != Display.STATE_OFF) {
638            animateScreenBrightness(brightness, slowChange
639                    ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
640        }
641
642        // Animate the screen state change unless already animating.
643        animateScreenStateChange(state, performScreenOffTransition);
644
645        // Report whether the display is ready for use and all changes have been applied.
646        if (mustNotify
647                && mPendingScreenOnUnblocker == null
648                && !mColorFadeOnAnimator.isStarted()
649                && !mColorFadeOffAnimator.isStarted()
650                && !mScreenBrightnessRampAnimator.isAnimating()
651                && mPowerState.waitUntilClean(mCleanListener)) {
652            synchronized (mLock) {
653                if (!mPendingRequestChangedLocked) {
654                    mDisplayReadyLocked = true;
655
656                    if (DEBUG) {
657                        Slog.d(TAG, "Display ready!");
658                    }
659                }
660            }
661            sendOnStateChangedWithWakelock();
662        }
663    }
664
665    @Override
666    public void updateBrightness() {
667        sendUpdatePowerState();
668    }
669
670    private void blockScreenOn() {
671        if (mPendingScreenOnUnblocker == null) {
672            Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
673            mPendingScreenOnUnblocker = new ScreenOnUnblocker();
674            mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
675            Slog.i(TAG, "Blocking screen on until initial contents have been drawn.");
676        }
677    }
678
679    private void unblockScreenOn() {
680        if (mPendingScreenOnUnblocker != null) {
681            mPendingScreenOnUnblocker = null;
682            long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
683            Slog.i(TAG, "Unblocked screen on after " + delay + " ms");
684            Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
685        }
686    }
687
688    private boolean setScreenState(int state) {
689        if (mPowerState.getScreenState() != state) {
690            final boolean wasOn = (mPowerState.getScreenState() != Display.STATE_OFF);
691            mPowerState.setScreenState(state);
692
693            // Tell battery stats about the transition.
694            try {
695                mBatteryStats.noteScreenState(state);
696            } catch (RemoteException ex) {
697                // same process
698            }
699
700            // Tell the window manager what's happening.
701            // Temporarily block turning the screen on until the window manager is ready
702            // by leaving a black surface covering the screen.  This surface is essentially
703            // the final state of the color fade animation.
704            boolean isOn = (state != Display.STATE_OFF);
705            if (wasOn && !isOn) {
706                unblockScreenOn();
707                mWindowManagerPolicy.screenTurnedOff();
708            } else if (!wasOn && isOn) {
709                if (mPowerState.getColorFadeLevel() == 0.0f) {
710                    blockScreenOn();
711                } else {
712                    unblockScreenOn();
713                }
714                mWindowManagerPolicy.screenTurningOn(mPendingScreenOnUnblocker);
715            }
716        }
717        return mPendingScreenOnUnblocker == null;
718    }
719
720    private int clampScreenBrightness(int value) {
721        return MathUtils.constrain(
722                value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
723    }
724
725    private void animateScreenBrightness(int target, int rate) {
726        if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
727            try {
728                mBatteryStats.noteScreenBrightness(target);
729            } catch (RemoteException ex) {
730                // same process
731            }
732        }
733    }
734
735    private void animateScreenStateChange(int target, boolean performScreenOffTransition) {
736        // If there is already an animation in progress, don't interfere with it.
737        if (mColorFadeOnAnimator.isStarted()
738                || mColorFadeOffAnimator.isStarted()) {
739            return;
740        }
741
742        // If we were in the process of turning off the screen but didn't quite
743        // finish.  Then finish up now to prevent a jarring transition back
744        // to screen on if we skipped blocking screen on as usual.
745        if (mPendingScreenOff && target != Display.STATE_OFF) {
746            setScreenState(Display.STATE_OFF);
747            mPendingScreenOff = false;
748        }
749
750        if (target == Display.STATE_ON) {
751            // Want screen on.  The contents of the screen may not yet
752            // be visible if the color fade has not been dismissed because
753            // its last frame of animation is solid black.
754            if (!setScreenState(Display.STATE_ON)) {
755                return; // screen on blocked
756            }
757            if (USE_COLOR_FADE_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {
758                // Perform screen on animation.
759                if (mPowerState.getColorFadeLevel() == 1.0f) {
760                    mPowerState.dismissColorFade();
761                } else if (mPowerState.prepareColorFade(mContext,
762                        mColorFadeFadesConfig ?
763                                ColorFade.MODE_FADE :
764                                        ColorFade.MODE_WARM_UP)) {
765                    mColorFadeOnAnimator.start();
766                } else {
767                    mColorFadeOnAnimator.end();
768                }
769            } else {
770                // Skip screen on animation.
771                mPowerState.setColorFadeLevel(1.0f);
772                mPowerState.dismissColorFade();
773            }
774        } else if (target == Display.STATE_DOZE) {
775            // Want screen dozing.
776            // Wait for brightness animation to complete beforehand when entering doze
777            // from screen on to prevent a perceptible jump because brightness may operate
778            // differently when the display is configured for dozing.
779            if (mScreenBrightnessRampAnimator.isAnimating()
780                    && mPowerState.getScreenState() == Display.STATE_ON) {
781                return;
782            }
783
784            // Set screen state.
785            if (!setScreenState(Display.STATE_DOZE)) {
786                return; // screen on blocked
787            }
788
789            // Dismiss the black surface without fanfare.
790            mPowerState.setColorFadeLevel(1.0f);
791            mPowerState.dismissColorFade();
792        } else if (target == Display.STATE_DOZE_SUSPEND) {
793            // Want screen dozing and suspended.
794            // Wait for brightness animation to complete beforehand unless already
795            // suspended because we may not be able to change it after suspension.
796            if (mScreenBrightnessRampAnimator.isAnimating()
797                    && mPowerState.getScreenState() != Display.STATE_DOZE_SUSPEND) {
798                return;
799            }
800
801            // If not already suspending, temporarily set the state to doze until the
802            // screen on is unblocked, then suspend.
803            if (mPowerState.getScreenState() != Display.STATE_DOZE_SUSPEND) {
804                if (!setScreenState(Display.STATE_DOZE)) {
805                    return; // screen on blocked
806                }
807                setScreenState(Display.STATE_DOZE_SUSPEND); // already on so can't block
808            }
809
810            // Dismiss the black surface without fanfare.
811            mPowerState.setColorFadeLevel(1.0f);
812            mPowerState.dismissColorFade();
813        } else {
814            // Want screen off.
815            mPendingScreenOff = true;
816            if (mPowerState.getColorFadeLevel() == 0.0f) {
817                // Turn the screen off.
818                // A black surface is already hiding the contents of the screen.
819                setScreenState(Display.STATE_OFF);
820                mPendingScreenOff = false;
821            } else if (performScreenOffTransition
822                    && mPowerState.prepareColorFade(mContext,
823                            mColorFadeFadesConfig ?
824                                    ColorFade.MODE_FADE : ColorFade.MODE_COOL_DOWN)
825                    && mPowerState.getScreenState() != Display.STATE_OFF) {
826                // Perform the screen off animation.
827                mColorFadeOffAnimator.start();
828            } else {
829                // Skip the screen off animation and add a black surface to hide the
830                // contents of the screen.
831                mColorFadeOffAnimator.end();
832            }
833        }
834    }
835
836    private final Runnable mCleanListener = new Runnable() {
837        @Override
838        public void run() {
839            sendUpdatePowerState();
840        }
841    };
842
843    private void setProximitySensorEnabled(boolean enable) {
844        if (enable) {
845            if (!mProximitySensorEnabled) {
846                // Register the listener.
847                // Proximity sensor state already cleared initially.
848                mProximitySensorEnabled = true;
849                mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
850                        SensorManager.SENSOR_DELAY_NORMAL, mHandler);
851            }
852        } else {
853            if (mProximitySensorEnabled) {
854                // Unregister the listener.
855                // Clear the proximity sensor state for next time.
856                mProximitySensorEnabled = false;
857                mProximity = PROXIMITY_UNKNOWN;
858                mPendingProximity = PROXIMITY_UNKNOWN;
859                mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
860                mSensorManager.unregisterListener(mProximitySensorListener);
861                clearPendingProximityDebounceTime(); // release wake lock (must be last)
862            }
863        }
864    }
865
866    private void handleProximitySensorEvent(long time, boolean positive) {
867        if (mProximitySensorEnabled) {
868            if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
869                return; // no change
870            }
871            if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
872                return; // no change
873            }
874
875            // Only accept a proximity sensor reading if it remains
876            // stable for the entire debounce delay.  We hold a wake lock while
877            // debouncing the sensor.
878            mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
879            if (positive) {
880                mPendingProximity = PROXIMITY_POSITIVE;
881                setPendingProximityDebounceTime(
882                        time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); // acquire wake lock
883            } else {
884                mPendingProximity = PROXIMITY_NEGATIVE;
885                setPendingProximityDebounceTime(
886                        time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); // acquire wake lock
887            }
888
889            // Debounce the new sensor reading.
890            debounceProximitySensor();
891        }
892    }
893
894    private void debounceProximitySensor() {
895        if (mProximitySensorEnabled
896                && mPendingProximity != PROXIMITY_UNKNOWN
897                && mPendingProximityDebounceTime >= 0) {
898            final long now = SystemClock.uptimeMillis();
899            if (mPendingProximityDebounceTime <= now) {
900                // Sensor reading accepted.  Apply the change then release the wake lock.
901                mProximity = mPendingProximity;
902                updatePowerState();
903                clearPendingProximityDebounceTime(); // release wake lock (must be last)
904            } else {
905                // Need to wait a little longer.
906                // Debounce again later.  We continue holding a wake lock while waiting.
907                Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
908                msg.setAsynchronous(true);
909                mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
910            }
911        }
912    }
913
914    private void clearPendingProximityDebounceTime() {
915        if (mPendingProximityDebounceTime >= 0) {
916            mPendingProximityDebounceTime = -1;
917            mCallbacks.releaseSuspendBlocker(); // release wake lock
918        }
919    }
920
921    private void setPendingProximityDebounceTime(long debounceTime) {
922        if (mPendingProximityDebounceTime < 0) {
923            mCallbacks.acquireSuspendBlocker(); // acquire wake lock
924        }
925        mPendingProximityDebounceTime = debounceTime;
926    }
927
928    private void sendOnStateChangedWithWakelock() {
929        mCallbacks.acquireSuspendBlocker();
930        mHandler.post(mOnStateChangedRunnable);
931    }
932
933    private final Runnable mOnStateChangedRunnable = new Runnable() {
934        @Override
935        public void run() {
936            mCallbacks.onStateChanged();
937            mCallbacks.releaseSuspendBlocker();
938        }
939    };
940
941    private void sendOnProximityPositiveWithWakelock() {
942        mCallbacks.acquireSuspendBlocker();
943        mHandler.post(mOnProximityPositiveRunnable);
944    }
945
946    private final Runnable mOnProximityPositiveRunnable = new Runnable() {
947        @Override
948        public void run() {
949            mCallbacks.onProximityPositive();
950            mCallbacks.releaseSuspendBlocker();
951        }
952    };
953
954    private void sendOnProximityNegativeWithWakelock() {
955        mCallbacks.acquireSuspendBlocker();
956        mHandler.post(mOnProximityNegativeRunnable);
957    }
958
959    private final Runnable mOnProximityNegativeRunnable = new Runnable() {
960        @Override
961        public void run() {
962            mCallbacks.onProximityNegative();
963            mCallbacks.releaseSuspendBlocker();
964        }
965    };
966
967    public void dump(final PrintWriter pw) {
968        synchronized (mLock) {
969            pw.println();
970            pw.println("Display Power Controller Locked State:");
971            pw.println("  mDisplayReadyLocked=" + mDisplayReadyLocked);
972            pw.println("  mPendingRequestLocked=" + mPendingRequestLocked);
973            pw.println("  mPendingRequestChangedLocked=" + mPendingRequestChangedLocked);
974            pw.println("  mPendingWaitForNegativeProximityLocked="
975                    + mPendingWaitForNegativeProximityLocked);
976            pw.println("  mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked);
977        }
978
979        pw.println();
980        pw.println("Display Power Controller Configuration:");
981        pw.println("  mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
982        pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
983        pw.println("  mScreenBrightnessDarkConfig=" + mScreenBrightnessDarkConfig);
984        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
985        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
986        pw.println("  mUseSoftwareAutoBrightnessConfig=" + mUseSoftwareAutoBrightnessConfig);
987        pw.println("  mColorFadeFadesConfig=" + mColorFadeFadesConfig);
988
989        mHandler.runWithScissors(new Runnable() {
990            @Override
991            public void run() {
992                dumpLocal(pw);
993            }
994        }, 1000);
995    }
996
997    private void dumpLocal(PrintWriter pw) {
998        pw.println();
999        pw.println("Display Power Controller Thread State:");
1000        pw.println("  mPowerRequest=" + mPowerRequest);
1001        pw.println("  mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
1002
1003        pw.println("  mProximitySensor=" + mProximitySensor);
1004        pw.println("  mProximitySensorEnabled=" + mProximitySensorEnabled);
1005        pw.println("  mProximityThreshold=" + mProximityThreshold);
1006        pw.println("  mProximity=" + proximityToString(mProximity));
1007        pw.println("  mPendingProximity=" + proximityToString(mPendingProximity));
1008        pw.println("  mPendingProximityDebounceTime="
1009                + TimeUtils.formatUptime(mPendingProximityDebounceTime));
1010        pw.println("  mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
1011        pw.println("  mAppliedAutoBrightness=" + mAppliedAutoBrightness);
1012        pw.println("  mAppliedDimming=" + mAppliedDimming);
1013        pw.println("  mAppliedLowPower=" + mAppliedLowPower);
1014        pw.println("  mPendingScreenOnUnblocker=" + mPendingScreenOnUnblocker);
1015        pw.println("  mPendingScreenOff=" + mPendingScreenOff);
1016
1017        pw.println("  mScreenBrightnessRampAnimator.isAnimating()=" +
1018                mScreenBrightnessRampAnimator.isAnimating());
1019
1020        if (mColorFadeOnAnimator != null) {
1021            pw.println("  mColorFadeOnAnimator.isStarted()=" +
1022                    mColorFadeOnAnimator.isStarted());
1023        }
1024        if (mColorFadeOffAnimator != null) {
1025            pw.println("  mColorFadeOffAnimator.isStarted()=" +
1026                    mColorFadeOffAnimator.isStarted());
1027        }
1028
1029        if (mPowerState != null) {
1030            mPowerState.dump(pw);
1031        }
1032
1033        if (mAutomaticBrightnessController != null) {
1034            mAutomaticBrightnessController.dump(pw);
1035        }
1036
1037    }
1038
1039    private static String proximityToString(int state) {
1040        switch (state) {
1041            case PROXIMITY_UNKNOWN:
1042                return "Unknown";
1043            case PROXIMITY_NEGATIVE:
1044                return "Negative";
1045            case PROXIMITY_POSITIVE:
1046                return "Positive";
1047            default:
1048                return Integer.toString(state);
1049        }
1050    }
1051
1052    private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
1053        try {
1054            final int n = brightness.length;
1055            float[] x = new float[n];
1056            float[] y = new float[n];
1057            y[0] = normalizeAbsoluteBrightness(brightness[0]);
1058            for (int i = 1; i < n; i++) {
1059                x[i] = lux[i - 1];
1060                y[i] = normalizeAbsoluteBrightness(brightness[i]);
1061            }
1062
1063            Spline spline = Spline.createSpline(x, y);
1064            if (DEBUG) {
1065                Slog.d(TAG, "Auto-brightness spline: " + spline);
1066                for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
1067                    Slog.d(TAG, String.format("  %7.1f: %7.1f", v, spline.interpolate(v)));
1068                }
1069            }
1070            return spline;
1071        } catch (IllegalArgumentException ex) {
1072            Slog.e(TAG, "Could not create auto-brightness spline.", ex);
1073            return null;
1074        }
1075    }
1076
1077    private static float normalizeAbsoluteBrightness(int value) {
1078        return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
1079    }
1080
1081    private static int clampAbsoluteBrightness(int value) {
1082        return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
1083    }
1084
1085    private final class DisplayControllerHandler extends Handler {
1086        public DisplayControllerHandler(Looper looper) {
1087            super(looper, null, true /*async*/);
1088        }
1089
1090        @Override
1091        public void handleMessage(Message msg) {
1092            switch (msg.what) {
1093                case MSG_UPDATE_POWER_STATE:
1094                    updatePowerState();
1095                    break;
1096
1097                case MSG_PROXIMITY_SENSOR_DEBOUNCED:
1098                    debounceProximitySensor();
1099                    break;
1100
1101                case MSG_SCREEN_ON_UNBLOCKED:
1102                    if (mPendingScreenOnUnblocker == msg.obj) {
1103                        unblockScreenOn();
1104                        updatePowerState();
1105                    }
1106                    break;
1107            }
1108        }
1109    }
1110
1111    private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
1112        @Override
1113        public void onSensorChanged(SensorEvent event) {
1114            if (mProximitySensorEnabled) {
1115                final long time = SystemClock.uptimeMillis();
1116                final float distance = event.values[0];
1117                boolean positive = distance >= 0.0f && distance < mProximityThreshold;
1118                handleProximitySensorEvent(time, positive);
1119            }
1120        }
1121
1122        @Override
1123        public void onAccuracyChanged(Sensor sensor, int accuracy) {
1124            // Not used.
1125        }
1126    };
1127
1128    private final class ScreenOnUnblocker implements WindowManagerPolicy.ScreenOnListener {
1129        @Override
1130        public void onScreenOn() {
1131            Message msg = mHandler.obtainMessage(MSG_SCREEN_ON_UNBLOCKED, this);
1132            msg.setAsynchronous(true);
1133            mHandler.sendMessage(msg);
1134        }
1135    }
1136}
1137