AutomaticBrightnessController.java revision 908b86c796443ba4ec55c669e8a0297fc80574a6
1639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright/*
2639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright * Copyright (C) 2014 The Android Open Source Project
3639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright *
4639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright * Licensed under the Apache License, Version 2.0 (the "License");
5639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright * you may not use this file except in compliance with the License.
6639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright * You may obtain a copy of the License at
7639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright *
8639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright *      http://www.apache.org/licenses/LICENSE-2.0
9639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright *
10639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright * Unless required by applicable law or agreed to in writing, software
11639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright * distributed under the License is distributed on an "AS IS" BASIS,
12639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright * See the License for the specific language governing permissions and
14639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright * limitations under the License.
15639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright */
16639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
17131206b8a9d07400d7c98aea50cc45c38769448fJeff Brownpackage com.android.server.display;
18639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
19a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brownimport com.android.server.EventLogTags;
20131206b8a9d07400d7c98aea50cc45c38769448fJeff Brownimport com.android.server.LocalServices;
21639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport com.android.server.twilight.TwilightListener;
22639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport com.android.server.twilight.TwilightManager;
23639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport com.android.server.twilight.TwilightState;
24639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
25908b86c796443ba4ec55c669e8a0297fc80574a6Justin Klaassenimport android.annotation.Nullable;
26639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.hardware.Sensor;
27639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.hardware.SensorEvent;
28639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.hardware.SensorEventListener;
29639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.hardware.SensorManager;
30639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.Handler;
31639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.Looper;
32639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.Message;
33639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.PowerManager;
34639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.SystemClock;
35639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.text.format.DateUtils;
36a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brownimport android.util.EventLog;
37639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.util.MathUtils;
38639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.util.Spline;
39639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.util.Slog;
40639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.util.TimeUtils;
41639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
42639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport java.io.PrintWriter;
43639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
44639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightclass AutomaticBrightnessController {
45639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final String TAG = "AutomaticBrightnessController";
46639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
47639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final boolean DEBUG = false;
48639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
49639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
50639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // If true, enables the use of the screen auto-brightness adjustment setting.
51daf7d410fc97647f2b3ab4254f73c09c923018deAdrian Roos    private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT = true;
52639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
53639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Hysteresis constraints for brightening or darkening.
54639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The recent lux must have changed by at least this fraction relative to the
55639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // current ambient lux before a change will be considered.
56639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final float BRIGHTENING_LIGHT_HYSTERESIS = 0.10f;
57639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final float DARKENING_LIGHT_HYSTERESIS = 0.20f;
58639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
59639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // How long the current sensor reading is assumed to be valid beyond the current time.
60639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // This provides a bit of prediction, as well as ensures that the weight for the last sample is
61639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // non-zero, which in turn ensures that the total weight is non-zero.
62639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final long AMBIENT_LIGHT_PREDICTION_TIME_MILLIS = 100;
63639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
64639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Specifies the maximum magnitude of the time of day adjustment.
655dbd4aad809e6fec51df62280bcc1bfe05cc7df5Jason Monk    private static final float TWILIGHT_ADJUSTMENT_MAX_GAMMA = 1f;
66639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
67a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    // Debounce for sampling user-initiated changes in display brightness to ensure
68a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    // the user is satisfied with the result before storing the sample.
69a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private static final int BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS = 10000;
70a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
71639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final int MSG_UPDATE_AMBIENT_LUX = 1;
72a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2;
73639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
74639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Callbacks for requesting updates to the the display's power state
75639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final Callbacks mCallbacks;
76639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
77639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The sensor manager.
78639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final SensorManager mSensorManager;
79639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
80639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The light sensor, or null if not available or needed.
81639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final Sensor mLightSensor;
82639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
83639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The twilight service.
84639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final TwilightManager mTwilight;
85639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
86639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The auto-brightness spline adjustment.
87639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The brightness values have been scaled to a range of 0..1.
88639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final Spline mScreenAutoBrightnessSpline;
89639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
90639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The minimum and maximum screen brightnesses.
91639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final int mScreenBrightnessRangeMinimum;
92639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final int mScreenBrightnessRangeMaximum;
93a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski    private final float mDozeScaleFactor;
94639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
95d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // Light sensor event rate in milliseconds.
96d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    private final int mLightSensorRate;
97d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski
98d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // Stability requirements in milliseconds for accepting a new brightness level.  This is used
99d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // for debouncing the light sensor.  Different constants are used to debounce the light sensor
100d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // when adapting to brighter or darker environments.  This parameter controls how quickly
101d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // brightness changes occur in response to an observed change in light level that exceeds the
102d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // hysteresis threshold.
103d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    private final long mBrighteningLightDebounceConfig;
104d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    private final long mDarkeningLightDebounceConfig;
105d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski
106d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // If true immediately after the screen is turned on the controller will try to adjust the
107d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // brightness based on the current sensor reads. If false, the controller will collect more data
108d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // and only then decide whether to change brightness.
109d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    private final boolean mResetAmbientLuxAfterWarmUpConfig;
110d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski
1116fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // Period of time in which to consider light samples in milliseconds.
1126fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private final int mAmbientLightHorizon;
1136fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic
1146fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // The intercept used for the weighting calculation. This is used in order to keep all possible
1156fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // weighting values positive.
1166fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private final int mWeightingIntercept;
1176fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic
118639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Amount of time to delay auto-brightness after screen on while waiting for
119639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // the light sensor to warm-up in milliseconds.
120639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // May be 0 if no warm-up is required.
121639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int mLightSensorWarmUpTimeConfig;
122639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
123639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Set to true if the light sensor is enabled.
124639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean mLightSensorEnabled;
125639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
126639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The time when the light sensor was enabled.
127639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long mLightSensorEnableTime;
128639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
129639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The currently accepted nominal ambient light level.
130639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mAmbientLux;
131639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
132639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // True if mAmbientLux holds a valid value.
133639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean mAmbientLuxValid;
134639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
135639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The ambient light level threshold at which to brighten or darken the screen.
136639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mBrighteningLuxThreshold;
137639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mDarkeningLuxThreshold;
138639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
139639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The most recent light sample.
140639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mLastObservedLux;
141639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
142639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The time of the most light recent sample.
143639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long mLastObservedLuxTime;
144639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
145639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The number of light samples collected since the light sensor was enabled.
146639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int mRecentLightSamples;
147639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
148639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // A ring buffer containing all of the recent ambient light sensor readings.
149639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private AmbientLightRingBuffer mAmbientLightRingBuffer;
150639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
151103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright    // A ring buffer containing the light sensor readings for the initial horizon period.
152103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright    private AmbientLightRingBuffer mInitialHorizonAmbientLightRingBuffer;
153103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright
154639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The handler
155639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private AutomaticBrightnessHandler mHandler;
156639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
157639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The screen brightness level that has been chosen by the auto-brightness
158639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // algorithm.  The actual brightness should ramp towards this value.
159639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // We preserve this value even when we stop using the light sensor so
160639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // that we can quickly revert to the previous auto-brightness level
161639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // while the light sensor warms up.
162639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Use -1 if there is no current auto-brightness value available.
163639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int mScreenAutoBrightness = -1;
164639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
165639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The screen auto-brightness adjustment factor in the range -1 (dimmer) to 1 (brighter)
166639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mScreenAutoBrightnessAdjustment = 0.0f;
167639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
1686fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // The maximum range of gamma adjustment possible using the screen
1696fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // auto-brightness adjustment setting.
1706fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private float mScreenAutoBrightnessAdjustmentMaxGamma;
1716fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic
172639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The last screen auto-brightness gamma.  (For printing in dump() only.)
173639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mLastScreenAutoBrightnessGamma = 1.0f;
174639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
175a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski    // Are we going to adjust brightness while dozing.
176a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski    private boolean mDozing;
177a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski
178a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    // True if we are collecting a brightness adjustment sample, along with some data
179a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    // for the initial state of the sample.
180a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private boolean mBrightnessAdjustmentSamplePending;
181a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private float mBrightnessAdjustmentSampleOldAdjustment;
182a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private float mBrightnessAdjustmentSampleOldLux;
183a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private int mBrightnessAdjustmentSampleOldBrightness;
184a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private float mBrightnessAdjustmentSampleOldGamma;
185a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
1865dbd4aad809e6fec51df62280bcc1bfe05cc7df5Jason Monk    private boolean mUseTwilight;
1875dbd4aad809e6fec51df62280bcc1bfe05cc7df5Jason Monk
188639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
189a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski            SensorManager sensorManager, Spline autoBrightnessSpline, int lightSensorWarmUpTime,
190d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski            int brightnessMin, int brightnessMax, float dozeScaleFactor,
191d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski            int lightSensorRate, long brighteningLightDebounceConfig,
1926fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic            long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
1936fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic            int ambientLightHorizon, float autoBrightnessAdjustmentMaxGamma ) {
194639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mCallbacks = callbacks;
195131206b8a9d07400d7c98aea50cc45c38769448fJeff Brown        mTwilight = LocalServices.getService(TwilightManager.class);
196639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mSensorManager = sensorManager;
197639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mScreenAutoBrightnessSpline = autoBrightnessSpline;
198639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mScreenBrightnessRangeMinimum = brightnessMin;
199639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mScreenBrightnessRangeMaximum = brightnessMax;
200639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime;
201a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        mDozeScaleFactor = dozeScaleFactor;
202d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mLightSensorRate = lightSensorRate;
203d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mBrighteningLightDebounceConfig = brighteningLightDebounceConfig;
204d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mDarkeningLightDebounceConfig = darkeningLightDebounceConfig;
205d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig;
2066fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        mAmbientLightHorizon = ambientLightHorizon;
2076fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        mWeightingIntercept = ambientLightHorizon;
2086fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        mScreenAutoBrightnessAdjustmentMaxGamma = autoBrightnessAdjustmentMaxGamma;
209639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
210639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mHandler = new AutomaticBrightnessHandler(looper);
211103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright        mAmbientLightRingBuffer =
212103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright            new AmbientLightRingBuffer(mLightSensorRate, mAmbientLightHorizon);
213103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright        mInitialHorizonAmbientLightRingBuffer =
214103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright            new AmbientLightRingBuffer(mLightSensorRate, mAmbientLightHorizon);
215639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
216639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
217639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
218639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
219639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
220639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
221639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    public int getAutomaticScreenBrightness() {
222a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        if (mDozing) {
223a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski            return (int) (mScreenAutoBrightness * mDozeScaleFactor);
224a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        }
225639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return mScreenAutoBrightness;
226639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
227639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
228a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    public void configure(boolean enable, float adjustment, boolean dozing,
2295dbd4aad809e6fec51df62280bcc1bfe05cc7df5Jason Monk            boolean userInitiatedChange, boolean useTwilight) {
230a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // While dozing, the application processor may be suspended which will prevent us from
231a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // receiving new information from the light sensor. On some devices, we may be able to
232a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // switch to a wake-up light sensor instead but for now we will simply disable the sensor
233a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // and hold onto the last computed screen auto brightness.  We save the dozing flag for
234a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // debugging purposes.
235a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        mDozing = dozing;
236a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        boolean changed = setLightSensorEnabled(enable && !dozing);
237970d4132ea28e748c1010be39450a98bbf7466f3Jeff Brown        changed |= setScreenAutoBrightnessAdjustment(adjustment);
2385dbd4aad809e6fec51df62280bcc1bfe05cc7df5Jason Monk        changed |= setUseTwilight(useTwilight);
239970d4132ea28e748c1010be39450a98bbf7466f3Jeff Brown        if (changed) {
240639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            updateAutoBrightness(false /*sendUpdate*/);
241639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
242a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        if (enable && !dozing && userInitiatedChange) {
243a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            prepareBrightnessAdjustmentSample();
244a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        }
245639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
246639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
2475dbd4aad809e6fec51df62280bcc1bfe05cc7df5Jason Monk    private boolean setUseTwilight(boolean useTwilight) {
2485dbd4aad809e6fec51df62280bcc1bfe05cc7df5Jason Monk        if (mUseTwilight == useTwilight) return false;
2495dbd4aad809e6fec51df62280bcc1bfe05cc7df5Jason Monk        if (useTwilight) {
2505dbd4aad809e6fec51df62280bcc1bfe05cc7df5Jason Monk            mTwilight.registerListener(mTwilightListener, mHandler);
2515dbd4aad809e6fec51df62280bcc1bfe05cc7df5Jason Monk        } else {
2525dbd4aad809e6fec51df62280bcc1bfe05cc7df5Jason Monk            mTwilight.unregisterListener(mTwilightListener);
2535dbd4aad809e6fec51df62280bcc1bfe05cc7df5Jason Monk        }
2545dbd4aad809e6fec51df62280bcc1bfe05cc7df5Jason Monk        mUseTwilight = useTwilight;
2555dbd4aad809e6fec51df62280bcc1bfe05cc7df5Jason Monk        return true;
2565dbd4aad809e6fec51df62280bcc1bfe05cc7df5Jason Monk    }
2575dbd4aad809e6fec51df62280bcc1bfe05cc7df5Jason Monk
258639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    public void dump(PrintWriter pw) {
259639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println();
260639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("Automatic Brightness Controller Configuration:");
261639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline);
262639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
263639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
264639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
265d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        pw.println("  mBrighteningLightDebounceConfig=" + mBrighteningLightDebounceConfig);
266d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        pw.println("  mDarkeningLightDebounceConfig=" + mDarkeningLightDebounceConfig);
267d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        pw.println("  mResetAmbientLuxAfterWarmUpConfig=" + mResetAmbientLuxAfterWarmUpConfig);
268639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
269639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println();
270639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("Automatic Brightness Controller State:");
271639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensor=" + mLightSensor);
272908b86c796443ba4ec55c669e8a0297fc80574a6Justin Klaassen        pw.println("  mTwilight.getLastTwilightState()=" + mTwilight.getLastTwilightState());
273639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensorEnabled=" + mLightSensorEnabled);
274639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensorEnableTime=" + TimeUtils.formatUptime(mLightSensorEnableTime));
275639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mAmbientLux=" + mAmbientLux);
2766fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        pw.println("  mAmbientLightHorizon=" + mAmbientLightHorizon);
277639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mBrighteningLuxThreshold=" + mBrighteningLuxThreshold);
278639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mDarkeningLuxThreshold=" + mDarkeningLuxThreshold);
279639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLastObservedLux=" + mLastObservedLux);
280639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLastObservedLuxTime=" + TimeUtils.formatUptime(mLastObservedLuxTime));
281639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mRecentLightSamples=" + mRecentLightSamples);
282639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mAmbientLightRingBuffer=" + mAmbientLightRingBuffer);
283103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright        pw.println("  mInitialHorizonAmbientLightRingBuffer=" +
284103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright                mInitialHorizonAmbientLightRingBuffer);
285639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenAutoBrightness=" + mScreenAutoBrightness);
286639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenAutoBrightnessAdjustment=" + mScreenAutoBrightnessAdjustment);
2876fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        pw.println("  mScreenAutoBrightnessAdjustmentMaxGamma=" + mScreenAutoBrightnessAdjustmentMaxGamma);
288639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
289a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        pw.println("  mDozing=" + mDozing);
290639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
291639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
292639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean setLightSensorEnabled(boolean enable) {
293639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (enable) {
294639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (!mLightSensorEnabled) {
295639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorEnabled = true;
296639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorEnableTime = SystemClock.uptimeMillis();
297639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mSensorManager.registerListener(mLightSensorListener, mLightSensor,
298d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski                        mLightSensorRate * 1000, mHandler);
299639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                return true;
300639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
301639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        } else {
302639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mLightSensorEnabled) {
303639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorEnabled = false;
304d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski                mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
305639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRecentLightSamples = 0;
306639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mAmbientLightRingBuffer.clear();
307103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright                mInitialHorizonAmbientLightRingBuffer.clear();
308639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
309639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mSensorManager.unregisterListener(mLightSensorListener);
310639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
311639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
312639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return false;
313639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
314639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
315639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void handleLightSensorEvent(long time, float lux) {
316639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
317639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
318639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        applyLightSensorMeasurement(time, lux);
319639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        updateAmbientLux(time);
320639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
321639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
322639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void applyLightSensorMeasurement(long time, float lux) {
323639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mRecentLightSamples++;
324103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright        // Store all of the light measurements for the intial horizon period. This is to help
325103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright        // diagnose dim wake ups and slow responses in b/27951906.
326103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright        if (time <= mLightSensorEnableTime + mAmbientLightHorizon) {
327103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright            mInitialHorizonAmbientLightRingBuffer.push(time, lux);
328103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright        }
3296fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
330639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mAmbientLightRingBuffer.push(time, lux);
331639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
332639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // Remember this sample value.
333639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mLastObservedLux = lux;
334639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mLastObservedLuxTime = time;
335639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
336639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
337639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean setScreenAutoBrightnessAdjustment(float adjustment) {
338639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (adjustment != mScreenAutoBrightnessAdjustment) {
339639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mScreenAutoBrightnessAdjustment = adjustment;
340639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return true;
341639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
342639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return false;
343639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
344639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
345639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void setAmbientLux(float lux) {
346639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mAmbientLux = lux;
347639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mBrighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
348639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mDarkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
349639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
350639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
351639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float calculateAmbientLux(long now) {
352639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        final int N = mAmbientLightRingBuffer.size();
353639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (N == 0) {
354639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            Slog.e(TAG, "calculateAmbientLux: No ambient light readings available");
355639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return -1;
356639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
357639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float sum = 0;
358639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float totalWeight = 0;
359639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long endTime = AMBIENT_LIGHT_PREDICTION_TIME_MILLIS;
360639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        for (int i = N - 1; i >= 0; i--) {
361639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            long startTime = (mAmbientLightRingBuffer.getTime(i) - now);
362639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            float weight = calculateWeight(startTime, endTime);
363639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            float lux = mAmbientLightRingBuffer.getLux(i);
364639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
365639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "calculateAmbientLux: [" +
366639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        (startTime) + ", " +
367639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        (endTime) + "]: lux=" + lux + ", weight=" + weight);
368639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
369639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            totalWeight += weight;
370639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            sum += mAmbientLightRingBuffer.getLux(i) * weight;
371639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            endTime = startTime;
372639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
373639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (DEBUG) {
374639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            Slog.d(TAG, "calculateAmbientLux: totalWeight=" + totalWeight +
375639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    ", newAmbientLux=" + (sum / totalWeight));
376639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
377639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return sum / totalWeight;
378639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
379639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
3806fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private float calculateWeight(long startDelta, long endDelta) {
381639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return weightIntegral(endDelta) - weightIntegral(startDelta);
382639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
383639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
3846fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // Evaluates the integral of y = x + mWeightingIntercept. This is always positive for the
385639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // horizon we're looking at and provides a non-linear weighting for light samples.
3866fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private float weightIntegral(long x) {
3876fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        return x * (x * 0.5f + mWeightingIntercept);
388639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
389639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
390639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long nextAmbientLightBrighteningTransition(long time) {
391639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        final int N = mAmbientLightRingBuffer.size();
392639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long earliestValidTime = time;
393639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        for (int i = N - 1; i >= 0; i--) {
394639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mAmbientLightRingBuffer.getLux(i) <= mBrighteningLuxThreshold) {
395639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                break;
396639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
397639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            earliestValidTime = mAmbientLightRingBuffer.getTime(i);
398639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
399d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        return earliestValidTime + mBrighteningLightDebounceConfig;
400639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
401639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
402639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long nextAmbientLightDarkeningTransition(long time) {
403639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        final int N = mAmbientLightRingBuffer.size();
404639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long earliestValidTime = time;
405639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        for (int i = N - 1; i >= 0; i--) {
406639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mAmbientLightRingBuffer.getLux(i) >= mDarkeningLuxThreshold) {
407639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                break;
408639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
409639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            earliestValidTime = mAmbientLightRingBuffer.getTime(i);
410639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
411d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        return earliestValidTime + mDarkeningLightDebounceConfig;
412639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
413639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
414639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void updateAmbientLux() {
415639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long time = SystemClock.uptimeMillis();
4166fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
417639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        updateAmbientLux(time);
418639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
419639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
420639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void updateAmbientLux(long time) {
421639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // If the light sensor was just turned on then immediately update our initial
422639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // estimate of the current ambient light level.
423639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (!mAmbientLuxValid) {
424639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            final long timeWhenSensorWarmedUp =
425639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
426639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (time < timeWhenSensorWarmedUp) {
427639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (DEBUG) {
428639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    Slog.d(TAG, "updateAmbientLux: Sensor not  ready yet: "
429639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                            + "time=" + time
430639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                            + ", timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp);
431639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
432639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX,
433639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        timeWhenSensorWarmedUp);
434639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                return;
435639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
436639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            setAmbientLux(calculateAmbientLux(time));
437639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mAmbientLuxValid = true;
438639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
439639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "updateAmbientLux: Initializing: "
440639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer
441639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + ", mAmbientLux=" + mAmbientLux);
442639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
443639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            updateAutoBrightness(true);
444639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
445639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
446639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
447639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
448639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float ambientLux = calculateAmbientLux(time);
449639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
450639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (ambientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time
451639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                || ambientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) {
452639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            setAmbientLux(ambientLux);
453639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
454639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "updateAmbientLux: "
455639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + ((ambientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
456639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
457639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + ", mAmbientLightRingBuffer=" + mAmbientLightRingBuffer
458639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + ", mAmbientLux=" + mAmbientLux);
459639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
460639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            updateAutoBrightness(true);
461639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
462639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
463639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
464639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long nextTransitionTime = Math.min(nextDarkenTransition, nextBrightenTransition);
465639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // If one of the transitions is ready to occur, but the total weighted ambient lux doesn't
466639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // exceed the necessary threshold, then it's possible we'll get a transition time prior to
467639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // now. Rather than continually checking to see whether the weighted lux exceeds the
468639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // threshold, schedule an update for when we'd normally expect another light sample, which
469639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // should be enough time to decide whether we should actually transition to the new
470639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // weighted ambient lux or not.
471639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        nextTransitionTime =
472d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski                nextTransitionTime > time ? nextTransitionTime : time + mLightSensorRate;
473639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (DEBUG) {
474639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for "
475639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    + nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
476639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
477639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);
478639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
479639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
480639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void updateAutoBrightness(boolean sendUpdate) {
481639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (!mAmbientLuxValid) {
482639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return;
483639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
484639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
485639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);
486639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float gamma = 1.0f;
487639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
488639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
489639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                && mScreenAutoBrightnessAdjustment != 0.0f) {
4906fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic            final float adjGamma = MathUtils.pow(mScreenAutoBrightnessAdjustmentMaxGamma,
491639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    Math.min(1.0f, Math.max(-1.0f, -mScreenAutoBrightnessAdjustment)));
492639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            gamma *= adjGamma;
493639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
494639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma);
495639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
496639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
497639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
4985dbd4aad809e6fec51df62280bcc1bfe05cc7df5Jason Monk        if (mUseTwilight) {
499908b86c796443ba4ec55c669e8a0297fc80574a6Justin Klaassen            TwilightState state = mTwilight.getLastTwilightState();
500639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (state != null && state.isNight()) {
501908b86c796443ba4ec55c669e8a0297fc80574a6Justin Klaassen                final long duration = state.sunriseTimeMillis() - state.sunsetTimeMillis();
502908b86c796443ba4ec55c669e8a0297fc80574a6Justin Klaassen                final long progress = System.currentTimeMillis() - state.sunsetTimeMillis();
503908b86c796443ba4ec55c669e8a0297fc80574a6Justin Klaassen                final float amount = (float) Math.pow(2.0 * progress / duration - 1.0, 2.0);
504908b86c796443ba4ec55c669e8a0297fc80574a6Justin Klaassen                gamma *= 1 + amount * TWILIGHT_ADJUSTMENT_MAX_GAMMA;
505639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (DEBUG) {
506908b86c796443ba4ec55c669e8a0297fc80574a6Justin Klaassen                    Slog.d(TAG, "updateAutoBrightness: twilight amount=" + amount);
507639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
508639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
509639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
510639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
511639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (gamma != 1.0f) {
512639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            final float in = value;
513639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            value = MathUtils.pow(value, gamma);
514639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
515639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma
516639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + ", in=" + in + ", out=" + value);
517639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
518639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
519639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
520639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        int newScreenAutoBrightness =
521a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));
522639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (mScreenAutoBrightness != newScreenAutoBrightness) {
523639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
524639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
525639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + mScreenAutoBrightness + ", newScreenAutoBrightness="
526639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + newScreenAutoBrightness);
527639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
528639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
529639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mScreenAutoBrightness = newScreenAutoBrightness;
530639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mLastScreenAutoBrightnessGamma = gamma;
531639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (sendUpdate) {
532639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mCallbacks.updateBrightness();
533639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
534639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
535639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
536639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
537639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int clampScreenBrightness(int value) {
538639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return MathUtils.constrain(value,
539639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
540639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
541639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
542a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private void prepareBrightnessAdjustmentSample() {
543a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        if (!mBrightnessAdjustmentSamplePending) {
544a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSamplePending = true;
545a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSampleOldAdjustment = mScreenAutoBrightnessAdjustment;
546a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSampleOldLux = mAmbientLuxValid ? mAmbientLux : -1;
547a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSampleOldBrightness = mScreenAutoBrightness;
548a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSampleOldGamma = mLastScreenAutoBrightnessGamma;
549a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        } else {
550a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
551a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        }
552a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
553a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        mHandler.sendEmptyMessageDelayed(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE,
554a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS);
555a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    }
556a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
557a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private void cancelBrightnessAdjustmentSample() {
558a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        if (mBrightnessAdjustmentSamplePending) {
559a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSamplePending = false;
560a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
561a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        }
562a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    }
563a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
564a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private void collectBrightnessAdjustmentSample() {
565a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        if (mBrightnessAdjustmentSamplePending) {
566a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSamplePending = false;
567a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            if (mAmbientLuxValid && mScreenAutoBrightness >= 0) {
568a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                if (DEBUG) {
569a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                    Slog.d(TAG, "Auto-brightness adjustment changed by user: "
570a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                            + "adj=" + mScreenAutoBrightnessAdjustment
571a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                            + ", lux=" + mAmbientLux
572a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                            + ", brightness=" + mScreenAutoBrightness
573a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                            + ", gamma=" + mLastScreenAutoBrightnessGamma
574a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                            + ", ring=" + mAmbientLightRingBuffer);
575a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                }
576a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
577a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                EventLog.writeEvent(EventLogTags.AUTO_BRIGHTNESS_ADJ,
578a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mBrightnessAdjustmentSampleOldAdjustment,
579a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mBrightnessAdjustmentSampleOldLux,
580a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mBrightnessAdjustmentSampleOldBrightness,
581a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mBrightnessAdjustmentSampleOldGamma,
582a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mScreenAutoBrightnessAdjustment,
583a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mAmbientLux,
584a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mScreenAutoBrightness,
585a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mLastScreenAutoBrightnessGamma);
586a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            }
587a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        }
588a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    }
589a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
590639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final class AutomaticBrightnessHandler extends Handler {
591639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public AutomaticBrightnessHandler(Looper looper) {
592639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            super(looper, null, true /*async*/);
593639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
594639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
595639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
596639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void handleMessage(Message msg) {
597639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            switch (msg.what) {
598639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                case MSG_UPDATE_AMBIENT_LUX:
599639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    updateAmbientLux();
600639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    break;
601a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
602a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                case MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE:
603a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                    collectBrightnessAdjustmentSample();
604a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                    break;
605639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
606639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
607639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
608639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
609639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final SensorEventListener mLightSensorListener = new SensorEventListener() {
610639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
611639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void onSensorChanged(SensorEvent event) {
612639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mLightSensorEnabled) {
613639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                final long time = SystemClock.uptimeMillis();
614639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                final float lux = event.values[0];
615639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                handleLightSensorEvent(time, lux);
616639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
617639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
618639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
619639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
620639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void onAccuracyChanged(Sensor sensor, int accuracy) {
621639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            // Not used.
622639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
623639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    };
624639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
625639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final TwilightListener mTwilightListener = new TwilightListener() {
626639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
627908b86c796443ba4ec55c669e8a0297fc80574a6Justin Klaassen        public void onTwilightStateChanged(@Nullable TwilightState state) {
628639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            updateAutoBrightness(true /*sendUpdate*/);
629639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
630639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    };
631639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
632639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    /** Callbacks to request updates to the display's power state. */
633639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    interface Callbacks {
634639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        void updateBrightness();
635639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
636639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
637103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright    private static final class AmbientLightRingBuffer {
638639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // Proportional extra capacity of the buffer beyond the expected number of light samples
639639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // in the horizon
640639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private static final float BUFFER_SLACK = 1.5f;
641639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private float[] mRingLux;
642639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private long[] mRingTime;
643639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mCapacity;
644639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
645639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // The first valid element and the next open slot.
646639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // Note that if mCount is zero then there are no valid elements.
647639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mStart;
648639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mEnd;
649639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mCount;
650639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
6516fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon) {
6526fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic            mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate);
653639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingLux = new float[mCapacity];
654639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingTime = new long[mCapacity];
655639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
656639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
657639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public float getLux(int index) {
658639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return mRingLux[offsetOf(index)];
659639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
660639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
661639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public long getTime(int index) {
662639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return mRingTime[offsetOf(index)];
663639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
664639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
665639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void push(long time, float lux) {
666639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            int next = mEnd;
667639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mCount == mCapacity) {
668639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                int newSize = mCapacity * 2;
669639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
670639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                float[] newRingLux = new float[newSize];
671639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                long[] newRingTime = new long[newSize];
672639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                int length = mCapacity - mStart;
673639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                System.arraycopy(mRingLux, mStart, newRingLux, 0, length);
674639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                System.arraycopy(mRingTime, mStart, newRingTime, 0, length);
675639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (mStart != 0) {
676639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    System.arraycopy(mRingLux, 0, newRingLux, length, mStart);
677639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    System.arraycopy(mRingTime, 0, newRingTime, length, mStart);
678639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
679639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRingLux = newRingLux;
680639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRingTime = newRingTime;
681639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
682639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                next = mCapacity;
683639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mCapacity = newSize;
684639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mStart = 0;
685639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
686639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingTime[next] = time;
687639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingLux[next] = lux;
688639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mEnd = next + 1;
689639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mEnd == mCapacity) {
690639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mEnd = 0;
691639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
692639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mCount++;
693639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
694639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
695639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void prune(long horizon) {
696639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mCount == 0) {
697639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                return;
698639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
699639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
700639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            while (mCount > 1) {
701639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                int next = mStart + 1;
702639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (next >= mCapacity) {
703639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    next -= mCapacity;
704639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
705639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (mRingTime[next] > horizon) {
706639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // Some light sensors only produce data upon a change in the ambient light
707639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // levels, so we need to consider the previous measurement as the ambient light
708639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // level for all points in time up until we receive a new measurement. Thus, we
709639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // always want to keep the youngest element that would be removed from the
710639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // buffer and just set its measurement time to the horizon time since at that
711639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // point it is the ambient light level, and to remove it would be to drop a
712639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // valid data point within our horizon.
713639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    break;
714639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
715639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mStart = next;
716639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mCount -= 1;
717639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
718639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
719639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mRingTime[mStart] < horizon) {
720639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRingTime[mStart] = horizon;
721639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
722639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
723639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
724639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public int size() {
725639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return mCount;
726639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
727639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
728639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void clear() {
729639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mStart = 0;
730639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mEnd = 0;
731639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mCount = 0;
732639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
733639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
734639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
735639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public String toString() {
736a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            StringBuffer buf = new StringBuffer();
737a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            buf.append('[');
738a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            for (int i = 0; i < mCount; i++) {
739a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                final long next = i + 1 < mCount ? getTime(i + 1) : SystemClock.uptimeMillis();
740a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                if (i != 0) {
741a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                    buf.append(", ");
742a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                }
743a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                buf.append(getLux(i));
744a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                buf.append(" / ");
745a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                buf.append(next - getTime(i));
746a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                buf.append("ms");
747639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
748a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            buf.append(']');
749a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            return buf.toString();
750639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
751639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
752639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int offsetOf(int index) {
753639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (index >= mCount || index < 0) {
754639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                throw new ArrayIndexOutOfBoundsException(index);
755639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
756639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            index += mStart;
757639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (index >= mCapacity) {
758639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                index -= mCapacity;
759639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
760639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return index;
761639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
762639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
763639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright}
764