1 /* 2 * Copyright (C) 2023 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 package com.android.server.display.brightness.strategy; 17 18 import android.annotation.Nullable; 19 import android.content.Context; 20 import android.hardware.display.BrightnessConfiguration; 21 import android.os.PowerManager; 22 import android.os.UserHandle; 23 import android.provider.Settings; 24 import android.view.Display; 25 26 import com.android.internal.annotations.VisibleForTesting; 27 import com.android.server.display.AutomaticBrightnessController; 28 import com.android.server.display.brightness.BrightnessEvent; 29 import com.android.server.display.brightness.BrightnessReason; 30 import com.android.server.display.brightness.BrightnessUtils; 31 32 import java.io.PrintWriter; 33 34 /** 35 * Helps manage the brightness based on the ambient environment (Ambient Light/lux sensor) using 36 * mappings from lux to nits to brightness, configured in the 37 * {@link com.android.server.display.DisplayDeviceConfig} class. This class inherently assumes 38 * that it is being executed from the power thread, and hence doesn't synchronize 39 * any of its resources 40 */ 41 public class AutomaticBrightnessStrategy { 42 private final Context mContext; 43 // The DisplayId of the associated logical display 44 private final int mDisplayId; 45 // The last auto brightness adjustment that was set by the user and is not temporary. Set to 46 // Float.NaN when an auto-brightness adjustment hasn't been recorded yet. 47 private float mAutoBrightnessAdjustment; 48 // The pending auto brightness adjustment that will take effect on the next power state update. 49 private float mPendingAutoBrightnessAdjustment; 50 // The temporary auto brightness adjustment. This was historically used when a user interacts 51 // with the adjustment slider but hasn't settled on a choice yet. 52 // Set to PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary adjustment set. 53 private float mTemporaryAutoBrightnessAdjustment; 54 // Indicates if the temporary auto brightness adjustment has been applied while updating the 55 // associated display brightness 56 private boolean mAppliedTemporaryAutoBrightnessAdjustment; 57 // Indicates if the auto brightness adjustment has happened. 58 private boolean mAutoBrightnessAdjustmentChanged; 59 // Indicates the reasons for the auto-brightness adjustment 60 private int mAutoBrightnessAdjustmentReasonsFlags = 0; 61 // Indicates if the short term model should be reset before fetching the new brightness 62 // Todo(273543270): Short term model is an internal information of 63 // AutomaticBrightnessController and shouldn't be exposed outside of that class 64 private boolean mShouldResetShortTermModel = false; 65 // Remembers whether the auto-brightness has been applied in the latest brightness update. 66 private boolean mAppliedAutoBrightness = false; 67 // The controller for the automatic brightness level. 68 @Nullable 69 private AutomaticBrightnessController mAutomaticBrightnessController; 70 // The system setting denoting if the auto-brightness for the current user is enabled or not 71 private boolean mUseAutoBrightness = false; 72 // Indicates if the auto-brightness is currently enabled or not. It's possible that even if 73 // the user has enabled the auto-brightness from the settings, it is disabled because the 74 // display is off 75 private boolean mIsAutoBrightnessEnabled = false; 76 // Indicates if auto-brightness is disabled due to the display being off. Needed for metric 77 // purposes. 78 private boolean mAutoBrightnessDisabledDueToDisplayOff; 79 // If the auto-brightness model for the last manual changes done by the user. 80 private boolean mIsShortTermModelActive = false; 81 82 // The BrightnessConfiguration currently being used 83 // Todo(273543270): BrightnessConfiguration is an internal implementation detail of 84 // AutomaticBrightnessController, and AutomaticBrightnessStrategy shouldn't be aware of its 85 // existence. 86 @Nullable 87 private BrightnessConfiguration mBrightnessConfiguration; 88 AutomaticBrightnessStrategy(Context context, int displayId)89 public AutomaticBrightnessStrategy(Context context, int displayId) { 90 mContext = context; 91 mDisplayId = displayId; 92 mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting(); 93 mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT; 94 mTemporaryAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT; 95 } 96 97 /** 98 * Sets up the automatic brightness states of this class. Also configures 99 * AutomaticBrightnessController accounting for any manual changes made by the user. 100 */ setAutoBrightnessState(int targetDisplayState, boolean allowAutoBrightnessWhileDozingConfig, int brightnessReason, int policy, float lastUserSetScreenBrightness, boolean userSetBrightnessChanged)101 public void setAutoBrightnessState(int targetDisplayState, 102 boolean allowAutoBrightnessWhileDozingConfig, int brightnessReason, int policy, 103 float lastUserSetScreenBrightness, boolean userSetBrightnessChanged) { 104 final boolean autoBrightnessEnabledInDoze = 105 allowAutoBrightnessWhileDozingConfig 106 && Display.isDozeState(targetDisplayState); 107 mIsAutoBrightnessEnabled = shouldUseAutoBrightness() 108 && (targetDisplayState == Display.STATE_ON || autoBrightnessEnabledInDoze) 109 && brightnessReason != BrightnessReason.REASON_OVERRIDE 110 && mAutomaticBrightnessController != null; 111 mAutoBrightnessDisabledDueToDisplayOff = shouldUseAutoBrightness() 112 && !(targetDisplayState == Display.STATE_ON || autoBrightnessEnabledInDoze); 113 final int autoBrightnessState = mIsAutoBrightnessEnabled 114 && brightnessReason != BrightnessReason.REASON_FOLLOWER 115 ? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED 116 : mAutoBrightnessDisabledDueToDisplayOff 117 ? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE 118 : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED; 119 120 accommodateUserBrightnessChanges(userSetBrightnessChanged, lastUserSetScreenBrightness, 121 policy, mBrightnessConfiguration, autoBrightnessState); 122 } 123 isAutoBrightnessEnabled()124 public boolean isAutoBrightnessEnabled() { 125 return mIsAutoBrightnessEnabled; 126 } 127 isAutoBrightnessDisabledDueToDisplayOff()128 public boolean isAutoBrightnessDisabledDueToDisplayOff() { 129 return mAutoBrightnessDisabledDueToDisplayOff; 130 } 131 132 /** 133 * Updates the {@link BrightnessConfiguration} that is currently being used by the associated 134 * display. 135 */ setBrightnessConfiguration(BrightnessConfiguration brightnessConfiguration, boolean shouldResetShortTermModel)136 public void setBrightnessConfiguration(BrightnessConfiguration brightnessConfiguration, 137 boolean shouldResetShortTermModel) { 138 mBrightnessConfiguration = brightnessConfiguration; 139 setShouldResetShortTermModel(shouldResetShortTermModel); 140 } 141 142 /** 143 * Promotes the pending auto-brightness adjustments which are yet to be applied to the current 144 * adjustments. Note that this is not applying the new adjustments to the AutoBrightness mapping 145 * strategies, but is only accommodating the changes in this class. 146 */ processPendingAutoBrightnessAdjustments()147 public boolean processPendingAutoBrightnessAdjustments() { 148 mAutoBrightnessAdjustmentChanged = false; 149 if (Float.isNaN(mPendingAutoBrightnessAdjustment)) { 150 return false; 151 } 152 if (mAutoBrightnessAdjustment == mPendingAutoBrightnessAdjustment) { 153 mPendingAutoBrightnessAdjustment = Float.NaN; 154 return false; 155 } 156 mAutoBrightnessAdjustment = mPendingAutoBrightnessAdjustment; 157 mPendingAutoBrightnessAdjustment = Float.NaN; 158 mTemporaryAutoBrightnessAdjustment = Float.NaN; 159 mAutoBrightnessAdjustmentChanged = true; 160 return true; 161 } 162 163 /** 164 * Updates the associated AutomaticBrightnessController 165 */ setAutomaticBrightnessController( AutomaticBrightnessController automaticBrightnessController)166 public void setAutomaticBrightnessController( 167 AutomaticBrightnessController automaticBrightnessController) { 168 if (automaticBrightnessController == mAutomaticBrightnessController) { 169 return; 170 } 171 if (mAutomaticBrightnessController != null) { 172 mAutomaticBrightnessController.stop(); 173 } 174 mAutomaticBrightnessController = automaticBrightnessController; 175 } 176 177 /** 178 * Returns if the auto-brightness of the associated display has been enabled or not 179 */ shouldUseAutoBrightness()180 public boolean shouldUseAutoBrightness() { 181 return mUseAutoBrightness; 182 } 183 184 /** 185 * Sets the auto-brightness state of the associated display. Called when the user makes a change 186 * in the system setting to enable/disable the auto-brightness. 187 */ setUseAutoBrightness(boolean useAutoBrightness)188 public void setUseAutoBrightness(boolean useAutoBrightness) { 189 mUseAutoBrightness = useAutoBrightness; 190 } 191 192 /** 193 * Returns if the user made brightness change events(Typically when they interact with the 194 * brightness slider) were accommodated in the auto-brightness mapping strategies. This doesn't 195 * account for the latest changes that have been made by the user. 196 */ isShortTermModelActive()197 public boolean isShortTermModelActive() { 198 return mIsShortTermModelActive; 199 } 200 201 /** 202 * Sets the pending auto-brightness adjustments in the system settings. Executed 203 * when there is a change in the brightness system setting, or when there is a user switch. 204 */ updatePendingAutoBrightnessAdjustments(boolean userSwitch)205 public void updatePendingAutoBrightnessAdjustments(boolean userSwitch) { 206 final float adj = Settings.System.getFloatForUser(mContext.getContentResolver(), 207 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f, UserHandle.USER_CURRENT); 208 mPendingAutoBrightnessAdjustment = Float.isNaN(adj) ? Float.NaN 209 : BrightnessUtils.clampBrightnessAdjustment(adj); 210 if (userSwitch) { 211 processPendingAutoBrightnessAdjustments(); 212 } 213 } 214 215 /** 216 * Sets the temporary auto-brightness adjustments 217 */ setTemporaryAutoBrightnessAdjustment(float temporaryAutoBrightnessAdjustment)218 public void setTemporaryAutoBrightnessAdjustment(float temporaryAutoBrightnessAdjustment) { 219 mTemporaryAutoBrightnessAdjustment = temporaryAutoBrightnessAdjustment; 220 } 221 222 /** 223 * Dumps the state of this class. 224 */ dump(PrintWriter writer)225 public void dump(PrintWriter writer) { 226 writer.println("AutomaticBrightnessStrategy:"); 227 writer.println(" mDisplayId=" + mDisplayId); 228 writer.println(" mAutoBrightnessAdjustment=" + mAutoBrightnessAdjustment); 229 writer.println(" mPendingAutoBrightnessAdjustment=" + mPendingAutoBrightnessAdjustment); 230 writer.println( 231 " mTemporaryAutoBrightnessAdjustment=" + mTemporaryAutoBrightnessAdjustment); 232 writer.println(" mShouldResetShortTermModel=" + mShouldResetShortTermModel); 233 writer.println(" mAppliedAutoBrightness=" + mAppliedAutoBrightness); 234 writer.println(" mAutoBrightnessAdjustmentChanged=" + mAutoBrightnessAdjustmentChanged); 235 writer.println(" mAppliedTemporaryAutoBrightnessAdjustment=" 236 + mAppliedTemporaryAutoBrightnessAdjustment); 237 writer.println(" mUseAutoBrightness=" + mUseAutoBrightness); 238 writer.println(" mWasShortTermModelActive=" + mIsShortTermModelActive); 239 writer.println(" mAutoBrightnessAdjustmentReasonsFlags=" 240 + mAutoBrightnessAdjustmentReasonsFlags); 241 } 242 243 /** 244 * Indicates if any auto-brightness adjustments have happened since the last auto-brightness was 245 * set. 246 */ getAutoBrightnessAdjustmentChanged()247 public boolean getAutoBrightnessAdjustmentChanged() { 248 return mAutoBrightnessAdjustmentChanged; 249 } 250 251 /** 252 * Returns whether the latest temporary auto-brightness adjustments have been applied or not 253 */ isTemporaryAutoBrightnessAdjustmentApplied()254 public boolean isTemporaryAutoBrightnessAdjustmentApplied() { 255 return mAppliedTemporaryAutoBrightnessAdjustment; 256 } 257 258 /** 259 * Evaluates the target automatic brightness of the associated display. 260 * @param brightnessEvent Event object to populate with details about why the specific 261 * brightness was chosen. 262 */ getAutomaticScreenBrightness(BrightnessEvent brightnessEvent)263 public float getAutomaticScreenBrightness(BrightnessEvent brightnessEvent) { 264 float brightness = (mAutomaticBrightnessController != null) 265 ? mAutomaticBrightnessController.getAutomaticScreenBrightness(brightnessEvent) 266 : PowerManager.BRIGHTNESS_INVALID_FLOAT; 267 adjustAutomaticBrightnessStateIfValid(brightness); 268 return brightness; 269 } 270 271 /** 272 * Gets the auto-brightness adjustment flag change reason 273 */ getAutoBrightnessAdjustmentReasonsFlags()274 public int getAutoBrightnessAdjustmentReasonsFlags() { 275 return mAutoBrightnessAdjustmentReasonsFlags; 276 } 277 278 /** 279 * Returns if the auto brightness has been applied 280 */ hasAppliedAutoBrightness()281 public boolean hasAppliedAutoBrightness() { 282 return mAppliedAutoBrightness; 283 } 284 285 /** 286 * Used to adjust the state of this class when the automatic brightness value for the 287 * associated display is valid 288 */ 289 @VisibleForTesting adjustAutomaticBrightnessStateIfValid(float brightnessState)290 void adjustAutomaticBrightnessStateIfValid(float brightnessState) { 291 mAutoBrightnessAdjustmentReasonsFlags = isTemporaryAutoBrightnessAdjustmentApplied() 292 ? BrightnessReason.ADJUSTMENT_AUTO_TEMP 293 : BrightnessReason.ADJUSTMENT_AUTO; 294 float newAutoBrightnessAdjustment = 295 (mAutomaticBrightnessController != null) 296 ? mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment() 297 : 0.0f; 298 if (!Float.isNaN(newAutoBrightnessAdjustment) 299 && mAutoBrightnessAdjustment != newAutoBrightnessAdjustment) { 300 // If the auto-brightness controller has decided to change the adjustment value 301 // used, make sure that's reflected in settings. 302 putAutoBrightnessAdjustmentSetting(newAutoBrightnessAdjustment); 303 } else { 304 mAutoBrightnessAdjustmentReasonsFlags = 0; 305 } 306 } 307 308 /** 309 * Sets up the system to reset the short term model. Note that this will not reset the model 310 * right away, but ensures that the reset happens whenever the next brightness change happens 311 */ 312 @VisibleForTesting setShouldResetShortTermModel(boolean shouldResetShortTermModel)313 void setShouldResetShortTermModel(boolean shouldResetShortTermModel) { 314 mShouldResetShortTermModel = shouldResetShortTermModel; 315 } 316 317 @VisibleForTesting shouldResetShortTermModel()318 boolean shouldResetShortTermModel() { 319 return mShouldResetShortTermModel; 320 } 321 322 @VisibleForTesting getAutoBrightnessAdjustment()323 float getAutoBrightnessAdjustment() { 324 return mAutoBrightnessAdjustment; 325 } 326 327 @VisibleForTesting getPendingAutoBrightnessAdjustment()328 float getPendingAutoBrightnessAdjustment() { 329 return mPendingAutoBrightnessAdjustment; 330 } 331 332 @VisibleForTesting getTemporaryAutoBrightnessAdjustment()333 float getTemporaryAutoBrightnessAdjustment() { 334 return mTemporaryAutoBrightnessAdjustment; 335 } 336 337 @VisibleForTesting putAutoBrightnessAdjustmentSetting(float adjustment)338 void putAutoBrightnessAdjustmentSetting(float adjustment) { 339 if (mDisplayId == Display.DEFAULT_DISPLAY) { 340 mAutoBrightnessAdjustment = adjustment; 341 Settings.System.putFloatForUser(mContext.getContentResolver(), 342 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adjustment, 343 UserHandle.USER_CURRENT); 344 } 345 } 346 347 /** 348 * Sets if the auto-brightness is applied on the latest brightness change. 349 */ setAutoBrightnessApplied(boolean autoBrightnessApplied)350 public void setAutoBrightnessApplied(boolean autoBrightnessApplied) { 351 mAppliedAutoBrightness = autoBrightnessApplied; 352 } 353 354 /** 355 * Accommodates the latest manual changes made by the user. Also updates {@link 356 * AutomaticBrightnessController} about the changes and configures it accordingly. 357 */ 358 @VisibleForTesting accommodateUserBrightnessChanges(boolean userSetBrightnessChanged, float lastUserSetScreenBrightness, int policy, BrightnessConfiguration brightnessConfiguration, int autoBrightnessState)359 void accommodateUserBrightnessChanges(boolean userSetBrightnessChanged, 360 float lastUserSetScreenBrightness, int policy, 361 BrightnessConfiguration brightnessConfiguration, int autoBrightnessState) { 362 // Update the pending auto-brightness adjustments if any. This typically checks and adjusts 363 // the state of the class if the user moves the brightness slider and has settled to a 364 // different value 365 processPendingAutoBrightnessAdjustments(); 366 // Update the temporary auto-brightness adjustments if any. This typically checks and 367 // adjusts the state of this class if the user is in the process of moving the brightness 368 // slider, but hasn't settled to any value yet 369 float autoBrightnessAdjustment = updateTemporaryAutoBrightnessAdjustments(); 370 mIsShortTermModelActive = false; 371 // Configure auto-brightness. 372 if (mAutomaticBrightnessController != null) { 373 // Accommodate user changes if any in the auto-brightness model 374 mAutomaticBrightnessController.configure(autoBrightnessState, 375 brightnessConfiguration, 376 lastUserSetScreenBrightness, 377 userSetBrightnessChanged, autoBrightnessAdjustment, 378 mAutoBrightnessAdjustmentChanged, policy, mShouldResetShortTermModel); 379 mShouldResetShortTermModel = false; 380 // We take note if the user brightness point is still being used in the current 381 // auto-brightness model. 382 mIsShortTermModelActive = mAutomaticBrightnessController.hasUserDataPoints(); 383 } 384 } 385 386 /** 387 * Evaluates if there are any temporary auto-brightness adjustments which is not applied yet. 388 * Temporary brightness adjustments happen when the user moves the brightness slider in the 389 * auto-brightness mode, but hasn't settled to a value yet 390 */ updateTemporaryAutoBrightnessAdjustments()391 private float updateTemporaryAutoBrightnessAdjustments() { 392 mAppliedTemporaryAutoBrightnessAdjustment = 393 !Float.isNaN(mTemporaryAutoBrightnessAdjustment); 394 // We do not update the mAutoBrightnessAdjustment with mTemporaryAutoBrightnessAdjustment 395 // since we have not settled to a value yet 396 return mAppliedTemporaryAutoBrightnessAdjustment 397 ? mTemporaryAutoBrightnessAdjustment : mAutoBrightnessAdjustment; 398 } 399 400 /** 401 * Returns the auto-brightness adjustment that is set in the system setting. 402 */ getAutoBrightnessAdjustmentSetting()403 private float getAutoBrightnessAdjustmentSetting() { 404 final float adj = Settings.System.getFloatForUser(mContext.getContentResolver(), 405 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f, UserHandle.USER_CURRENT); 406 return Float.isNaN(adj) ? 0.0f : BrightnessUtils.clampBrightnessAdjustment(adj); 407 } 408 } 409