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;
232155bc2be3d38b876335eb06f08e81fc2d563831Michael Wrightimport android.app.ActivityManager;
24639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.hardware.Sensor;
25639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.hardware.SensorEvent;
26639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.hardware.SensorEventListener;
27639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.hardware.SensorManager;
28eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wrightimport android.hardware.display.BrightnessConfiguration;
29d846023804ddadcd692666152db420c54594ddb9Michael Wrightimport android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
302155bc2be3d38b876335eb06f08e81fc2d563831Michael Wrightimport android.os.Build;
31639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.Handler;
32639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.Looper;
33639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.Message;
34639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.PowerManager;
35639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.SystemClock;
36b0a1d3d08fc459e0d9937e299e16de17d1388ac4Michael Wrightimport android.os.Trace;
37639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.text.format.DateUtils;
38a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brownimport android.util.EventLog;
39639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.util.MathUtils;
40639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.util.Slog;
41639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.util.TimeUtils;
42639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
43639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport java.io.PrintWriter;
44639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
45639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightclass AutomaticBrightnessController {
46639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final String TAG = "AutomaticBrightnessController";
47639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
48639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final boolean DEBUG = false;
49639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
50639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
51639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // If true, enables the use of the screen auto-brightness adjustment setting.
52daf7d410fc97647f2b3ab4254f73c09c923018deAdrian Roos    private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT = true;
53639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
54639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // How long the current sensor reading is assumed to be valid beyond the current time.
55639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // This provides a bit of prediction, as well as ensures that the weight for the last sample is
56639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // non-zero, which in turn ensures that the total weight is non-zero.
57639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final long AMBIENT_LIGHT_PREDICTION_TIME_MILLIS = 100;
58639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
59a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    // Debounce for sampling user-initiated changes in display brightness to ensure
60a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    // the user is satisfied with the result before storing the sample.
61a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private static final int BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS = 10000;
62a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
63d846023804ddadcd692666152db420c54594ddb9Michael Wright    // Timeout after which we remove the effects any user interactions might've had on the
64d846023804ddadcd692666152db420c54594ddb9Michael Wright    // brightness mapping. This timeout doesn't start until we transition to a non-interactive
65d846023804ddadcd692666152db420c54594ddb9Michael Wright    // display policy so that we don't reset while users are using their devices, but also so that
66d846023804ddadcd692666152db420c54594ddb9Michael Wright    // we don't erroneously keep the short-term model if the device is dozing but the display is
67d846023804ddadcd692666152db420c54594ddb9Michael Wright    // fully on.
68d846023804ddadcd692666152db420c54594ddb9Michael Wright    private static final int SHORT_TERM_MODEL_TIMEOUT_MILLIS = 30000;
69d846023804ddadcd692666152db420c54594ddb9Michael Wright
70639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final int MSG_UPDATE_AMBIENT_LUX = 1;
71a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2;
72c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    private static final int MSG_INVALIDATE_SHORT_TERM_MODEL = 3;
73639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
740a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    // Length of the ambient light horizon used to calculate the long term estimate of ambient
750a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    // light.
760a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    private static final int AMBIENT_LIGHT_LONG_HORIZON_MILLIS = 10000;
770a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright
780a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    // Length of the ambient light horizon used to calculate short-term estimate of ambient light.
790a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    private static final int AMBIENT_LIGHT_SHORT_HORIZON_MILLIS = 2000;
800a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright
81428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza    // Callbacks for requesting updates to the display's power state
82639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final Callbacks mCallbacks;
83639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
84639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The sensor manager.
85639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final SensorManager mSensorManager;
86639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
87639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The light sensor, or null if not available or needed.
88639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final Sensor mLightSensor;
89639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
90eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright    // The mapper to translate ambient lux to screen brightness in the range [0, 1.0].
91eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright    private final BrightnessMappingStrategy mBrightnessMapper;
92639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
93639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The minimum and maximum screen brightnesses.
94639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final int mScreenBrightnessRangeMinimum;
95639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final int mScreenBrightnessRangeMaximum;
962155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright
972155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright    // How much to scale doze brightness by (should be (0, 1.0]).
98a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski    private final float mDozeScaleFactor;
99639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
1005d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    // Initial light sensor event rate in milliseconds.
1015d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    private final int mInitialLightSensorRate;
1025d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza
1035d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    // Steady-state light sensor event rate in milliseconds.
1045d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    private final int mNormalLightSensorRate;
1055d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza
1065d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    // The current light sensor event rate in milliseconds.
1075d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    private int mCurrentLightSensorRate;
108d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski
109d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // Stability requirements in milliseconds for accepting a new brightness level.  This is used
110d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // for debouncing the light sensor.  Different constants are used to debounce the light sensor
111d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // when adapting to brighter or darker environments.  This parameter controls how quickly
112d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // brightness changes occur in response to an observed change in light level that exceeds the
113d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // hysteresis threshold.
114d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    private final long mBrighteningLightDebounceConfig;
115d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    private final long mDarkeningLightDebounceConfig;
116d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski
117d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // If true immediately after the screen is turned on the controller will try to adjust the
118d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // brightness based on the current sensor reads. If false, the controller will collect more data
119d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // and only then decide whether to change brightness.
120d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    private final boolean mResetAmbientLuxAfterWarmUpConfig;
121d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski
1226fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // Period of time in which to consider light samples in milliseconds.
1236fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private final int mAmbientLightHorizon;
1246fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic
1256fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // The intercept used for the weighting calculation. This is used in order to keep all possible
1266fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // weighting values positive.
1276fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private final int mWeightingIntercept;
1286fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic
1292155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright    // Configuration object for determining thresholds to change brightness dynamically
1302155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright    private final HysteresisLevels mHysteresisLevels;
131428aed01e1e2923968027dff57132d8d8d5c4905Julius D'souza
132639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Amount of time to delay auto-brightness after screen on while waiting for
133639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // the light sensor to warm-up in milliseconds.
134639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // May be 0 if no warm-up is required.
135639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int mLightSensorWarmUpTimeConfig;
136639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
137639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Set to true if the light sensor is enabled.
138639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean mLightSensorEnabled;
139639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
140639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The time when the light sensor was enabled.
141639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long mLightSensorEnableTime;
142639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
143639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The currently accepted nominal ambient light level.
144639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mAmbientLux;
145639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
146639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // True if mAmbientLux holds a valid value.
147639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean mAmbientLuxValid;
148639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
149639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The ambient light level threshold at which to brighten or darken the screen.
150639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mBrighteningLuxThreshold;
151639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mDarkeningLuxThreshold;
152639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
153639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The most recent light sample.
154639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mLastObservedLux;
155639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
156639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The time of the most light recent sample.
157639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long mLastObservedLuxTime;
158639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
159639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The number of light samples collected since the light sensor was enabled.
160639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int mRecentLightSamples;
161639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
162639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // A ring buffer containing all of the recent ambient light sensor readings.
163639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private AmbientLightRingBuffer mAmbientLightRingBuffer;
164639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
165639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The handler
166639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private AutomaticBrightnessHandler mHandler;
167639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
168639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The screen brightness level that has been chosen by the auto-brightness
169639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // algorithm.  The actual brightness should ramp towards this value.
170639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // We preserve this value even when we stop using the light sensor so
171639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // that we can quickly revert to the previous auto-brightness level
172639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // while the light sensor warms up.
173639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Use -1 if there is no current auto-brightness value available.
174639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int mScreenAutoBrightness = -1;
175639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
176d846023804ddadcd692666152db420c54594ddb9Michael Wright    // The current display policy. This is useful, for example,  for knowing when we're dozing,
177d846023804ddadcd692666152db420c54594ddb9Michael Wright    // where the light sensor may not be available.
178d846023804ddadcd692666152db420c54594ddb9Michael Wright    private int mDisplayPolicy = DisplayPowerRequest.POLICY_OFF;
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 mBrightnessAdjustmentSampleOldLux;
184a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private int mBrightnessAdjustmentSampleOldBrightness;
185a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
186c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    // When the short term model is invalidated, we don't necessarily reset it (i.e. clear the
187c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    // user's adjustment) immediately, but wait for a drastic enough change in the ambient light.
188c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    // The anchor determines what were the light levels when the user has set her preference, and
189c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    // we use a relative threshold to determine when to revert to the OEM curve.
190c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    private boolean mShortTermModelValid;
191c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    private float mShortTermModelAnchor;
192c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    private float SHORT_TERM_MODEL_THRESHOLD_RATIO = 0.6f;
193c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik
194639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
19557d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik            SensorManager sensorManager, BrightnessMappingStrategy mapper,
19657d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik            int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor,
1975d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
1986fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic            long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
1992155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright            HysteresisLevels hysteresisLevels) {
200639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mCallbacks = callbacks;
201639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mSensorManager = sensorManager;
202eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright        mBrightnessMapper = mapper;
203639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mScreenBrightnessRangeMinimum = brightnessMin;
204639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mScreenBrightnessRangeMaximum = brightnessMax;
205639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime;
206a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        mDozeScaleFactor = dozeScaleFactor;
2075d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        mNormalLightSensorRate = lightSensorRate;
2085d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        mInitialLightSensorRate = initialLightSensorRate;
2095d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        mCurrentLightSensorRate = -1;
210d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mBrighteningLightDebounceConfig = brighteningLightDebounceConfig;
211d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mDarkeningLightDebounceConfig = darkeningLightDebounceConfig;
212d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig;
2132155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        mAmbientLightHorizon = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
2142155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        mWeightingIntercept = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
2152155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        mHysteresisLevels = hysteresisLevels;
216c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        mShortTermModelValid = true;
217c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        mShortTermModelAnchor = -1;
218639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
219639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mHandler = new AutomaticBrightnessHandler(looper);
220103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright        mAmbientLightRingBuffer =
2215d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
222639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
223639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
224639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
225639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
226639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
227639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
228639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    public int getAutomaticScreenBrightness() {
2295878442bc6c23a1c1cd87a5fb1a2c241329835aaDan Gittik        if (!mAmbientLuxValid) {
2305878442bc6c23a1c1cd87a5fb1a2c241329835aaDan Gittik            return -1;
2315878442bc6c23a1c1cd87a5fb1a2c241329835aaDan Gittik        }
232d846023804ddadcd692666152db420c54594ddb9Michael Wright        if (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE) {
233a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski            return (int) (mScreenAutoBrightness * mDozeScaleFactor);
234a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        }
235639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return mScreenAutoBrightness;
236639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
237639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
238617564ff2cdee2e9a50339544129283503ae71a8Michael Wright    public float getAutomaticScreenBrightnessAdjustment() {
23957d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik        return mBrightnessMapper.getAutoBrightnessAdjustment();
240617564ff2cdee2e9a50339544129283503ae71a8Michael Wright    }
241617564ff2cdee2e9a50339544129283503ae71a8Michael Wright
242eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright    public void configure(boolean enable, @Nullable BrightnessConfiguration configuration,
243617564ff2cdee2e9a50339544129283503ae71a8Michael Wright            float brightness, boolean userChangedBrightness, float adjustment,
244617564ff2cdee2e9a50339544129283503ae71a8Michael Wright            boolean userChangedAutoBrightnessAdjustment, int displayPolicy) {
245a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // While dozing, the application processor may be suspended which will prevent us from
246a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // receiving new information from the light sensor. On some devices, we may be able to
247a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // switch to a wake-up light sensor instead but for now we will simply disable the sensor
248a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // and hold onto the last computed screen auto brightness.  We save the dozing flag for
249a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // debugging purposes.
250d846023804ddadcd692666152db420c54594ddb9Michael Wright        boolean dozing = (displayPolicy == DisplayPowerRequest.POLICY_DOZE);
251eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright        boolean changed = setBrightnessConfiguration(configuration);
252d846023804ddadcd692666152db420c54594ddb9Michael Wright        changed |= setDisplayPolicy(displayPolicy);
25357d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik        if (userChangedAutoBrightnessAdjustment) {
25457d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik            changed |= setAutoBrightnessAdjustment(adjustment);
25557d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik        }
256617564ff2cdee2e9a50339544129283503ae71a8Michael Wright        if (userChangedBrightness && enable) {
257617564ff2cdee2e9a50339544129283503ae71a8Michael Wright            // Update the brightness curve with the new user control point. It's critical this
258617564ff2cdee2e9a50339544129283503ae71a8Michael Wright            // happens after we update the autobrightness adjustment since it may reset it.
259d846023804ddadcd692666152db420c54594ddb9Michael Wright            changed |= setScreenBrightnessByUser(brightness);
260617564ff2cdee2e9a50339544129283503ae71a8Michael Wright        }
261617564ff2cdee2e9a50339544129283503ae71a8Michael Wright        final boolean userInitiatedChange =
262617564ff2cdee2e9a50339544129283503ae71a8Michael Wright                userChangedBrightness || userChangedAutoBrightnessAdjustment;
263617564ff2cdee2e9a50339544129283503ae71a8Michael Wright        if (userInitiatedChange && enable && !dozing) {
264a8edffd804d3940dec1fa5c9777d10beccb2f6a6Soroosh Mariooryad            prepareBrightnessAdjustmentSample();
265a8edffd804d3940dec1fa5c9777d10beccb2f6a6Soroosh Mariooryad        }
266d846023804ddadcd692666152db420c54594ddb9Michael Wright        changed |= setLightSensorEnabled(enable && !dozing);
267970d4132ea28e748c1010be39450a98bbf7466f3Jeff Brown        if (changed) {
268639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            updateAutoBrightness(false /*sendUpdate*/);
269639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
270639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
271639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
27253d0661f38d6ada39aefaac5ce016f802e74bd44Kenny Guy    public boolean hasUserDataPoints() {
27353d0661f38d6ada39aefaac5ce016f802e74bd44Kenny Guy        return mBrightnessMapper.hasUserDataPoints();
27453d0661f38d6ada39aefaac5ce016f802e74bd44Kenny Guy    }
27553d0661f38d6ada39aefaac5ce016f802e74bd44Kenny Guy
27653d0661f38d6ada39aefaac5ce016f802e74bd44Kenny Guy    public boolean isDefaultConfig() {
27753d0661f38d6ada39aefaac5ce016f802e74bd44Kenny Guy        return mBrightnessMapper.isDefaultConfig();
27853d0661f38d6ada39aefaac5ce016f802e74bd44Kenny Guy    }
27953d0661f38d6ada39aefaac5ce016f802e74bd44Kenny Guy
2806d1009f882f1b0234e77ec3bb583a58090bfff39Kenny Guy    public BrightnessConfiguration getDefaultConfig() {
2816d1009f882f1b0234e77ec3bb583a58090bfff39Kenny Guy        return mBrightnessMapper.getDefaultConfig();
2826d1009f882f1b0234e77ec3bb583a58090bfff39Kenny Guy    }
2836d1009f882f1b0234e77ec3bb583a58090bfff39Kenny Guy
284d846023804ddadcd692666152db420c54594ddb9Michael Wright    private boolean setDisplayPolicy(int policy) {
285d846023804ddadcd692666152db420c54594ddb9Michael Wright        if (mDisplayPolicy == policy) {
286d846023804ddadcd692666152db420c54594ddb9Michael Wright            return false;
287d846023804ddadcd692666152db420c54594ddb9Michael Wright        }
288d846023804ddadcd692666152db420c54594ddb9Michael Wright        final int oldPolicy = mDisplayPolicy;
289d846023804ddadcd692666152db420c54594ddb9Michael Wright        mDisplayPolicy = policy;
290d846023804ddadcd692666152db420c54594ddb9Michael Wright        if (DEBUG) {
291c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            Slog.d(TAG, "Display policy transitioning from " + oldPolicy + " to " + policy);
292d846023804ddadcd692666152db420c54594ddb9Michael Wright        }
293d846023804ddadcd692666152db420c54594ddb9Michael Wright        if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy)) {
294c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_SHORT_TERM_MODEL,
295d846023804ddadcd692666152db420c54594ddb9Michael Wright                    SHORT_TERM_MODEL_TIMEOUT_MILLIS);
296d846023804ddadcd692666152db420c54594ddb9Michael Wright        } else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) {
297c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mHandler.removeMessages(MSG_INVALIDATE_SHORT_TERM_MODEL);
298d846023804ddadcd692666152db420c54594ddb9Michael Wright        }
299d846023804ddadcd692666152db420c54594ddb9Michael Wright        return true;
300d846023804ddadcd692666152db420c54594ddb9Michael Wright    }
301d846023804ddadcd692666152db420c54594ddb9Michael Wright
302d846023804ddadcd692666152db420c54594ddb9Michael Wright    private static boolean isInteractivePolicy(int policy) {
303d846023804ddadcd692666152db420c54594ddb9Michael Wright        return policy == DisplayPowerRequest.POLICY_BRIGHT
304d846023804ddadcd692666152db420c54594ddb9Michael Wright                || policy == DisplayPowerRequest.POLICY_DIM
305d846023804ddadcd692666152db420c54594ddb9Michael Wright                || policy == DisplayPowerRequest.POLICY_VR;
306d846023804ddadcd692666152db420c54594ddb9Michael Wright    }
307d846023804ddadcd692666152db420c54594ddb9Michael Wright
308d846023804ddadcd692666152db420c54594ddb9Michael Wright    private boolean setScreenBrightnessByUser(float brightness) {
309d846023804ddadcd692666152db420c54594ddb9Michael Wright        if (!mAmbientLuxValid) {
310d846023804ddadcd692666152db420c54594ddb9Michael Wright            // If we don't have a valid ambient lux then we don't have a valid brightness anyways,
311d846023804ddadcd692666152db420c54594ddb9Michael Wright            // and we can't use this data to add a new control point to the short-term model.
312d846023804ddadcd692666152db420c54594ddb9Michael Wright            return false;
313d846023804ddadcd692666152db420c54594ddb9Michael Wright        }
314d846023804ddadcd692666152db420c54594ddb9Michael Wright        mBrightnessMapper.addUserDataPoint(mAmbientLux, brightness);
315c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        mShortTermModelValid = true;
316c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        mShortTermModelAnchor = mAmbientLux;
317c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        if (DEBUG) {
318c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            Slog.d(TAG, "ShortTermModel: anchor=" + mShortTermModelAnchor);
319c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        }
320d846023804ddadcd692666152db420c54594ddb9Michael Wright        return true;
321d846023804ddadcd692666152db420c54594ddb9Michael Wright    }
322d846023804ddadcd692666152db420c54594ddb9Michael Wright
323c135225466eb1b209e12c8c2df135641a21c5d66Dan Gittik    public void resetShortTermModel() {
324d846023804ddadcd692666152db420c54594ddb9Michael Wright        mBrightnessMapper.clearUserDataPoints();
325c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        mShortTermModelValid = true;
326c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        mShortTermModelAnchor = -1;
327c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    }
328c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik
329c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik    private void invalidateShortTermModel() {
330c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        if (DEBUG) {
331c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            Slog.d(TAG, "ShortTermModel: invalidate user data");
332c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        }
333c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        mShortTermModelValid = false;
334d846023804ddadcd692666152db420c54594ddb9Michael Wright    }
335d846023804ddadcd692666152db420c54594ddb9Michael Wright
336eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright    public boolean setBrightnessConfiguration(BrightnessConfiguration configuration) {
337b8f4f77d9e12e125408b058bcbd505f4a0bdd50eMichael Wright        if (mBrightnessMapper.setBrightnessConfiguration(configuration)) {
338b8f4f77d9e12e125408b058bcbd505f4a0bdd50eMichael Wright            resetShortTermModel();
339b8f4f77d9e12e125408b058bcbd505f4a0bdd50eMichael Wright            return true;
340b8f4f77d9e12e125408b058bcbd505f4a0bdd50eMichael Wright        }
341b8f4f77d9e12e125408b058bcbd505f4a0bdd50eMichael Wright        return false;
342eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright    }
343eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright
344639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    public void dump(PrintWriter pw) {
345639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println();
346639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("Automatic Brightness Controller Configuration:");
347639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
348639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
3492155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        pw.println("  mDozeScaleFactor=" + mDozeScaleFactor);
3502155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        pw.println("  mInitialLightSensorRate=" + mInitialLightSensorRate);
3512155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        pw.println("  mNormalLightSensorRate=" + mNormalLightSensorRate);
352639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
353d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        pw.println("  mBrighteningLightDebounceConfig=" + mBrighteningLightDebounceConfig);
354d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        pw.println("  mDarkeningLightDebounceConfig=" + mDarkeningLightDebounceConfig);
355d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        pw.println("  mResetAmbientLuxAfterWarmUpConfig=" + mResetAmbientLuxAfterWarmUpConfig);
3562155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        pw.println("  mAmbientLightHorizon=" + mAmbientLightHorizon);
3572155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        pw.println("  mWeightingIntercept=" + mWeightingIntercept);
358639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
359639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println();
360639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("Automatic Brightness Controller State:");
361639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensor=" + mLightSensor);
362639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensorEnabled=" + mLightSensorEnabled);
363639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensorEnableTime=" + TimeUtils.formatUptime(mLightSensorEnableTime));
3642155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        pw.println("  mCurrentLightSensorRate=" + mCurrentLightSensorRate);
365639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mAmbientLux=" + mAmbientLux);
3665878442bc6c23a1c1cd87a5fb1a2c241329835aaDan Gittik        pw.println("  mAmbientLuxValid=" + mAmbientLuxValid);
367639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mBrighteningLuxThreshold=" + mBrighteningLuxThreshold);
368639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mDarkeningLuxThreshold=" + mDarkeningLuxThreshold);
369639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLastObservedLux=" + mLastObservedLux);
370639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLastObservedLuxTime=" + TimeUtils.formatUptime(mLastObservedLuxTime));
371639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mRecentLightSamples=" + mRecentLightSamples);
372639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mAmbientLightRingBuffer=" + mAmbientLightRingBuffer);
373639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenAutoBrightness=" + mScreenAutoBrightness);
3742155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        pw.println("  mDisplayPolicy=" + DisplayPowerRequest.policyToString(mDisplayPolicy));
375c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        pw.println("  mShortTermModelAnchor=" + mShortTermModelAnchor);
3762155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        pw.println("  mShortTermModelValid=" + mShortTermModelValid);
3772155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        pw.println("  mBrightnessAdjustmentSamplePending=" + mBrightnessAdjustmentSamplePending);
3782155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        pw.println("  mBrightnessAdjustmentSampleOldLux=" + mBrightnessAdjustmentSampleOldLux);
3792155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        pw.println("  mBrightnessAdjustmentSampleOldBrightness="
3802155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright                + mBrightnessAdjustmentSampleOldBrightness);
3812155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        pw.println("  mShortTermModelValid=" + mShortTermModelValid);
382eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright
383eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright        pw.println();
384eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright        mBrightnessMapper.dump(pw);
3852155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright
3862155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        pw.println();
3872155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        mHysteresisLevels.dump(pw);
388639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
389639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
390639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean setLightSensorEnabled(boolean enable) {
391639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (enable) {
392639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (!mLightSensorEnabled) {
393639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorEnabled = true;
394639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorEnableTime = SystemClock.uptimeMillis();
3955d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza                mCurrentLightSensorRate = mInitialLightSensorRate;
396639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mSensorManager.registerListener(mLightSensorListener, mLightSensor,
3975d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza                        mCurrentLightSensorRate * 1000, mHandler);
398639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                return true;
399639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
400c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        } else if (mLightSensorEnabled) {
401c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mLightSensorEnabled = false;
402c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
403c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mRecentLightSamples = 0;
404c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mAmbientLightRingBuffer.clear();
405c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mCurrentLightSensorRate = -1;
406c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
407c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            mSensorManager.unregisterListener(mLightSensorListener);
408639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
409639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return false;
410639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
411639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
412639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void handleLightSensorEvent(long time, float lux) {
413b0a1d3d08fc459e0d9937e299e16de17d1388ac4Michael Wright        Trace.traceCounter(Trace.TRACE_TAG_POWER, "ALS", (int) lux);
414639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
415639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
4165d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        if (mAmbientLightRingBuffer.size() == 0) {
4175d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            // switch to using the steady-state sample rate after grabbing the initial light sample
4185d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            adjustLightSensorRate(mNormalLightSensorRate);
4195d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        }
420639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        applyLightSensorMeasurement(time, lux);
421639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        updateAmbientLux(time);
422639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
423639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
424639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void applyLightSensorMeasurement(long time, float lux) {
425639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mRecentLightSamples++;
4266fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
427639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mAmbientLightRingBuffer.push(time, lux);
428639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
429639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // Remember this sample value.
430639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mLastObservedLux = lux;
431639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mLastObservedLuxTime = time;
432639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
433639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
4345d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    private void adjustLightSensorRate(int lightSensorRate) {
4355d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        // if the light sensor rate changed, update the sensor listener
4365d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        if (lightSensorRate != mCurrentLightSensorRate) {
4375d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            if (DEBUG) {
438c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                Slog.d(TAG, "adjustLightSensorRate: " +
43957d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "previousRate=" + mCurrentLightSensorRate + ", " +
44057d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "currentRate=" + lightSensorRate);
4415d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            }
4425d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            mCurrentLightSensorRate = lightSensorRate;
4435d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            mSensorManager.unregisterListener(mLightSensorListener);
4445d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza            mSensorManager.registerListener(mLightSensorListener, mLightSensor,
4455d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza                    lightSensorRate * 1000, mHandler);
4465d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza        }
4475d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza    }
4485d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza
44957d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik    private boolean setAutoBrightnessAdjustment(float adjustment) {
45057d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik        return mBrightnessMapper.setAutoBrightnessAdjustment(adjustment);
451639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
452639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
453639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void setAmbientLux(float lux) {
4540a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        if (DEBUG) {
4550a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            Slog.d(TAG, "setAmbientLux(" + lux + ")");
4560a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        }
457d846023804ddadcd692666152db420c54594ddb9Michael Wright        if (lux < 0) {
458c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            Slog.w(TAG, "Ambient lux was negative, ignoring and setting to 0");
459d846023804ddadcd692666152db420c54594ddb9Michael Wright            lux = 0;
460d846023804ddadcd692666152db420c54594ddb9Michael Wright        }
461639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mAmbientLux = lux;
4622155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        mBrighteningLuxThreshold = mHysteresisLevels.getBrighteningThreshold(lux);
4632155bc2be3d38b876335eb06f08e81fc2d563831Michael Wright        mDarkeningLuxThreshold = mHysteresisLevels.getDarkeningThreshold(lux);
464c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik
465c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        // If the short term model was invalidated and the change is drastic enough, reset it.
466c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        if (!mShortTermModelValid && mShortTermModelAnchor != -1) {
467c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            final float minAmbientLux =
468c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                mShortTermModelAnchor - mShortTermModelAnchor * SHORT_TERM_MODEL_THRESHOLD_RATIO;
469c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            final float maxAmbientLux =
470c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                mShortTermModelAnchor + mShortTermModelAnchor * SHORT_TERM_MODEL_THRESHOLD_RATIO;
471c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            if (minAmbientLux < mAmbientLux && mAmbientLux < maxAmbientLux) {
47257d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                if (DEBUG) {
47357d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                    Slog.d(TAG, "ShortTermModel: re-validate user data, ambient lux is " +
47457d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                            minAmbientLux + " < " + mAmbientLux + " < " + maxAmbientLux);
47557d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                }
476c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                mShortTermModelValid = true;
477c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            } else {
478c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                Slog.d(TAG, "ShortTermModel: reset data, ambient lux is " + mAmbientLux +
47957d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "(" + minAmbientLux + ", " + maxAmbientLux + ")");
480c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                resetShortTermModel();
481c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            }
482c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        }
483639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
484639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
4850a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    private float calculateAmbientLux(long now, long horizon) {
4860a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        if (DEBUG) {
4870a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            Slog.d(TAG, "calculateAmbientLux(" + now + ", " + horizon + ")");
4880a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        }
489639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        final int N = mAmbientLightRingBuffer.size();
490639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (N == 0) {
491639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            Slog.e(TAG, "calculateAmbientLux: No ambient light readings available");
492639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return -1;
493639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
4940a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright
4950a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // Find the first measurement that is just outside of the horizon.
4960a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        int endIndex = 0;
4970a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        final long horizonStartTime = now - horizon;
4980a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        for (int i = 0; i < N-1; i++) {
4990a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            if (mAmbientLightRingBuffer.getTime(i + 1) <= horizonStartTime) {
5000a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                endIndex++;
5010a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            } else {
5020a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                break;
5030a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            }
5040a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        }
5050a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        if (DEBUG) {
50657d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik            Slog.d(TAG, "calculateAmbientLux: selected endIndex=" + endIndex + ", point=(" +
50757d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                    mAmbientLightRingBuffer.getTime(endIndex) + ", " +
50857d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                    mAmbientLightRingBuffer.getLux(endIndex) + ")");
5090a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        }
510639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float sum = 0;
511639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float totalWeight = 0;
512639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long endTime = AMBIENT_LIGHT_PREDICTION_TIME_MILLIS;
5130a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        for (int i = N - 1; i >= endIndex; i--) {
5140a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            long eventTime = mAmbientLightRingBuffer.getTime(i);
5150a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            if (i == endIndex && eventTime < horizonStartTime) {
5160a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                // If we're at the final value, make sure we only consider the part of the sample
5170a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                // within our desired horizon.
5180a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright                eventTime = horizonStartTime;
5190a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            }
5200a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            final long startTime = eventTime - now;
521639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            float weight = calculateWeight(startTime, endTime);
522639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            float lux = mAmbientLightRingBuffer.getLux(i);
523639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
524c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                Slog.d(TAG, "calculateAmbientLux: [" + startTime + ", " + endTime + "]: " +
52557d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "lux=" + lux + ", " +
52657d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "weight=" + weight);
527639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
528639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            totalWeight += weight;
529c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            sum += lux * weight;
530639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            endTime = startTime;
531639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
532639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (DEBUG) {
533c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            Slog.d(TAG, "calculateAmbientLux: " +
53457d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                    "totalWeight=" + totalWeight + ", " +
53557d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                    "newAmbientLux=" + (sum / totalWeight));
536639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
537639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return sum / totalWeight;
538639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
539639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
5406fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private float calculateWeight(long startDelta, long endDelta) {
541639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return weightIntegral(endDelta) - weightIntegral(startDelta);
542639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
543639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
5446fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    // Evaluates the integral of y = x + mWeightingIntercept. This is always positive for the
545639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // horizon we're looking at and provides a non-linear weighting for light samples.
5466fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic    private float weightIntegral(long x) {
5476fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        return x * (x * 0.5f + mWeightingIntercept);
548639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
549639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
550639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long nextAmbientLightBrighteningTransition(long time) {
551639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        final int N = mAmbientLightRingBuffer.size();
552639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long earliestValidTime = time;
553639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        for (int i = N - 1; i >= 0; i--) {
554639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mAmbientLightRingBuffer.getLux(i) <= mBrighteningLuxThreshold) {
555639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                break;
556639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
557639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            earliestValidTime = mAmbientLightRingBuffer.getTime(i);
558639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
559d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        return earliestValidTime + mBrighteningLightDebounceConfig;
560639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
561639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
562639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long nextAmbientLightDarkeningTransition(long time) {
563639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        final int N = mAmbientLightRingBuffer.size();
564639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long earliestValidTime = time;
565639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        for (int i = N - 1; i >= 0; i--) {
566639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mAmbientLightRingBuffer.getLux(i) >= mDarkeningLuxThreshold) {
567639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                break;
568639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
569639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            earliestValidTime = mAmbientLightRingBuffer.getTime(i);
570639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
571d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        return earliestValidTime + mDarkeningLightDebounceConfig;
572639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
573639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
574639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void updateAmbientLux() {
575639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long time = SystemClock.uptimeMillis();
5766fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
577639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        updateAmbientLux(time);
578639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
579639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
580639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void updateAmbientLux(long time) {
581639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // If the light sensor was just turned on then immediately update our initial
582639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // estimate of the current ambient light level.
583639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (!mAmbientLuxValid) {
584639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            final long timeWhenSensorWarmedUp =
585639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
586639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (time < timeWhenSensorWarmedUp) {
587639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (DEBUG) {
588c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                    Slog.d(TAG, "updateAmbientLux: Sensor not  ready yet: " +
58957d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                            "time=" + time + ", " +
59057d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                            "timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp);
591639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
592639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX,
593639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        timeWhenSensorWarmedUp);
594639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                return;
595639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
5960a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            setAmbientLux(calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS));
597639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mAmbientLuxValid = true;
598639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
599c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                Slog.d(TAG, "updateAmbientLux: Initializing: " +
600c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                        "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", " +
601c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                        "mAmbientLux=" + mAmbientLux);
602639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
603639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            updateAutoBrightness(true);
604639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
605639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
606639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
607639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
6080a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // Essentially, we calculate both a slow ambient lux, to ensure there's a true long-term
6090a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // change in lighting conditions, and a fast ambient lux to determine what the new
6100a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // brightness situation is since the slow lux can be quite slow to converge.
6110a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        //
6120a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // Note that both values need to be checked for sufficient change before updating the
6130a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // proposed ambient light value since the slow value might be sufficiently far enough away
6140a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // from the fast value to cause a recalculation while its actually just converging on
6150a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        // the fast value still.
6160a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        float slowAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_LONG_HORIZON_MILLIS);
6170a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright        float fastAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS);
6180a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright
619c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik        if ((slowAmbientLux >= mBrighteningLuxThreshold &&
620c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik             fastAmbientLux >= mBrighteningLuxThreshold &&
621c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik             nextBrightenTransition <= time)
622c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik             ||
623c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            (slowAmbientLux <= mDarkeningLuxThreshold &&
624c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik             fastAmbientLux <= mDarkeningLuxThreshold &&
625c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik             nextDarkenTransition <= time)) {
6260a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright            setAmbientLux(fastAmbientLux);
627639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
628c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                Slog.d(TAG, "updateAmbientLux: " +
62957d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        ((fastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": " +
63057d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold + ", " +
63157d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", " +
63257d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "mAmbientLux=" + mAmbientLux);
633639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
634639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            updateAutoBrightness(true);
635639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
636639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
637639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
638639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long nextTransitionTime = Math.min(nextDarkenTransition, nextBrightenTransition);
639639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // If one of the transitions is ready to occur, but the total weighted ambient lux doesn't
640639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // exceed the necessary threshold, then it's possible we'll get a transition time prior to
641639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // now. Rather than continually checking to see whether the weighted lux exceeds the
642639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // threshold, schedule an update for when we'd normally expect another light sample, which
643639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // should be enough time to decide whether we should actually transition to the new
644639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // weighted ambient lux or not.
645639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        nextTransitionTime =
6465d7170963ac0cfa30400292841c3673b8cdea5b5Julius D'souza                nextTransitionTime > time ? nextTransitionTime : time + mNormalLightSensorRate;
647639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (DEBUG) {
648c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik            Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for " +
64957d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                    nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
650639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
651639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);
652639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
653639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
654639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void updateAutoBrightness(boolean sendUpdate) {
655639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (!mAmbientLuxValid) {
656639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return;
657639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
658639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
659eef0e13f018f33bf3db2f8311bbb429369e13394Michael Wright        float value = mBrightnessMapper.getBrightness(mAmbientLux);
660639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
661639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        int newScreenAutoBrightness =
662a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));
663639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (mScreenAutoBrightness != newScreenAutoBrightness) {
664639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
665c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                Slog.d(TAG, "updateAutoBrightness: " +
66657d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "mScreenAutoBrightness=" + mScreenAutoBrightness + ", " +
66757d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        "newScreenAutoBrightness=" + newScreenAutoBrightness);
668639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
669639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
670639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mScreenAutoBrightness = newScreenAutoBrightness;
671639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (sendUpdate) {
672639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mCallbacks.updateBrightness();
673639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
674639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
675639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
676639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
677639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int clampScreenBrightness(int value) {
678639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return MathUtils.constrain(value,
679639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
680639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
681639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
682a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private void prepareBrightnessAdjustmentSample() {
683a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        if (!mBrightnessAdjustmentSamplePending) {
684a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSamplePending = true;
685a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSampleOldLux = mAmbientLuxValid ? mAmbientLux : -1;
686a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSampleOldBrightness = mScreenAutoBrightness;
687a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        } else {
688a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
689a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        }
690a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
691a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        mHandler.sendEmptyMessageDelayed(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE,
692a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS);
693a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    }
694a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
695a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private void cancelBrightnessAdjustmentSample() {
696a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        if (mBrightnessAdjustmentSamplePending) {
697a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSamplePending = false;
698a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE);
699a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        }
700a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    }
701a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
702a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    private void collectBrightnessAdjustmentSample() {
703a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        if (mBrightnessAdjustmentSamplePending) {
704a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            mBrightnessAdjustmentSamplePending = false;
705a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            if (mAmbientLuxValid && mScreenAutoBrightness >= 0) {
706a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                if (DEBUG) {
707c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                    Slog.d(TAG, "Auto-brightness adjustment changed by user: " +
70857d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                            "lux=" + mAmbientLux + ", " +
70957d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                            "brightness=" + mScreenAutoBrightness + ", " +
71057d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                            "ring=" + mAmbientLightRingBuffer);
711a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                }
712a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
713a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                EventLog.writeEvent(EventLogTags.AUTO_BRIGHTNESS_ADJ,
714a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mBrightnessAdjustmentSampleOldLux,
715a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mBrightnessAdjustmentSampleOldBrightness,
716a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                        mAmbientLux,
71757d6f11d6ab5d409f3291923ea34f9be709925bcDan Gittik                        mScreenAutoBrightness);
718a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            }
719a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown        }
720a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown    }
721a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
722639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final class AutomaticBrightnessHandler extends Handler {
723639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public AutomaticBrightnessHandler(Looper looper) {
724639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            super(looper, null, true /*async*/);
725639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
726639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
727639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
728639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void handleMessage(Message msg) {
729639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            switch (msg.what) {
730639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                case MSG_UPDATE_AMBIENT_LUX:
731639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    updateAmbientLux();
732639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    break;
733a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown
734a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                case MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE:
735a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                    collectBrightnessAdjustmentSample();
736a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                    break;
737d846023804ddadcd692666152db420c54594ddb9Michael Wright
738c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                case MSG_INVALIDATE_SHORT_TERM_MODEL:
739c5d3291487d4b6a09cbeac222831bb1b2203d957Dan Gittik                    invalidateShortTermModel();
740d846023804ddadcd692666152db420c54594ddb9Michael Wright                    break;
741639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
742639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
743639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
744639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
745639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final SensorEventListener mLightSensorListener = new SensorEventListener() {
746639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
747639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void onSensorChanged(SensorEvent event) {
748639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mLightSensorEnabled) {
749639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                final long time = SystemClock.uptimeMillis();
750639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                final float lux = event.values[0];
751639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                handleLightSensorEvent(time, lux);
752639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
753639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
754639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
755639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
756639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void onAccuracyChanged(Sensor sensor, int accuracy) {
757639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            // Not used.
758639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
759639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    };
760639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
761639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    /** Callbacks to request updates to the display's power state. */
762639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    interface Callbacks {
763639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        void updateBrightness();
764639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
765639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
7660a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright    /**
7670a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright     * A ring buffer of ambient light measurements sorted by time.
7680a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright     *
7690a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright     * Each entry consists of a timestamp and a lux measurement, and the overall buffer is sorted
7700a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright     * from oldest to newest.
7710a933141e2dd72bc868598cfa2146b2c72b85d5dMichael Wright     */
772103fb78ac1b91874f8b90cc5a165e6f0502179c4Michael Wright    private static final class AmbientLightRingBuffer {
773639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // Proportional extra capacity of the buffer beyond the expected number of light samples
774639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // in the horizon
775639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private static final float BUFFER_SLACK = 1.5f;
776639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private float[] mRingLux;
777639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private long[] mRingTime;
778639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mCapacity;
779639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
780639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // The first valid element and the next open slot.
781639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // Note that if mCount is zero then there are no valid elements.
782639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mStart;
783639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mEnd;
784639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mCount;
785639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
7866fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic        public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon) {
7876fc42f549a6a67fe48e6e8e368dc2b164030d7c3Zoran Jovanovic            mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate);
788639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingLux = new float[mCapacity];
789639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingTime = new long[mCapacity];
790639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
791639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
792639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public float getLux(int index) {
793639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return mRingLux[offsetOf(index)];
794639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
795639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
796639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public long getTime(int index) {
797639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return mRingTime[offsetOf(index)];
798639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
799639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
800639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void push(long time, float lux) {
801639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            int next = mEnd;
802639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mCount == mCapacity) {
803639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                int newSize = mCapacity * 2;
804639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
805639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                float[] newRingLux = new float[newSize];
806639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                long[] newRingTime = new long[newSize];
807639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                int length = mCapacity - mStart;
808639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                System.arraycopy(mRingLux, mStart, newRingLux, 0, length);
809639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                System.arraycopy(mRingTime, mStart, newRingTime, 0, length);
810639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (mStart != 0) {
811639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    System.arraycopy(mRingLux, 0, newRingLux, length, mStart);
812639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    System.arraycopy(mRingTime, 0, newRingTime, length, mStart);
813639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
814639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRingLux = newRingLux;
815639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRingTime = newRingTime;
816639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
817639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                next = mCapacity;
818639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mCapacity = newSize;
819639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mStart = 0;
820639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
821639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingTime[next] = time;
822639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingLux[next] = lux;
823639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mEnd = next + 1;
824639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mEnd == mCapacity) {
825639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mEnd = 0;
826639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
827639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mCount++;
828639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
829639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
830639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void prune(long horizon) {
831639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mCount == 0) {
832639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                return;
833639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
834639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
835639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            while (mCount > 1) {
836639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                int next = mStart + 1;
837639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (next >= mCapacity) {
838639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    next -= mCapacity;
839639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
840639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (mRingTime[next] > horizon) {
841639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // Some light sensors only produce data upon a change in the ambient light
842639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // levels, so we need to consider the previous measurement as the ambient light
843639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // level for all points in time up until we receive a new measurement. Thus, we
844639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // always want to keep the youngest element that would be removed from the
845639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // buffer and just set its measurement time to the horizon time since at that
846639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // point it is the ambient light level, and to remove it would be to drop a
847639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // valid data point within our horizon.
848639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    break;
849639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
850639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mStart = next;
851639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mCount -= 1;
852639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
853639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
854639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mRingTime[mStart] < horizon) {
855639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRingTime[mStart] = horizon;
856639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
857639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
858639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
859639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public int size() {
860639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return mCount;
861639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
862639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
863639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void clear() {
864639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mStart = 0;
865639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mEnd = 0;
866639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mCount = 0;
867639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
868639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
869639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
870639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public String toString() {
871a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            StringBuffer buf = new StringBuffer();
872a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            buf.append('[');
873a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            for (int i = 0; i < mCount; i++) {
874a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                final long next = i + 1 < mCount ? getTime(i + 1) : SystemClock.uptimeMillis();
875a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                if (i != 0) {
876a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                    buf.append(", ");
877a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                }
878a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                buf.append(getLux(i));
879a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                buf.append(" / ");
880a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                buf.append(next - getTime(i));
881a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown                buf.append("ms");
882639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
883a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            buf.append(']');
884a576b4d3be8687f0a65fc5777424955d551604e4Jeff Brown            return buf.toString();
885639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
886639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
887639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int offsetOf(int index) {
888639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (index >= mCount || index < 0) {
889639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                throw new ArrayIndexOutOfBoundsException(index);
890639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
891639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            index += mStart;
892639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (index >= mCapacity) {
893639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                index -= mCapacity;
894639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
895639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return index;
896639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
897639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
898639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright}
899