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