DisplayPowerController.java revision 6a5cacb8683ddd78fc78f01ef726f410bf4e0479
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2012 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.server.display;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.app.IBatteryStats;
2007481ccd1dcc2912797ec64f0bfa5641b39adceaJesse Wilsonimport com.android.server.LocalServices;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.server.am.BatteryStatsService;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.server.lights.LightsManager;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2441e2e1f9919c9ae3593610f7e05f0d9cf69ec9b2Joe Malinimport android.animation.Animator;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.animation.ObjectAnimator;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.hardware.Sensor;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.hardware.SensorEvent;
3007481ccd1dcc2912797ec64f0bfa5641b39adceaJesse Wilsonimport android.hardware.SensorEventListener;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.hardware.SensorManager;
3207481ccd1dcc2912797ec64f0bfa5641b39adceaJesse Wilsonimport android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
3307481ccd1dcc2912797ec64f0bfa5641b39adceaJesse Wilsonimport android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Looper;
36bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackbornimport android.os.Message;
37bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackbornimport android.os.PowerManager;
3807481ccd1dcc2912797ec64f0bfa5641b39adceaJesse Wilsonimport android.os.RemoteException;
39bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackbornimport android.os.SystemClock;
40bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackbornimport android.text.format.DateUtils;
4107481ccd1dcc2912797ec64f0bfa5641b39adceaJesse Wilsonimport android.util.MathUtils;
42bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackbornimport android.util.Slog;
43bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackbornimport android.util.Spline;
44bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackbornimport android.util.TimeUtils;
45bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackbornimport android.view.Display;
4607481ccd1dcc2912797ec64f0bfa5641b39adceaJesse Wilson
47bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackbornimport java.io.PrintWriter;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Controls the power state of the display.
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Handles the proximity sensor, light sensor, and animations between states
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * including the screen off animation.
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This component acts independently of the rest of the power manager service.
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * In particular, it does not share any state and it only communicates
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * via asynchronous callbacks to inform the power manager that something has
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * changed.
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Everything this class does internally is serialized on its handler although
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * it may be accessed by other threads from the outside.
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Note that the power manager service guarantees that it will hold a suspend
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * blocker as long as the display is not ready.  So most of the work done here
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * does not need to worry about holding a suspend blocker unless it happens
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * independently of the display ready signal.
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For debugging, you can make the electron beam and brightness animations run
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * slower by changing the "animator duration scale" option in Development Settings.
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectfinal class DisplayPowerController implements AutomaticBrightnessController.Callbacks {
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "DisplayPowerController";
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
74bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackborn    private static boolean DEBUG = false;
75bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackborn    private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
76bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackborn
77bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackborn    // If true, uses the electron beam on animation.
78bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackborn    // We might want to turn this off if we cannot get a guarantee that the screen
79bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackborn    // actually turns on and starts showing new content after the call to set the
80bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackborn    // screen state returns.  Playing the animation can also be somewhat slow.
81bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackborn    private static final boolean USE_ELECTRON_BEAM_ON_ANIMATION = false;
82bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackborn
83bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackborn
84bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackborn    // The minimum reduction in brightness when dimmed.
85bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackborn    private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
86bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackborn
87bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackborn    private static final int ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS = 250;
88bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackborn    private static final int ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS = 400;
89bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackborn
90bfe319e06aa56c081d0d94d64a8181291d7f7388Dianne Hackborn    private static final int MSG_UPDATE_POWER_STATE = 1;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
927351dd113f26580f3bcc7500746f3a26aecc4260Eric Fischer
937351dd113f26580f3bcc7500746f3a26aecc4260Eric Fischer    private static final int PROXIMITY_UNKNOWN = -1;
947351dd113f26580f3bcc7500746f3a26aecc4260Eric Fischer    private static final int PROXIMITY_NEGATIVE = 0;
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int PROXIMITY_POSITIVE = 1;
9607481ccd1dcc2912797ec64f0bfa5641b39adceaJesse Wilson
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Proximity sensor debounce delay in milliseconds for positive or negative transitions.
98fbf37c79bdedbdd7b82ad7d5862dd82e3c068590Elliott Hughes    private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
99fbf37c79bdedbdd7b82ad7d5862dd82e3c068590Elliott Hughes    private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 250;
100fbf37c79bdedbdd7b82ad7d5862dd82e3c068590Elliott Hughes
10107481ccd1dcc2912797ec64f0bfa5641b39adceaJesse Wilson    // Trigger proximity if distance is less than 5 cm.
102fbf37c79bdedbdd7b82ad7d5862dd82e3c068590Elliott Hughes    private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
103fbf37c79bdedbdd7b82ad7d5862dd82e3c068590Elliott Hughes
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Brightness animation ramp rate in brightness units per second.
10507481ccd1dcc2912797ec64f0bfa5641b39adceaJesse Wilson    private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
10607481ccd1dcc2912797ec64f0bfa5641b39adceaJesse Wilson    private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
10707481ccd1dcc2912797ec64f0bfa5641b39adceaJesse Wilson
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Object mLock = new Object();
109260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
110260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // Our handler.
111260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private final DisplayControllerHandler mHandler;
112260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
113874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos    // Asynchronous callbacks into the power manager service.
114260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // Only invoked from the handler thread while no locks are held.
115260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private final DisplayPowerCallbacks mCallbacks;
116260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
117260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // Battery stats.
118260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private final IBatteryStats mBatteryStats;
119260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
120260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // The lights service.
121260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private final LightsManager mLights;
122260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
123260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // The sensor manager.
124260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private final SensorManager mSensorManager;
125260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
126260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // The display blanker.
127260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private final DisplayBlanker mBlanker;
128260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
129260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // The proximity sensor, or null if not available or needed.
130260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private Sensor mProximitySensor;
131260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
132260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // The doze screen brightness.
133260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private final int mScreenBrightnessDozeConfig;
134260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
135260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // The dim screen brightness.
136260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private final int mScreenBrightnessDimConfig;
137260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
138260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // The minimum allowed brightness.
139260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private final int mScreenBrightnessRangeMinimum;
140260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
141260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // The maximum allowed brightness.
142260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private final int mScreenBrightnessRangeMaximum;
143260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
144260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // True if auto-brightness should be used.
145260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private boolean mUseSoftwareAutoBrightnessConfig;
146260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
147260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // True if we should fade the screen while turning it off, false if we should play
148260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // a stylish electron beam animation instead.
149260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private boolean mElectronBeamFadesConfig;
150260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
151260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // The pending power request.
152260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // Initially null until the first call to requestPowerState.
153260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // Guarded by mLock.
154260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private DisplayPowerRequest mPendingRequestLocked;
155260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
156260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // True if a request has been made to wait for the proximity sensor to go negative.
157260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // Guarded by mLock.
158260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private boolean mPendingWaitForNegativeProximityLocked;
159260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
160260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // True if the pending power request or wait for negative proximity flag
161260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // has been changed since the last update occurred.
162260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // Guarded by mLock.
163260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private boolean mPendingRequestChangedLocked;
164260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
165260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // Set to true when the important parts of the pending power request have been applied.
166260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // The important parts are mainly the screen state.  Brightness changes may occur
167260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // concurrently.
168260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // Guarded by mLock.
169260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private boolean mDisplayReadyLocked;
170260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
171260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // Set to true if a power state update is required.
172260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    // Guarded by mLock.
173260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn    private boolean mPendingUpdatePowerStateLocked;
174260c5020ae65ddd14668b8ae496c169082aa13f6Dianne Hackborn
175874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos    /* The following state must only be accessed by the handler thread. */
176874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos
177874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos    // The currently requested power state.
178874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos    // The power controller will progressively update its internal state to match
179874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos    // the requested power state.  Initially null until the first update.
180874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos    private DisplayPowerRequest mPowerRequest;
181874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos
182874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos    // The current power state.
183874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos    // Must only be accessed on the handler thread.
184874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos    private DisplayPowerState mPowerState;
185874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos
186874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos    // True if the device should wait for negative proximity sensor before
187874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos    // waking up the screen.  This is set to false as soon as a negative
188874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos    // proximity sensor measurement is observed or when the device is forced to
189874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos    // go to sleep by the user.  While true, the screen remains off.
190874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos    private boolean mWaitingForNegativeProximity;
191874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos
192874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos    // The actual proximity sensor threshold value.
193874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos    private float mProximityThreshold;
194874b35b83613eac69d5a9a35bc62e4ac5efc385cAdrian Roos
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Set to true if the proximity sensor listener has been registered
196    // with the sensor manager.
197    private boolean mProximitySensorEnabled;
198
199    // The debounced proximity sensor state.
200    private int mProximity = PROXIMITY_UNKNOWN;
201
202    // The raw non-debounced proximity sensor state.
203    private int mPendingProximity = PROXIMITY_UNKNOWN;
204    private long mPendingProximityDebounceTime = -1; // -1 if fully debounced
205
206    // True if the screen was turned off because of the proximity sensor.
207    // When the screen turns on again, we report user activity to the power manager.
208    private boolean mScreenOffBecauseOfProximity;
209
210    // True if the screen on is being blocked.
211    private boolean mScreenOnWasBlocked;
212
213    // The elapsed real time when the screen on was blocked.
214    private long mScreenOnBlockStartRealTime;
215
216    // True if the screen auto-brightness value is actually being used to
217    // set the display brightness.
218    private boolean mUsingScreenAutoBrightness;
219
220    // The controller for the automatic brightness level.
221    private AutomaticBrightnessController mAutomaticBrightnessController;
222
223    // Animators.
224    private ObjectAnimator mElectronBeamOnAnimator;
225    private ObjectAnimator mElectronBeamOffAnimator;
226    private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
227
228    /**
229     * Creates the display power controller.
230     */
231    public DisplayPowerController(Context context,
232            DisplayPowerCallbacks callbacks, Handler handler,
233            SensorManager sensorManager, DisplayBlanker blanker) {
234        mHandler = new DisplayControllerHandler(handler.getLooper());
235        mCallbacks = callbacks;
236
237        mBatteryStats = BatteryStatsService.getService();
238        mLights = LocalServices.getService(LightsManager.class);
239        mSensorManager = sensorManager;
240        mBlanker = blanker;
241
242        final Resources resources = context.getResources();
243
244        mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger(
245                com.android.internal.R.integer.config_screenBrightnessDoze));
246
247        mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
248                com.android.internal.R.integer.config_screenBrightnessDim));
249
250        int screenBrightnessRangeMinimum = clampAbsoluteBrightness(Math.min(resources.getInteger(
251                com.android.internal.R.integer.config_screenBrightnessSettingMinimum),
252                mScreenBrightnessDimConfig));
253
254        mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
255
256        mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
257                com.android.internal.R.bool.config_automatic_brightness_available);
258        if (mUseSoftwareAutoBrightnessConfig) {
259            int[] lux = resources.getIntArray(
260                    com.android.internal.R.array.config_autoBrightnessLevels);
261            int[] screenBrightness = resources.getIntArray(
262                    com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
263            int lightSensorWarmUpTimeConfig = resources.getInteger(
264                    com.android.internal.R.integer.config_lightSensorWarmupTime);
265
266            Spline screenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
267            if (screenAutoBrightnessSpline == null) {
268                Slog.e(TAG, "Error in config.xml.  config_autoBrightnessLcdBacklightValues "
269                        + "(size " + screenBrightness.length + ") "
270                        + "must be monotic and have exactly one more entry than "
271                        + "config_autoBrightnessLevels (size " + lux.length + ") "
272                        + "which must be strictly increasing.  "
273                        + "Auto-brightness will be disabled.");
274                mUseSoftwareAutoBrightnessConfig = false;
275            } else {
276                if (screenBrightness[0] < screenBrightnessRangeMinimum) {
277                    screenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightness[0]);
278                }
279                mAutomaticBrightnessController = new AutomaticBrightnessController(this,
280                        handler.getLooper(), sensorManager, screenAutoBrightnessSpline,
281                        lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
282                        mScreenBrightnessRangeMaximum);
283            }
284        }
285
286        mScreenBrightnessRangeMinimum = screenBrightnessRangeMinimum;
287
288        mElectronBeamFadesConfig = resources.getBoolean(
289                com.android.internal.R.bool.config_animateScreenLights);
290
291        if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
292            mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
293            if (mProximitySensor != null) {
294                mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
295                        TYPICAL_PROXIMITY_THRESHOLD);
296            }
297        }
298
299    }
300
301    /**
302     * Returns true if the proximity sensor screen-off function is available.
303     */
304    public boolean isProximitySensorAvailable() {
305        return mProximitySensor != null;
306    }
307
308    /**
309     * Requests a new power state.
310     * The controller makes a copy of the provided object and then
311     * begins adjusting the power state to match what was requested.
312     *
313     * @param request The requested power state.
314     * @param waitForNegativeProximity If true, issues a request to wait for
315     * negative proximity before turning the screen back on, assuming the screen
316     * was turned off by the proximity sensor.
317     * @return True if display is ready, false if there are important changes that must
318     * be made asynchronously (such as turning the screen on), in which case the caller
319     * should grab a wake lock, watch for {@link Callbacks#onStateChanged()} then try
320     * the request again later until the state converges.
321     */
322    public boolean requestPowerState(DisplayPowerRequest request,
323            boolean waitForNegativeProximity) {
324        if (DEBUG) {
325            Slog.d(TAG, "requestPowerState: "
326                    + request + ", waitForNegativeProximity=" + waitForNegativeProximity);
327        }
328
329        synchronized (mLock) {
330            boolean changed = false;
331
332            if (waitForNegativeProximity
333                    && !mPendingWaitForNegativeProximityLocked) {
334                mPendingWaitForNegativeProximityLocked = true;
335                changed = true;
336            }
337
338            if (mPendingRequestLocked == null) {
339                mPendingRequestLocked = new DisplayPowerRequest(request);
340                changed = true;
341            } else if (!mPendingRequestLocked.equals(request)) {
342                mPendingRequestLocked.copyFrom(request);
343                changed = true;
344            }
345
346            if (changed) {
347                mDisplayReadyLocked = false;
348            }
349
350            if (changed && !mPendingRequestChangedLocked) {
351                mPendingRequestChangedLocked = true;
352                sendUpdatePowerStateLocked();
353            }
354
355            return mDisplayReadyLocked;
356        }
357    }
358
359    private void sendUpdatePowerState() {
360        synchronized (mLock) {
361            sendUpdatePowerStateLocked();
362        }
363    }
364
365    private void sendUpdatePowerStateLocked() {
366        if (!mPendingUpdatePowerStateLocked) {
367            mPendingUpdatePowerStateLocked = true;
368            Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
369            msg.setAsynchronous(true);
370            mHandler.sendMessage(msg);
371        }
372    }
373
374    private void initialize() {
375        // Initialize the power state object for the default display.
376        // In the future, we might manage multiple displays independently.
377        mPowerState = new DisplayPowerState(mBlanker,
378                mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
379                new ElectronBeam(Display.DEFAULT_DISPLAY));
380
381        mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
382                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
383        mElectronBeamOnAnimator.setDuration(ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS);
384        mElectronBeamOnAnimator.addListener(mAnimatorListener);
385
386        mElectronBeamOffAnimator = ObjectAnimator.ofFloat(
387                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 1.0f, 0.0f);
388        mElectronBeamOffAnimator.setDuration(ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS);
389        mElectronBeamOffAnimator.addListener(mAnimatorListener);
390
391        mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
392                mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
393        mScreenBrightnessRampAnimator.setListener(mRampAnimatorListener);
394
395        // Initialize screen state for battery stats.
396        try {
397            mBatteryStats.noteScreenState(mPowerState.getScreenState());
398            mBatteryStats.noteScreenBrightness(mPowerState.getScreenBrightness());
399        } catch (RemoteException ex) {
400            // same process
401        }
402    }
403
404    private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
405        @Override
406        public void onAnimationStart(Animator animation) {
407        }
408        @Override
409        public void onAnimationEnd(Animator animation) {
410            sendUpdatePowerState();
411        }
412        @Override
413        public void onAnimationRepeat(Animator animation) {
414        }
415        @Override
416        public void onAnimationCancel(Animator animation) {
417        }
418    };
419
420    private final RampAnimator.Listener mRampAnimatorListener = new RampAnimator.Listener() {
421        @Override
422        public void onAnimationEnd() {
423            sendUpdatePowerState();
424        }
425    };
426
427    private void updatePowerState() {
428        // Update the power state request.
429        final boolean mustNotify;
430        boolean mustInitialize = false;
431        boolean wasDimOrDoze = false;
432        boolean autoBrightnessAdjustmentChanged = false;
433
434        synchronized (mLock) {
435            mPendingUpdatePowerStateLocked = false;
436            if (mPendingRequestLocked == null) {
437                return; // wait until first actual power request
438            }
439
440            if (mPowerRequest == null) {
441                mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
442                mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
443                mPendingWaitForNegativeProximityLocked = false;
444                mPendingRequestChangedLocked = false;
445                mustInitialize = true;
446            } else if (mPendingRequestChangedLocked) {
447                wasDimOrDoze = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM
448                        || mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE);
449                autoBrightnessAdjustmentChanged = (mPowerRequest.screenAutoBrightnessAdjustment
450                        != mPendingRequestLocked.screenAutoBrightnessAdjustment);
451                mPowerRequest.copyFrom(mPendingRequestLocked);
452                mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
453                mPendingWaitForNegativeProximityLocked = false;
454                mPendingRequestChangedLocked = false;
455                mDisplayReadyLocked = false;
456            }
457
458            mustNotify = !mDisplayReadyLocked;
459        }
460
461        // Initialize things the first time the power state is changed.
462        if (mustInitialize) {
463            initialize();
464        }
465
466        // Apply the proximity sensor.
467        if (mProximitySensor != null) {
468            if (mPowerRequest.useProximitySensor
469                    && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
470                setProximitySensorEnabled(true);
471                if (!mScreenOffBecauseOfProximity
472                        && mProximity == PROXIMITY_POSITIVE) {
473                    mScreenOffBecauseOfProximity = true;
474                    sendOnProximityPositiveWithWakelock();
475                }
476            } else if (mWaitingForNegativeProximity
477                    && mScreenOffBecauseOfProximity
478                    && mProximity == PROXIMITY_POSITIVE
479                    && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
480                setProximitySensorEnabled(true);
481            } else {
482                setProximitySensorEnabled(false);
483                mWaitingForNegativeProximity = false;
484            }
485            if (mScreenOffBecauseOfProximity
486                    && mProximity != PROXIMITY_POSITIVE) {
487                mScreenOffBecauseOfProximity = false;
488                sendOnProximityNegativeWithWakelock();
489            }
490        } else {
491            mWaitingForNegativeProximity = false;
492        }
493
494        // Turn on the light sensor if needed.
495        if (mAutomaticBrightnessController != null) {
496            mAutomaticBrightnessController.updatePowerState(mPowerRequest);
497        }
498
499        // Set the screen brightness.
500        if (mPowerRequest.wantScreenOnAny()) {
501            int target;
502            boolean slow;
503            int screenAutoBrightness = mAutomaticBrightnessController != null ?
504                    mAutomaticBrightnessController.getAutomaticScreenBrightness() : -1;
505            if (screenAutoBrightness >= 0 && mPowerRequest.useAutoBrightness) {
506                // Use current auto-brightness value.
507                target = screenAutoBrightness;
508                slow = mUsingScreenAutoBrightness && !autoBrightnessAdjustmentChanged;
509                mUsingScreenAutoBrightness = true;
510            } else {
511                // Light sensor is disabled or not ready yet.
512                // Use the current brightness setting from the request, which is expected
513                // provide a nominal default value for the case where auto-brightness
514                // is not ready yet.
515                target = mPowerRequest.screenBrightness;
516                slow = false;
517                mUsingScreenAutoBrightness = false;
518            }
519            if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE) {
520                // Dim quickly to the doze state.
521                target = mScreenBrightnessDozeConfig;
522                slow = false;
523            } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
524                // Dim quickly by at least some minimum amount.
525                target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
526                        mScreenBrightnessDimConfig);
527                slow = false;
528            } else if (wasDimOrDoze) {
529                // Brighten quickly.
530                slow = false;
531            }
532            // If low power mode is enabled, brightness level
533            // would be scaled down to half
534            if (mPowerRequest.lowPowerMode) {
535                target = target/2;
536            }
537            animateScreenBrightness(clampScreenBrightness(target),
538                    slow ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
539        } else {
540            // Screen is off.  Don't bother changing the brightness.
541            mUsingScreenAutoBrightness = false;
542        }
543
544        // Animate the screen on or off unless blocked.
545        if (mScreenOffBecauseOfProximity) {
546            // Screen off due to proximity.
547            setScreenState(Display.STATE_OFF);
548            unblockScreenOn();
549        } else if (mPowerRequest.wantScreenOnAny()) {
550            // Want screen on.
551            // Wait for previous off animation to complete beforehand.
552            // It is relatively short but if we cancel it and switch to the
553            // on animation immediately then the results are pretty ugly.
554            if (!mElectronBeamOffAnimator.isStarted()) {
555                // Turn the screen on.  The contents of the screen may not yet
556                // be visible if the electron beam has not been dismissed because
557                // its last frame of animation is solid black.
558
559                if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE) {
560                    if (!mScreenBrightnessRampAnimator.isAnimating()) {
561                        setScreenState(Display.STATE_DOZING);
562                    }
563                } else {
564                    setScreenState(Display.STATE_ON);
565                }
566
567                if (mPowerRequest.blockScreenOn
568                        && mPowerState.getElectronBeamLevel() == 0.0f) {
569                    blockScreenOn();
570                } else {
571                    unblockScreenOn();
572                    if (USE_ELECTRON_BEAM_ON_ANIMATION) {
573                        if (!mElectronBeamOnAnimator.isStarted()) {
574                            if (mPowerState.getElectronBeamLevel() == 1.0f) {
575                                mPowerState.dismissElectronBeam();
576                            } else if (mPowerState.prepareElectronBeam(
577                                    mElectronBeamFadesConfig ?
578                                            ElectronBeam.MODE_FADE :
579                                                    ElectronBeam.MODE_WARM_UP)) {
580                                mElectronBeamOnAnimator.start();
581                            } else {
582                                mElectronBeamOnAnimator.end();
583                            }
584                        }
585                    } else {
586                        mPowerState.setElectronBeamLevel(1.0f);
587                        mPowerState.dismissElectronBeam();
588                    }
589                }
590            }
591        } else {
592            // Want screen off.
593            // Wait for previous on animation to complete beforehand.
594            unblockScreenOn();
595            if (!mElectronBeamOnAnimator.isStarted()) {
596                if (!mElectronBeamOffAnimator.isStarted()) {
597                    if (mPowerState.getElectronBeamLevel() == 0.0f) {
598                        setScreenState(Display.STATE_OFF);
599                    } else if (mPowerState.prepareElectronBeam(
600                            mElectronBeamFadesConfig ?
601                                    ElectronBeam.MODE_FADE :
602                                            ElectronBeam.MODE_COOL_DOWN)
603                            && mPowerState.getScreenState() != Display.STATE_OFF) {
604                        mElectronBeamOffAnimator.start();
605                    } else {
606                        mElectronBeamOffAnimator.end();
607                    }
608                }
609            }
610        }
611
612        // Report whether the display is ready for use.
613        // We mostly care about the screen state here, ignoring brightness changes
614        // which will be handled asynchronously.
615        if (mustNotify
616                && !mScreenOnWasBlocked
617                && !mElectronBeamOnAnimator.isStarted()
618                && !mElectronBeamOffAnimator.isStarted()
619                && !mScreenBrightnessRampAnimator.isAnimating()
620                && mPowerState.waitUntilClean(mCleanListener)) {
621            synchronized (mLock) {
622                if (!mPendingRequestChangedLocked) {
623                    mDisplayReadyLocked = true;
624
625                    if (DEBUG) {
626                        Slog.d(TAG, "Display ready!");
627                    }
628                }
629            }
630            sendOnStateChangedWithWakelock();
631        }
632    }
633
634    @Override
635    public void updateBrightness() {
636        sendUpdatePowerState();
637    }
638
639    private void blockScreenOn() {
640        if (!mScreenOnWasBlocked) {
641            mScreenOnWasBlocked = true;
642            mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
643            if (DEBUG) {
644                Slog.d(TAG, "Blocked screen on.");
645            }
646        }
647    }
648
649    private void unblockScreenOn() {
650        if (mScreenOnWasBlocked) {
651            mScreenOnWasBlocked = false;
652            long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
653            if (delay > 1000 || DEBUG) {
654                Slog.d(TAG, "Unblocked screen on after " + delay + " ms");
655            }
656        }
657    }
658
659    private void setScreenState(int state) {
660        if (mPowerState.getScreenState() != state) {
661            mPowerState.setScreenState(state);
662            try {
663                mBatteryStats.noteScreenState(state);
664            } catch (RemoteException ex) {
665                // same process
666            }
667        }
668    }
669
670    private int clampScreenBrightness(int value) {
671        return MathUtils.constrain(
672                value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
673    }
674
675    private void animateScreenBrightness(int target, int rate) {
676        if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
677            try {
678                mBatteryStats.noteScreenBrightness(target);
679            } catch (RemoteException ex) {
680                // same process
681            }
682        }
683    }
684
685    private final Runnable mCleanListener = new Runnable() {
686        @Override
687        public void run() {
688            sendUpdatePowerState();
689        }
690    };
691
692    private void setProximitySensorEnabled(boolean enable) {
693        if (enable) {
694            if (!mProximitySensorEnabled) {
695                // Register the listener.
696                // Proximity sensor state already cleared initially.
697                mProximitySensorEnabled = true;
698                mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
699                        SensorManager.SENSOR_DELAY_NORMAL, mHandler);
700            }
701        } else {
702            if (mProximitySensorEnabled) {
703                // Unregister the listener.
704                // Clear the proximity sensor state for next time.
705                mProximitySensorEnabled = false;
706                mProximity = PROXIMITY_UNKNOWN;
707                mPendingProximity = PROXIMITY_UNKNOWN;
708                mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
709                mSensorManager.unregisterListener(mProximitySensorListener);
710                clearPendingProximityDebounceTime(); // release wake lock (must be last)
711            }
712        }
713    }
714
715    private void handleProximitySensorEvent(long time, boolean positive) {
716        if (mProximitySensorEnabled) {
717            if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
718                return; // no change
719            }
720            if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
721                return; // no change
722            }
723
724            // Only accept a proximity sensor reading if it remains
725            // stable for the entire debounce delay.  We hold a wake lock while
726            // debouncing the sensor.
727            mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
728            if (positive) {
729                mPendingProximity = PROXIMITY_POSITIVE;
730                setPendingProximityDebounceTime(
731                        time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); // acquire wake lock
732            } else {
733                mPendingProximity = PROXIMITY_NEGATIVE;
734                setPendingProximityDebounceTime(
735                        time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); // acquire wake lock
736            }
737
738            // Debounce the new sensor reading.
739            debounceProximitySensor();
740        }
741    }
742
743    private void debounceProximitySensor() {
744        if (mProximitySensorEnabled
745                && mPendingProximity != PROXIMITY_UNKNOWN
746                && mPendingProximityDebounceTime >= 0) {
747            final long now = SystemClock.uptimeMillis();
748            if (mPendingProximityDebounceTime <= now) {
749                // Sensor reading accepted.  Apply the change then release the wake lock.
750                mProximity = mPendingProximity;
751                updatePowerState();
752                clearPendingProximityDebounceTime(); // release wake lock (must be last)
753            } else {
754                // Need to wait a little longer.
755                // Debounce again later.  We continue holding a wake lock while waiting.
756                Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
757                msg.setAsynchronous(true);
758                mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
759            }
760        }
761    }
762
763    private void clearPendingProximityDebounceTime() {
764        if (mPendingProximityDebounceTime >= 0) {
765            mPendingProximityDebounceTime = -1;
766            mCallbacks.releaseSuspendBlocker(); // release wake lock
767        }
768    }
769
770    private void setPendingProximityDebounceTime(long debounceTime) {
771        if (mPendingProximityDebounceTime < 0) {
772            mCallbacks.acquireSuspendBlocker(); // acquire wake lock
773        }
774        mPendingProximityDebounceTime = debounceTime;
775    }
776
777    private void sendOnStateChangedWithWakelock() {
778        mCallbacks.acquireSuspendBlocker();
779        mHandler.post(mOnStateChangedRunnable);
780    }
781
782    private final Runnable mOnStateChangedRunnable = new Runnable() {
783        @Override
784        public void run() {
785            mCallbacks.onStateChanged();
786            mCallbacks.releaseSuspendBlocker();
787        }
788    };
789
790    private void sendOnProximityPositiveWithWakelock() {
791        mCallbacks.acquireSuspendBlocker();
792        mHandler.post(mOnProximityPositiveRunnable);
793    }
794
795    private final Runnable mOnProximityPositiveRunnable = new Runnable() {
796        @Override
797        public void run() {
798            mCallbacks.onProximityPositive();
799            mCallbacks.releaseSuspendBlocker();
800        }
801    };
802
803    private void sendOnProximityNegativeWithWakelock() {
804        mCallbacks.acquireSuspendBlocker();
805        mHandler.post(mOnProximityNegativeRunnable);
806    }
807
808    private final Runnable mOnProximityNegativeRunnable = new Runnable() {
809        @Override
810        public void run() {
811            mCallbacks.onProximityNegative();
812            mCallbacks.releaseSuspendBlocker();
813        }
814    };
815
816    public void dump(final PrintWriter pw) {
817        synchronized (mLock) {
818            pw.println();
819            pw.println("Display Power Controller Locked State:");
820            pw.println("  mDisplayReadyLocked=" + mDisplayReadyLocked);
821            pw.println("  mPendingRequestLocked=" + mPendingRequestLocked);
822            pw.println("  mPendingRequestChangedLocked=" + mPendingRequestChangedLocked);
823            pw.println("  mPendingWaitForNegativeProximityLocked="
824                    + mPendingWaitForNegativeProximityLocked);
825            pw.println("  mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked);
826        }
827
828        pw.println();
829        pw.println("Display Power Controller Configuration:");
830        pw.println("  mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
831        pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
832        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
833        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
834        pw.println("  mUseSoftwareAutoBrightnessConfig="
835                + mUseSoftwareAutoBrightnessConfig);
836
837        mHandler.runWithScissors(new Runnable() {
838            @Override
839            public void run() {
840                dumpLocal(pw);
841            }
842        }, 1000);
843    }
844
845    private void dumpLocal(PrintWriter pw) {
846        pw.println();
847        pw.println("Display Power Controller Thread State:");
848        pw.println("  mPowerRequest=" + mPowerRequest);
849        pw.println("  mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
850
851        pw.println("  mProximitySensor=" + mProximitySensor);
852        pw.println("  mProximitySensorEnabled=" + mProximitySensorEnabled);
853        pw.println("  mProximityThreshold=" + mProximityThreshold);
854        pw.println("  mProximity=" + proximityToString(mProximity));
855        pw.println("  mPendingProximity=" + proximityToString(mPendingProximity));
856        pw.println("  mPendingProximityDebounceTime="
857                + TimeUtils.formatUptime(mPendingProximityDebounceTime));
858        pw.println("  mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
859        pw.println("  mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
860
861        pw.println("  mScreenBrightnessRampAnimator.isAnimating()=" +
862                mScreenBrightnessRampAnimator.isAnimating());
863
864        if (mElectronBeamOnAnimator != null) {
865            pw.println("  mElectronBeamOnAnimator.isStarted()=" +
866                    mElectronBeamOnAnimator.isStarted());
867        }
868        if (mElectronBeamOffAnimator != null) {
869            pw.println("  mElectronBeamOffAnimator.isStarted()=" +
870                    mElectronBeamOffAnimator.isStarted());
871        }
872
873        if (mPowerState != null) {
874            mPowerState.dump(pw);
875        }
876
877        if (mAutomaticBrightnessController != null) {
878            mAutomaticBrightnessController.dump(pw);
879        }
880
881    }
882
883    private static String proximityToString(int state) {
884        switch (state) {
885            case PROXIMITY_UNKNOWN:
886                return "Unknown";
887            case PROXIMITY_NEGATIVE:
888                return "Negative";
889            case PROXIMITY_POSITIVE:
890                return "Positive";
891            default:
892                return Integer.toString(state);
893        }
894    }
895
896    private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
897        try {
898            final int n = brightness.length;
899            float[] x = new float[n];
900            float[] y = new float[n];
901            y[0] = normalizeAbsoluteBrightness(brightness[0]);
902            for (int i = 1; i < n; i++) {
903                x[i] = lux[i - 1];
904                y[i] = normalizeAbsoluteBrightness(brightness[i]);
905            }
906
907            Spline spline = Spline.createMonotoneCubicSpline(x, y);
908            if (DEBUG) {
909                Slog.d(TAG, "Auto-brightness spline: " + spline);
910                for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
911                    Slog.d(TAG, String.format("  %7.1f: %7.1f", v, spline.interpolate(v)));
912                }
913            }
914            return spline;
915        } catch (IllegalArgumentException ex) {
916            Slog.e(TAG, "Could not create auto-brightness spline.", ex);
917            return null;
918        }
919    }
920
921    private static float normalizeAbsoluteBrightness(int value) {
922        return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
923    }
924
925    private static int clampAbsoluteBrightness(int value) {
926        return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
927    }
928
929    private final class DisplayControllerHandler extends Handler {
930        public DisplayControllerHandler(Looper looper) {
931            super(looper, null, true /*async*/);
932        }
933
934        @Override
935        public void handleMessage(Message msg) {
936            switch (msg.what) {
937                case MSG_UPDATE_POWER_STATE:
938                    updatePowerState();
939                    break;
940
941                case MSG_PROXIMITY_SENSOR_DEBOUNCED:
942                    debounceProximitySensor();
943                    break;
944            }
945        }
946    }
947
948    private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
949        @Override
950        public void onSensorChanged(SensorEvent event) {
951            if (mProximitySensorEnabled) {
952                final long time = SystemClock.uptimeMillis();
953                final float distance = event.values[0];
954                boolean positive = distance >= 0.0f && distance < mProximityThreshold;
955                handleProximitySensorEvent(time, positive);
956            }
957        }
958
959        @Override
960        public void onAccuracyChanged(Sensor sensor, int accuracy) {
961            // Not used.
962        }
963    };
964}
965