AutomaticBrightnessController.java revision d81ecd12cec5e1efa8ca49036bb023746f63d90a
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
19131206b8a9d07400d7c98aea50cc45c38769448fJeff Brownimport com.android.server.LocalServices;
20639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport com.android.server.twilight.TwilightListener;
21639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport com.android.server.twilight.TwilightManager;
22639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport com.android.server.twilight.TwilightState;
23639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
24639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.hardware.Sensor;
25639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.hardware.SensorEvent;
26639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.hardware.SensorEventListener;
27639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.hardware.SensorManager;
28639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.Handler;
29639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.Looper;
30639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.Message;
31639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.PowerManager;
32639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.os.SystemClock;
33639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.text.format.DateUtils;
34639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.util.MathUtils;
35639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.util.Spline;
36639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.util.Slog;
37639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport android.util.TimeUtils;
38639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
39639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport java.io.PrintWriter;
40639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightimport java.util.Arrays;
41639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
42639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wrightclass AutomaticBrightnessController {
43639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final String TAG = "AutomaticBrightnessController";
44639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
45639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final boolean DEBUG = false;
46639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
47639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
48639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // If true, enables the use of the screen auto-brightness adjustment setting.
49daf7d410fc97647f2b3ab4254f73c09c923018deAdrian Roos    private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT = true;
50639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
51639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The maximum range of gamma adjustment possible using the screen
52639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // auto-brightness adjustment setting.
53639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final float SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA = 3.0f;
54639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
55639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Period of time in which to consider light samples in milliseconds.
56639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final int AMBIENT_LIGHT_HORIZON = 10000;
57639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
58639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Hysteresis constraints for brightening or darkening.
59639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The recent lux must have changed by at least this fraction relative to the
60639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // current ambient lux before a change will be considered.
61639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final float BRIGHTENING_LIGHT_HYSTERESIS = 0.10f;
62639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final float DARKENING_LIGHT_HYSTERESIS = 0.20f;
63639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
64639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The intercept used for the weighting calculation. This is used in order to keep all possible
65639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // weighting values positive.
66639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final int WEIGHTING_INTERCEPT = AMBIENT_LIGHT_HORIZON;
67639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
68639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // How long the current sensor reading is assumed to be valid beyond the current time.
69639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // This provides a bit of prediction, as well as ensures that the weight for the last sample is
70639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // non-zero, which in turn ensures that the total weight is non-zero.
71639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final long AMBIENT_LIGHT_PREDICTION_TIME_MILLIS = 100;
72639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
73639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // If true, enables the use of the current time as an auto-brightness adjustment.
74639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The basic idea here is to expand the dynamic range of auto-brightness
75639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // when it is especially dark outside.  The light sensor tends to perform
76639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // poorly at low light levels so we compensate for it by making an
77639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // assumption about the environment.
78639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final boolean USE_TWILIGHT_ADJUSTMENT =
79639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            PowerManager.useTwilightAdjustmentFeature();
80639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
81639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Specifies the maximum magnitude of the time of day adjustment.
82639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final float TWILIGHT_ADJUSTMENT_MAX_GAMMA = 1.5f;
83639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
84639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The amount of time after or before sunrise over which to start adjusting
85639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // the gamma.  We want the change to happen gradually so that it is below the
86639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // threshold of perceptibility and so that the adjustment has maximum effect
87639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // well after dusk.
88639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final long TWILIGHT_ADJUSTMENT_TIME = DateUtils.HOUR_IN_MILLIS * 2;
89639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
90639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final int MSG_UPDATE_AMBIENT_LUX = 1;
91639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
92639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Callbacks for requesting updates to the the display's power state
93639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final Callbacks mCallbacks;
94639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
95639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The sensor manager.
96639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final SensorManager mSensorManager;
97639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
98639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The light sensor, or null if not available or needed.
99639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final Sensor mLightSensor;
100639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
101639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The twilight service.
102639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final TwilightManager mTwilight;
103639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
104639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The auto-brightness spline adjustment.
105639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The brightness values have been scaled to a range of 0..1.
106639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final Spline mScreenAutoBrightnessSpline;
107639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
108639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The minimum and maximum screen brightnesses.
109639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final int mScreenBrightnessRangeMinimum;
110639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final int mScreenBrightnessRangeMaximum;
111a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski    private final float mDozeScaleFactor;
112639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
113d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // Light sensor event rate in milliseconds.
114d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    private final int mLightSensorRate;
115d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski
116d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // Stability requirements in milliseconds for accepting a new brightness level.  This is used
117d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // for debouncing the light sensor.  Different constants are used to debounce the light sensor
118d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // when adapting to brighter or darker environments.  This parameter controls how quickly
119d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // brightness changes occur in response to an observed change in light level that exceeds the
120d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // hysteresis threshold.
121d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    private final long mBrighteningLightDebounceConfig;
122d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    private final long mDarkeningLightDebounceConfig;
123d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski
124d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // If true immediately after the screen is turned on the controller will try to adjust the
125d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // brightness based on the current sensor reads. If false, the controller will collect more data
126d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    // and only then decide whether to change brightness.
127d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski    private final boolean mResetAmbientLuxAfterWarmUpConfig;
128d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski
129639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Amount of time to delay auto-brightness after screen on while waiting for
130639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // the light sensor to warm-up in milliseconds.
131639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // May be 0 if no warm-up is required.
132639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int mLightSensorWarmUpTimeConfig;
133639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
134639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Set to true if the light sensor is enabled.
135639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean mLightSensorEnabled;
136639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
137639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The time when the light sensor was enabled.
138639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long mLightSensorEnableTime;
139639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
140639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The currently accepted nominal ambient light level.
141639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mAmbientLux;
142639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
143639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // True if mAmbientLux holds a valid value.
144639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean mAmbientLuxValid;
145639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
146639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The ambient light level threshold at which to brighten or darken the screen.
147639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mBrighteningLuxThreshold;
148639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mDarkeningLuxThreshold;
149639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
150639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The most recent light sample.
151639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mLastObservedLux;
152639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
153639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The time of the most light recent sample.
154639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long mLastObservedLuxTime;
155639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
156639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The number of light samples collected since the light sensor was enabled.
157639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int mRecentLightSamples;
158639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
159639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // A ring buffer containing all of the recent ambient light sensor readings.
160639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private AmbientLightRingBuffer mAmbientLightRingBuffer;
161639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
162639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The handler
163639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private AutomaticBrightnessHandler mHandler;
164639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
165639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The screen brightness level that has been chosen by the auto-brightness
166639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // algorithm.  The actual brightness should ramp towards this value.
167639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // We preserve this value even when we stop using the light sensor so
168639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // that we can quickly revert to the previous auto-brightness level
169639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // while the light sensor warms up.
170639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Use -1 if there is no current auto-brightness value available.
171639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int mScreenAutoBrightness = -1;
172639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
173639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The screen auto-brightness adjustment factor in the range -1 (dimmer) to 1 (brighter)
174639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mScreenAutoBrightnessAdjustment = 0.0f;
175639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
176639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // The last screen auto-brightness gamma.  (For printing in dump() only.)
177639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float mLastScreenAutoBrightnessGamma = 1.0f;
178639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
179a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski    // Are we going to adjust brightness while dozing.
180a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski    private boolean mDozing;
181a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski
182639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
183a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski            SensorManager sensorManager, Spline autoBrightnessSpline, int lightSensorWarmUpTime,
184d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski            int brightnessMin, int brightnessMax, float dozeScaleFactor,
185d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski            int lightSensorRate, long brighteningLightDebounceConfig,
186d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski            long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig) {
187639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mCallbacks = callbacks;
188131206b8a9d07400d7c98aea50cc45c38769448fJeff Brown        mTwilight = LocalServices.getService(TwilightManager.class);
189639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mSensorManager = sensorManager;
190639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mScreenAutoBrightnessSpline = autoBrightnessSpline;
191639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mScreenBrightnessRangeMinimum = brightnessMin;
192639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mScreenBrightnessRangeMaximum = brightnessMax;
193639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime;
194a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        mDozeScaleFactor = dozeScaleFactor;
195d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mLightSensorRate = lightSensorRate;
196d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mBrighteningLightDebounceConfig = brighteningLightDebounceConfig;
197d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mDarkeningLightDebounceConfig = darkeningLightDebounceConfig;
198d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig;
199639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
200639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mHandler = new AutomaticBrightnessHandler(looper);
201d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        mAmbientLightRingBuffer = new AmbientLightRingBuffer(mLightSensorRate);
202639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
203639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
204639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
205639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
206639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
207639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (USE_TWILIGHT_ADJUSTMENT) {
208639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mTwilight.registerListener(mTwilightListener, mHandler);
209639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
210639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
211639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
212639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    public int getAutomaticScreenBrightness() {
213a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        if (mDozing) {
214a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski            return (int) (mScreenAutoBrightness * mDozeScaleFactor);
215a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        }
216639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return mScreenAutoBrightness;
217639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
218639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
219a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski    public void configure(boolean enable, float adjustment, boolean dozing) {
220a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // While dozing, the application processor may be suspended which will prevent us from
221a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // receiving new information from the light sensor. On some devices, we may be able to
222a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // switch to a wake-up light sensor instead but for now we will simply disable the sensor
223a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // and hold onto the last computed screen auto brightness.  We save the dozing flag for
224a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        // debugging purposes.
225a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        mDozing = dozing;
226a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        boolean changed = setLightSensorEnabled(enable && !dozing);
227970d4132ea28e748c1010be39450a98bbf7466f3Jeff Brown        changed |= setScreenAutoBrightnessAdjustment(adjustment);
228970d4132ea28e748c1010be39450a98bbf7466f3Jeff Brown        if (changed) {
229639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            updateAutoBrightness(false /*sendUpdate*/);
230639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
231639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
232639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
233639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    public void dump(PrintWriter pw) {
234639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println();
235639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("Automatic Brightness Controller Configuration:");
236639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline);
237639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
238639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
239639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
240d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        pw.println("  mBrighteningLightDebounceConfig=" + mBrighteningLightDebounceConfig);
241d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        pw.println("  mDarkeningLightDebounceConfig=" + mDarkeningLightDebounceConfig);
242d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        pw.println("  mResetAmbientLuxAfterWarmUpConfig=" + mResetAmbientLuxAfterWarmUpConfig);
243639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
244639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println();
245639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("Automatic Brightness Controller State:");
246639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensor=" + mLightSensor);
247639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mTwilight.getCurrentState()=" + mTwilight.getCurrentState());
248639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensorEnabled=" + mLightSensorEnabled);
249639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLightSensorEnableTime=" + TimeUtils.formatUptime(mLightSensorEnableTime));
250639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mAmbientLux=" + mAmbientLux);
251639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mBrighteningLuxThreshold=" + mBrighteningLuxThreshold);
252639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mDarkeningLuxThreshold=" + mDarkeningLuxThreshold);
253639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLastObservedLux=" + mLastObservedLux);
254639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLastObservedLuxTime=" + TimeUtils.formatUptime(mLastObservedLuxTime));
255639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mRecentLightSamples=" + mRecentLightSamples);
256639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mAmbientLightRingBuffer=" + mAmbientLightRingBuffer);
257639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenAutoBrightness=" + mScreenAutoBrightness);
258639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mScreenAutoBrightnessAdjustment=" + mScreenAutoBrightnessAdjustment);
259639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        pw.println("  mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
260a15aa7d426972daecc0e8cd31dcf4d6bc656f1e9Filip Gruszczynski        pw.println("  mDozing=" + mDozing);
261639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
262639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
263639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean setLightSensorEnabled(boolean enable) {
264639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (enable) {
265639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (!mLightSensorEnabled) {
266639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorEnabled = true;
267639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorEnableTime = SystemClock.uptimeMillis();
268639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mSensorManager.registerListener(mLightSensorListener, mLightSensor,
269d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski                        mLightSensorRate * 1000, mHandler);
270639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                return true;
271639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
272639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        } else {
273639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mLightSensorEnabled) {
274639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorEnabled = false;
275d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski                mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
276639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRecentLightSamples = 0;
277639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mAmbientLightRingBuffer.clear();
278639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
279639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mSensorManager.unregisterListener(mLightSensorListener);
280639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
281639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
282639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return false;
283639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
284639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
285639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void handleLightSensorEvent(long time, float lux) {
286639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
287639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
288639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        applyLightSensorMeasurement(time, lux);
289639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        updateAmbientLux(time);
290639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
291639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
292639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void applyLightSensorMeasurement(long time, float lux) {
293639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mRecentLightSamples++;
294639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mAmbientLightRingBuffer.prune(time - AMBIENT_LIGHT_HORIZON);
295639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mAmbientLightRingBuffer.push(time, lux);
296639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
297639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // Remember this sample value.
298639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mLastObservedLux = lux;
299639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mLastObservedLuxTime = time;
300639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
301639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
302639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private boolean setScreenAutoBrightnessAdjustment(float adjustment) {
303639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (adjustment != mScreenAutoBrightnessAdjustment) {
304639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mScreenAutoBrightnessAdjustment = adjustment;
305639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return true;
306639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
307639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return false;
308639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
309639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
310639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void setAmbientLux(float lux) {
311639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mAmbientLux = lux;
312639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mBrighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
313639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mDarkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
314639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
315639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
316639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private float calculateAmbientLux(long now) {
317639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        final int N = mAmbientLightRingBuffer.size();
318639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (N == 0) {
319639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            Slog.e(TAG, "calculateAmbientLux: No ambient light readings available");
320639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return -1;
321639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
322639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float sum = 0;
323639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float totalWeight = 0;
324639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long endTime = AMBIENT_LIGHT_PREDICTION_TIME_MILLIS;
325639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        for (int i = N - 1; i >= 0; i--) {
326639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            long startTime = (mAmbientLightRingBuffer.getTime(i) - now);
327639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            float weight = calculateWeight(startTime, endTime);
328639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            float lux = mAmbientLightRingBuffer.getLux(i);
329639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
330639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "calculateAmbientLux: [" +
331639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        (startTime) + ", " +
332639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        (endTime) + "]: lux=" + lux + ", weight=" + weight);
333639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
334639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            totalWeight += weight;
335639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            sum += mAmbientLightRingBuffer.getLux(i) * weight;
336639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            endTime = startTime;
337639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
338639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (DEBUG) {
339639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            Slog.d(TAG, "calculateAmbientLux: totalWeight=" + totalWeight +
340639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    ", newAmbientLux=" + (sum / totalWeight));
341639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
342639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return sum / totalWeight;
343639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
344639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
345639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static float calculateWeight(long startDelta, long endDelta) {
346639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return weightIntegral(endDelta) - weightIntegral(startDelta);
347639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
348639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
349639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // Evaluates the integral of y = x + WEIGHTING_INTERCEPT. This is always positive for the
350639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    // horizon we're looking at and provides a non-linear weighting for light samples.
351639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static float weightIntegral(long x) {
352639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return x * (x * 0.5f + WEIGHTING_INTERCEPT);
353639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
354639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
355639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long nextAmbientLightBrighteningTransition(long time) {
356639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        final int N = mAmbientLightRingBuffer.size();
357639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long earliestValidTime = time;
358639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        for (int i = N - 1; i >= 0; i--) {
359639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mAmbientLightRingBuffer.getLux(i) <= mBrighteningLuxThreshold) {
360639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                break;
361639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
362639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            earliestValidTime = mAmbientLightRingBuffer.getTime(i);
363639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
364d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        return earliestValidTime + mBrighteningLightDebounceConfig;
365639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
366639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
367639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private long nextAmbientLightDarkeningTransition(long time) {
368639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        final int N = mAmbientLightRingBuffer.size();
369639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long earliestValidTime = time;
370639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        for (int i = N - 1; i >= 0; i--) {
371639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mAmbientLightRingBuffer.getLux(i) >= mDarkeningLuxThreshold) {
372639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                break;
373639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
374639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            earliestValidTime = mAmbientLightRingBuffer.getTime(i);
375639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
376d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        return earliestValidTime + mDarkeningLightDebounceConfig;
377639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
378639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
379639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void updateAmbientLux() {
380639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long time = SystemClock.uptimeMillis();
381639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mAmbientLightRingBuffer.prune(time - AMBIENT_LIGHT_HORIZON);
382639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        updateAmbientLux(time);
383639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
384639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
385639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void updateAmbientLux(long time) {
386639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // If the light sensor was just turned on then immediately update our initial
387639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // estimate of the current ambient light level.
388639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (!mAmbientLuxValid) {
389639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            final long timeWhenSensorWarmedUp =
390639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
391639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (time < timeWhenSensorWarmedUp) {
392639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (DEBUG) {
393639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    Slog.d(TAG, "updateAmbientLux: Sensor not  ready yet: "
394639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                            + "time=" + time
395639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                            + ", timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp);
396639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
397639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX,
398639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        timeWhenSensorWarmedUp);
399639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                return;
400639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
401639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            setAmbientLux(calculateAmbientLux(time));
402639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mAmbientLuxValid = true;
403639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
404639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "updateAmbientLux: Initializing: "
405639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer
406639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + ", mAmbientLux=" + mAmbientLux);
407639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
408639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            updateAutoBrightness(true);
409639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
410639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
411639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
412639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
413639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float ambientLux = calculateAmbientLux(time);
414639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
415639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (ambientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time
416639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                || ambientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) {
417639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            setAmbientLux(ambientLux);
418639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
419639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "updateAmbientLux: "
420639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + ((ambientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
421639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
422639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + ", mAmbientLightRingBuffer=" + mAmbientLightRingBuffer
423639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + ", mAmbientLux=" + mAmbientLux);
424639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
425639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            updateAutoBrightness(true);
426639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
427639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
428639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
429639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        long nextTransitionTime = Math.min(nextDarkenTransition, nextBrightenTransition);
430639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // If one of the transitions is ready to occur, but the total weighted ambient lux doesn't
431639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // exceed the necessary threshold, then it's possible we'll get a transition time prior to
432639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // now. Rather than continually checking to see whether the weighted lux exceeds the
433639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // threshold, schedule an update for when we'd normally expect another light sample, which
434639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // should be enough time to decide whether we should actually transition to the new
435639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // weighted ambient lux or not.
436639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        nextTransitionTime =
437d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski                nextTransitionTime > time ? nextTransitionTime : time + mLightSensorRate;
438639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (DEBUG) {
439639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for "
440639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    + nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
441639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
442639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);
443639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
444639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
445639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private void updateAutoBrightness(boolean sendUpdate) {
446639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (!mAmbientLuxValid) {
447639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return;
448639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
449639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
450639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);
451639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        float gamma = 1.0f;
452639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
453639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
454639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                && mScreenAutoBrightnessAdjustment != 0.0f) {
455639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            final float adjGamma = MathUtils.pow(SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA,
456639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    Math.min(1.0f, Math.max(-1.0f, -mScreenAutoBrightnessAdjustment)));
457639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            gamma *= adjGamma;
458639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
459639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma);
460639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
461639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
462639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
463639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (USE_TWILIGHT_ADJUSTMENT) {
464639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            TwilightState state = mTwilight.getCurrentState();
465639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (state != null && state.isNight()) {
466639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                final long now = System.currentTimeMillis();
467639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                final float earlyGamma =
468639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        getTwilightGamma(now, state.getYesterdaySunset(), state.getTodaySunrise());
469639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                final float lateGamma =
470639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        getTwilightGamma(now, state.getTodaySunset(), state.getTomorrowSunrise());
471639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                gamma *= earlyGamma * lateGamma;
472639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (DEBUG) {
473639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    Slog.d(TAG, "updateAutoBrightness: earlyGamma=" + earlyGamma
474639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                            + ", lateGamma=" + lateGamma);
475639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
476639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
477639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
478639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
479639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (gamma != 1.0f) {
480639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            final float in = value;
481639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            value = MathUtils.pow(value, gamma);
482639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
483639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma
484639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + ", in=" + in + ", out=" + value);
485639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
486639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
487639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
488639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        int newScreenAutoBrightness =
489639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));
490639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (mScreenAutoBrightness != newScreenAutoBrightness) {
491639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (DEBUG) {
492639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
493639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + mScreenAutoBrightness + ", newScreenAutoBrightness="
494639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                        + newScreenAutoBrightness);
495639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
496639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
497639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mScreenAutoBrightness = newScreenAutoBrightness;
498639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mLastScreenAutoBrightnessGamma = gamma;
499639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (sendUpdate) {
500639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mCallbacks.updateBrightness();
501639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
502639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
503639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
504639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
505639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private int clampScreenBrightness(int value) {
506639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return MathUtils.constrain(value,
507639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
508639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
509639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
510639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static float getTwilightGamma(long now, long lastSunset, long nextSunrise) {
511639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (lastSunset < 0 || nextSunrise < 0
512639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                || now < lastSunset || now > nextSunrise) {
513639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return 1.0f;
514639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
515639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
516639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (now < lastSunset + TWILIGHT_ADJUSTMENT_TIME) {
517639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return MathUtils.lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
518639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    (float)(now - lastSunset) / TWILIGHT_ADJUSTMENT_TIME);
519639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
520639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
521639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        if (now > nextSunrise - TWILIGHT_ADJUSTMENT_TIME) {
522639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return MathUtils.lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
523639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    (float)(nextSunrise - now) / TWILIGHT_ADJUSTMENT_TIME);
524639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
525639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
526639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        return TWILIGHT_ADJUSTMENT_MAX_GAMMA;
527639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
528639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
529639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final class AutomaticBrightnessHandler extends Handler {
530639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public AutomaticBrightnessHandler(Looper looper) {
531639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            super(looper, null, true /*async*/);
532639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
533639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
534639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
535639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void handleMessage(Message msg) {
536639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            switch (msg.what) {
537639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                case MSG_UPDATE_AMBIENT_LUX:
538639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    updateAmbientLux();
539639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    break;
540639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
541639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
542639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
543639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
544639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final SensorEventListener mLightSensorListener = new SensorEventListener() {
545639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
546639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void onSensorChanged(SensorEvent event) {
547639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mLightSensorEnabled) {
548639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                final long time = SystemClock.uptimeMillis();
549639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                final float lux = event.values[0];
550639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                handleLightSensorEvent(time, lux);
551639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
552639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
553639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
554639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
555639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void onAccuracyChanged(Sensor sensor, int accuracy) {
556639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            // Not used.
557639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
558639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    };
559639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
560639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private final TwilightListener mTwilightListener = new TwilightListener() {
561639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
562639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void onTwilightStateChanged() {
563639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            updateAutoBrightness(true /*sendUpdate*/);
564639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
565639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    };
566639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
567639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    /** Callbacks to request updates to the display's power state. */
568639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    interface Callbacks {
569639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        void updateBrightness();
570639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
571639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
572639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    private static final class AmbientLightRingBuffer{
573639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // Proportional extra capacity of the buffer beyond the expected number of light samples
574639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // in the horizon
575639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private static final float BUFFER_SLACK = 1.5f;
576639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private float[] mRingLux;
577639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private long[] mRingTime;
578639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mCapacity;
579639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
580639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // The first valid element and the next open slot.
581639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        // Note that if mCount is zero then there are no valid elements.
582639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mStart;
583639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mEnd;
584639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int mCount;
585639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
586d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski        public AmbientLightRingBuffer(long lightSensorRate) {
587d81ecd12cec5e1efa8ca49036bb023746f63d90aFilip Gruszczynski            this((int) Math.ceil(AMBIENT_LIGHT_HORIZON * BUFFER_SLACK / lightSensorRate));
588639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
589639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
590639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public AmbientLightRingBuffer(int initialCapacity) {
591639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mCapacity = initialCapacity;
592639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingLux = new float[mCapacity];
593639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingTime = new long[mCapacity];
594639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
595639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
596639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public float getLux(int index) {
597639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return mRingLux[offsetOf(index)];
598639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
599639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
600639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public long getTime(int index) {
601639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return mRingTime[offsetOf(index)];
602639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
603639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
604639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void push(long time, float lux) {
605639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            int next = mEnd;
606639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mCount == mCapacity) {
607639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                int newSize = mCapacity * 2;
608639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
609639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                float[] newRingLux = new float[newSize];
610639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                long[] newRingTime = new long[newSize];
611639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                int length = mCapacity - mStart;
612639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                System.arraycopy(mRingLux, mStart, newRingLux, 0, length);
613639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                System.arraycopy(mRingTime, mStart, newRingTime, 0, length);
614639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (mStart != 0) {
615639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    System.arraycopy(mRingLux, 0, newRingLux, length, mStart);
616639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    System.arraycopy(mRingTime, 0, newRingTime, length, mStart);
617639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
618639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRingLux = newRingLux;
619639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRingTime = newRingTime;
620639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
621639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                next = mCapacity;
622639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mCapacity = newSize;
623639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mStart = 0;
624639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
625639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingTime[next] = time;
626639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mRingLux[next] = lux;
627639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mEnd = next + 1;
628639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mEnd == mCapacity) {
629639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mEnd = 0;
630639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
631639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mCount++;
632639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
633639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
634639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void prune(long horizon) {
635639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mCount == 0) {
636639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                return;
637639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
638639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
639639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            while (mCount > 1) {
640639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                int next = mStart + 1;
641639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (next >= mCapacity) {
642639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    next -= mCapacity;
643639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
644639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                if (mRingTime[next] > horizon) {
645639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // Some light sensors only produce data upon a change in the ambient light
646639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // levels, so we need to consider the previous measurement as the ambient light
647639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // level for all points in time up until we receive a new measurement. Thus, we
648639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // always want to keep the youngest element that would be removed from the
649639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // buffer and just set its measurement time to the horizon time since at that
650639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // point it is the ambient light level, and to remove it would be to drop a
651639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    // valid data point within our horizon.
652639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                    break;
653639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                }
654639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mStart = next;
655639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mCount -= 1;
656639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
657639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
658639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mRingTime[mStart] < horizon) {
659639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                mRingTime[mStart] = horizon;
660639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
661639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
662639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
663639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public int size() {
664639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return mCount;
665639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
666639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
667639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public boolean isEmpty() {
668639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return mCount == 0;
669639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
670639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
671639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public void clear() {
672639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mStart = 0;
673639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mEnd = 0;
674639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            mCount = 0;
675639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
676639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
677639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        @Override
678639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        public String toString() {
679639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            final int length = mCapacity - mStart;
680639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            float[] lux = new float[mCount];
681639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            long[] time = new long[mCount];
682639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
683639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (mCount <= length) {
684639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                System.arraycopy(mRingLux, mStart, lux, 0, mCount);
685639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                System.arraycopy(mRingTime, mStart, time, 0, mCount);
686639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            } else {
687639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                System.arraycopy(mRingLux, mStart, lux, 0, length);
688639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                System.arraycopy(mRingLux, 0, lux, length, mCount - length);
689639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
690639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                System.arraycopy(mRingTime, mStart, time, 0, length);
691639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                System.arraycopy(mRingTime, 0, time, length, mCount - length);
692639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
693639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return "AmbientLightRingBuffer{mCapacity=" + mCapacity
694639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                + ", mStart=" + mStart
695639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                + ", mEnd=" + mEnd
696639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                + ", mCount=" + mCount
697639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                + ", mRingLux=" + Arrays.toString(lux)
698639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                + ", mRingTime=" + Arrays.toString(time)
699639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                + "}";
700639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
701639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright
702639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        private int offsetOf(int index) {
703639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (index >= mCount || index < 0) {
704639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                throw new ArrayIndexOutOfBoundsException(index);
705639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
706639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            index += mStart;
707639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            if (index >= mCapacity) {
708639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright                index -= mCapacity;
709639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            }
710639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright            return index;
711639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright        }
712639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright    }
713639c8becc6d0efe9c205f3abf1e9347464a95020Michael Wright}
714