1 /* 2 * Copyright (C) 2022 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.brightness; 18 19 import android.annotation.Nullable; 20 import android.content.Context; 21 import android.hardware.display.DisplayManagerInternal; 22 import android.os.HandlerExecutor; 23 import android.os.PowerManager; 24 import android.util.IndentingPrintWriter; 25 import android.view.Display; 26 27 import com.android.internal.annotations.GuardedBy; 28 import com.android.internal.annotations.VisibleForTesting; 29 import com.android.server.display.AutomaticBrightnessController; 30 import com.android.server.display.BrightnessSetting; 31 import com.android.server.display.DisplayBrightnessState; 32 import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy; 33 import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy; 34 35 import java.io.PrintWriter; 36 37 /** 38 * Deploys different DozeBrightnessStrategy to choose the current brightness for a specified 39 * display. Applies the chosen brightness. 40 */ 41 public final class DisplayBrightnessController { 42 private static final int DEFAULT_USER_SERIAL = -1; 43 44 // The ID of the display tied to this DisplayBrightnessController 45 private final int mDisplayId; 46 47 // The lock which is to be used to synchronize the resources being used in this class 48 private final Object mLock = new Object(); 49 50 // The default screen brightness to be used when no value is available in BrightnessSetting. 51 private final float mScreenBrightnessDefault; 52 53 // This is used to persist the changes happening to the brightness. 54 private final BrightnessSetting mBrightnessSetting; 55 56 // A runnable to update the clients registered via DisplayManagerGlobal 57 // .EVENT_DISPLAY_BRIGHTNESS_CHANGED about the brightness change. Called when 58 // mCurrentScreenBrightness is updated. 59 private Runnable mOnBrightnessChangeRunnable; 60 61 // The screen brightness that has changed but not taken effect yet. If this is different 62 // from the current screen brightness then this is coming from something other than us 63 // and should be considered a user interaction. 64 @GuardedBy("mLock") 65 private float mPendingScreenBrightness; 66 67 // The last observed screen brightness, either set by us or by the settings app on 68 // behalf of the user. 69 @GuardedBy("mLock") 70 private float mCurrentScreenBrightness; 71 72 // The last brightness that was set by the user and not temporary. Set to 73 // PowerManager.BRIGHTNESS_INVALID_FLOAT when a brightness has yet to be recorded. 74 @GuardedBy("mLock") 75 private float mLastUserSetScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; 76 77 // The listener which is to be notified everytime there is a change in the brightness in the 78 // BrightnessSetting. 79 private BrightnessSetting.BrightnessSettingListener mBrightnessSettingListener; 80 81 // Selects an appropriate strategy based on the request provided by the clients. 82 @GuardedBy("mLock") 83 private DisplayBrightnessStrategySelector mDisplayBrightnessStrategySelector; 84 85 // Currently selected DisplayBrightnessStrategy. 86 @GuardedBy("mLock") 87 private DisplayBrightnessStrategy mDisplayBrightnessStrategy; 88 89 // The executor on which the mOnBrightnessChangeRunnable is executed. This ensures that the 90 // callback is not executed in sync and is not blocking the thread from which it is called. 91 private final HandlerExecutor mBrightnessChangeExecutor; 92 93 // True if we want to persist the brightness value in nits even if the underlying display 94 // device changes. 95 private final boolean mPersistBrightnessNitsForDefaultDisplay; 96 97 // The controller for the automatic brightness level. 98 // TODO(b/265415257): Move to the automatic brightness strategy 99 @Nullable 100 private AutomaticBrightnessController mAutomaticBrightnessController; 101 102 /** 103 * The constructor of DisplayBrightnessController. 104 */ DisplayBrightnessController(Context context, Injector injector, int displayId, float defaultScreenBrightness, BrightnessSetting brightnessSetting, Runnable onBrightnessChangeRunnable, HandlerExecutor brightnessChangeExecutor)105 public DisplayBrightnessController(Context context, Injector injector, int displayId, 106 float defaultScreenBrightness, BrightnessSetting brightnessSetting, 107 Runnable onBrightnessChangeRunnable, HandlerExecutor brightnessChangeExecutor) { 108 if (injector == null) { 109 injector = new Injector(); 110 } 111 mDisplayId = displayId; 112 // TODO: b/186428377 update brightness setting when display changes 113 mBrightnessSetting = brightnessSetting; 114 mPendingScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; 115 mScreenBrightnessDefault = BrightnessUtils.clampAbsoluteBrightness(defaultScreenBrightness); 116 mCurrentScreenBrightness = getScreenBrightnessSetting(); 117 mOnBrightnessChangeRunnable = onBrightnessChangeRunnable; 118 mDisplayBrightnessStrategySelector = injector.getDisplayBrightnessStrategySelector(context, 119 displayId); 120 mBrightnessChangeExecutor = brightnessChangeExecutor; 121 mPersistBrightnessNitsForDefaultDisplay = context.getResources().getBoolean( 122 com.android.internal.R.bool.config_persistBrightnessNitsForDefaultDisplay); 123 } 124 125 /** 126 * Updates the display brightness. This delegates the responsibility of selecting an appropriate 127 * strategy to DisplayBrightnessStrategySelector, which is then applied to evaluate the 128 * DisplayBrightnessState. In the future, 129 * 1. This will account for clamping the brightness if needed. 130 * 2. This will notify the system about the updated brightness 131 * 132 * @param displayPowerRequest The request to update the brightness 133 * @param targetDisplayState The target display state of the system 134 */ updateBrightness( DisplayManagerInternal.DisplayPowerRequest displayPowerRequest, int targetDisplayState)135 public DisplayBrightnessState updateBrightness( 136 DisplayManagerInternal.DisplayPowerRequest displayPowerRequest, 137 int targetDisplayState) { 138 139 DisplayBrightnessState state; 140 synchronized (mLock) { 141 mDisplayBrightnessStrategy = mDisplayBrightnessStrategySelector.selectStrategy( 142 displayPowerRequest, targetDisplayState); 143 state = mDisplayBrightnessStrategy.updateBrightness(displayPowerRequest); 144 } 145 146 // This is a temporary measure until AutomaticBrightnessStrategy works as a traditional 147 // strategy. 148 // TODO: Remove when AutomaticBrightnessStrategy is populating the values directly. 149 if (state != null) { 150 state = addAutomaticBrightnessState(state); 151 } 152 return state; 153 } 154 155 /** 156 * Sets the temporary brightness 157 */ setTemporaryBrightness(Float temporaryBrightness)158 public void setTemporaryBrightness(Float temporaryBrightness) { 159 synchronized (mLock) { 160 setTemporaryBrightnessLocked(temporaryBrightness); 161 } 162 } 163 164 /** 165 * Sets the brightness to follow 166 */ setBrightnessToFollow(float brightnessToFollow, boolean slowChange)167 public void setBrightnessToFollow(float brightnessToFollow, boolean slowChange) { 168 synchronized (mLock) { 169 mDisplayBrightnessStrategySelector.getFollowerDisplayBrightnessStrategy() 170 .setBrightnessToFollow(brightnessToFollow, slowChange); 171 } 172 } 173 174 /** 175 * Returns a boolean flag indicating if the light sensor is to be used to decide the screen 176 * brightness when dozing 177 */ isAllowAutoBrightnessWhileDozingConfig()178 public boolean isAllowAutoBrightnessWhileDozingConfig() { 179 synchronized (mLock) { 180 return mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozingConfig(); 181 } 182 } 183 184 /** 185 * Sets the current screen brightness to the supplied value, and notifies all the listeners 186 * requesting for change events on brightness change. 187 */ setAndNotifyCurrentScreenBrightness(float brightnessValue)188 public void setAndNotifyCurrentScreenBrightness(float brightnessValue) { 189 final boolean hasBrightnessChanged; 190 synchronized (mLock) { 191 hasBrightnessChanged = (brightnessValue != mCurrentScreenBrightness); 192 setCurrentScreenBrightnessLocked(brightnessValue); 193 } 194 if (hasBrightnessChanged) { 195 notifyCurrentScreenBrightness(); 196 } 197 } 198 199 /** 200 * Returns the last observed screen brightness. 201 */ getCurrentBrightness()202 public float getCurrentBrightness() { 203 synchronized (mLock) { 204 return mCurrentScreenBrightness; 205 } 206 } 207 208 /** 209 * Returns the screen brightness which has changed but has not taken any effect so far. 210 */ getPendingScreenBrightness()211 public float getPendingScreenBrightness() { 212 synchronized (mLock) { 213 return mPendingScreenBrightness; 214 } 215 } 216 217 /** 218 * Sets the pending screen brightness setting, representing a value which is requested, but not 219 * yet processed. 220 * @param brightnessValue The value to which the pending screen brightness is to be set. 221 */ setPendingScreenBrightness(float brightnessValue)222 public void setPendingScreenBrightness(float brightnessValue) { 223 synchronized (mLock) { 224 mPendingScreenBrightness = brightnessValue; 225 } 226 } 227 228 /** 229 * We want to return true if the user has set the screen brightness. 230 * RBC on, off, and intensity changes will return false. 231 * Slider interactions whilst in RBC will return true, just as when in non-rbc. 232 */ updateUserSetScreenBrightness()233 public boolean updateUserSetScreenBrightness() { 234 synchronized (mLock) { 235 if (!BrightnessUtils.isValidBrightnessValue(mPendingScreenBrightness)) { 236 return false; 237 } 238 if (mCurrentScreenBrightness == mPendingScreenBrightness) { 239 mPendingScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; 240 setTemporaryBrightnessLocked(PowerManager.BRIGHTNESS_INVALID_FLOAT); 241 return false; 242 } 243 setCurrentScreenBrightnessLocked(mPendingScreenBrightness); 244 mLastUserSetScreenBrightness = mPendingScreenBrightness; 245 mPendingScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; 246 setTemporaryBrightnessLocked(PowerManager.BRIGHTNESS_INVALID_FLOAT); 247 } 248 notifyCurrentScreenBrightness(); 249 return true; 250 251 } 252 253 /** 254 * Registers the BrightnessSettingListener with the BrightnessSetting, which will be notified 255 * everytime there is a change in the brightness. 256 */ registerBrightnessSettingChangeListener( BrightnessSetting.BrightnessSettingListener brightnessSettingListener)257 public void registerBrightnessSettingChangeListener( 258 BrightnessSetting.BrightnessSettingListener brightnessSettingListener) { 259 mBrightnessSettingListener = brightnessSettingListener; 260 mBrightnessSetting.registerListener(mBrightnessSettingListener); 261 } 262 263 /** 264 * Returns the last user set brightness which is not temporary. 265 */ getLastUserSetScreenBrightness()266 public float getLastUserSetScreenBrightness() { 267 synchronized (mLock) { 268 return mLastUserSetScreenBrightness; 269 } 270 } 271 272 /** 273 * Returns the current screen brightnessSetting which is responsible for saving the brightness 274 * in the persistent store 275 */ getScreenBrightnessSetting()276 public float getScreenBrightnessSetting() { 277 float brightness = mBrightnessSetting.getBrightness(); 278 synchronized (mLock) { 279 if (Float.isNaN(brightness)) { 280 brightness = mScreenBrightnessDefault; 281 } 282 return BrightnessUtils.clampAbsoluteBrightness(brightness); 283 } 284 } 285 286 /** 287 * Notifies the brightnessSetting to persist the supplied brightness value. 288 */ setBrightness(float brightnessValue)289 public void setBrightness(float brightnessValue) { 290 setBrightness(brightnessValue, DEFAULT_USER_SERIAL); 291 } 292 293 /** 294 * Notifies the brightnessSetting to persist the supplied brightness value for a user. 295 */ setBrightness(float brightnessValue, int userSerial)296 public void setBrightness(float brightnessValue, int userSerial) { 297 // Update the setting, which will eventually call back into DPC to have us actually 298 // update the display with the new value. 299 mBrightnessSetting.setUserSerial(userSerial); 300 mBrightnessSetting.setBrightness(brightnessValue); 301 if (mDisplayId == Display.DEFAULT_DISPLAY && mPersistBrightnessNitsForDefaultDisplay) { 302 float nits = convertToNits(brightnessValue); 303 if (nits >= 0) { 304 mBrightnessSetting.setBrightnessNitsForDefaultDisplay(nits); 305 } 306 } 307 } 308 309 /** 310 * Sets the current screen brightness, and notifies the BrightnessSetting about the change. 311 */ updateScreenBrightnessSetting(float brightnessValue)312 public void updateScreenBrightnessSetting(float brightnessValue) { 313 synchronized (mLock) { 314 if (!BrightnessUtils.isValidBrightnessValue(brightnessValue) 315 || brightnessValue == mCurrentScreenBrightness) { 316 return; 317 } 318 setCurrentScreenBrightnessLocked(brightnessValue); 319 } 320 notifyCurrentScreenBrightness(); 321 setBrightness(brightnessValue); 322 } 323 324 /** 325 * Set the {@link AutomaticBrightnessController} which is needed to perform nit-to-float-scale 326 * conversion. 327 * @param automaticBrightnessController The ABC 328 */ setAutomaticBrightnessController( AutomaticBrightnessController automaticBrightnessController)329 public void setAutomaticBrightnessController( 330 AutomaticBrightnessController automaticBrightnessController) { 331 mAutomaticBrightnessController = automaticBrightnessController; 332 loadNitBasedBrightnessSetting(); 333 } 334 335 /** 336 * TODO(b/253226419): Remove once auto-brightness is a fully-functioning strategy. 337 */ getAutomaticBrightnessStrategy()338 public AutomaticBrightnessStrategy getAutomaticBrightnessStrategy() { 339 return mDisplayBrightnessStrategySelector.getAutomaticBrightnessStrategy(); 340 } 341 342 /** 343 * Convert a brightness float scale value to a nit value. Adjustments, such as RBC, are not 344 * applied. This is used when storing the brightness in nits for the default display and when 345 * passing the brightness value to follower displays. 346 * 347 * @param brightness The float scale value 348 * @return The nit value or -1f if no conversion is possible. 349 */ convertToNits(float brightness)350 public float convertToNits(float brightness) { 351 if (mAutomaticBrightnessController == null) { 352 return -1f; 353 } 354 return mAutomaticBrightnessController.convertToNits(brightness); 355 } 356 357 /** 358 * Convert a brightness float scale value to a nit value. Adjustments, such as RBC are applied. 359 * This is used when sending the brightness value to 360 * {@link com.android.server.display.BrightnessTracker}. 361 * 362 * @param brightness The float scale value 363 * @return The nit value or -1f if no conversion is possible. 364 */ convertToAdjustedNits(float brightness)365 public float convertToAdjustedNits(float brightness) { 366 if (mAutomaticBrightnessController == null) { 367 return -1f; 368 } 369 return mAutomaticBrightnessController.convertToAdjustedNits(brightness); 370 } 371 372 /** 373 * Convert a brightness nit value to a float scale value. It is assumed that the nit value 374 * provided does not have adjustments, such as RBC, applied. 375 * 376 * @param nits The nit value 377 * @return The float scale value or {@link PowerManager.BRIGHTNESS_INVALID_FLOAT} if no 378 * conversion is possible. 379 */ convertToFloatScale(float nits)380 public float convertToFloatScale(float nits) { 381 if (mAutomaticBrightnessController == null) { 382 return PowerManager.BRIGHTNESS_INVALID_FLOAT; 383 } 384 return mAutomaticBrightnessController.convertToFloatScale(nits); 385 } 386 387 /** 388 * Stops the associated listeners when the display is stopped. Invoked when the {@link 389 * #mDisplayId} is being removed. 390 */ stop()391 public void stop() { 392 if (mBrightnessSetting != null) { 393 mBrightnessSetting.unregisterListener(mBrightnessSettingListener); 394 } 395 } 396 397 /** 398 * Used to dump the state. 399 * 400 * @param writer The PrintWriter used to dump the state. 401 */ dump(PrintWriter writer)402 public void dump(PrintWriter writer) { 403 writer.println(); 404 writer.println("DisplayBrightnessController:"); 405 writer.println(" mDisplayId=: " + mDisplayId); 406 writer.println(" mScreenBrightnessDefault=" + mScreenBrightnessDefault); 407 writer.println(" mPersistBrightnessNitsForDefaultDisplay=" 408 + mPersistBrightnessNitsForDefaultDisplay); 409 synchronized (mLock) { 410 writer.println(" mPendingScreenBrightness=" + mPendingScreenBrightness); 411 writer.println(" mCurrentScreenBrightness=" + mCurrentScreenBrightness); 412 writer.println(" mLastUserSetScreenBrightness=" 413 + mLastUserSetScreenBrightness); 414 if (mDisplayBrightnessStrategy != null) { 415 writer.println(" Last selected DisplayBrightnessStrategy= " 416 + mDisplayBrightnessStrategy.getName()); 417 } 418 IndentingPrintWriter ipw = new IndentingPrintWriter(writer, " "); 419 mDisplayBrightnessStrategySelector.dump(ipw); 420 } 421 } 422 423 @VisibleForTesting 424 static class Injector { getDisplayBrightnessStrategySelector(Context context, int displayId)425 DisplayBrightnessStrategySelector getDisplayBrightnessStrategySelector(Context context, 426 int displayId) { 427 return new DisplayBrightnessStrategySelector(context, /* injector= */ null, displayId); 428 } 429 } 430 431 @VisibleForTesting getBrightnessSettingListener()432 BrightnessSetting.BrightnessSettingListener getBrightnessSettingListener() { 433 return mBrightnessSettingListener; 434 } 435 436 /** 437 * Returns the current selected DisplayBrightnessStrategy 438 */ 439 @VisibleForTesting getCurrentDisplayBrightnessStrategy()440 DisplayBrightnessStrategy getCurrentDisplayBrightnessStrategy() { 441 synchronized (mLock) { 442 return mDisplayBrightnessStrategy; 443 } 444 } 445 446 /** 447 * TODO(b/253226419): Remove once auto-brightness is a fully-functioning strategy. 448 */ addAutomaticBrightnessState(DisplayBrightnessState state)449 private DisplayBrightnessState addAutomaticBrightnessState(DisplayBrightnessState state) { 450 AutomaticBrightnessStrategy autoStrat = getAutomaticBrightnessStrategy(); 451 452 DisplayBrightnessState.Builder builder = DisplayBrightnessState.Builder.from(state); 453 builder.setShouldUseAutoBrightness( 454 autoStrat != null && autoStrat.shouldUseAutoBrightness()); 455 return builder.build(); 456 } 457 458 @GuardedBy("mLock") setTemporaryBrightnessLocked(float temporaryBrightness)459 private void setTemporaryBrightnessLocked(float temporaryBrightness) { 460 mDisplayBrightnessStrategySelector.getTemporaryDisplayBrightnessStrategy() 461 .setTemporaryScreenBrightness(temporaryBrightness); 462 } 463 464 @GuardedBy("mLock") setCurrentScreenBrightnessLocked(float brightnessValue)465 private void setCurrentScreenBrightnessLocked(float brightnessValue) { 466 if (brightnessValue != mCurrentScreenBrightness) { 467 mCurrentScreenBrightness = brightnessValue; 468 } 469 } 470 notifyCurrentScreenBrightness()471 private void notifyCurrentScreenBrightness() { 472 mBrightnessChangeExecutor.execute(mOnBrightnessChangeRunnable); 473 } 474 475 /** 476 * Loads the brightness value. If this is the default display and the config says that we should 477 * persist the nit value, the nit value for the default display will be loaded. 478 */ loadNitBasedBrightnessSetting()479 private void loadNitBasedBrightnessSetting() { 480 float currentBrightnessSetting = Float.NaN; 481 if (mDisplayId == Display.DEFAULT_DISPLAY && mPersistBrightnessNitsForDefaultDisplay) { 482 float brightnessNitsForDefaultDisplay = 483 mBrightnessSetting.getBrightnessNitsForDefaultDisplay(); 484 if (brightnessNitsForDefaultDisplay >= 0) { 485 float brightnessForDefaultDisplay = convertToFloatScale( 486 brightnessNitsForDefaultDisplay); 487 if (BrightnessUtils.isValidBrightnessValue(brightnessForDefaultDisplay)) { 488 mBrightnessSetting.setBrightness(brightnessForDefaultDisplay); 489 currentBrightnessSetting = brightnessForDefaultDisplay; 490 } 491 } 492 } 493 494 if (Float.isNaN(currentBrightnessSetting)) { 495 currentBrightnessSetting = getScreenBrightnessSetting(); 496 } 497 498 synchronized (mLock) { 499 mCurrentScreenBrightness = currentBrightnessSetting; 500 } 501 } 502 } 503