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