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