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