AutomaticBrightnessController.java revision 57d6f11d6ab5d409f3291923ea34f9be709925bc
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;
27eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wrightimport android.hardware.display.BrightnessConfiguration;
28d846023804ddadcd692666152db420c54594ddb9Michael Wrightimport android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
29639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.Handler;
30639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.Looper;
31639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.Message;
32639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.PowerManager;
33639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.SystemClock;
34b0a1d3d08fc459e0d9937e299e16de17d1388ac4Michael Wrightimport android.os.Trace;
35639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.text.format.DateUtils;
36a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brownimport android.util.EventLog;
37639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.util.MathUtils;
38639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.util.Slog;
39639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.util.TimeUtils;
40639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
41639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport java.io.PrintWriter;
42639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
43639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightclass AutomaticBrightnessController {
44639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final String TAG = "AutomaticBrightnessController";
45639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
46639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final boolean DEBUG = false;
47639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
48639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
49639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // If true, enables the use of the screen auto-brightness adjustment setting.
50daf7d410fc97647f2b3ab4254f73c09c923018deAdrian Roos    private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT = true;
51639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
52639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // How long the current sensor reading is assumed to be valid beyond the current time.
53639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // This provides a bit of prediction, as well as ensures that the weight for the last sample is
54639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // non-zero, which in turn ensures that the total weight is non-zero.
55639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final long AMBIENT_LIGHT_PREDICTION_TIME_MILLIS = 100;
56639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
57a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    // Debounce for sampling user-initiated changes in display brightness to ensure
58a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    // the user is satisfied with the result before storing the sample.
59a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private static final int BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS = 10000;
60a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
61d846023804ddadcd692666152db420c54594ddb9Michael Wright    // Timeout after which we remove the effects any user interactions might've had on the
62d846023804ddadcd692666152db420c54594ddb9Michael Wright    // brightness mapping. This timeout doesn't start until we transition to a non-interactive
63d846023804ddadcd692666152db420c54594ddb9Michael Wright    // display policy so that we don't reset while users are using their devices, but also so that
64d846023804ddadcd692666152db420c54594ddb9Michael Wright    // we don't erroneously keep the short-term model if the device is dozing but the display is
65d846023804ddadcd692666152db420c54594ddb9Michael Wright    // fully on.
66d846023804ddadcd692666152db420c54594ddb9Michael Wright    private static final int SHORT_TERM_MODEL_TIMEOUT_MILLIS = 30000;
67d846023804ddadcd692666152db420c54594ddb9Michael Wright
68639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final int MSG_UPDATE_AMBIENT_LUX = 1;
69a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2;
70c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    private static final int MSG_INVALIDATE_SHORT_TERM_MODEL = 3;
71639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
720a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    // Length of the ambient light horizon used to calculate the long term estimate of ambient
730a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    // light.
740a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    private static final int AMBIENT_LIGHT_LONG_HORIZON_MILLIS = 10000;
750a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright
760a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    // Length of the ambient light horizon used to calculate short-term estimate of ambient light.
770a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    private static final int AMBIENT_LIGHT_SHORT_HORIZON_MILLIS = 2000;
780a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright
79428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza    // Callbacks for requesting updates to the display's power state
80639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final Callbacks mCallbacks;
81639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
82639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The sensor manager.
83639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final SensorManager mSensorManager;
84639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
85639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The light sensor, or null if not available or needed.
86639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final Sensor mLightSensor;
87639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
88eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright    // The mapper to translate ambient lux to screen brightness in the range [0, 1.0].
89eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright    private final BrightnessMappingStrategy mBrightnessMapper;
90639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
91639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The minimum and maximum screen brightnesses.
92639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final int mScreenBrightnessRangeMinimum;
93639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final int mScreenBrightnessRangeMaximum;
94a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski    private final float mDozeScaleFactor;
95639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
965d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    // Initial light sensor event rate in milliseconds.
975d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    private final int mInitialLightSensorRate;
985d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza
995d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    // Steady-state light sensor event rate in milliseconds.
1005d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    private final int mNormalLightSensorRate;
1015d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza
1025d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    // The current light sensor event rate in milliseconds.
1035d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    private int mCurrentLightSensorRate;
104d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski
105d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // Stability requirements in milliseconds for accepting a new brightness level.  This is used
106d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // for debouncing the light sensor.  Different constants are used to debounce the light sensor
107d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // when adapting to brighter or darker environments.  This parameter controls how quickly
108d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // brightness changes occur in response to an observed change in light level that exceeds the
109d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // hysteresis threshold.
110d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    private final long mBrighteningLightDebounceConfig;
111d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    private final long mDarkeningLightDebounceConfig;
112d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski
113d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // If true immediately after the screen is turned on the controller will try to adjust the
114d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // brightness based on the current sensor reads. If false, the controller will collect more data
115d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // and only then decide whether to change brightness.
116d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    private final boolean mResetAmbientLuxAfterWarmUpConfig;
117d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski
1186fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // Period of time in which to consider light samples in milliseconds.
1196fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private final int mAmbientLightHorizon;
1206fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic
1216fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // The intercept used for the weighting calculation. This is used in order to keep all possible
1226fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // weighting values positive.
1236fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private final int mWeightingIntercept;
1246fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic
125428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza    // accessor object for determining thresholds to change brightness dynamically
126428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza    private final HysteresisLevels mDynamicHysteresis;
127428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza
128639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Amount of time to delay auto-brightness after screen on while waiting for
129639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // the light sensor to warm-up in milliseconds.
130639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // May be 0 if no warm-up is required.
131639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int mLightSensorWarmUpTimeConfig;
132639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
133639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Set to true if the light sensor is enabled.
134639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean mLightSensorEnabled;
135639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
136639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The time when the light sensor was enabled.
137639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long mLightSensorEnableTime;
138639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
139639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The currently accepted nominal ambient light level.
140639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mAmbientLux;
141639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
142639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // True if mAmbientLux holds a valid value.
143639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean mAmbientLuxValid;
144639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
145639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The ambient light level threshold at which to brighten or darken the screen.
146639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mBrighteningLuxThreshold;
147639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mDarkeningLuxThreshold;
148639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
149639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The most recent light sample.
150639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mLastObservedLux;
151639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
152639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The time of the most light recent sample.
153639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long mLastObservedLuxTime;
154639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
155639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The number of light samples collected since the light sensor was enabled.
156639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int mRecentLightSamples;
157639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
158639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // A ring buffer containing all of the recent ambient light sensor readings.
159639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private AmbientLightRingBuffer mAmbientLightRingBuffer;
160639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
161639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The handler
162639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private AutomaticBrightnessHandler mHandler;
163639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
164639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The screen brightness level that has been chosen by the auto-brightness
165639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // algorithm.  The actual brightness should ramp towards this value.
166639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // We preserve this value even when we stop using the light sensor so
167639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // that we can quickly revert to the previous auto-brightness level
168639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // while the light sensor warms up.
169639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Use -1 if there is no current auto-brightness value available.
170639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int mScreenAutoBrightness = -1;
171639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
172d846023804ddadcd692666152db420c54594ddb9Michael Wright    // The current display policy. This is useful, for example,  for knowing when we're dozing,
173d846023804ddadcd692666152db420c54594ddb9Michael Wright    // where the light sensor may not be available.
174d846023804ddadcd692666152db420c54594ddb9Michael Wright    private int mDisplayPolicy = DisplayPowerRequest.POLICY_OFF;
175a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski
176a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    // True if we are collecting a brightness adjustment sample, along with some data
177a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    // for the initial state of the sample.
178a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private boolean mBrightnessAdjustmentSamplePending;
179a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private float mBrightnessAdjustmentSampleOldLux;
180a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private int mBrightnessAdjustmentSampleOldBrightness;
181a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
182c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    // When the short term model is invalidated, we don't necessarily reset it (i.e. clear the
183c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    // user's adjustment) immediately, but wait for a drastic enough change in the ambient light.
184c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    // The anchor determines what were the light levels when the user has set her preference, and
185c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    // we use a relative threshold to determine when to revert to the OEM curve.
186c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    private boolean mShortTermModelValid;
187c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    private float mShortTermModelAnchor;
188c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    private float SHORT_TERM_MODEL_THRESHOLD_RATIO = 0.6f;
189c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik
190639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
19157d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik            SensorManager sensorManager, BrightnessMappingStrategy mapper,
19257d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik            int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor,
1935d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
1946fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic            long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
19557d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik            int ambientLightHorizon, HysteresisLevels dynamicHysteresis) {
196639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mCallbacks = callbacks;
197639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mSensorManager = sensorManager;
198eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright        mBrightnessMapper = mapper;
199639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mScreenBrightnessRangeMinimum = brightnessMin;
200639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mScreenBrightnessRangeMaximum = brightnessMax;
201639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime;
202a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        mDozeScaleFactor = dozeScaleFactor;
2035d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        mNormalLightSensorRate = lightSensorRate;
2045d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        mInitialLightSensorRate = initialLightSensorRate;
2055d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        mCurrentLightSensorRate = -1;
206d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mBrighteningLightDebounceConfig = brighteningLightDebounceConfig;
207d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mDarkeningLightDebounceConfig = darkeningLightDebounceConfig;
208d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig;
2096fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        mAmbientLightHorizon = ambientLightHorizon;
2106fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        mWeightingIntercept = ambientLightHorizon;
211428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza        mDynamicHysteresis = dynamicHysteresis;
212c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        mShortTermModelValid = true;
213c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        mShortTermModelAnchor = -1;
214639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
215639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mHandler = new AutomaticBrightnessHandler(looper);
216103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright        mAmbientLightRingBuffer =
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() {
225d846023804ddadcd692666152db420c54594ddb9Michael Wright        if (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE) {
226a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski            return (int) (mScreenAutoBrightness * mDozeScaleFactor);
227a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        }
228639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return mScreenAutoBrightness;
229639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
230639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
231617564ff2cdee2e9a50339544129283503ae71a8Michael Wright    public float getAutomaticScreenBrightnessAdjustment() {
23257d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik        return mBrightnessMapper.getAutoBrightnessAdjustment();
233617564ff2cdee2e9a50339544129283503ae71a8Michael Wright    }
234617564ff2cdee2e9a50339544129283503ae71a8Michael Wright
235eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright    public void configure(boolean enable, @Nullable BrightnessConfiguration configuration,
236617564ff2cdee2e9a50339544129283503ae71a8Michael Wright            float brightness, boolean userChangedBrightness, float adjustment,
237617564ff2cdee2e9a50339544129283503ae71a8Michael Wright            boolean userChangedAutoBrightnessAdjustment, int displayPolicy) {
238a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // While dozing, the application processor may be suspended which will prevent us from
239a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // receiving new information from the light sensor. On some devices, we may be able to
240a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // switch to a wake-up light sensor instead but for now we will simply disable the sensor
241a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // and hold onto the last computed screen auto brightness.  We save the dozing flag for
242a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // debugging purposes.
243d846023804ddadcd692666152db420c54594ddb9Michael Wright        boolean dozing = (displayPolicy == DisplayPowerRequest.POLICY_DOZE);
244eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright        boolean changed = setBrightnessConfiguration(configuration);
245d846023804ddadcd692666152db420c54594ddb9Michael Wright        changed |= setDisplayPolicy(displayPolicy);
24657d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik        if (userChangedAutoBrightnessAdjustment) {
24757d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik            changed |= setAutoBrightnessAdjustment(adjustment);
24857d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik        }
249617564ff2cdee2e9a50339544129283503ae71a8Michael Wright        if (userChangedBrightness && enable) {
250617564ff2cdee2e9a50339544129283503ae71a8Michael Wright            // Update the brightness curve with the new user control point. It's critical this
251617564ff2cdee2e9a50339544129283503ae71a8Michael Wright            // happens after we update the autobrightness adjustment since it may reset it.
252d846023804ddadcd692666152db420c54594ddb9Michael Wright            changed |= setScreenBrightnessByUser(brightness);
253617564ff2cdee2e9a50339544129283503ae71a8Michael Wright        }
254617564ff2cdee2e9a50339544129283503ae71a8Michael Wright        final boolean userInitiatedChange =
255617564ff2cdee2e9a50339544129283503ae71a8Michael Wright                userChangedBrightness || userChangedAutoBrightnessAdjustment;
256617564ff2cdee2e9a50339544129283503ae71a8Michael Wright        if (userInitiatedChange && enable && !dozing) {
257a8edffd804d3940dec1fa5c9777d10beccb2f6a6Soroosh Mariooryad            prepareBrightnessAdjustmentSample();
258a8edffd804d3940dec1fa5c9777d10beccb2f6a6Soroosh Mariooryad        }
259d846023804ddadcd692666152db420c54594ddb9Michael Wright        changed |= setLightSensorEnabled(enable && !dozing);
260970d4132ea28e748c1010be39450a98bbf7466f3Jeff Brown        if (changed) {
261639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            updateAutoBrightness(false /*sendUpdate*/);
262639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
263639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
264639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
26553d0661f38d6ada39aefaac5ce016f802e74bd44Kenny Guy    public boolean hasUserDataPoints() {
26653d0661f38d6ada39aefaac5ce016f802e74bd44Kenny Guy        return mBrightnessMapper.hasUserDataPoints();
26753d0661f38d6ada39aefaac5ce016f802e74bd44Kenny Guy    }
26853d0661f38d6ada39aefaac5ce016f802e74bd44Kenny Guy
26953d0661f38d6ada39aefaac5ce016f802e74bd44Kenny Guy    public boolean isDefaultConfig() {
27053d0661f38d6ada39aefaac5ce016f802e74bd44Kenny Guy        return mBrightnessMapper.isDefaultConfig();
27153d0661f38d6ada39aefaac5ce016f802e74bd44Kenny Guy    }
27253d0661f38d6ada39aefaac5ce016f802e74bd44Kenny Guy
2736d1009f882f1b0234e77ec3bb583a58090bfff39Kenny Guy    public BrightnessConfiguration getDefaultConfig() {
2746d1009f882f1b0234e77ec3bb583a58090bfff39Kenny Guy        return mBrightnessMapper.getDefaultConfig();
2756d1009f882f1b0234e77ec3bb583a58090bfff39Kenny Guy    }
2766d1009f882f1b0234e77ec3bb583a58090bfff39Kenny Guy
277d846023804ddadcd692666152db420c54594ddb9Michael Wright    private boolean setDisplayPolicy(int policy) {
278d846023804ddadcd692666152db420c54594ddb9Michael Wright        if (mDisplayPolicy == policy) {
279d846023804ddadcd692666152db420c54594ddb9Michael Wright            return false;
280d846023804ddadcd692666152db420c54594ddb9Michael Wright        }
281d846023804ddadcd692666152db420c54594ddb9Michael Wright        final int oldPolicy = mDisplayPolicy;
282d846023804ddadcd692666152db420c54594ddb9Michael Wright        mDisplayPolicy = policy;
283d846023804ddadcd692666152db420c54594ddb9Michael Wright        if (DEBUG) {
284c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            Slog.d(TAG, "Display policy transitioning from " + oldPolicy + " to " + policy);
285d846023804ddadcd692666152db420c54594ddb9Michael Wright        }
286d846023804ddadcd692666152db420c54594ddb9Michael Wright        if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy)) {
287c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_SHORT_TERM_MODEL,
288d846023804ddadcd692666152db420c54594ddb9Michael Wright                    SHORT_TERM_MODEL_TIMEOUT_MILLIS);
289d846023804ddadcd692666152db420c54594ddb9Michael Wright        } else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) {
290c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mHandler.removeMessages(MSG_INVALIDATE_SHORT_TERM_MODEL);
291d846023804ddadcd692666152db420c54594ddb9Michael Wright        }
292d846023804ddadcd692666152db420c54594ddb9Michael Wright        return true;
293d846023804ddadcd692666152db420c54594ddb9Michael Wright    }
294d846023804ddadcd692666152db420c54594ddb9Michael Wright
295d846023804ddadcd692666152db420c54594ddb9Michael Wright    private static boolean isInteractivePolicy(int policy) {
296d846023804ddadcd692666152db420c54594ddb9Michael Wright        return policy == DisplayPowerRequest.POLICY_BRIGHT
297d846023804ddadcd692666152db420c54594ddb9Michael Wright                || policy == DisplayPowerRequest.POLICY_DIM
298d846023804ddadcd692666152db420c54594ddb9Michael Wright                || policy == DisplayPowerRequest.POLICY_VR;
299d846023804ddadcd692666152db420c54594ddb9Michael Wright    }
300d846023804ddadcd692666152db420c54594ddb9Michael Wright
301d846023804ddadcd692666152db420c54594ddb9Michael Wright    private boolean setScreenBrightnessByUser(float brightness) {
302d846023804ddadcd692666152db420c54594ddb9Michael Wright        if (!mAmbientLuxValid) {
303d846023804ddadcd692666152db420c54594ddb9Michael Wright            // If we don't have a valid ambient lux then we don't have a valid brightness anyways,
304d846023804ddadcd692666152db420c54594ddb9Michael Wright            // and we can't use this data to add a new control point to the short-term model.
305d846023804ddadcd692666152db420c54594ddb9Michael Wright            return false;
306d846023804ddadcd692666152db420c54594ddb9Michael Wright        }
307d846023804ddadcd692666152db420c54594ddb9Michael Wright        mBrightnessMapper.addUserDataPoint(mAmbientLux, brightness);
308c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        mShortTermModelValid = true;
309c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        mShortTermModelAnchor = mAmbientLux;
310c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        if (DEBUG) {
311c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            Slog.d(TAG, "ShortTermModel: anchor=" + mShortTermModelAnchor);
312c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        }
313d846023804ddadcd692666152db420c54594ddb9Michael Wright        return true;
314d846023804ddadcd692666152db420c54594ddb9Michael Wright    }
315d846023804ddadcd692666152db420c54594ddb9Michael Wright
316d846023804ddadcd692666152db420c54594ddb9Michael Wright    private void resetShortTermModel() {
317d846023804ddadcd692666152db420c54594ddb9Michael Wright        mBrightnessMapper.clearUserDataPoints();
318c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        mShortTermModelValid = true;
319c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        mShortTermModelAnchor = -1;
320c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    }
321c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik
322c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    private void invalidateShortTermModel() {
323c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        if (DEBUG) {
324c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            Slog.d(TAG, "ShortTermModel: invalidate user data");
325c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        }
326c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        mShortTermModelValid = false;
327d846023804ddadcd692666152db420c54594ddb9Michael Wright    }
328d846023804ddadcd692666152db420c54594ddb9Michael Wright
329eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright    public boolean setBrightnessConfiguration(BrightnessConfiguration configuration) {
330eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright        return mBrightnessMapper.setBrightnessConfiguration(configuration);
331eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright    }
332eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright
333639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    public void dump(PrintWriter pw) {
334639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println();
335639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("Automatic Brightness Controller Configuration:");
336639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
337639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
338639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
339d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        pw.println("  mBrighteningLightDebounceConfig=" + mBrighteningLightDebounceConfig);
340d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        pw.println("  mDarkeningLightDebounceConfig=" + mDarkeningLightDebounceConfig);
341d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        pw.println("  mResetAmbientLuxAfterWarmUpConfig=" + mResetAmbientLuxAfterWarmUpConfig);
342639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
343639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println();
344639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("Automatic Brightness Controller State:");
345639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensor=" + mLightSensor);
346639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensorEnabled=" + mLightSensorEnabled);
347639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensorEnableTime=" + TimeUtils.formatUptime(mLightSensorEnableTime));
348639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mAmbientLux=" + mAmbientLux);
3496fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        pw.println("  mAmbientLightHorizon=" + mAmbientLightHorizon);
350639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mBrighteningLuxThreshold=" + mBrighteningLuxThreshold);
351639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mDarkeningLuxThreshold=" + mDarkeningLuxThreshold);
352639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLastObservedLux=" + mLastObservedLux);
353639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLastObservedLuxTime=" + TimeUtils.formatUptime(mLastObservedLuxTime));
354639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mRecentLightSamples=" + mRecentLightSamples);
355639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mAmbientLightRingBuffer=" + mAmbientLightRingBuffer);
356639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenAutoBrightness=" + mScreenAutoBrightness);
357d846023804ddadcd692666152db420c54594ddb9Michael Wright        pw.println("  mDisplayPolicy=" + mDisplayPolicy);
358c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        pw.println("  mShortTermModelAnchor=" + mShortTermModelAnchor);
359eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright
360eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright        pw.println();
361eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright        mBrightnessMapper.dump(pw);
362639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
363639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
364639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean setLightSensorEnabled(boolean enable) {
365639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (enable) {
366639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (!mLightSensorEnabled) {
367639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorEnabled = true;
368639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorEnableTime = SystemClock.uptimeMillis();
3695d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza                mCurrentLightSensorRate = mInitialLightSensorRate;
370639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mSensorManager.registerListener(mLightSensorListener, mLightSensor,
3715d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza                        mCurrentLightSensorRate * 1000, mHandler);
372639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                return true;
373639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
374c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        } else if (mLightSensorEnabled) {
375c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mLightSensorEnabled = false;
376c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
377c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mRecentLightSamples = 0;
378c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mAmbientLightRingBuffer.clear();
379c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mCurrentLightSensorRate = -1;
380c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
381c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mSensorManager.unregisterListener(mLightSensorListener);
382639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
383639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return false;
384639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
385639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
386639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void handleLightSensorEvent(long time, float lux) {
387b0a1d3d08fc459e0d9937e299e16de17d1388ac4Michael Wright        Trace.traceCounter(Trace.TRACE_TAG_POWER, "ALS", (int) lux);
388639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
389639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
3905d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        if (mAmbientLightRingBuffer.size() == 0) {
3915d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            // switch to using the steady-state sample rate after grabbing the initial light sample
3925d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            adjustLightSensorRate(mNormalLightSensorRate);
3935d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        }
394639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        applyLightSensorMeasurement(time, lux);
395639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        updateAmbientLux(time);
396639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
397639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
398639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void applyLightSensorMeasurement(long time, float lux) {
399639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mRecentLightSamples++;
4006fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
401639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mAmbientLightRingBuffer.push(time, lux);
402639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
403639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // Remember this sample value.
404639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mLastObservedLux = lux;
405639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mLastObservedLuxTime = time;
406639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
407639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
4085d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    private void adjustLightSensorRate(int lightSensorRate) {
4095d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        // if the light sensor rate changed, update the sensor listener
4105d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        if (lightSensorRate != mCurrentLightSensorRate) {
4115d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            if (DEBUG) {
412c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                Slog.d(TAG, "adjustLightSensorRate: " +
41357d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "previousRate=" + mCurrentLightSensorRate + ", " +
41457d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "currentRate=" + lightSensorRate);
4155d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            }
4165d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            mCurrentLightSensorRate = lightSensorRate;
4175d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            mSensorManager.unregisterListener(mLightSensorListener);
4185d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            mSensorManager.registerListener(mLightSensorListener, mLightSensor,
4195d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza                    lightSensorRate * 1000, mHandler);
4205d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        }
4215d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    }
4225d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza
42357d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik    private boolean setAutoBrightnessAdjustment(float adjustment) {
42457d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik        return mBrightnessMapper.setAutoBrightnessAdjustment(adjustment);
425639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
426639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
427639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void setAmbientLux(float lux) {
4280a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        if (DEBUG) {
4290a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            Slog.d(TAG, "setAmbientLux(" + lux + ")");
4300a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        }
431d846023804ddadcd692666152db420c54594ddb9Michael Wright        if (lux < 0) {
432c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            Slog.w(TAG, "Ambient lux was negative, ignoring and setting to 0");
433d846023804ddadcd692666152db420c54594ddb9Michael Wright            lux = 0;
434d846023804ddadcd692666152db420c54594ddb9Michael Wright        }
435639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mAmbientLux = lux;
436428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza        mBrighteningLuxThreshold = mDynamicHysteresis.getBrighteningThreshold(lux);
437428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza        mDarkeningLuxThreshold = mDynamicHysteresis.getDarkeningThreshold(lux);
438c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik
439c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        // If the short term model was invalidated and the change is drastic enough, reset it.
440c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        if (!mShortTermModelValid && mShortTermModelAnchor != -1) {
441c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            final float minAmbientLux =
442c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                mShortTermModelAnchor - mShortTermModelAnchor * SHORT_TERM_MODEL_THRESHOLD_RATIO;
443c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            final float maxAmbientLux =
444c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                mShortTermModelAnchor + mShortTermModelAnchor * SHORT_TERM_MODEL_THRESHOLD_RATIO;
445c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            if (minAmbientLux < mAmbientLux && mAmbientLux < maxAmbientLux) {
44657d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                if (DEBUG) {
44757d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                    Slog.d(TAG, "ShortTermModel: re-validate user data, ambient lux is " +
44857d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                            minAmbientLux + " < " + mAmbientLux + " < " + maxAmbientLux);
44957d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                }
450c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                mShortTermModelValid = true;
451c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            } else {
452c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                Slog.d(TAG, "ShortTermModel: reset data, ambient lux is " + mAmbientLux +
45357d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "(" + minAmbientLux + ", " + maxAmbientLux + ")");
454c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                resetShortTermModel();
455c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            }
456c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        }
457639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
458639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
4590a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    private float calculateAmbientLux(long now, long horizon) {
4600a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        if (DEBUG) {
4610a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            Slog.d(TAG, "calculateAmbientLux(" + now + ", " + horizon + ")");
4620a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        }
463639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        final int N = mAmbientLightRingBuffer.size();
464639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (N == 0) {
465639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            Slog.e(TAG, "calculateAmbientLux: No ambient light readings available");
466639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return -1;
467639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
4680a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright
4690a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // Find the first measurement that is just outside of the horizon.
4700a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        int endIndex = 0;
4710a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        final long horizonStartTime = now - horizon;
4720a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        for (int i = 0; i < N-1; i++) {
4730a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            if (mAmbientLightRingBuffer.getTime(i + 1) <= horizonStartTime) {
4740a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                endIndex++;
4750a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            } else {
4760a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                break;
4770a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            }
4780a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        }
4790a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        if (DEBUG) {
48057d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik            Slog.d(TAG, "calculateAmbientLux: selected endIndex=" + endIndex + ", point=(" +
48157d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                    mAmbientLightRingBuffer.getTime(endIndex) + ", " +
48257d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                    mAmbientLightRingBuffer.getLux(endIndex) + ")");
4830a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        }
484639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float sum = 0;
485639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float totalWeight = 0;
486639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long endTime = AMBIENT_LIGHT_PREDICTION_TIME_MILLIS;
4870a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        for (int i = N - 1; i >= endIndex; i--) {
4880a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            long eventTime = mAmbientLightRingBuffer.getTime(i);
4890a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            if (i == endIndex && eventTime < horizonStartTime) {
4900a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                // If we're at the final value, make sure we only consider the part of the sample
4910a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                // within our desired horizon.
4920a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                eventTime = horizonStartTime;
4930a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            }
4940a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            final long startTime = eventTime - now;
495639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            float weight = calculateWeight(startTime, endTime);
496639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            float lux = mAmbientLightRingBuffer.getLux(i);
497639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
498c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                Slog.d(TAG, "calculateAmbientLux: [" + startTime + ", " + endTime + "]: " +
49957d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "lux=" + lux + ", " +
50057d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "weight=" + weight);
501639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
502639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            totalWeight += weight;
503c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            sum += lux * weight;
504639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            endTime = startTime;
505639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
506639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (DEBUG) {
507c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            Slog.d(TAG, "calculateAmbientLux: " +
50857d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                    "totalWeight=" + totalWeight + ", " +
50957d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                    "newAmbientLux=" + (sum / totalWeight));
510639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
511639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return sum / totalWeight;
512639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
513639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
5146fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private float calculateWeight(long startDelta, long endDelta) {
515639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return weightIntegral(endDelta) - weightIntegral(startDelta);
516639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
517639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
5186fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // Evaluates the integral of y = x + mWeightingIntercept. This is always positive for the
519639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // horizon we're looking at and provides a non-linear weighting for light samples.
5206fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private float weightIntegral(long x) {
5216fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        return x * (x * 0.5f + mWeightingIntercept);
522639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
523639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
524639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long nextAmbientLightBrighteningTransition(long time) {
525639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        final int N = mAmbientLightRingBuffer.size();
526639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long earliestValidTime = time;
527639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        for (int i = N - 1; i >= 0; i--) {
528639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mAmbientLightRingBuffer.getLux(i) <= mBrighteningLuxThreshold) {
529639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                break;
530639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
531639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            earliestValidTime = mAmbientLightRingBuffer.getTime(i);
532639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
533d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        return earliestValidTime + mBrighteningLightDebounceConfig;
534639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
535639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
536639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long nextAmbientLightDarkeningTransition(long time) {
537639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        final int N = mAmbientLightRingBuffer.size();
538639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long earliestValidTime = time;
539639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        for (int i = N - 1; i >= 0; i--) {
540639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mAmbientLightRingBuffer.getLux(i) >= mDarkeningLuxThreshold) {
541639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                break;
542639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
543639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            earliestValidTime = mAmbientLightRingBuffer.getTime(i);
544639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
545d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        return earliestValidTime + mDarkeningLightDebounceConfig;
546639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
547639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
548639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void updateAmbientLux() {
549639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long time = SystemClock.uptimeMillis();
5506fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
551639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        updateAmbientLux(time);
552639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
553639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
554639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void updateAmbientLux(long time) {
555639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // If the light sensor was just turned on then immediately update our initial
556639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // estimate of the current ambient light level.
557639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (!mAmbientLuxValid) {
558639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            final long timeWhenSensorWarmedUp =
559639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
560639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (time < timeWhenSensorWarmedUp) {
561639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (DEBUG) {
562c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                    Slog.d(TAG, "updateAmbientLux: Sensor not  ready yet: " +
56357d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                            "time=" + time + ", " +
56457d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                            "timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp);
565639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
566639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX,
567639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        timeWhenSensorWarmedUp);
568639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                return;
569639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
5700a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            setAmbientLux(calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS));
571639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mAmbientLuxValid = true;
572639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
573c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                Slog.d(TAG, "updateAmbientLux: Initializing: " +
574c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                        "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", " +
575c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                        "mAmbientLux=" + mAmbientLux);
576639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
577639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            updateAutoBrightness(true);
578639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
579639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
580639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
581639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
5820a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // Essentially, we calculate both a slow ambient lux, to ensure there's a true long-term
5830a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // change in lighting conditions, and a fast ambient lux to determine what the new
5840a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // brightness situation is since the slow lux can be quite slow to converge.
5850a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        //
5860a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // Note that both values need to be checked for sufficient change before updating the
5870a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // proposed ambient light value since the slow value might be sufficiently far enough away
5880a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // from the fast value to cause a recalculation while its actually just converging on
5890a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // the fast value still.
5900a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        float slowAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_LONG_HORIZON_MILLIS);
5910a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        float fastAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS);
5920a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright
593c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        if ((slowAmbientLux >= mBrighteningLuxThreshold &&
594c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik             fastAmbientLux >= mBrighteningLuxThreshold &&
595c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik             nextBrightenTransition <= time)
596c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik             ||
597c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            (slowAmbientLux <= mDarkeningLuxThreshold &&
598c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik             fastAmbientLux <= mDarkeningLuxThreshold &&
599c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik             nextDarkenTransition <= time)) {
6000a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            setAmbientLux(fastAmbientLux);
601639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
602c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                Slog.d(TAG, "updateAmbientLux: " +
60357d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        ((fastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": " +
60457d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold + ", " +
60557d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", " +
60657d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "mAmbientLux=" + mAmbientLux);
607639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
608639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            updateAutoBrightness(true);
609639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
610639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
611639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
612639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long nextTransitionTime = Math.min(nextDarkenTransition, nextBrightenTransition);
613639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // If one of the transitions is ready to occur, but the total weighted ambient lux doesn't
614639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // exceed the necessary threshold, then it's possible we'll get a transition time prior to
615639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // now. Rather than continually checking to see whether the weighted lux exceeds the
616639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // threshold, schedule an update for when we'd normally expect another light sample, which
617639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // should be enough time to decide whether we should actually transition to the new
618639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // weighted ambient lux or not.
619639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        nextTransitionTime =
6205d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza                nextTransitionTime > time ? nextTransitionTime : time + mNormalLightSensorRate;
621639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (DEBUG) {
622c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for " +
62357d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                    nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
624639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
625639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);
626639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
627639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
628639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void updateAutoBrightness(boolean sendUpdate) {
629639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (!mAmbientLuxValid) {
630639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return;
631639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
632639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
633eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright        float value = mBrightnessMapper.getBrightness(mAmbientLux);
634639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
635639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        int newScreenAutoBrightness =
636a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));
637639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (mScreenAutoBrightness != newScreenAutoBrightness) {
638639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
639c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                Slog.d(TAG, "updateAutoBrightness: " +
64057d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "mScreenAutoBrightness=" + mScreenAutoBrightness + ", " +
64157d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "newScreenAutoBrightness=" + newScreenAutoBrightness);
642639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
643639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
644639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mScreenAutoBrightness = newScreenAutoBrightness;
645639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (sendUpdate) {
646639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mCallbacks.updateBrightness();
647639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
648639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
649639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
650639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
651639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int clampScreenBrightness(int value) {
652639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return MathUtils.constrain(value,
653639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
654639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
655639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
656a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private void prepareBrightnessAdjustmentSample() {
657a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        if (!mBrightnessAdjustmentSamplePending) {
658a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSamplePending = true;
659a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSampleOldLux = mAmbientLuxValid ? mAmbientLux : -1;
660a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSampleOldBrightness = mScreenAutoBrightness;
661a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        } else {
662a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
663a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        }
664a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
665a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        mHandler.sendEmptyMessageDelayed(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE,
666a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS);
667a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    }
668a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
669a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private void cancelBrightnessAdjustmentSample() {
670a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        if (mBrightnessAdjustmentSamplePending) {
671a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSamplePending = false;
672a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
673a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        }
674a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    }
675a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
676a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private void collectBrightnessAdjustmentSample() {
677a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        if (mBrightnessAdjustmentSamplePending) {
678a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSamplePending = false;
679a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            if (mAmbientLuxValid && mScreenAutoBrightness >= 0) {
680a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                if (DEBUG) {
681c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                    Slog.d(TAG, "Auto-brightness adjustment changed by user: " +
68257d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                            "lux=" + mAmbientLux + ", " +
68357d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                            "brightness=" + mScreenAutoBrightness + ", " +
68457d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                            "ring=" + mAmbientLightRingBuffer);
685a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                }
686a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
687a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                EventLog.writeEvent(EventLogTags.AUTO_BRIGHTNESS_ADJ,
688a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mBrightnessAdjustmentSampleOldLux,
689a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mBrightnessAdjustmentSampleOldBrightness,
690a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mAmbientLux,
69157d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        mScreenAutoBrightness);
692a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            }
693a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        }
694a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    }
695a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
696639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final class AutomaticBrightnessHandler extends Handler {
697639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public AutomaticBrightnessHandler(Looper looper) {
698639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            super(looper, null, true /*async*/);
699639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
700639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
701639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
702639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void handleMessage(Message msg) {
703639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            switch (msg.what) {
704639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                case MSG_UPDATE_AMBIENT_LUX:
705639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    updateAmbientLux();
706639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    break;
707a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
708a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                case MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE:
709a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                    collectBrightnessAdjustmentSample();
710a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                    break;
711d846023804ddadcd692666152db420c54594ddb9Michael Wright
712c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                case MSG_INVALIDATE_SHORT_TERM_MODEL:
713c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                    invalidateShortTermModel();
714d846023804ddadcd692666152db420c54594ddb9Michael Wright                    break;
715639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
716639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
717639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
718639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
719639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final SensorEventListener mLightSensorListener = new SensorEventListener() {
720639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
721639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void onSensorChanged(SensorEvent event) {
722639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mLightSensorEnabled) {
723639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                final long time = SystemClock.uptimeMillis();
724639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                final float lux = event.values[0];
725639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                handleLightSensorEvent(time, lux);
726639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
727639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
728639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
729639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
730639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void onAccuracyChanged(Sensor sensor, int accuracy) {
731639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            // Not used.
732639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
733639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    };
734639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
735639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    /** Callbacks to request updates to the display's power state. */
736639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    interface Callbacks {
737639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        void updateBrightness();
738639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
739639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
7400a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    /**
7410a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright     * A ring buffer of ambient light measurements sorted by time.
7420a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright     *
7430a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright     * Each entry consists of a timestamp and a lux measurement, and the overall buffer is sorted
7440a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright     * from oldest to newest.
7450a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright     */
746103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright    private static final class AmbientLightRingBuffer {
747639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // Proportional extra capacity of the buffer beyond the expected number of light samples
748639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // in the horizon
749639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private static final float BUFFER_SLACK = 1.5f;
750639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private float[] mRingLux;
751639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private long[] mRingTime;
752639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mCapacity;
753639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
754639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // The first valid element and the next open slot.
755639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // Note that if mCount is zero then there are no valid elements.
756639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mStart;
757639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mEnd;
758639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mCount;
759639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
7606fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon) {
7616fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic            mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate);
762639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingLux = new float[mCapacity];
763639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingTime = new long[mCapacity];
764639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
765639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
766639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public float getLux(int index) {
767639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return mRingLux[offsetOf(index)];
768639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
769639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
770639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public long getTime(int index) {
771639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return mRingTime[offsetOf(index)];
772639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
773639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
774639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void push(long time, float lux) {
775639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            int next = mEnd;
776639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mCount == mCapacity) {
777639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                int newSize = mCapacity * 2;
778639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
779639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                float[] newRingLux = new float[newSize];
780639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                long[] newRingTime = new long[newSize];
781639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                int length = mCapacity - mStart;
782639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                System.arraycopy(mRingLux, mStart, newRingLux, 0, length);
783639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                System.arraycopy(mRingTime, mStart, newRingTime, 0, length);
784639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (mStart != 0) {
785639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    System.arraycopy(mRingLux, 0, newRingLux, length, mStart);
786639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    System.arraycopy(mRingTime, 0, newRingTime, length, mStart);
787639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
788639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRingLux = newRingLux;
789639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRingTime = newRingTime;
790639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
791639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                next = mCapacity;
792639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mCapacity = newSize;
793639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mStart = 0;
794639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
795639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingTime[next] = time;
796639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingLux[next] = lux;
797639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mEnd = next + 1;
798639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mEnd == mCapacity) {
799639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mEnd = 0;
800639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
801639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mCount++;
802639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
803639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
804639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void prune(long horizon) {
805639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mCount == 0) {
806639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                return;
807639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
808639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
809639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            while (mCount > 1) {
810639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                int next = mStart + 1;
811639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (next >= mCapacity) {
812639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    next -= mCapacity;
813639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
814639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (mRingTime[next] > horizon) {
815639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // Some light sensors only produce data upon a change in the ambient light
816639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // levels, so we need to consider the previous measurement as the ambient light
817639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // level for all points in time up until we receive a new measurement. Thus, we
818639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // always want to keep the youngest element that would be removed from the
819639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // buffer and just set its measurement time to the horizon time since at that
820639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // point it is the ambient light level, and to remove it would be to drop a
821639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // valid data point within our horizon.
822639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    break;
823639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
824639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mStart = next;
825639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mCount -= 1;
826639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
827639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
828639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mRingTime[mStart] < horizon) {
829639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRingTime[mStart] = horizon;
830639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
831639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
832639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
833639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public int size() {
834639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return mCount;
835639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
836639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
837639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void clear() {
838639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mStart = 0;
839639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mEnd = 0;
840639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mCount = 0;
841639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
842639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
843639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
844639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public String toString() {
845a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            StringBuffer buf = new StringBuffer();
846a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            buf.append('[');
847a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            for (int i = 0; i < mCount; i++) {
848a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                final long next = i + 1 < mCount ? getTime(i + 1) : SystemClock.uptimeMillis();
849a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                if (i != 0) {
850a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                    buf.append(", ");
851a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                }
852a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                buf.append(getLux(i));
853a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                buf.append(" / ");
854a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                buf.append(next - getTime(i));
855a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                buf.append("ms");
856639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
857a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            buf.append(']');
858a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            return buf.toString();
859639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
860639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
861639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int offsetOf(int index) {
862639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (index >= mCount || index < 0) {
863639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                throw new ArrayIndexOutOfBoundsException(index);
864639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
865639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            index += mStart;
866639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (index >= mCapacity) {
867639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                index -= mCapacity;
868639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
869639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return index;
870639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
871639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
872639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright}
873