1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.display; 18 19 import static com.android.server.display.BrightnessMappingStrategy.INVALID_LUX; 20 import static com.android.server.display.config.DisplayBrightnessMappingConfig.autoBrightnessModeToString; 21 22 import android.annotation.IntDef; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.app.ActivityTaskManager; 26 import android.app.ActivityTaskManager.RootTaskInfo; 27 import android.app.IActivityTaskManager; 28 import android.app.TaskStackListener; 29 import android.content.Context; 30 import android.content.pm.ApplicationInfo; 31 import android.content.pm.PackageManager; 32 import android.hardware.Sensor; 33 import android.hardware.SensorEvent; 34 import android.hardware.SensorEventListener; 35 import android.hardware.SensorManager; 36 import android.hardware.display.BrightnessConfiguration; 37 import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; 38 import android.os.Handler; 39 import android.os.Looper; 40 import android.os.Message; 41 import android.os.PowerManager; 42 import android.os.RemoteException; 43 import android.os.SystemClock; 44 import android.os.Trace; 45 import android.util.EventLog; 46 import android.util.MathUtils; 47 import android.util.Slog; 48 import android.util.SparseArray; 49 import android.util.TimeUtils; 50 import android.view.Display; 51 52 import com.android.internal.annotations.VisibleForTesting; 53 import com.android.internal.display.BrightnessSynchronizer; 54 import com.android.internal.os.BackgroundThread; 55 import com.android.server.EventLogTags; 56 import com.android.server.display.brightness.BrightnessEvent; 57 import com.android.server.display.config.HysteresisLevels; 58 import com.android.server.display.feature.DisplayManagerFlags; 59 60 import java.io.PrintWriter; 61 import java.lang.annotation.Retention; 62 import java.lang.annotation.RetentionPolicy; 63 import java.util.concurrent.TimeUnit; 64 65 /** 66 * Manages the associated display brightness when in auto-brightness mode. This is also 67 * responsible for managing the brightness lux-nits mapping strategies. Internally also listens to 68 * the LightSensor and adjusts the system brightness in case of changes in the surrounding lux. 69 */ 70 public class AutomaticBrightnessController { 71 private static final String TAG = "AutomaticBrightnessController"; 72 73 private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false; 74 75 public static final int AUTO_BRIGHTNESS_ENABLED = 1; 76 public static final int AUTO_BRIGHTNESS_DISABLED = 2; 77 public static final int AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE = 3; 78 79 @IntDef(prefix = { "AUTO_BRIGHTNESS_MODE_" }, value = { 80 AUTO_BRIGHTNESS_MODE_DEFAULT, 81 AUTO_BRIGHTNESS_MODE_IDLE, 82 AUTO_BRIGHTNESS_MODE_DOZE 83 }) 84 @Retention(RetentionPolicy.SOURCE) 85 public @interface AutomaticBrightnessMode{} 86 87 public static final int AUTO_BRIGHTNESS_MODE_DEFAULT = 0; 88 public static final int AUTO_BRIGHTNESS_MODE_IDLE = 1; 89 public static final int AUTO_BRIGHTNESS_MODE_DOZE = 2; 90 public static final int AUTO_BRIGHTNESS_MODE_MAX = AUTO_BRIGHTNESS_MODE_DOZE; 91 92 // How long the current sensor reading is assumed to be valid beyond the current time. 93 // This provides a bit of prediction, as well as ensures that the weight for the last sample is 94 // non-zero, which in turn ensures that the total weight is non-zero. 95 private static final long AMBIENT_LIGHT_PREDICTION_TIME_MILLIS = 100; 96 97 // Debounce for sampling user-initiated changes in display brightness to ensure 98 // the user is satisfied with the result before storing the sample. 99 private static final int BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS = 10000; 100 101 private static final int MSG_UPDATE_AMBIENT_LUX = 1; 102 private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2; 103 private static final int MSG_INVALIDATE_CURRENT_SHORT_TERM_MODEL = 3; 104 private static final int MSG_UPDATE_FOREGROUND_APP = 4; 105 private static final int MSG_UPDATE_FOREGROUND_APP_SYNC = 5; 106 private static final int MSG_RUN_UPDATE = 6; 107 private static final int MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL = 7; 108 109 // Callbacks for requesting updates to the display's power state 110 private final Callbacks mCallbacks; 111 112 // The sensor manager. 113 private final SensorManager mSensorManager; 114 115 // The light sensor, or null if not available or needed. 116 private final Sensor mLightSensor; 117 118 // The mapper to translate ambient lux to screen brightness in the range [0, 1.0]. 119 @NonNull 120 private BrightnessMappingStrategy mCurrentBrightnessMapper; 121 122 // A map of Brightness Mapping Strategies indexed by AutomaticBrightnessMode 123 private final SparseArray<BrightnessMappingStrategy> mBrightnessMappingStrategyMap; 124 125 // The minimum and maximum screen brightnesses. 126 private final float mScreenBrightnessRangeMinimum; 127 private final float mScreenBrightnessRangeMaximum; 128 129 // How much to scale doze brightness by (should be (0, 1.0]). 130 private final float mDozeScaleFactor; 131 132 // Initial light sensor event rate in milliseconds. 133 private final int mInitialLightSensorRate; 134 135 // Steady-state light sensor event rate in milliseconds. 136 private final int mNormalLightSensorRate; 137 138 // The current light sensor event rate in milliseconds. 139 private int mCurrentLightSensorRate; 140 141 // Stability requirements in milliseconds for accepting a new brightness level. This is used 142 // for debouncing the light sensor. Different constants are used to debounce the light sensor 143 // when adapting to brighter or darker environments. This parameter controls how quickly 144 // brightness changes occur in response to an observed change in light level that exceeds the 145 // hysteresis threshold. 146 private final long mBrighteningLightDebounceConfig; 147 private final long mDarkeningLightDebounceConfig; 148 private final long mBrighteningLightDebounceConfigIdle; 149 private final long mDarkeningLightDebounceConfigIdle; 150 151 // If true immediately after the screen is turned on the controller will try to adjust the 152 // brightness based on the current sensor reads. If false, the controller will collect more data 153 // and only then decide whether to change brightness. 154 private final boolean mResetAmbientLuxAfterWarmUpConfig; 155 156 // Period of time in which to consider light samples for a short/long-term estimate of ambient 157 // light in milliseconds. 158 private final int mAmbientLightHorizonLong; 159 private final int mAmbientLightHorizonShort; 160 161 // The intercept used for the weighting calculation. This is used in order to keep all possible 162 // weighting values positive. 163 private final int mWeightingIntercept; 164 165 // Configuration object for determining thresholds to change brightness dynamically 166 private final HysteresisLevels mAmbientBrightnessThresholds; 167 private final HysteresisLevels mScreenBrightnessThresholds; 168 private final HysteresisLevels mAmbientBrightnessThresholdsIdle; 169 private final HysteresisLevels mScreenBrightnessThresholdsIdle; 170 171 private boolean mLoggingEnabled; 172 173 // Amount of time to delay auto-brightness after screen on while waiting for 174 // the light sensor to warm-up in milliseconds. 175 // May be 0 if no warm-up is required. 176 private int mLightSensorWarmUpTimeConfig; 177 178 // Set to true if the light sensor is enabled. 179 private boolean mLightSensorEnabled; 180 181 // The time when the light sensor was enabled. 182 private long mLightSensorEnableTime; 183 184 // The currently accepted nominal ambient light level. 185 private float mAmbientLux = INVALID_LUX; 186 187 // The last calculated ambient light level (long time window). 188 private float mSlowAmbientLux; 189 190 // The last calculated ambient light level (short time window). 191 private float mFastAmbientLux; 192 193 // The last ambient lux value prior to passing the darkening or brightening threshold. 194 private float mPreThresholdLux; 195 196 // True if mAmbientLux holds a valid value. 197 private boolean mAmbientLuxValid; 198 199 // The ambient light level threshold at which to brighten or darken the screen. 200 private float mAmbientBrighteningThreshold; 201 private float mAmbientDarkeningThreshold; 202 203 // The last brightness value prior to passing the darkening or brightening threshold. 204 private float mPreThresholdBrightness; 205 206 // The screen brightness threshold at which to brighten or darken the screen. 207 private float mScreenBrighteningThreshold; 208 private float mScreenDarkeningThreshold; 209 // The most recent light sample. 210 private float mLastObservedLux; 211 212 // The time of the most light recent sample. 213 private long mLastObservedLuxTime; 214 215 // The number of light samples collected since the light sensor was enabled. 216 private int mRecentLightSamples; 217 218 // A ring buffer containing all of the recent ambient light sensor readings. 219 private AmbientLightRingBuffer mAmbientLightRingBuffer; 220 221 // The handler 222 private AutomaticBrightnessHandler mHandler; 223 224 // The screen brightness level that has been chosen by the auto-brightness 225 // algorithm. The actual brightness should ramp towards this value. 226 // We preserve this value even when we stop using the light sensor so 227 // that we can quickly revert to the previous auto-brightness level 228 // while the light sensor warms up. 229 // Use PowerManager.BRIGHTNESS_INVALID_FLOAT if there is no current auto-brightness value 230 // available. 231 private float mScreenAutoBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; 232 233 // The screen brightness level before clamping and throttling. This value needs to be stored 234 // for concurrent displays mode and passed to the additional displays which will do their own 235 // clamping and throttling. 236 private float mRawScreenAutoBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; 237 238 // The current display policy. This is useful, for example, for knowing when we're dozing, 239 // where the light sensor may not be available. 240 private int mDisplayPolicy = DisplayPowerRequest.POLICY_OFF; 241 242 private int mDisplayState = Display.STATE_UNKNOWN; 243 244 // True if we are collecting a brightness adjustment sample, along with some data 245 // for the initial state of the sample. 246 private boolean mBrightnessAdjustmentSamplePending; 247 private float mBrightnessAdjustmentSampleOldLux; 248 private float mBrightnessAdjustmentSampleOldBrightness; 249 250 // The short term models, current and previous. Eg, we might use the "paused" one to save out 251 // the interactive short term model when switching to idle screen brightness mode, and 252 // vice-versa. 253 private final ShortTermModel mShortTermModel; 254 private final ShortTermModel mPausedShortTermModel; 255 256 // Controls Brightness range (including High Brightness Mode). 257 private final BrightnessRangeController mBrightnessRangeController; 258 259 // Throttles (caps) maximum allowed brightness 260 private final BrightnessThrottler mBrightnessThrottler; 261 private boolean mIsBrightnessThrottled; 262 263 // Context-sensitive brightness configurations require keeping track of the foreground app's 264 // package name and category, which is done by registering a TaskStackListener to call back to 265 // us onTaskStackChanged, and then using the ActivityTaskManager to get the foreground app's 266 // package name and PackageManager to get its category (so might as well cache them). 267 private String mForegroundAppPackageName; 268 private String mPendingForegroundAppPackageName; 269 private @ApplicationInfo.Category int mForegroundAppCategory; 270 private @ApplicationInfo.Category int mPendingForegroundAppCategory; 271 private TaskStackListenerImpl mTaskStackListener; 272 private IActivityTaskManager mActivityTaskManager; 273 private PackageManager mPackageManager; 274 private Context mContext; 275 private int mState = AUTO_BRIGHTNESS_DISABLED; 276 277 private Clock mClock; 278 private final Injector mInjector; 279 280 private final DisplayManagerFlags mDisplayManagerFlags; 281 AutomaticBrightnessController(Callbacks callbacks, Looper looper, SensorManager sensorManager, Sensor lightSensor, SparseArray<BrightnessMappingStrategy> brightnessMappingStrategyMap, int lightSensorWarmUpTime, float brightnessMin, float brightnessMax, float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig, long darkeningLightDebounceConfig, long brighteningLightDebounceConfigIdle, long darkeningLightDebounceConfigIdle, boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds, HysteresisLevels screenBrightnessThresholds, HysteresisLevels ambientBrightnessThresholdsIdle, HysteresisLevels screenBrightnessThresholdsIdle, Context context, BrightnessRangeController brightnessModeController, BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort, int ambientLightHorizonLong, float userLux, float userNits, DisplayManagerFlags displayManagerFlags)282 AutomaticBrightnessController(Callbacks callbacks, Looper looper, 283 SensorManager sensorManager, Sensor lightSensor, 284 SparseArray<BrightnessMappingStrategy> brightnessMappingStrategyMap, 285 int lightSensorWarmUpTime, float brightnessMin, float brightnessMax, 286 float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate, 287 long brighteningLightDebounceConfig, long darkeningLightDebounceConfig, 288 long brighteningLightDebounceConfigIdle, long darkeningLightDebounceConfigIdle, 289 boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds, 290 HysteresisLevels screenBrightnessThresholds, 291 HysteresisLevels ambientBrightnessThresholdsIdle, 292 HysteresisLevels screenBrightnessThresholdsIdle, Context context, 293 BrightnessRangeController brightnessModeController, 294 BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort, 295 int ambientLightHorizonLong, float userLux, float userNits, 296 DisplayManagerFlags displayManagerFlags) { 297 this(new Injector(), callbacks, looper, sensorManager, lightSensor, 298 brightnessMappingStrategyMap, lightSensorWarmUpTime, brightnessMin, brightnessMax, 299 dozeScaleFactor, lightSensorRate, initialLightSensorRate, 300 brighteningLightDebounceConfig, darkeningLightDebounceConfig, 301 brighteningLightDebounceConfigIdle, darkeningLightDebounceConfigIdle, 302 resetAmbientLuxAfterWarmUpConfig, ambientBrightnessThresholds, 303 screenBrightnessThresholds, ambientBrightnessThresholdsIdle, 304 screenBrightnessThresholdsIdle, context, brightnessModeController, 305 brightnessThrottler, ambientLightHorizonShort, ambientLightHorizonLong, userLux, 306 userNits, displayManagerFlags 307 ); 308 } 309 310 @VisibleForTesting AutomaticBrightnessController(Injector injector, Callbacks callbacks, Looper looper, SensorManager sensorManager, Sensor lightSensor, SparseArray<BrightnessMappingStrategy> brightnessMappingStrategyMap, int lightSensorWarmUpTime, float brightnessMin, float brightnessMax, float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig, long darkeningLightDebounceConfig, long brighteningLightDebounceConfigIdle, long darkeningLightDebounceConfigIdle, boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds, HysteresisLevels screenBrightnessThresholds, HysteresisLevels ambientBrightnessThresholdsIdle, HysteresisLevels screenBrightnessThresholdsIdle, Context context, BrightnessRangeController brightnessRangeController, BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort, int ambientLightHorizonLong, float userLux, float userNits, DisplayManagerFlags displayManagerFlags)311 AutomaticBrightnessController(Injector injector, Callbacks callbacks, Looper looper, 312 SensorManager sensorManager, Sensor lightSensor, 313 SparseArray<BrightnessMappingStrategy> brightnessMappingStrategyMap, 314 int lightSensorWarmUpTime, float brightnessMin, float brightnessMax, 315 float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate, 316 long brighteningLightDebounceConfig, long darkeningLightDebounceConfig, 317 long brighteningLightDebounceConfigIdle, long darkeningLightDebounceConfigIdle, 318 boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds, 319 HysteresisLevels screenBrightnessThresholds, 320 HysteresisLevels ambientBrightnessThresholdsIdle, 321 HysteresisLevels screenBrightnessThresholdsIdle, Context context, 322 BrightnessRangeController brightnessRangeController, 323 BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort, 324 int ambientLightHorizonLong, float userLux, float userNits, 325 DisplayManagerFlags displayManagerFlags) { 326 mInjector = injector; 327 mClock = injector.createClock(displayManagerFlags.offloadControlsDozeAutoBrightness()); 328 mContext = context; 329 mCallbacks = callbacks; 330 mSensorManager = sensorManager; 331 mCurrentBrightnessMapper = brightnessMappingStrategyMap.get(AUTO_BRIGHTNESS_MODE_DEFAULT); 332 mScreenBrightnessRangeMinimum = brightnessMin; 333 mScreenBrightnessRangeMaximum = brightnessMax; 334 mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime; 335 mDozeScaleFactor = dozeScaleFactor; 336 mNormalLightSensorRate = lightSensorRate; 337 mInitialLightSensorRate = initialLightSensorRate; 338 mCurrentLightSensorRate = -1; 339 mBrighteningLightDebounceConfig = brighteningLightDebounceConfig; 340 mDarkeningLightDebounceConfig = darkeningLightDebounceConfig; 341 mBrighteningLightDebounceConfigIdle = brighteningLightDebounceConfigIdle; 342 mDarkeningLightDebounceConfigIdle = darkeningLightDebounceConfigIdle; 343 mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig; 344 mAmbientLightHorizonLong = ambientLightHorizonLong; 345 mAmbientLightHorizonShort = ambientLightHorizonShort; 346 mWeightingIntercept = ambientLightHorizonLong; 347 mAmbientBrightnessThresholds = ambientBrightnessThresholds; 348 mAmbientBrightnessThresholdsIdle = ambientBrightnessThresholdsIdle; 349 mScreenBrightnessThresholds = screenBrightnessThresholds; 350 mScreenBrightnessThresholdsIdle = screenBrightnessThresholdsIdle; 351 mShortTermModel = new ShortTermModel(); 352 mPausedShortTermModel = new ShortTermModel(); 353 mHandler = new AutomaticBrightnessHandler(looper); 354 mAmbientLightRingBuffer = 355 new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizonLong, mClock); 356 357 if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) { 358 mLightSensor = lightSensor; 359 } 360 361 mActivityTaskManager = ActivityTaskManager.getService(); 362 mPackageManager = mContext.getPackageManager(); 363 mTaskStackListener = new TaskStackListenerImpl(); 364 mForegroundAppPackageName = null; 365 mPendingForegroundAppPackageName = null; 366 mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED; 367 mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED; 368 mBrightnessRangeController = brightnessRangeController; 369 mBrightnessThrottler = brightnessThrottler; 370 mBrightnessMappingStrategyMap = brightnessMappingStrategyMap; 371 mDisplayManagerFlags = displayManagerFlags; 372 373 // Use the given short-term model 374 if (userNits != BrightnessMappingStrategy.INVALID_NITS) { 375 setScreenBrightnessByUser(userLux, getBrightnessFromNits(userNits)); 376 } 377 } 378 379 /** 380 * Enable/disable logging. 381 * 382 * @param loggingEnabled 383 * Whether logging should be on/off. 384 * 385 * @return Whether the method succeeded or not. 386 */ setLoggingEnabled(boolean loggingEnabled)387 public boolean setLoggingEnabled(boolean loggingEnabled) { 388 if (mLoggingEnabled == loggingEnabled) { 389 return false; 390 } 391 for (int i = 0; i < mBrightnessMappingStrategyMap.size(); i++) { 392 mBrightnessMappingStrategyMap.valueAt(i).setLoggingEnabled(loggingEnabled); 393 } 394 mLoggingEnabled = loggingEnabled; 395 return true; 396 } 397 getAutomaticScreenBrightness()398 public float getAutomaticScreenBrightness() { 399 return getAutomaticScreenBrightness(null); 400 } 401 402 /** 403 * @param brightnessEvent Holds details about how the brightness is calculated. 404 * 405 * @return The current automatic brightness recommended value. Populates brightnessEvent 406 * parameters with details about how the brightness was calculated. 407 */ getAutomaticScreenBrightness(BrightnessEvent brightnessEvent)408 public float getAutomaticScreenBrightness(BrightnessEvent brightnessEvent) { 409 if (brightnessEvent != null) { 410 brightnessEvent.setLux( 411 mAmbientLuxValid ? mAmbientLux : PowerManager.BRIGHTNESS_INVALID_FLOAT); 412 brightnessEvent.setPreThresholdLux(mPreThresholdLux); 413 brightnessEvent.setPreThresholdBrightness(mPreThresholdBrightness); 414 brightnessEvent.setRecommendedBrightness(mScreenAutoBrightness); 415 brightnessEvent.setFlags(brightnessEvent.getFlags() 416 | (!mAmbientLuxValid ? BrightnessEvent.FLAG_INVALID_LUX : 0) 417 | (shouldApplyDozeScaleFactor() ? BrightnessEvent.FLAG_DOZE_SCALE : 0)); 418 brightnessEvent.setAutoBrightnessMode(getMode()); 419 } 420 421 if (!mAmbientLuxValid) { 422 return PowerManager.BRIGHTNESS_INVALID_FLOAT; 423 } 424 if (shouldApplyDozeScaleFactor()) { 425 return mScreenAutoBrightness * mDozeScaleFactor; 426 } 427 return mScreenAutoBrightness; 428 } 429 getRawAutomaticScreenBrightness()430 public float getRawAutomaticScreenBrightness() { 431 return mRawScreenAutoBrightness; 432 } 433 hasValidAmbientLux()434 public boolean hasValidAmbientLux() { 435 return mAmbientLuxValid; 436 } 437 getAutomaticScreenBrightnessAdjustment()438 public float getAutomaticScreenBrightnessAdjustment() { 439 return mCurrentBrightnessMapper.getAutoBrightnessAdjustment(); 440 } 441 configure(int state, @Nullable BrightnessConfiguration configuration, float brightness, boolean userChangedBrightness, float adjustment, boolean userChangedAutoBrightnessAdjustment, int displayPolicy, int displayState, boolean shouldResetShortTermModel)442 public void configure(int state, @Nullable BrightnessConfiguration configuration, 443 float brightness, boolean userChangedBrightness, float adjustment, 444 boolean userChangedAutoBrightnessAdjustment, int displayPolicy, int displayState, 445 boolean shouldResetShortTermModel) { 446 mState = state; 447 boolean changed = setBrightnessConfiguration(configuration, shouldResetShortTermModel); 448 changed |= setDisplayPolicy(displayPolicy); 449 mDisplayState = displayState; 450 if (userChangedAutoBrightnessAdjustment) { 451 changed |= setAutoBrightnessAdjustment(adjustment); 452 } 453 final boolean enable = mState == AUTO_BRIGHTNESS_ENABLED; 454 if (userChangedBrightness && enable) { 455 // Update the brightness curve with the new user control point. It's critical this 456 // happens after we update the autobrightness adjustment since it may reset it. 457 changed |= setScreenBrightnessByUser(brightness); 458 } 459 final boolean userInitiatedChange = 460 userChangedBrightness || userChangedAutoBrightnessAdjustment; 461 if (userInitiatedChange && enable) { 462 prepareBrightnessAdjustmentSample(); 463 } 464 changed |= setLightSensorEnabled(enable); 465 466 if (mIsBrightnessThrottled != mBrightnessThrottler.isThrottled()) { 467 // Maximum brightness has changed, so recalculate display brightness. 468 mIsBrightnessThrottled = mBrightnessThrottler.isThrottled(); 469 changed = true; 470 } 471 472 if (changed) { 473 updateAutoBrightness(false /*sendUpdate*/, userInitiatedChange); 474 } 475 } 476 stop()477 public void stop() { 478 setLightSensorEnabled(false); 479 } 480 hasUserDataPoints()481 public boolean hasUserDataPoints() { 482 return mCurrentBrightnessMapper.hasUserDataPoints(); 483 } 484 485 // Used internally to establish whether we have deviated from the default config. isDefaultConfig()486 public boolean isDefaultConfig() { 487 return mCurrentBrightnessMapper.getMode() == AUTO_BRIGHTNESS_MODE_DEFAULT 488 && mCurrentBrightnessMapper.isDefaultConfig(); 489 } 490 491 // Called from APIs to get the configuration. getDefaultConfig()492 public BrightnessConfiguration getDefaultConfig() { 493 return mBrightnessMappingStrategyMap.get(AUTO_BRIGHTNESS_MODE_DEFAULT).getDefaultConfig(); 494 } 495 496 /** 497 * Force recalculate of the state of automatic brightness. 498 */ update()499 public void update() { 500 mHandler.sendEmptyMessage(MSG_RUN_UPDATE); 501 } 502 getAmbientLux()503 float getAmbientLux() { 504 return mAmbientLux; 505 } 506 getSlowAmbientLux()507 float getSlowAmbientLux() { 508 return mSlowAmbientLux; 509 } 510 getFastAmbientLux()511 float getFastAmbientLux() { 512 return mFastAmbientLux; 513 } 514 setDisplayPolicy(int policy)515 private boolean setDisplayPolicy(int policy) { 516 if (mDisplayPolicy == policy) { 517 return false; 518 } 519 final int oldPolicy = mDisplayPolicy; 520 mDisplayPolicy = policy; 521 if (mLoggingEnabled) { 522 Slog.d(TAG, "Display policy transitioning from " + oldPolicy + " to " + policy); 523 } 524 if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy) && !isInIdleMode()) { 525 mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_CURRENT_SHORT_TERM_MODEL, 526 mCurrentBrightnessMapper.getShortTermModelTimeout()); 527 } else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) { 528 mHandler.removeMessages(MSG_INVALIDATE_CURRENT_SHORT_TERM_MODEL); 529 } 530 return true; 531 } 532 isInteractivePolicy(int policy)533 private static boolean isInteractivePolicy(int policy) { 534 return policy == DisplayPowerRequest.POLICY_BRIGHT 535 || policy == DisplayPowerRequest.POLICY_DIM; 536 } 537 setScreenBrightnessByUser(float brightness)538 private boolean setScreenBrightnessByUser(float brightness) { 539 if (!mAmbientLuxValid) { 540 // If we don't have a valid ambient lux then we don't have a valid brightness anyway, 541 // and we can't use this data to add a new control point to the short-term model. 542 return false; 543 } 544 return setScreenBrightnessByUser(mAmbientLux, brightness); 545 } 546 setScreenBrightnessByUser(float lux, float brightness)547 private boolean setScreenBrightnessByUser(float lux, float brightness) { 548 if (lux == INVALID_LUX || Float.isNaN(brightness)) { 549 return false; 550 } 551 mCurrentBrightnessMapper.addUserDataPoint(lux, brightness); 552 mShortTermModel.setUserBrightness(lux, brightness); 553 return true; 554 } 555 resetShortTermModel()556 public void resetShortTermModel() { 557 mCurrentBrightnessMapper.clearUserDataPoints(); 558 mShortTermModel.reset(); 559 } 560 setBrightnessConfiguration(BrightnessConfiguration configuration, boolean shouldResetShortTermModel)561 public boolean setBrightnessConfiguration(BrightnessConfiguration configuration, 562 boolean shouldResetShortTermModel) { 563 if (mBrightnessMappingStrategyMap.get(AUTO_BRIGHTNESS_MODE_DEFAULT) 564 .setBrightnessConfiguration(configuration)) { 565 if (!isInIdleMode() && shouldResetShortTermModel) { 566 resetShortTermModel(); 567 } 568 return true; 569 } 570 return false; 571 } 572 573 /** 574 * @return The auto-brightness mode of the current mapping strategy. Different modes use 575 * different brightness curves. 576 */ 577 @AutomaticBrightnessController.AutomaticBrightnessMode getMode()578 public int getMode() { 579 return mCurrentBrightnessMapper.getMode(); 580 } 581 isInIdleMode()582 public boolean isInIdleMode() { 583 return mCurrentBrightnessMapper.getMode() == AUTO_BRIGHTNESS_MODE_IDLE; 584 } 585 dump(PrintWriter pw)586 public void dump(PrintWriter pw) { 587 pw.println(); 588 pw.println("Automatic Brightness Controller Configuration:"); 589 pw.println(" mState=" + configStateToString(mState)); 590 pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum); 591 pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum); 592 pw.println(" mDozeScaleFactor=" + mDozeScaleFactor); 593 pw.println(" mInitialLightSensorRate=" + mInitialLightSensorRate); 594 pw.println(" mNormalLightSensorRate=" + mNormalLightSensorRate); 595 pw.println(" mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig); 596 pw.println(" mBrighteningLightDebounceConfig=" + mBrighteningLightDebounceConfig); 597 pw.println(" mDarkeningLightDebounceConfig=" + mDarkeningLightDebounceConfig); 598 pw.println(" mBrighteningLightDebounceConfigIdle=" + mBrighteningLightDebounceConfigIdle); 599 pw.println(" mDarkeningLightDebounceConfigIdle=" + mDarkeningLightDebounceConfigIdle); 600 pw.println(" mResetAmbientLuxAfterWarmUpConfig=" + mResetAmbientLuxAfterWarmUpConfig); 601 pw.println(" mAmbientLightHorizonLong=" + mAmbientLightHorizonLong); 602 pw.println(" mAmbientLightHorizonShort=" + mAmbientLightHorizonShort); 603 pw.println(" mWeightingIntercept=" + mWeightingIntercept); 604 605 pw.println(); 606 pw.println("Automatic Brightness Controller State:"); 607 pw.println(" mLightSensor=" + mLightSensor); 608 pw.println(" mLightSensorEnabled=" + mLightSensorEnabled); 609 pw.println(" mLightSensorEnableTime=" + TimeUtils.formatUptime(mLightSensorEnableTime)); 610 pw.println(" mCurrentLightSensorRate=" + mCurrentLightSensorRate); 611 pw.println(" mAmbientLux=" + mAmbientLux); 612 pw.println(" mAmbientLuxValid=" + mAmbientLuxValid); 613 pw.println(" mPreThresholdLux=" + mPreThresholdLux); 614 pw.println(" mPreThresholdBrightness=" + mPreThresholdBrightness); 615 pw.println(" mAmbientBrighteningThreshold=" + mAmbientBrighteningThreshold); 616 pw.println(" mAmbientDarkeningThreshold=" + mAmbientDarkeningThreshold); 617 pw.println(" mScreenBrighteningThreshold=" + mScreenBrighteningThreshold); 618 pw.println(" mScreenDarkeningThreshold=" + mScreenDarkeningThreshold); 619 pw.println(" mLastObservedLux=" + mLastObservedLux); 620 pw.println(" mLastObservedLuxTime=" + TimeUtils.formatUptime(mLastObservedLuxTime)); 621 pw.println(" mRecentLightSamples=" + mRecentLightSamples); 622 pw.println(" mAmbientLightRingBuffer=" + mAmbientLightRingBuffer); 623 pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness); 624 pw.println(" mDisplayPolicy=" + DisplayPowerRequest.policyToString(mDisplayPolicy)); 625 pw.println(" mShortTermModel="); 626 mShortTermModel.dump(pw); 627 pw.println(" mPausedShortTermModel="); 628 mPausedShortTermModel.dump(pw); 629 630 pw.println(); 631 pw.println(" mBrightnessAdjustmentSamplePending=" + mBrightnessAdjustmentSamplePending); 632 pw.println(" mBrightnessAdjustmentSampleOldLux=" + mBrightnessAdjustmentSampleOldLux); 633 pw.println(" mBrightnessAdjustmentSampleOldBrightness=" 634 + mBrightnessAdjustmentSampleOldBrightness); 635 pw.println(" mForegroundAppPackageName=" + mForegroundAppPackageName); 636 pw.println(" mPendingForegroundAppPackageName=" + mPendingForegroundAppPackageName); 637 pw.println(" mForegroundAppCategory=" + mForegroundAppCategory); 638 pw.println(" mPendingForegroundAppCategory=" + mPendingForegroundAppCategory); 639 pw.println(" Current mode=" 640 + autoBrightnessModeToString(mCurrentBrightnessMapper.getMode())); 641 642 for (int i = 0; i < mBrightnessMappingStrategyMap.size(); i++) { 643 pw.println(); 644 pw.println(" Mapper for mode " 645 + autoBrightnessModeToString(mBrightnessMappingStrategyMap.keyAt(i)) + ":"); 646 mBrightnessMappingStrategyMap.valueAt(i).dump(pw, 647 mBrightnessRangeController.getNormalBrightnessMax()); 648 } 649 650 pw.println(); 651 pw.println(" mAmbientBrightnessThresholds=" + mAmbientBrightnessThresholds); 652 pw.println(" mAmbientBrightnessThresholdsIdle=" + mAmbientBrightnessThresholdsIdle); 653 pw.println(" mScreenBrightnessThresholds=" + mScreenBrightnessThresholds); 654 pw.println(" mScreenBrightnessThresholdsIdle=" + mScreenBrightnessThresholdsIdle); 655 } 656 getLastSensorValues()657 public float[] getLastSensorValues() { 658 return mAmbientLightRingBuffer.getAllLuxValues(); 659 } 660 getLastSensorTimestamps()661 public long[] getLastSensorTimestamps() { 662 return mAmbientLightRingBuffer.getAllTimestamps(); 663 } 664 configStateToString(int state)665 private String configStateToString(int state) { 666 switch (state) { 667 case AUTO_BRIGHTNESS_ENABLED: 668 return "AUTO_BRIGHTNESS_ENABLED"; 669 case AUTO_BRIGHTNESS_DISABLED: 670 return "AUTO_BRIGHTNESS_DISABLED"; 671 case AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE: 672 return "AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE"; 673 default: 674 return String.valueOf(state); 675 } 676 } 677 setLightSensorEnabled(boolean enable)678 private boolean setLightSensorEnabled(boolean enable) { 679 if (enable) { 680 if (!mLightSensorEnabled) { 681 mLightSensorEnabled = true; 682 mLightSensorEnableTime = mClock.uptimeMillis(); 683 mCurrentLightSensorRate = mInitialLightSensorRate; 684 registerForegroundAppUpdater(); 685 mSensorManager.registerListener(mLightSensorListener, mLightSensor, 686 mCurrentLightSensorRate * 1000, mHandler); 687 return true; 688 } 689 } else if (mLightSensorEnabled) { 690 mLightSensorEnabled = false; 691 mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig; 692 if (!mAmbientLuxValid) { 693 mPreThresholdLux = PowerManager.BRIGHTNESS_INVALID_FLOAT; 694 } 695 mScreenAutoBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; 696 mRawScreenAutoBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; 697 mPreThresholdBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; 698 mRecentLightSamples = 0; 699 mAmbientLightRingBuffer.clear(); 700 mCurrentLightSensorRate = -1; 701 mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX); 702 unregisterForegroundAppUpdater(); 703 mSensorManager.unregisterListener(mLightSensorListener); 704 } 705 return false; 706 } 707 handleLightSensorEvent(long time, float lux)708 private void handleLightSensorEvent(long time, float lux) { 709 Trace.traceCounter(Trace.TRACE_TAG_POWER, "ALS", (int) lux); 710 mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX); 711 712 if (mAmbientLightRingBuffer.size() == 0) { 713 // switch to using the steady-state sample rate after grabbing the initial light sample 714 adjustLightSensorRate(mNormalLightSensorRate); 715 } 716 applyLightSensorMeasurement(time, lux); 717 updateAmbientLux(time); 718 } 719 applyLightSensorMeasurement(long time, float lux)720 private void applyLightSensorMeasurement(long time, float lux) { 721 mRecentLightSamples++; 722 mAmbientLightRingBuffer.prune(time - mAmbientLightHorizonLong); 723 mAmbientLightRingBuffer.push(time, lux); 724 // Remember this sample value. 725 mLastObservedLux = lux; 726 mLastObservedLuxTime = time; 727 } 728 adjustLightSensorRate(int lightSensorRate)729 private void adjustLightSensorRate(int lightSensorRate) { 730 // if the light sensor rate changed, update the sensor listener 731 if (lightSensorRate != mCurrentLightSensorRate) { 732 if (mLoggingEnabled) { 733 Slog.d(TAG, "adjustLightSensorRate: " + 734 "previousRate=" + mCurrentLightSensorRate + ", " + 735 "currentRate=" + lightSensorRate); 736 } 737 mCurrentLightSensorRate = lightSensorRate; 738 mSensorManager.unregisterListener(mLightSensorListener); 739 mSensorManager.registerListener(mLightSensorListener, mLightSensor, 740 lightSensorRate * 1000, mHandler); 741 } 742 } 743 setAutoBrightnessAdjustment(float adjustment)744 private boolean setAutoBrightnessAdjustment(float adjustment) { 745 return mCurrentBrightnessMapper.setAutoBrightnessAdjustment(adjustment); 746 } 747 setAmbientLux(float lux)748 private void setAmbientLux(float lux) { 749 if (mLoggingEnabled) { 750 Slog.d(TAG, "setAmbientLux(" + lux + ")"); 751 } 752 if (lux < 0) { 753 Slog.w(TAG, "Ambient lux was negative, ignoring and setting to 0"); 754 lux = 0; 755 } 756 mAmbientLux = lux; 757 if (isInIdleMode()) { 758 mAmbientBrighteningThreshold = 759 mAmbientBrightnessThresholdsIdle.getBrighteningThreshold(lux); 760 mAmbientDarkeningThreshold = 761 mAmbientBrightnessThresholdsIdle.getDarkeningThreshold(lux); 762 } else { 763 mAmbientBrighteningThreshold = 764 mAmbientBrightnessThresholds.getBrighteningThreshold(lux); 765 mAmbientDarkeningThreshold = 766 mAmbientBrightnessThresholds.getDarkeningThreshold(lux); 767 } 768 mBrightnessRangeController.onAmbientLuxChange(mAmbientLux); 769 770 // If the short term model was invalidated and the change is drastic enough, reset it. 771 mShortTermModel.maybeReset(mAmbientLux); 772 } 773 calculateAmbientLux(long now, long horizon)774 private float calculateAmbientLux(long now, long horizon) { 775 if (mLoggingEnabled) { 776 Slog.d(TAG, "calculateAmbientLux(" + now + ", " + horizon + ")"); 777 } 778 final int N = mAmbientLightRingBuffer.size(); 779 if (N == 0) { 780 Slog.e(TAG, "calculateAmbientLux: No ambient light readings available"); 781 return -1; 782 } 783 784 // Find the first measurement that is just outside of the horizon. 785 int endIndex = 0; 786 final long horizonStartTime = now - horizon; 787 for (int i = 0; i < N-1; i++) { 788 if (mAmbientLightRingBuffer.getTime(i + 1) <= horizonStartTime) { 789 endIndex++; 790 } else { 791 break; 792 } 793 } 794 if (mLoggingEnabled) { 795 Slog.d(TAG, "calculateAmbientLux: selected endIndex=" + endIndex + ", point=(" + 796 mAmbientLightRingBuffer.getTime(endIndex) + ", " + 797 mAmbientLightRingBuffer.getLux(endIndex) + ")"); 798 } 799 float sum = 0; 800 float totalWeight = 0; 801 long endTime = AMBIENT_LIGHT_PREDICTION_TIME_MILLIS; 802 for (int i = N - 1; i >= endIndex; i--) { 803 long eventTime = mAmbientLightRingBuffer.getTime(i); 804 if (i == endIndex && eventTime < horizonStartTime) { 805 // If we're at the final value, make sure we only consider the part of the sample 806 // within our desired horizon. 807 eventTime = horizonStartTime; 808 } 809 final long startTime = eventTime - now; 810 float weight = calculateWeight(startTime, endTime); 811 float lux = mAmbientLightRingBuffer.getLux(i); 812 if (mLoggingEnabled) { 813 Slog.d(TAG, "calculateAmbientLux: [" + startTime + ", " + endTime + "]: " + 814 "lux=" + lux + ", " + 815 "weight=" + weight); 816 } 817 totalWeight += weight; 818 sum += lux * weight; 819 endTime = startTime; 820 } 821 if (mLoggingEnabled) { 822 Slog.d(TAG, "calculateAmbientLux: " + 823 "totalWeight=" + totalWeight + ", " + 824 "newAmbientLux=" + (sum / totalWeight)); 825 } 826 return sum / totalWeight; 827 } 828 calculateWeight(long startDelta, long endDelta)829 private float calculateWeight(long startDelta, long endDelta) { 830 return weightIntegral(endDelta) - weightIntegral(startDelta); 831 } 832 833 // Evaluates the integral of y = x + mWeightingIntercept. This is always positive for the 834 // horizon we're looking at and provides a non-linear weighting for light samples. weightIntegral(long x)835 private float weightIntegral(long x) { 836 return x * (x * 0.5f + mWeightingIntercept); 837 } 838 nextAmbientLightBrighteningTransition(long time)839 private long nextAmbientLightBrighteningTransition(long time) { 840 final int N = mAmbientLightRingBuffer.size(); 841 long earliestValidTime = time; 842 for (int i = N - 1; i >= 0; i--) { 843 if (mAmbientLightRingBuffer.getLux(i) <= mAmbientBrighteningThreshold) { 844 break; 845 } 846 earliestValidTime = mAmbientLightRingBuffer.getTime(i); 847 } 848 return earliestValidTime + (isInIdleMode() 849 ? mBrighteningLightDebounceConfigIdle : mBrighteningLightDebounceConfig); 850 } 851 nextAmbientLightDarkeningTransition(long time)852 private long nextAmbientLightDarkeningTransition(long time) { 853 final int N = mAmbientLightRingBuffer.size(); 854 long earliestValidTime = time; 855 for (int i = N - 1; i >= 0; i--) { 856 if (mAmbientLightRingBuffer.getLux(i) >= mAmbientDarkeningThreshold) { 857 break; 858 } 859 earliestValidTime = mAmbientLightRingBuffer.getTime(i); 860 } 861 return earliestValidTime + (isInIdleMode() 862 ? mDarkeningLightDebounceConfigIdle : mDarkeningLightDebounceConfig); 863 } 864 updateAmbientLux()865 private void updateAmbientLux() { 866 long time = mClock.getSensorEventScaleTime(); 867 mAmbientLightRingBuffer.prune(time - mAmbientLightHorizonLong); 868 updateAmbientLux(time); 869 } 870 updateAmbientLux(long time)871 private void updateAmbientLux(long time) { 872 // If the light sensor was just turned on then immediately update our initial 873 // estimate of the current ambient light level. 874 if (!mAmbientLuxValid) { 875 final long timeWhenSensorWarmedUp = 876 mLightSensorWarmUpTimeConfig + mLightSensorEnableTime; 877 if (time < timeWhenSensorWarmedUp) { 878 if (mLoggingEnabled) { 879 Slog.d(TAG, "updateAmbientLux: Sensor not ready yet: " 880 + "time=" + time + ", " 881 + "timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp); 882 } 883 mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, 884 timeWhenSensorWarmedUp); 885 return; 886 } 887 setAmbientLux(calculateAmbientLux(time, mAmbientLightHorizonShort)); 888 mAmbientLuxValid = true; 889 if (mLoggingEnabled) { 890 Slog.d(TAG, "updateAmbientLux: Initializing: " + 891 "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", " + 892 "mAmbientLux=" + mAmbientLux); 893 } 894 updateAutoBrightness(true /* sendUpdate */, false /* isManuallySet */); 895 } 896 897 long nextBrightenTransition = nextAmbientLightBrighteningTransition(time); 898 long nextDarkenTransition = nextAmbientLightDarkeningTransition(time); 899 // Essentially, we calculate both a slow ambient lux, to ensure there's a true long-term 900 // change in lighting conditions, and a fast ambient lux to determine what the new 901 // brightness situation is since the slow lux can be quite slow to converge. 902 // 903 // Note that both values need to be checked for sufficient change before updating the 904 // proposed ambient light value since the slow value might be sufficiently far enough away 905 // from the fast value to cause a recalculation while its actually just converging on 906 // the fast value still. 907 mSlowAmbientLux = calculateAmbientLux(time, mAmbientLightHorizonLong); 908 mFastAmbientLux = calculateAmbientLux(time, mAmbientLightHorizonShort); 909 910 if ((mSlowAmbientLux >= mAmbientBrighteningThreshold 911 && mFastAmbientLux >= mAmbientBrighteningThreshold 912 && nextBrightenTransition <= time) 913 || (mSlowAmbientLux <= mAmbientDarkeningThreshold 914 && mFastAmbientLux <= mAmbientDarkeningThreshold 915 && nextDarkenTransition <= time)) { 916 mPreThresholdLux = mAmbientLux; 917 setAmbientLux(mFastAmbientLux); 918 if (mLoggingEnabled) { 919 Slog.d(TAG, "updateAmbientLux: " 920 + ((mFastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": " 921 + "mAmbientBrighteningThreshold=" + mAmbientBrighteningThreshold + ", " 922 + "mAmbientDarkeningThreshold=" + mAmbientDarkeningThreshold + ", " 923 + "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", " 924 + "mAmbientLux=" + mAmbientLux); 925 } 926 updateAutoBrightness(true /* sendUpdate */, false /* isManuallySet */); 927 nextBrightenTransition = nextAmbientLightBrighteningTransition(time); 928 nextDarkenTransition = nextAmbientLightDarkeningTransition(time); 929 } 930 long nextTransitionTime = Math.min(nextDarkenTransition, nextBrightenTransition); 931 // If one of the transitions is ready to occur, but the total weighted ambient lux doesn't 932 // exceed the necessary threshold, then it's possible we'll get a transition time prior to 933 // now. Rather than continually checking to see whether the weighted lux exceeds the 934 // threshold, schedule an update for when we'd normally expect another light sample, which 935 // should be enough time to decide whether we should actually transition to the new 936 // weighted ambient lux or not. 937 nextTransitionTime = 938 nextTransitionTime > time ? nextTransitionTime : time + mNormalLightSensorRate; 939 if (mLoggingEnabled) { 940 Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for " + 941 nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime)); 942 } 943 944 // The nextTransitionTime is computed as elapsedTime(Which also accounts for the time when 945 // android was sleeping) as the main reference. However, handlers work on the uptime(Not 946 // accounting for the time when android was sleeping) 947 mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, 948 convertToUptime(nextTransitionTime)); 949 } 950 convertToUptime(long time)951 private long convertToUptime(long time) { 952 return time - mClock.getSensorEventScaleTime() + mClock.uptimeMillis(); 953 } 954 updateAutoBrightness(boolean sendUpdate, boolean isManuallySet)955 private void updateAutoBrightness(boolean sendUpdate, boolean isManuallySet) { 956 if (!mAmbientLuxValid) { 957 return; 958 } 959 960 float value = mCurrentBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName, 961 mForegroundAppCategory); 962 mRawScreenAutoBrightness = value; 963 float newScreenAutoBrightness = clampScreenBrightness(value); 964 965 // The min/max range can change for brightness due to HBM. See if the current brightness 966 // value still falls within the current range (which could have changed). 967 final boolean currentBrightnessWithinAllowedRange = BrightnessSynchronizer.floatEquals( 968 mScreenAutoBrightness, clampScreenBrightness(mScreenAutoBrightness)); 969 // If screenAutoBrightness is set, we should have screen{Brightening,Darkening}Threshold, 970 // in which case we ignore the new screen brightness if it doesn't differ enough from the 971 // previous one. 972 boolean withinThreshold = !Float.isNaN(mScreenAutoBrightness) 973 && newScreenAutoBrightness > mScreenDarkeningThreshold 974 && newScreenAutoBrightness < mScreenBrighteningThreshold; 975 976 if (withinThreshold && !isManuallySet && currentBrightnessWithinAllowedRange) { 977 if (mLoggingEnabled) { 978 Slog.d(TAG, "ignoring newScreenAutoBrightness: " 979 + mScreenDarkeningThreshold + " < " + newScreenAutoBrightness 980 + " < " + mScreenBrighteningThreshold); 981 } 982 return; 983 } 984 if (!BrightnessSynchronizer.floatEquals(mScreenAutoBrightness, 985 newScreenAutoBrightness)) { 986 if (mLoggingEnabled) { 987 Slog.d(TAG, "updateAutoBrightness: " 988 + "mScreenAutoBrightness=" + mScreenAutoBrightness + ", " 989 + "newScreenAutoBrightness=" + newScreenAutoBrightness); 990 } 991 if (!withinThreshold) { 992 mPreThresholdBrightness = mScreenAutoBrightness; 993 } 994 mScreenAutoBrightness = newScreenAutoBrightness; 995 if (isInIdleMode()) { 996 mScreenBrighteningThreshold = clampScreenBrightness( 997 mScreenBrightnessThresholdsIdle.getBrighteningThreshold( 998 newScreenAutoBrightness)); 999 mScreenDarkeningThreshold = clampScreenBrightness( 1000 mScreenBrightnessThresholdsIdle.getDarkeningThreshold( 1001 newScreenAutoBrightness)); 1002 } else { 1003 mScreenBrighteningThreshold = clampScreenBrightness( 1004 mScreenBrightnessThresholds.getBrighteningThreshold( 1005 newScreenAutoBrightness)); 1006 mScreenDarkeningThreshold = clampScreenBrightness( 1007 mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness)); 1008 } 1009 1010 if (sendUpdate) { 1011 mCallbacks.updateBrightness(); 1012 } 1013 } 1014 } 1015 1016 // Clamps values with float range [0.0-1.0] 1017 private float clampScreenBrightness(float value) { 1018 final float minBrightness = Math.min(mBrightnessRangeController.getCurrentBrightnessMin(), 1019 mBrightnessThrottler.getBrightnessCap()); 1020 final float maxBrightness = Math.min(mBrightnessRangeController.getCurrentBrightnessMax(), 1021 mBrightnessThrottler.getBrightnessCap()); 1022 return MathUtils.constrain(value, minBrightness, maxBrightness); 1023 } 1024 1025 private void prepareBrightnessAdjustmentSample() { 1026 if (!mBrightnessAdjustmentSamplePending) { 1027 mBrightnessAdjustmentSamplePending = true; 1028 mBrightnessAdjustmentSampleOldLux = mAmbientLuxValid ? mAmbientLux : -1; 1029 mBrightnessAdjustmentSampleOldBrightness = mScreenAutoBrightness; 1030 } else { 1031 mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE); 1032 } 1033 1034 mHandler.sendEmptyMessageDelayed(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE, 1035 BRIGHTNESS_ADJUSTMENT_SAMPLE_DEBOUNCE_MILLIS); 1036 } 1037 1038 private void cancelBrightnessAdjustmentSample() { 1039 if (mBrightnessAdjustmentSamplePending) { 1040 mBrightnessAdjustmentSamplePending = false; 1041 mHandler.removeMessages(MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE); 1042 } 1043 } 1044 1045 private void collectBrightnessAdjustmentSample() { 1046 if (mBrightnessAdjustmentSamplePending) { 1047 mBrightnessAdjustmentSamplePending = false; 1048 if (mAmbientLuxValid && (mScreenAutoBrightness >= PowerManager.BRIGHTNESS_MIN 1049 || mScreenAutoBrightness == PowerManager.BRIGHTNESS_OFF_FLOAT)) { 1050 if (mLoggingEnabled) { 1051 Slog.d(TAG, "Auto-brightness adjustment changed by user: " 1052 + "lux=" + mAmbientLux + ", " 1053 + "brightness=" + mScreenAutoBrightness + ", " 1054 + "ring=" + mAmbientLightRingBuffer); 1055 } 1056 1057 EventLog.writeEvent(EventLogTags.AUTO_BRIGHTNESS_ADJ, 1058 mBrightnessAdjustmentSampleOldLux, 1059 mBrightnessAdjustmentSampleOldBrightness, 1060 mAmbientLux, 1061 mScreenAutoBrightness); 1062 } 1063 } 1064 } 1065 1066 // Register a TaskStackListener to call back to us onTaskStackChanged, so we can update the 1067 // foreground app's package name and category and correct the brightness accordingly. 1068 private void registerForegroundAppUpdater() { 1069 try { 1070 mActivityTaskManager.registerTaskStackListener(mTaskStackListener); 1071 // This will not get called until the foreground app changes for the first time, so 1072 // call it explicitly to get the current foreground app's info. 1073 updateForegroundApp(); 1074 } catch (RemoteException e) { 1075 if (mLoggingEnabled) { 1076 Slog.e(TAG, "Failed to register foreground app updater: " + e); 1077 } 1078 // Nothing to do. 1079 } 1080 } 1081 1082 private void unregisterForegroundAppUpdater() { 1083 try { 1084 mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); 1085 } catch (RemoteException e) { 1086 // Nothing to do. 1087 } 1088 mForegroundAppPackageName = null; 1089 mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED; 1090 } 1091 1092 // Set the foreground app's package name and category, so brightness can be corrected per app. 1093 private void updateForegroundApp() { 1094 if (mLoggingEnabled) { 1095 Slog.d(TAG, "Attempting to update foreground app"); 1096 } 1097 // The ActivityTaskManager's lock tends to get contended, so this is done in a background 1098 // thread and applied via this thread's handler synchronously. 1099 mInjector.getBackgroundThreadHandler().post(new Runnable() { 1100 public void run() { 1101 try { 1102 // The foreground app is the top activity of the focused tasks stack. 1103 final RootTaskInfo info = mActivityTaskManager.getFocusedRootTaskInfo(); 1104 if (info == null || info.topActivity == null) { 1105 return; 1106 } 1107 final String packageName = info.topActivity.getPackageName(); 1108 // If the app didn't change, there's nothing to do. Otherwise, we have to 1109 // update the category and re-apply the brightness correction. 1110 String currentForegroundAppPackageName = mForegroundAppPackageName; 1111 if (currentForegroundAppPackageName != null 1112 && currentForegroundAppPackageName.equals(packageName)) { 1113 return; 1114 } 1115 mPendingForegroundAppPackageName = packageName; 1116 mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED; 1117 try { 1118 ApplicationInfo app = mPackageManager.getApplicationInfo(packageName, 1119 PackageManager.MATCH_ANY_USER); 1120 mPendingForegroundAppCategory = app.category; 1121 } catch (PackageManager.NameNotFoundException e) { 1122 // Nothing to do 1123 } 1124 mHandler.sendEmptyMessage(MSG_UPDATE_FOREGROUND_APP_SYNC); 1125 } catch (RemoteException e) { 1126 // Nothing to do 1127 } 1128 } 1129 }); 1130 } 1131 1132 private void updateForegroundAppSync() { 1133 if (mLoggingEnabled) { 1134 Slog.d(TAG, "Updating foreground app: packageName=" + mPendingForegroundAppPackageName 1135 + ", category=" + mPendingForegroundAppCategory); 1136 } 1137 mForegroundAppPackageName = mPendingForegroundAppPackageName; 1138 mPendingForegroundAppPackageName = null; 1139 mForegroundAppCategory = mPendingForegroundAppCategory; 1140 mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED; 1141 updateAutoBrightness(true /* sendUpdate */, false /* isManuallySet */); 1142 } 1143 1144 private void switchModeAndShortTermModels(@AutomaticBrightnessMode int mode) { 1145 // Stash short term model 1146 ShortTermModel tempShortTermModel = new ShortTermModel(); 1147 tempShortTermModel.set(mCurrentBrightnessMapper.getUserLux(), 1148 mCurrentBrightnessMapper.getUserBrightness(), /* valid= */ true); 1149 mHandler.removeMessages(MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL); 1150 // Send delayed timeout 1151 mHandler.sendEmptyMessageAtTime(MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL, 1152 mClock.uptimeMillis() 1153 + mCurrentBrightnessMapper.getShortTermModelTimeout()); 1154 1155 Slog.i(TAG, "mPreviousShortTermModel: " + mPausedShortTermModel); 1156 // new brightness mapper 1157 mCurrentBrightnessMapper = mBrightnessMappingStrategyMap.get(mode); 1158 1159 // if previous stm has been invalidated, and lux has drastically changed, just use 1160 // the new, reset stm. 1161 // if previous stm is still valid then revalidate it 1162 if (mPausedShortTermModel != null) { 1163 if (!mPausedShortTermModel.maybeReset(mAmbientLux)) { 1164 setScreenBrightnessByUser(mPausedShortTermModel.mAnchor, 1165 mPausedShortTermModel.mBrightness); 1166 } 1167 mPausedShortTermModel.copyFrom(tempShortTermModel); 1168 } 1169 } 1170 1171 /** 1172 * Responsible for switching the AutomaticBrightnessMode of the associated display. Also takes 1173 * care of resetting the short term model wherever required 1174 */ 1175 public void switchMode(@AutomaticBrightnessMode int mode, boolean sendUpdate) { 1176 if (!mBrightnessMappingStrategyMap.contains(mode)) { 1177 return; 1178 } 1179 if (mCurrentBrightnessMapper.getMode() == mode) { 1180 return; 1181 } 1182 Slog.i(TAG, "Switching to mode " + autoBrightnessModeToString(mode)); 1183 if (mode == AUTO_BRIGHTNESS_MODE_IDLE 1184 || mCurrentBrightnessMapper.getMode() == AUTO_BRIGHTNESS_MODE_IDLE) { 1185 switchModeAndShortTermModels(mode); 1186 } else { 1187 resetShortTermModel(); 1188 mCurrentBrightnessMapper = mBrightnessMappingStrategyMap.get(mode); 1189 } 1190 if (sendUpdate) { 1191 update(); 1192 } else { 1193 updateAutoBrightness(/* sendUpdate= */ false, /* isManuallySet= */ false); 1194 } 1195 } 1196 1197 float getUserLux() { 1198 return mCurrentBrightnessMapper.getUserLux(); 1199 } 1200 1201 float getUserNits() { 1202 return convertToNits(mCurrentBrightnessMapper.getUserBrightness()); 1203 } 1204 1205 /** 1206 * Convert a brightness float scale value to a nit value. Adjustments, such as RBC, are not 1207 * applied. This is used when storing the brightness in nits for the default display and when 1208 * passing the brightness value to follower displays. 1209 * 1210 * @param brightness The float scale value 1211 * @return The nit value or {@link BrightnessMappingStrategy.INVALID_NITS} if no conversion is 1212 * possible. 1213 */ 1214 public float convertToNits(float brightness) { 1215 return mCurrentBrightnessMapper.convertToNits(brightness); 1216 } 1217 1218 /** 1219 * Convert a brightness float scale value to a nit value. Adjustments, such as RBC are applied. 1220 * This is used when sending the brightness value to 1221 * {@link com.android.server.display.BrightnessTracker}. 1222 * 1223 * @param brightness The float scale value 1224 * @return The nit value or {@link BrightnessMappingStrategy.INVALID_NITS} if no conversion is 1225 * possible. 1226 */ 1227 public float convertToAdjustedNits(float brightness) { 1228 return mCurrentBrightnessMapper.convertToAdjustedNits(brightness); 1229 } 1230 1231 /** 1232 * Convert a brightness nit value to a float scale value. It is assumed that the nit value 1233 * provided does not have adjustments, such as RBC, applied. 1234 * 1235 * @param nits The nit value 1236 * @return The float scale value or {@link PowerManager.BRIGHTNESS_INVALID_FLOAT} if no 1237 * conversion is possible. 1238 */ 1239 public float getBrightnessFromNits(float nits) { 1240 return mCurrentBrightnessMapper.getBrightnessFromNits(nits); 1241 } 1242 1243 public void recalculateSplines(boolean applyAdjustment, float[] adjustment) { 1244 mCurrentBrightnessMapper.recalculateSplines(applyAdjustment, adjustment); 1245 1246 // If rbc is turned on, off or there is a change in strength, we want to reset the short 1247 // term model. Since the nits range at which brightness now operates has changed due to 1248 // RBC/strength change, any short term model based on the previous range should be 1249 // invalidated. 1250 resetShortTermModel(); 1251 1252 // When rbc is turned on, we want to accommodate this change in the short term model. 1253 if (applyAdjustment) { 1254 setScreenBrightnessByUser(getAutomaticScreenBrightness()); 1255 } 1256 } 1257 1258 private boolean shouldApplyDozeScaleFactor() { 1259 // Apply the doze scale factor if the display is in doze. We shouldn't rely on the display 1260 // policy here - the screen might turn on while the policy is POLICY_DOZE and in this 1261 // situation, we shouldn't apply the doze scale factor. We also don't apply the doze scale 1262 // factor if we have a designated brightness curve for doze. 1263 return Display.isDozeState(mDisplayState) && getMode() != AUTO_BRIGHTNESS_MODE_DOZE; 1264 } 1265 1266 private class ShortTermModel { 1267 // When the short term model is invalidated, we don't necessarily reset it (i.e. clear the 1268 // user's adjustment) immediately, but wait for a drastic enough change in the ambient 1269 // light. 1270 // The anchor determines what were the light levels when the user has set their preference, 1271 // and we use a relative threshold to determine when to revert to the OEM curve. 1272 private float mAnchor = INVALID_LUX; 1273 private float mBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; 1274 private boolean mIsValid = false; 1275 1276 private void reset() { 1277 mAnchor = INVALID_LUX; 1278 mBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; 1279 mIsValid = false; 1280 } 1281 1282 private void invalidate() { 1283 mIsValid = false; 1284 if (mLoggingEnabled) { 1285 Slog.d(TAG, "ShortTermModel: invalidate user data"); 1286 } 1287 } 1288 1289 private void setUserBrightness(float lux, float brightness) { 1290 mAnchor = lux; 1291 mBrightness = brightness; 1292 mIsValid = true; 1293 if (mLoggingEnabled) { 1294 Slog.d(TAG, "ShortTermModel: anchor=" + mAnchor); 1295 } 1296 } 1297 1298 private boolean maybeReset(float currentLux) { 1299 // If the short term model was invalidated and the change is drastic enough, reset it. 1300 // Otherwise, we revalidate it. 1301 if (!mIsValid && mAnchor != INVALID_LUX) { 1302 if (mCurrentBrightnessMapper.shouldResetShortTermModel(currentLux, mAnchor)) { 1303 resetShortTermModel(); 1304 } else { 1305 mIsValid = true; 1306 } 1307 return mIsValid; 1308 } 1309 return false; 1310 } 1311 1312 private void set(float anchor, float brightness, boolean valid) { 1313 mAnchor = anchor; 1314 mBrightness = brightness; 1315 mIsValid = valid; 1316 } 1317 private void copyFrom(ShortTermModel from) { 1318 mAnchor = from.mAnchor; 1319 mBrightness = from.mBrightness; 1320 mIsValid = from.mIsValid; 1321 } 1322 1323 public String toString() { 1324 return "mAnchor: " + mAnchor 1325 + "\n mBrightness: " + mBrightness 1326 + "\n mIsValid: " + mIsValid; 1327 } 1328 1329 void dump(PrintWriter pw) { 1330 pw.println(this); 1331 } 1332 1333 } 1334 1335 private final class AutomaticBrightnessHandler extends Handler { 1336 public AutomaticBrightnessHandler(Looper looper) { 1337 super(looper, null, true /*async*/); 1338 } 1339 1340 @Override 1341 public void handleMessage(Message msg) { 1342 switch (msg.what) { 1343 case MSG_RUN_UPDATE: 1344 updateAutoBrightness(true /*sendUpdate*/, false /*isManuallySet*/); 1345 break; 1346 1347 case MSG_UPDATE_AMBIENT_LUX: 1348 updateAmbientLux(); 1349 break; 1350 1351 case MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE: 1352 collectBrightnessAdjustmentSample(); 1353 break; 1354 1355 case MSG_INVALIDATE_CURRENT_SHORT_TERM_MODEL: 1356 mShortTermModel.invalidate(); 1357 break; 1358 1359 case MSG_UPDATE_FOREGROUND_APP: 1360 updateForegroundApp(); 1361 break; 1362 1363 case MSG_UPDATE_FOREGROUND_APP_SYNC: 1364 updateForegroundAppSync(); 1365 break; 1366 1367 case MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL: 1368 mPausedShortTermModel.invalidate(); 1369 break; 1370 } 1371 } 1372 } 1373 1374 private final SensorEventListener mLightSensorListener = new SensorEventListener() { 1375 @Override 1376 public void onSensorChanged(SensorEvent event) { 1377 if (mLightSensorEnabled) { 1378 // The time received from the sensor is in nano seconds, hence changing it to ms 1379 final long time = (mDisplayManagerFlags.offloadControlsDozeAutoBrightness()) 1380 ? TimeUnit.NANOSECONDS.toMillis(event.timestamp) : mClock.uptimeMillis(); 1381 final float lux = event.values[0]; 1382 handleLightSensorEvent(time, lux); 1383 } 1384 } 1385 1386 @Override 1387 public void onAccuracyChanged(Sensor sensor, int accuracy) { 1388 // Not used. 1389 } 1390 }; 1391 1392 // Call back whenever the tasks stack changes, which includes tasks being created, removed, and 1393 // moving to top. 1394 class TaskStackListenerImpl extends TaskStackListener { 1395 @Override onTaskStackChanged()1396 public void onTaskStackChanged() { 1397 mHandler.sendEmptyMessage(MSG_UPDATE_FOREGROUND_APP); 1398 } 1399 } 1400 1401 /** Callbacks to request updates to the display's power state. */ 1402 interface Callbacks { 1403 void updateBrightness(); 1404 } 1405 1406 /** Functional interface for providing time. */ 1407 @VisibleForTesting 1408 interface Clock { 1409 /** 1410 * Returns current time in milliseconds since boot, not counting time spent in deep sleep. 1411 */ 1412 long uptimeMillis(); 1413 1414 /** 1415 * Gets the time on either the elapsedTime or the uptime scale, depending on how we 1416 * processing the events from the sensor 1417 */ 1418 long getSensorEventScaleTime(); 1419 } 1420 1421 /** 1422 * A ring buffer of ambient light measurements sorted by time. 1423 * 1424 * Each entry consists of a timestamp and a lux measurement, and the overall buffer is sorted 1425 * from oldest to newest. 1426 */ 1427 private static final class AmbientLightRingBuffer { 1428 // Proportional extra capacity of the buffer beyond the expected number of light samples 1429 // in the horizon 1430 private static final float BUFFER_SLACK = 1.5f; 1431 private float[] mRingLux; 1432 private long[] mRingTime; 1433 private int mCapacity; 1434 1435 // The first valid element and the next open slot. 1436 // Note that if mCount is zero then there are no valid elements. 1437 private int mStart; 1438 private int mEnd; 1439 private int mCount; 1440 Clock mClock; 1441 AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon, Clock clock)1442 public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon, Clock clock) { 1443 if (lightSensorRate <= 0) { 1444 throw new IllegalArgumentException("lightSensorRate must be above 0"); 1445 } 1446 mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate); 1447 mRingLux = new float[mCapacity]; 1448 mRingTime = new long[mCapacity]; 1449 mClock = clock; 1450 } 1451 getLux(int index)1452 public float getLux(int index) { 1453 return mRingLux[offsetOf(index)]; 1454 } 1455 getAllLuxValues()1456 public float[] getAllLuxValues() { 1457 float[] values = new float[mCount]; 1458 if (mCount == 0) { 1459 return values; 1460 } 1461 1462 if (mStart < mEnd) { 1463 System.arraycopy(mRingLux, mStart, values, 0, mCount); 1464 } else { 1465 System.arraycopy(mRingLux, mStart, values, 0, mCapacity - mStart); 1466 System.arraycopy(mRingLux, 0, values, mCapacity - mStart, mEnd); 1467 } 1468 1469 return values; 1470 } 1471 getTime(int index)1472 public long getTime(int index) { 1473 return mRingTime[offsetOf(index)]; 1474 } 1475 getAllTimestamps()1476 public long[] getAllTimestamps() { 1477 long[] values = new long[mCount]; 1478 if (mCount == 0) { 1479 return values; 1480 } 1481 1482 if (mStart < mEnd) { 1483 System.arraycopy(mRingTime, mStart, values, 0, mCount); 1484 } else { 1485 System.arraycopy(mRingTime, mStart, values, 0, mCapacity - mStart); 1486 System.arraycopy(mRingTime, 0, values, mCapacity - mStart, mEnd); 1487 } 1488 1489 return values; 1490 } 1491 push(long time, float lux)1492 public void push(long time, float lux) { 1493 int next = mEnd; 1494 if (mCount == mCapacity) { 1495 int newSize = mCapacity * 2; 1496 1497 float[] newRingLux = new float[newSize]; 1498 long[] newRingTime = new long[newSize]; 1499 int length = mCapacity - mStart; 1500 System.arraycopy(mRingLux, mStart, newRingLux, 0, length); 1501 System.arraycopy(mRingTime, mStart, newRingTime, 0, length); 1502 if (mStart != 0) { 1503 System.arraycopy(mRingLux, 0, newRingLux, length, mStart); 1504 System.arraycopy(mRingTime, 0, newRingTime, length, mStart); 1505 } 1506 mRingLux = newRingLux; 1507 mRingTime = newRingTime; 1508 1509 next = mCapacity; 1510 mCapacity = newSize; 1511 mStart = 0; 1512 } 1513 mRingTime[next] = time; 1514 mRingLux[next] = lux; 1515 mEnd = next + 1; 1516 if (mEnd == mCapacity) { 1517 mEnd = 0; 1518 } 1519 mCount++; 1520 } 1521 prune(long horizon)1522 public void prune(long horizon) { 1523 if (mCount == 0) { 1524 return; 1525 } 1526 1527 while (mCount > 1) { 1528 int next = mStart + 1; 1529 if (next >= mCapacity) { 1530 next -= mCapacity; 1531 } 1532 if (mRingTime[next] > horizon) { 1533 // Some light sensors only produce data upon a change in the ambient light 1534 // levels, so we need to consider the previous measurement as the ambient light 1535 // level for all points in time up until we receive a new measurement. Thus, we 1536 // always want to keep the youngest element that would be removed from the 1537 // buffer and just set its measurement time to the horizon time since at that 1538 // point it is the ambient light level, and to remove it would be to drop a 1539 // valid data point within our horizon. 1540 break; 1541 } 1542 mStart = next; 1543 mCount -= 1; 1544 } 1545 1546 if (mRingTime[mStart] < horizon) { 1547 mRingTime[mStart] = horizon; 1548 } 1549 } 1550 size()1551 public int size() { 1552 return mCount; 1553 } 1554 clear()1555 public void clear() { 1556 mStart = 0; 1557 mEnd = 0; 1558 mCount = 0; 1559 } 1560 1561 @Override toString()1562 public String toString() { 1563 StringBuilder buf = new StringBuilder(); 1564 buf.append('['); 1565 for (int i = 0; i < mCount; i++) { 1566 final long next = i + 1 < mCount ? getTime(i + 1) 1567 : mClock.getSensorEventScaleTime(); 1568 if (i != 0) { 1569 buf.append(", "); 1570 } 1571 buf.append(getLux(i)); 1572 buf.append(" / "); 1573 buf.append(next - getTime(i)); 1574 buf.append("ms"); 1575 } 1576 buf.append(']'); 1577 return buf.toString(); 1578 } 1579 1580 private int offsetOf(int index) { 1581 if (index >= mCount || index < 0) { 1582 throw new ArrayIndexOutOfBoundsException(index); 1583 } 1584 index += mStart; 1585 if (index >= mCapacity) { 1586 index -= mCapacity; 1587 } 1588 return index; 1589 } 1590 } 1591 1592 private static class RealClock implements Clock { 1593 private final boolean mOffloadControlsDozeBrightness; 1594 RealClock(boolean offloadControlsDozeBrightness)1595 RealClock(boolean offloadControlsDozeBrightness) { 1596 mOffloadControlsDozeBrightness = offloadControlsDozeBrightness; 1597 } 1598 1599 @Override uptimeMillis()1600 public long uptimeMillis() { 1601 return SystemClock.uptimeMillis(); 1602 } 1603 getSensorEventScaleTime()1604 public long getSensorEventScaleTime() { 1605 return (mOffloadControlsDozeBrightness) 1606 ? SystemClock.elapsedRealtime() : uptimeMillis(); 1607 } 1608 } 1609 1610 public static class Injector { getBackgroundThreadHandler()1611 public Handler getBackgroundThreadHandler() { 1612 return BackgroundThread.getHandler(); 1613 } 1614 createClock(boolean offloadControlsDozeBrightness)1615 Clock createClock(boolean offloadControlsDozeBrightness) { 1616 return new RealClock(offloadControlsDozeBrightness); 1617 } 1618 } 1619 } 1620