AutomaticBrightnessController.java revision b0a1d3d08fc459e0d9937e299e16de17d1388ac4
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 Wright
22908b86c796443ba4ec55c669e8a0297fc80574a6Justin Klaassenimport android.annotation.Nullable;
23639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.hardware.Sensor;
24639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.hardware.SensorEvent;
25639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.hardware.SensorEventListener;
26639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.hardware.SensorManager;
27639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.Handler;
28639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.Looper;
29639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.Message;
30639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.PowerManager;
31639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.SystemClock;
32b0a1d3d08fc459e0d9937e299e16de17d1388ac4Michael Wrightimport android.os.Trace;
33639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.text.format.DateUtils;
34a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brownimport android.util.EventLog;
35639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.util.MathUtils;
36639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.util.Slog;
37a8edffd804d3940dec1fa5c9777d10beccb2f6a6Soroosh Mariooryadimport android.util.Spline;
38639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.util.TimeUtils;
39639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
40639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport java.io.PrintWriter;
41639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
42639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightclass AutomaticBrightnessController {
43639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final String TAG = "AutomaticBrightnessController";
44639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
45639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final boolean DEBUG = false;
46639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
47639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
48639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // If true, enables the use of the screen auto-brightness adjustment setting.
49daf7d410fc97647f2b3ab4254f73c09c923018deAdrian Roos    private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT = true;
50639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
51639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // How long the current sensor reading is assumed to be valid beyond the current time.
52639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // This provides a bit of prediction, as well as ensures that the weight for the last sample is
53639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // non-zero, which in turn ensures that the total weight is non-zero.
54639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final long AMBIENT_LIGHT_PREDICTION_TIME_MILLIS = 100;
55639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
56a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    // Debounce for sampling user-initiated changes in display brightness to ensure
57a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    // the user is satisfied with the result before storing the sample.
58a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private static final int BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS = 10000;
59a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
60639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final int MSG_UPDATE_AMBIENT_LUX = 1;
61a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2;
62639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
630a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    // Length of the ambient light horizon used to calculate the long term estimate of ambient
640a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    // light.
650a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    private static final int AMBIENT_LIGHT_LONG_HORIZON_MILLIS = 10000;
660a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright
670a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    // Length of the ambient light horizon used to calculate short-term estimate of ambient light.
680a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    private static final int AMBIENT_LIGHT_SHORT_HORIZON_MILLIS = 2000;
690a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright
70428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza    // Callbacks for requesting updates to the display's power state
71639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final Callbacks mCallbacks;
72639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
73639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The sensor manager.
74639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final SensorManager mSensorManager;
75639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
76639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The light sensor, or null if not available or needed.
77639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final Sensor mLightSensor;
78639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
79639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The auto-brightness spline adjustment.
80639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The brightness values have been scaled to a range of 0..1.
81639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final Spline mScreenAutoBrightnessSpline;
82639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
83639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The minimum and maximum screen brightnesses.
84639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final int mScreenBrightnessRangeMinimum;
85639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final int mScreenBrightnessRangeMaximum;
86a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski    private final float mDozeScaleFactor;
87639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
885d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    // Initial light sensor event rate in milliseconds.
895d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    private final int mInitialLightSensorRate;
905d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza
915d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    // Steady-state light sensor event rate in milliseconds.
925d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    private final int mNormalLightSensorRate;
935d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza
945d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    // The current light sensor event rate in milliseconds.
955d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    private int mCurrentLightSensorRate;
96d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski
97d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // Stability requirements in milliseconds for accepting a new brightness level.  This is used
98d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // for debouncing the light sensor.  Different constants are used to debounce the light sensor
99d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // when adapting to brighter or darker environments.  This parameter controls how quickly
100d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // brightness changes occur in response to an observed change in light level that exceeds the
101d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // hysteresis threshold.
102d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    private final long mBrighteningLightDebounceConfig;
103d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    private final long mDarkeningLightDebounceConfig;
104d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski
105d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // If true immediately after the screen is turned on the controller will try to adjust the
106d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // brightness based on the current sensor reads. If false, the controller will collect more data
107d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // and only then decide whether to change brightness.
108d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    private final boolean mResetAmbientLuxAfterWarmUpConfig;
109d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski
1106fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // Period of time in which to consider light samples in milliseconds.
1116fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private final int mAmbientLightHorizon;
1126fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic
1136fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // The intercept used for the weighting calculation. This is used in order to keep all possible
1146fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // weighting values positive.
1156fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private final int mWeightingIntercept;
1166fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic
117428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza    // accessor object for determining thresholds to change brightness dynamically
118428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza    private final HysteresisLevels mDynamicHysteresis;
119428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza
120639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Amount of time to delay auto-brightness after screen on while waiting for
121639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // the light sensor to warm-up in milliseconds.
122639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // May be 0 if no warm-up is required.
123639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int mLightSensorWarmUpTimeConfig;
124639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
125639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Set to true if the light sensor is enabled.
126639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean mLightSensorEnabled;
127639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
128639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The time when the light sensor was enabled.
129639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long mLightSensorEnableTime;
130639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
131639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The currently accepted nominal ambient light level.
132639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mAmbientLux;
133639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
134639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // True if mAmbientLux holds a valid value.
135639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean mAmbientLuxValid;
136639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
137639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The ambient light level threshold at which to brighten or darken the screen.
138639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mBrighteningLuxThreshold;
139639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mDarkeningLuxThreshold;
140639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
141639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The most recent light sample.
142639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mLastObservedLux;
143639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
144639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The time of the most light recent sample.
145639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long mLastObservedLuxTime;
146639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
147639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The number of light samples collected since the light sensor was enabled.
148639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int mRecentLightSamples;
149639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
150639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // A ring buffer containing all of the recent ambient light sensor readings.
151639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private AmbientLightRingBuffer mAmbientLightRingBuffer;
152639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
153103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright    // A ring buffer containing the light sensor readings for the initial horizon period.
154103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright    private AmbientLightRingBuffer mInitialHorizonAmbientLightRingBuffer;
155103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright
156639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The handler
157639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private AutomaticBrightnessHandler mHandler;
158639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
159639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The screen brightness level that has been chosen by the auto-brightness
160639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // algorithm.  The actual brightness should ramp towards this value.
161639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // We preserve this value even when we stop using the light sensor so
162639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // that we can quickly revert to the previous auto-brightness level
163639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // while the light sensor warms up.
164639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Use -1 if there is no current auto-brightness value available.
165639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int mScreenAutoBrightness = -1;
166639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
167639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The screen auto-brightness adjustment factor in the range -1 (dimmer) to 1 (brighter)
168639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mScreenAutoBrightnessAdjustment = 0.0f;
169639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
1706fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // The maximum range of gamma adjustment possible using the screen
1716fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // auto-brightness adjustment setting.
1726fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private float mScreenAutoBrightnessAdjustmentMaxGamma;
1736fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic
174639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The last screen auto-brightness gamma.  (For printing in dump() only.)
175639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mLastScreenAutoBrightnessGamma = 1.0f;
176639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
177a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski    // Are we going to adjust brightness while dozing.
178a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski    private boolean mDozing;
179a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski
180a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    // True if we are collecting a brightness adjustment sample, along with some data
181a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    // for the initial state of the sample.
182a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private boolean mBrightnessAdjustmentSamplePending;
183a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private float mBrightnessAdjustmentSampleOldAdjustment;
184a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private float mBrightnessAdjustmentSampleOldLux;
185a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private int mBrightnessAdjustmentSampleOldBrightness;
186a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private float mBrightnessAdjustmentSampleOldGamma;
187a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
188639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
189a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski            SensorManager sensorManager, Spline autoBrightnessSpline, int lightSensorWarmUpTime,
190d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski            int brightnessMin, int brightnessMax, float dozeScaleFactor,
1915d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
1926fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic            long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
193428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza            int ambientLightHorizon, float autoBrightnessAdjustmentMaxGamma,
194428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza            HysteresisLevels dynamicHysteresis) {
195639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mCallbacks = callbacks;
196639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mSensorManager = sensorManager;
197639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mScreenAutoBrightnessSpline = autoBrightnessSpline;
198639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mScreenBrightnessRangeMinimum = brightnessMin;
199639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mScreenBrightnessRangeMaximum = brightnessMax;
200639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime;
201a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        mDozeScaleFactor = dozeScaleFactor;
2025d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        mNormalLightSensorRate = lightSensorRate;
2035d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        mInitialLightSensorRate = initialLightSensorRate;
2045d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        mCurrentLightSensorRate = -1;
205d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mBrighteningLightDebounceConfig = brighteningLightDebounceConfig;
206d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mDarkeningLightDebounceConfig = darkeningLightDebounceConfig;
207d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig;
2086fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        mAmbientLightHorizon = ambientLightHorizon;
2096fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        mWeightingIntercept = ambientLightHorizon;
2106fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        mScreenAutoBrightnessAdjustmentMaxGamma = autoBrightnessAdjustmentMaxGamma;
211428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza        mDynamicHysteresis = dynamicHysteresis;
212639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
213639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mHandler = new AutomaticBrightnessHandler(looper);
214103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright        mAmbientLightRingBuffer =
2155d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
216103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright        mInitialHorizonAmbientLightRingBuffer =
2175d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
218639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
219639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
220639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
221639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
222639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
223639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
224639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    public int getAutomaticScreenBrightness() {
225a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        if (mDozing) {
226a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski            return (int) (mScreenAutoBrightness * mDozeScaleFactor);
227a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        }
228639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return mScreenAutoBrightness;
229639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
230639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
231a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    public void configure(boolean enable, float adjustment, boolean dozing,
2325483cea67a60d3c5012fa7120f62e6eacc6ad3baJustin Klaassen            boolean userInitiatedChange) {
233a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // While dozing, the application processor may be suspended which will prevent us from
234a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // receiving new information from the light sensor. On some devices, we may be able to
235a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // switch to a wake-up light sensor instead but for now we will simply disable the sensor
236a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // and hold onto the last computed screen auto brightness.  We save the dozing flag for
237a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // debugging purposes.
238a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        mDozing = dozing;
239a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        boolean changed = setLightSensorEnabled(enable && !dozing);
240a8edffd804d3940dec1fa5c9777d10beccb2f6a6Soroosh Mariooryad        if (enable && !dozing && userInitiatedChange) {
241a8edffd804d3940dec1fa5c9777d10beccb2f6a6Soroosh Mariooryad            prepareBrightnessAdjustmentSample();
242a8edffd804d3940dec1fa5c9777d10beccb2f6a6Soroosh Mariooryad        }
243970d4132ea28e748c1010be39450a98bbf7466f3Jeff Brown        changed |= setScreenAutoBrightnessAdjustment(adjustment);
244970d4132ea28e748c1010be39450a98bbf7466f3Jeff Brown        if (changed) {
245639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            updateAutoBrightness(false /*sendUpdate*/);
246639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
247639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
248639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
249639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    public void dump(PrintWriter pw) {
250639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println();
251639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("Automatic Brightness Controller Configuration:");
252639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline);
253639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
254639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
255639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
256d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        pw.println("  mBrighteningLightDebounceConfig=" + mBrighteningLightDebounceConfig);
257d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        pw.println("  mDarkeningLightDebounceConfig=" + mDarkeningLightDebounceConfig);
258d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        pw.println("  mResetAmbientLuxAfterWarmUpConfig=" + mResetAmbientLuxAfterWarmUpConfig);
259639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
260639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println();
261639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("Automatic Brightness Controller State:");
262639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensor=" + mLightSensor);
263639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensorEnabled=" + mLightSensorEnabled);
264639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensorEnableTime=" + TimeUtils.formatUptime(mLightSensorEnableTime));
265639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mAmbientLux=" + mAmbientLux);
2666fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        pw.println("  mAmbientLightHorizon=" + mAmbientLightHorizon);
267639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mBrighteningLuxThreshold=" + mBrighteningLuxThreshold);
268639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mDarkeningLuxThreshold=" + mDarkeningLuxThreshold);
269639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLastObservedLux=" + mLastObservedLux);
270639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLastObservedLuxTime=" + TimeUtils.formatUptime(mLastObservedLuxTime));
271639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mRecentLightSamples=" + mRecentLightSamples);
272639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mAmbientLightRingBuffer=" + mAmbientLightRingBuffer);
273103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright        pw.println("  mInitialHorizonAmbientLightRingBuffer=" +
274103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright                mInitialHorizonAmbientLightRingBuffer);
275639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenAutoBrightness=" + mScreenAutoBrightness);
276639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenAutoBrightnessAdjustment=" + mScreenAutoBrightnessAdjustment);
2776fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        pw.println("  mScreenAutoBrightnessAdjustmentMaxGamma=" + mScreenAutoBrightnessAdjustmentMaxGamma);
278639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
279a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        pw.println("  mDozing=" + mDozing);
280639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
281639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
282639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean setLightSensorEnabled(boolean enable) {
283639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (enable) {
284639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (!mLightSensorEnabled) {
285639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorEnabled = true;
286639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorEnableTime = SystemClock.uptimeMillis();
2875d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza                mCurrentLightSensorRate = mInitialLightSensorRate;
288639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mSensorManager.registerListener(mLightSensorListener, mLightSensor,
2895d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza                        mCurrentLightSensorRate * 1000, mHandler);
290639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                return true;
291639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
292639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        } else {
293639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mLightSensorEnabled) {
294639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorEnabled = false;
295d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski                mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
296639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRecentLightSamples = 0;
297639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mAmbientLightRingBuffer.clear();
298103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright                mInitialHorizonAmbientLightRingBuffer.clear();
2995d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza                mCurrentLightSensorRate = -1;
300639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
301639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mSensorManager.unregisterListener(mLightSensorListener);
302639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
303639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
304639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return false;
305639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
306639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
307639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void handleLightSensorEvent(long time, float lux) {
308b0a1d3d08fc459e0d9937e299e16de17d1388ac4Michael Wright        Trace.traceCounter(Trace.TRACE_TAG_POWER, "ALS", (int) lux);
309639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
310639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
3115d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        if (mAmbientLightRingBuffer.size() == 0) {
3125d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            // switch to using the steady-state sample rate after grabbing the initial light sample
3135d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            adjustLightSensorRate(mNormalLightSensorRate);
3145d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        }
315639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        applyLightSensorMeasurement(time, lux);
316639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        updateAmbientLux(time);
317639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
318639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
319639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void applyLightSensorMeasurement(long time, float lux) {
320639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mRecentLightSamples++;
321103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright        // Store all of the light measurements for the intial horizon period. This is to help
322103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright        // diagnose dim wake ups and slow responses in b/27951906.
323103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright        if (time <= mLightSensorEnableTime + mAmbientLightHorizon) {
324103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright            mInitialHorizonAmbientLightRingBuffer.push(time, lux);
325103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright        }
3266fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
327639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mAmbientLightRingBuffer.push(time, lux);
328639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
329639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // Remember this sample value.
330639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mLastObservedLux = lux;
331639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mLastObservedLuxTime = time;
332639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
333639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
3345d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    private void adjustLightSensorRate(int lightSensorRate) {
3355d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        // if the light sensor rate changed, update the sensor listener
3365d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        if (lightSensorRate != mCurrentLightSensorRate) {
3375d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            if (DEBUG) {
3385d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza                Slog.d(TAG, "adjustLightSensorRate: previousRate=" + mCurrentLightSensorRate
3395d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza                    + ", currentRate=" + lightSensorRate);
3405d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            }
3415d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            mCurrentLightSensorRate = lightSensorRate;
3425d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            mSensorManager.unregisterListener(mLightSensorListener);
3435d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            mSensorManager.registerListener(mLightSensorListener, mLightSensor,
3445d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza                    lightSensorRate * 1000, mHandler);
3455d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        }
3465d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    }
3475d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza
348639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean setScreenAutoBrightnessAdjustment(float adjustment) {
349639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (adjustment != mScreenAutoBrightnessAdjustment) {
350639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mScreenAutoBrightnessAdjustment = adjustment;
351639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return true;
352639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
353639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return false;
354639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
355639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
356639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void setAmbientLux(float lux) {
3570a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        if (DEBUG) {
3580a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            Slog.d(TAG, "setAmbientLux(" + lux + ")");
3590a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        }
360639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mAmbientLux = lux;
361428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza        mBrighteningLuxThreshold = mDynamicHysteresis.getBrighteningThreshold(lux);
362428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza        mDarkeningLuxThreshold = mDynamicHysteresis.getDarkeningThreshold(lux);
363639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
364639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
3650a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    private float calculateAmbientLux(long now, long horizon) {
3660a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        if (DEBUG) {
3670a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            Slog.d(TAG, "calculateAmbientLux(" + now + ", " + horizon + ")");
3680a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        }
369639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        final int N = mAmbientLightRingBuffer.size();
370639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (N == 0) {
371639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            Slog.e(TAG, "calculateAmbientLux: No ambient light readings available");
372639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return -1;
373639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
3740a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright
3750a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // Find the first measurement that is just outside of the horizon.
3760a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        int endIndex = 0;
3770a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        final long horizonStartTime = now - horizon;
3780a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        for (int i = 0; i < N-1; i++) {
3790a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            if (mAmbientLightRingBuffer.getTime(i + 1) <= horizonStartTime) {
3800a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                endIndex++;
3810a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            } else {
3820a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                break;
3830a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            }
3840a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        }
3850a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        if (DEBUG) {
3860a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            Slog.d(TAG, "calculateAmbientLux: selected endIndex=" + endIndex + ", point=("
3870a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                    + mAmbientLightRingBuffer.getTime(endIndex) + ", "
3880a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                    + mAmbientLightRingBuffer.getLux(endIndex)
3890a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                    + ")");
3900a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        }
391639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float sum = 0;
392639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float totalWeight = 0;
393639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long endTime = AMBIENT_LIGHT_PREDICTION_TIME_MILLIS;
3940a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        for (int i = N - 1; i >= endIndex; i--) {
3950a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            long eventTime = mAmbientLightRingBuffer.getTime(i);
3960a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            if (i == endIndex && eventTime < horizonStartTime) {
3970a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                // If we're at the final value, make sure we only consider the part of the sample
3980a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                // within our desired horizon.
3990a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                eventTime = horizonStartTime;
4000a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            }
4010a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            final long startTime = eventTime - now;
402639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            float weight = calculateWeight(startTime, endTime);
403639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            float lux = mAmbientLightRingBuffer.getLux(i);
404639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
405639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "calculateAmbientLux: [" +
406639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        (startTime) + ", " +
407639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        (endTime) + "]: lux=" + lux + ", weight=" + weight);
408639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
409639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            totalWeight += weight;
410639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            sum += mAmbientLightRingBuffer.getLux(i) * weight;
411639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            endTime = startTime;
412639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
413639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (DEBUG) {
414639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            Slog.d(TAG, "calculateAmbientLux: totalWeight=" + totalWeight +
415639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    ", newAmbientLux=" + (sum / totalWeight));
416639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
417639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return sum / totalWeight;
418639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
419639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
4206fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private float calculateWeight(long startDelta, long endDelta) {
421639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return weightIntegral(endDelta) - weightIntegral(startDelta);
422639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
423639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
4246fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // Evaluates the integral of y = x + mWeightingIntercept. This is always positive for the
425639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // horizon we're looking at and provides a non-linear weighting for light samples.
4266fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private float weightIntegral(long x) {
4276fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        return x * (x * 0.5f + mWeightingIntercept);
428639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
429639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
430639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long nextAmbientLightBrighteningTransition(long time) {
431639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        final int N = mAmbientLightRingBuffer.size();
432639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long earliestValidTime = time;
433639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        for (int i = N - 1; i >= 0; i--) {
434639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mAmbientLightRingBuffer.getLux(i) <= mBrighteningLuxThreshold) {
435639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                break;
436639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
437639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            earliestValidTime = mAmbientLightRingBuffer.getTime(i);
438639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
439d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        return earliestValidTime + mBrighteningLightDebounceConfig;
440639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
441639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
442639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long nextAmbientLightDarkeningTransition(long time) {
443639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        final int N = mAmbientLightRingBuffer.size();
444639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long earliestValidTime = time;
445639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        for (int i = N - 1; i >= 0; i--) {
446639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mAmbientLightRingBuffer.getLux(i) >= mDarkeningLuxThreshold) {
447639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                break;
448639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
449639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            earliestValidTime = mAmbientLightRingBuffer.getTime(i);
450639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
451d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        return earliestValidTime + mDarkeningLightDebounceConfig;
452639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
453639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
454639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void updateAmbientLux() {
455639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long time = SystemClock.uptimeMillis();
4566fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
457639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        updateAmbientLux(time);
458639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
459639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
460639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void updateAmbientLux(long time) {
461639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // If the light sensor was just turned on then immediately update our initial
462639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // estimate of the current ambient light level.
463639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (!mAmbientLuxValid) {
464639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            final long timeWhenSensorWarmedUp =
465639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
466639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (time < timeWhenSensorWarmedUp) {
467639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (DEBUG) {
468639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    Slog.d(TAG, "updateAmbientLux: Sensor not  ready yet: "
469639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                            + "time=" + time
470639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                            + ", timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp);
471639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
472639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX,
473639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        timeWhenSensorWarmedUp);
474639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                return;
475639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
4760a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            setAmbientLux(calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS));
477639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mAmbientLuxValid = true;
478639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
479639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "updateAmbientLux: Initializing: "
480639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer
481639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + ", mAmbientLux=" + mAmbientLux);
482639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
483639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            updateAutoBrightness(true);
484639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
485639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
486639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
487639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
4880a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // Essentially, we calculate both a slow ambient lux, to ensure there's a true long-term
4890a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // change in lighting conditions, and a fast ambient lux to determine what the new
4900a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // brightness situation is since the slow lux can be quite slow to converge.
4910a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        //
4920a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // Note that both values need to be checked for sufficient change before updating the
4930a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // proposed ambient light value since the slow value might be sufficiently far enough away
4940a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // from the fast value to cause a recalculation while its actually just converging on
4950a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // the fast value still.
4960a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        float slowAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_LONG_HORIZON_MILLIS);
4970a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        float fastAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS);
4980a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright
4990a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        if (slowAmbientLux >= mBrighteningLuxThreshold &&
5000a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                fastAmbientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time
5010a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                || slowAmbientLux <= mDarkeningLuxThreshold
5020a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                && fastAmbientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) {
5030a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            setAmbientLux(fastAmbientLux);
504639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
505639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "updateAmbientLux: "
5060a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                        + ((fastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
507639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
508639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + ", mAmbientLightRingBuffer=" + mAmbientLightRingBuffer
509639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + ", mAmbientLux=" + mAmbientLux);
510639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
511639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            updateAutoBrightness(true);
512639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
513639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
514639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
515639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long nextTransitionTime = Math.min(nextDarkenTransition, nextBrightenTransition);
516639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // If one of the transitions is ready to occur, but the total weighted ambient lux doesn't
517639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // exceed the necessary threshold, then it's possible we'll get a transition time prior to
518639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // now. Rather than continually checking to see whether the weighted lux exceeds the
519639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // threshold, schedule an update for when we'd normally expect another light sample, which
520639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // should be enough time to decide whether we should actually transition to the new
521639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // weighted ambient lux or not.
522639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        nextTransitionTime =
5235d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza                nextTransitionTime > time ? nextTransitionTime : time + mNormalLightSensorRate;
524639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (DEBUG) {
525639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for "
526639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    + nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
527639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
528639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);
529639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
530639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
531639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void updateAutoBrightness(boolean sendUpdate) {
532639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (!mAmbientLuxValid) {
533639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return;
534639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
535639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
536639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);
537639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float gamma = 1.0f;
538639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
539639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
540639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                && mScreenAutoBrightnessAdjustment != 0.0f) {
5416fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic            final float adjGamma = MathUtils.pow(mScreenAutoBrightnessAdjustmentMaxGamma,
542639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    Math.min(1.0f, Math.max(-1.0f, -mScreenAutoBrightnessAdjustment)));
543639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            gamma *= adjGamma;
544639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
545639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma);
546639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
547639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
548639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
549639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (gamma != 1.0f) {
550639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            final float in = value;
551639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            value = MathUtils.pow(value, gamma);
552639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
553639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma
554639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + ", in=" + in + ", out=" + value);
555639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
556639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
557639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
558639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        int newScreenAutoBrightness =
559a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));
560639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (mScreenAutoBrightness != newScreenAutoBrightness) {
561639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
562639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
563639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + mScreenAutoBrightness + ", newScreenAutoBrightness="
564639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + newScreenAutoBrightness);
565639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
566639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
567639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mScreenAutoBrightness = newScreenAutoBrightness;
568639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mLastScreenAutoBrightnessGamma = gamma;
569639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (sendUpdate) {
570639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mCallbacks.updateBrightness();
571639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
572639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
573639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
574639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
575639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int clampScreenBrightness(int value) {
576639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return MathUtils.constrain(value,
577639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
578639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
579639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
580a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private void prepareBrightnessAdjustmentSample() {
581a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        if (!mBrightnessAdjustmentSamplePending) {
582a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSamplePending = true;
583a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSampleOldAdjustment = mScreenAutoBrightnessAdjustment;
584a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSampleOldLux = mAmbientLuxValid ? mAmbientLux : -1;
585a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSampleOldBrightness = mScreenAutoBrightness;
586a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSampleOldGamma = mLastScreenAutoBrightnessGamma;
587a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        } else {
588a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
589a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        }
590a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
591a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        mHandler.sendEmptyMessageDelayed(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE,
592a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS);
593a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    }
594a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
595a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private void cancelBrightnessAdjustmentSample() {
596a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        if (mBrightnessAdjustmentSamplePending) {
597a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSamplePending = false;
598a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
599a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        }
600a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    }
601a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
602a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private void collectBrightnessAdjustmentSample() {
603a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        if (mBrightnessAdjustmentSamplePending) {
604a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSamplePending = false;
605a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            if (mAmbientLuxValid && mScreenAutoBrightness >= 0) {
606a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                if (DEBUG) {
607a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                    Slog.d(TAG, "Auto-brightness adjustment changed by user: "
608a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                            + "adj=" + mScreenAutoBrightnessAdjustment
609a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                            + ", lux=" + mAmbientLux
610a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                            + ", brightness=" + mScreenAutoBrightness
611a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                            + ", gamma=" + mLastScreenAutoBrightnessGamma
612a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                            + ", ring=" + mAmbientLightRingBuffer);
613a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                }
614a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
615a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                EventLog.writeEvent(EventLogTags.AUTO_BRIGHTNESS_ADJ,
616a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mBrightnessAdjustmentSampleOldAdjustment,
617a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mBrightnessAdjustmentSampleOldLux,
618a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mBrightnessAdjustmentSampleOldBrightness,
619a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mBrightnessAdjustmentSampleOldGamma,
620a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mScreenAutoBrightnessAdjustment,
621a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mAmbientLux,
622a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mScreenAutoBrightness,
623a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mLastScreenAutoBrightnessGamma);
624a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            }
625a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        }
626a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    }
627a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
628639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final class AutomaticBrightnessHandler extends Handler {
629639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public AutomaticBrightnessHandler(Looper looper) {
630639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            super(looper, null, true /*async*/);
631639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
632639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
633639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
634639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void handleMessage(Message msg) {
635639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            switch (msg.what) {
636639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                case MSG_UPDATE_AMBIENT_LUX:
637639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    updateAmbientLux();
638639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    break;
639a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
640a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                case MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE:
641a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                    collectBrightnessAdjustmentSample();
642a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                    break;
643639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
644639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
645639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
646639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
647639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final SensorEventListener mLightSensorListener = new SensorEventListener() {
648639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
649639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void onSensorChanged(SensorEvent event) {
650639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mLightSensorEnabled) {
651639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                final long time = SystemClock.uptimeMillis();
652639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                final float lux = event.values[0];
653639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                handleLightSensorEvent(time, lux);
654639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
655639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
656639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
657639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
658639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void onAccuracyChanged(Sensor sensor, int accuracy) {
659639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            // Not used.
660639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
661639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    };
662639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
663639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    /** Callbacks to request updates to the display's power state. */
664639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    interface Callbacks {
665639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        void updateBrightness();
666639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
667639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
6680a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    /**
6690a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright     * A ring buffer of ambient light measurements sorted by time.
6700a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright     *
6710a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright     * Each entry consists of a timestamp and a lux measurement, and the overall buffer is sorted
6720a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright     * from oldest to newest.
6730a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright     */
674103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright    private static final class AmbientLightRingBuffer {
675639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // Proportional extra capacity of the buffer beyond the expected number of light samples
676639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // in the horizon
677639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private static final float BUFFER_SLACK = 1.5f;
678639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private float[] mRingLux;
679639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private long[] mRingTime;
680639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mCapacity;
681639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
682639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // The first valid element and the next open slot.
683639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // Note that if mCount is zero then there are no valid elements.
684639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mStart;
685639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mEnd;
686639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mCount;
687639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
6886fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon) {
6896fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic            mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate);
690639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingLux = new float[mCapacity];
691639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingTime = new long[mCapacity];
692639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
693639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
694639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public float getLux(int index) {
695639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return mRingLux[offsetOf(index)];
696639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
697639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
698639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public long getTime(int index) {
699639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return mRingTime[offsetOf(index)];
700639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
701639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
702639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void push(long time, float lux) {
703639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            int next = mEnd;
704639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mCount == mCapacity) {
705639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                int newSize = mCapacity * 2;
706639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
707639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                float[] newRingLux = new float[newSize];
708639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                long[] newRingTime = new long[newSize];
709639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                int length = mCapacity - mStart;
710639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                System.arraycopy(mRingLux, mStart, newRingLux, 0, length);
711639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                System.arraycopy(mRingTime, mStart, newRingTime, 0, length);
712639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (mStart != 0) {
713639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    System.arraycopy(mRingLux, 0, newRingLux, length, mStart);
714639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    System.arraycopy(mRingTime, 0, newRingTime, length, mStart);
715639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
716639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRingLux = newRingLux;
717639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRingTime = newRingTime;
718639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
719639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                next = mCapacity;
720639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mCapacity = newSize;
721639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mStart = 0;
722639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
723639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingTime[next] = time;
724639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingLux[next] = lux;
725639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mEnd = next + 1;
726639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mEnd == mCapacity) {
727639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mEnd = 0;
728639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
729639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mCount++;
730639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
731639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
732639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void prune(long horizon) {
733639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mCount == 0) {
734639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                return;
735639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
736639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
737639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            while (mCount > 1) {
738639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                int next = mStart + 1;
739639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (next >= mCapacity) {
740639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    next -= mCapacity;
741639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
742639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (mRingTime[next] > horizon) {
743639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // Some light sensors only produce data upon a change in the ambient light
744639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // levels, so we need to consider the previous measurement as the ambient light
745639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // level for all points in time up until we receive a new measurement. Thus, we
746639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // always want to keep the youngest element that would be removed from the
747639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // buffer and just set its measurement time to the horizon time since at that
748639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // point it is the ambient light level, and to remove it would be to drop a
749639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // valid data point within our horizon.
750639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    break;
751639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
752639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mStart = next;
753639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mCount -= 1;
754639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
755639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
756639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mRingTime[mStart] < horizon) {
757639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRingTime[mStart] = horizon;
758639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
759639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
760639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
761639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public int size() {
762639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return mCount;
763639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
764639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
765639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void clear() {
766639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mStart = 0;
767639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mEnd = 0;
768639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mCount = 0;
769639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
770639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
771639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
772639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public String toString() {
773a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            StringBuffer buf = new StringBuffer();
774a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            buf.append('[');
775a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            for (int i = 0; i < mCount; i++) {
776a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                final long next = i + 1 < mCount ? getTime(i + 1) : SystemClock.uptimeMillis();
777a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                if (i != 0) {
778a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                    buf.append(", ");
779a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                }
780a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                buf.append(getLux(i));
781a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                buf.append(" / ");
782a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                buf.append(next - getTime(i));
783a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                buf.append("ms");
784639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
785a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            buf.append(']');
786a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            return buf.toString();
787639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
788639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
789639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int offsetOf(int index) {
790639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (index >= mCount || index < 0) {
791639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                throw new ArrayIndexOutOfBoundsException(index);
792639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
793639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            index += mStart;
794639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (index >= mCapacity) {
795639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                index -= mCapacity;
796639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
797639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return index;
798639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
799639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
800639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright}
801