1 /* 2 * Copyright (C) 2019 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.whitebalance; 18 19 import android.annotation.NonNull; 20 import android.util.Slog; 21 import android.util.Spline; 22 23 import com.android.internal.annotations.VisibleForTesting; 24 import com.android.server.LocalServices; 25 import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal; 26 import com.android.server.display.utils.AmbientFilter; 27 import com.android.server.display.utils.History; 28 29 import java.io.PrintWriter; 30 import java.util.Objects; 31 32 /** 33 * The DisplayWhiteBalanceController drives display white-balance (automatically correcting the 34 * display color temperature depending on the ambient color temperature). 35 * 36 * The DisplayWhiteBalanceController: 37 * - Uses the AmbientColorTemperatureSensor to detect changes in the ambient color temperature; 38 * - Uses the AmbientColorTemperatureFilter to average these changes over time, filter out the 39 * noise, and arrive at an estimate of the actual ambient color temperature; 40 * - Uses the DisplayWhiteBalanceThrottler to decide whether the display color temperature should 41 * be updated, suppressing changes that are too frequent or too minor. 42 * 43 * Calls to this class must happen on the DisplayPowerController(2) handler, to ensure 44 * values do not get out of sync. 45 */ 46 public class DisplayWhiteBalanceController implements 47 AmbientSensor.AmbientBrightnessSensor.Callbacks, 48 AmbientSensor.AmbientColorTemperatureSensor.Callbacks { 49 50 private static final String TAG = "DisplayWhiteBalanceController"; 51 private boolean mLoggingEnabled; 52 53 private final ColorDisplayServiceInternal mColorDisplayServiceInternal; 54 55 private final AmbientSensor.AmbientBrightnessSensor mBrightnessSensor; 56 @VisibleForTesting 57 AmbientFilter mBrightnessFilter; 58 private final AmbientSensor.AmbientColorTemperatureSensor mColorTemperatureSensor; 59 @VisibleForTesting 60 AmbientFilter mColorTemperatureFilter; 61 private final DisplayWhiteBalanceThrottler mThrottler; 62 // In low brightness conditions the ALS readings are more noisy and produce 63 // high errors. This default is introduced to provide a fixed display color 64 // temperature when sensor readings become unreliable. 65 private final float mLowLightAmbientColorTemperature; 66 // As above, but used when in strong mode (idle screen brightness mode). 67 private final float mLowLightAmbientColorTemperatureStrong; 68 69 // In high brightness conditions certain color temperatures can cause peak display 70 // brightness to drop. This fixed color temperature can be used to compensate for 71 // this effect. 72 private final float mHighLightAmbientColorTemperature; 73 // As above, but used when in strong mode (idle screen brightness mode). 74 private final float mHighLightAmbientColorTemperatureStrong; 75 76 private final boolean mLightModeAllowed; 77 78 private float mAmbientColorTemperature; 79 @VisibleForTesting 80 float mPendingAmbientColorTemperature; 81 private float mLastAmbientColorTemperature; 82 83 // The most recent ambient color temperature values are kept for debugging purposes. 84 private final History mAmbientColorTemperatureHistory; 85 86 // Override the ambient color temperature for debugging purposes. 87 private float mAmbientColorTemperatureOverride; 88 89 // A piecewise linear relationship between ambient and display color temperatures. 90 private Spline.LinearSpline mAmbientToDisplayColorTemperatureSpline; 91 92 // A piecewise linear relationship between ambient and display color temperatures, with a 93 // stronger change between the two sets of values. 94 private Spline.LinearSpline mStrongAmbientToDisplayColorTemperatureSpline; 95 96 // In very low or very high brightness conditions Display White Balance should 97 // be to set to a default instead of using mAmbientToDisplayColorTemperatureSpline. 98 // However, setting Display White Balance based on thresholds can cause the 99 // display to rapidly change color temperature. To solve this, 100 // mLowLightAmbientBrightnessToBiasSpline and 101 // mHighLightAmbientBrightnessToBiasSpline are used to smoothly interpolate from 102 // ambient color temperature to the defaults. A piecewise linear relationship 103 // between low light brightness and low light bias. 104 private Spline.LinearSpline mLowLightAmbientBrightnessToBiasSpline; 105 private Spline.LinearSpline mLowLightAmbientBrightnessToBiasSplineStrong; 106 107 // A piecewise linear relationship between high light brightness and high light bias. 108 private Spline.LinearSpline mHighLightAmbientBrightnessToBiasSpline; 109 private Spline.LinearSpline mHighLightAmbientBrightnessToBiasSplineStrong; 110 111 private float mLatestAmbientColorTemperature; 112 private float mLatestAmbientBrightness; 113 private float mLatestLowLightBias; 114 private float mLatestHighLightBias; 115 116 private boolean mEnabled; 117 118 // Whether a higher-strength adjustment should be applied; this must be enabled in addition to 119 // mEnabled in order to be applied. 120 private boolean mStrongModeEnabled; 121 122 // To decouple the DisplayPowerController from the DisplayWhiteBalanceController, the DPC 123 // implements Callbacks and passes itself to the DWBC so it can call back into it without 124 // knowing about it. 125 private Callbacks mDisplayPowerControllerCallbacks; 126 127 /** 128 * @param brightnessSensor 129 * The sensor used to detect changes in the ambient brightness. 130 * @param brightnessFilter 131 * The filter used to avergae ambient brightness changes over time, filter out the noise 132 * and arrive at an estimate of the actual ambient brightness. 133 * @param colorTemperatureSensor 134 * The sensor used to detect changes in the ambient color temperature. 135 * @param colorTemperatureFilter 136 * The filter used to average ambient color temperature changes over time, filter out the 137 * noise and arrive at an estimate of the actual ambient color temperature. 138 * @param throttler 139 * The throttler used to determine whether the new display color temperature should be 140 * updated or not. 141 * @param lowLightAmbientBrightnesses 142 * The ambient brightness used to map the ambient brightnesses to the biases used to 143 * interpolate to lowLightAmbientColorTemperature. 144 * @param lowLightAmbientBrightnessesStrong 145 * The ambient brightness used to map the ambient brightnesses to the biases used to 146 * interpolate to lowLightAmbientColorTemperature. 147 * @param lowLightAmbientBiases 148 * The biases used to map the ambient brightnesses to the biases used to interpolate to 149 * lowLightAmbientColorTemperature. 150 * @param lowLightAmbientBiasesStrong 151 * The biases used to map the ambient brightnesses to the biases used to interpolate to 152 * lowLightAmbientColorTemperature. 153 * @param lowLightAmbientColorTemperature 154 * The ambient color temperature to which we interpolate to based on the low light curve. 155 * @param highLightAmbientBrightnesses 156 * The ambient brightness used to map the ambient brightnesses to the biases used to 157 * interpolate to highLightAmbientColorTemperature. 158 * @param highLightAmbientBrightnessesStrong 159 * The ambient brightness used to map the ambient brightnesses to the biases used to 160 * interpolate to highLightAmbientColorTemperature. 161 * @param highLightAmbientBiases 162 * The biases used to map the ambient brightnesses to the biases used to interpolate to 163 * highLightAmbientColorTemperature. 164 * @param highLightAmbientBiasesStrong 165 * The biases used to map the ambient brightnesses to the biases used to interpolate to 166 * highLightAmbientColorTemperature. 167 * @param highLightAmbientColorTemperature 168 * The ambient color temperature to which we interpolate to based on the high light curve. 169 * @param ambientColorTemperatures 170 * The ambient color tempeartures used to map the ambient color temperature to the display 171 * color temperature (or null if no mapping is necessary). 172 * @param displayColorTemperatures 173 * The display color temperatures used to map the ambient color temperature to the display 174 * color temperature (or null if no mapping is necessary). 175 * @param lightModeAllowed 176 * Whether a lighter version should be applied when Strong Mode is not enabled. 177 * 178 * @throws NullPointerException 179 * - brightnessSensor is null; 180 * - brightnessFilter is null; 181 * - colorTemperatureSensor is null; 182 * - colorTemperatureFilter is null; 183 * - throttler is null. 184 */ DisplayWhiteBalanceController( @onNull AmbientSensor.AmbientBrightnessSensor brightnessSensor, @NonNull AmbientFilter brightnessFilter, @NonNull AmbientSensor.AmbientColorTemperatureSensor colorTemperatureSensor, @NonNull AmbientFilter colorTemperatureFilter, @NonNull DisplayWhiteBalanceThrottler throttler, float[] lowLightAmbientBrightnesses, float[] lowLightAmbientBrightnessesStrong, float[] lowLightAmbientBiases, float[] lowLightAmbientBiasesStrong, float lowLightAmbientColorTemperature, float lowLightAmbientColorTemperatureStrong, float[] highLightAmbientBrightnesses, float[] highLightAmbientBrightnessesStrong, float[] highLightAmbientBiases, float[] highLightAmbientBiasesStrong, float highLightAmbientColorTemperature, float highLightAmbientColorTemperatureStrong, float[] ambientColorTemperatures, float[] displayColorTemperatures, float[] strongAmbientColorTemperatures, float[] strongDisplayColorTemperatures, boolean lightModeAllowed)185 public DisplayWhiteBalanceController( 186 @NonNull AmbientSensor.AmbientBrightnessSensor brightnessSensor, 187 @NonNull AmbientFilter brightnessFilter, 188 @NonNull AmbientSensor.AmbientColorTemperatureSensor colorTemperatureSensor, 189 @NonNull AmbientFilter colorTemperatureFilter, 190 @NonNull DisplayWhiteBalanceThrottler throttler, 191 float[] lowLightAmbientBrightnesses, 192 float[] lowLightAmbientBrightnessesStrong, 193 float[] lowLightAmbientBiases, 194 float[] lowLightAmbientBiasesStrong, 195 float lowLightAmbientColorTemperature, 196 float lowLightAmbientColorTemperatureStrong, 197 float[] highLightAmbientBrightnesses, 198 float[] highLightAmbientBrightnessesStrong, 199 float[] highLightAmbientBiases, 200 float[] highLightAmbientBiasesStrong, 201 float highLightAmbientColorTemperature, 202 float highLightAmbientColorTemperatureStrong, 203 float[] ambientColorTemperatures, 204 float[] displayColorTemperatures, 205 float[] strongAmbientColorTemperatures, 206 float[] strongDisplayColorTemperatures, 207 boolean lightModeAllowed) { 208 validateArguments(brightnessSensor, brightnessFilter, colorTemperatureSensor, 209 colorTemperatureFilter, throttler); 210 mBrightnessSensor = brightnessSensor; 211 mBrightnessFilter = brightnessFilter; 212 mColorTemperatureSensor = colorTemperatureSensor; 213 mColorTemperatureFilter = colorTemperatureFilter; 214 mThrottler = throttler; 215 mLowLightAmbientColorTemperature = lowLightAmbientColorTemperature; 216 mLowLightAmbientColorTemperatureStrong = lowLightAmbientColorTemperatureStrong; 217 mHighLightAmbientColorTemperature = highLightAmbientColorTemperature; 218 mHighLightAmbientColorTemperatureStrong = highLightAmbientColorTemperatureStrong; 219 mAmbientColorTemperature = -1.0f; 220 mPendingAmbientColorTemperature = -1.0f; 221 mLastAmbientColorTemperature = -1.0f; 222 mAmbientColorTemperatureHistory = new History(/* size= */ 50); 223 mAmbientColorTemperatureOverride = -1.0f; 224 mLightModeAllowed = lightModeAllowed; 225 226 try { 227 mLowLightAmbientBrightnessToBiasSpline = new Spline.LinearSpline( 228 lowLightAmbientBrightnesses, lowLightAmbientBiases); 229 } catch (Exception e) { 230 Slog.e(TAG, "failed to create low light ambient brightness to bias spline.", e); 231 mLowLightAmbientBrightnessToBiasSpline = null; 232 } 233 if (mLowLightAmbientBrightnessToBiasSpline != null) { 234 if (mLowLightAmbientBrightnessToBiasSpline.interpolate(0.0f) != 0.0f || 235 mLowLightAmbientBrightnessToBiasSpline.interpolate(Float.POSITIVE_INFINITY) 236 != 1.0f) { 237 Slog.d(TAG, "invalid low light ambient brightness to bias spline, " 238 + "bias must begin at 0.0 and end at 1.0."); 239 mLowLightAmbientBrightnessToBiasSpline = null; 240 } 241 } 242 243 try { 244 mLowLightAmbientBrightnessToBiasSplineStrong = new Spline.LinearSpline( 245 lowLightAmbientBrightnessesStrong, lowLightAmbientBiasesStrong); 246 } catch (Exception e) { 247 Slog.e(TAG, "failed to create strong low light ambient brightness to bias spline.", e); 248 mLowLightAmbientBrightnessToBiasSplineStrong = null; 249 } 250 if (mLowLightAmbientBrightnessToBiasSplineStrong != null) { 251 if (mLowLightAmbientBrightnessToBiasSplineStrong.interpolate(0.0f) != 0.0f 252 || mLowLightAmbientBrightnessToBiasSplineStrong.interpolate( 253 Float.POSITIVE_INFINITY) != 1.0f) { 254 Slog.d(TAG, "invalid strong low light ambient brightness to bias spline, " 255 + "bias must begin at 0.0 and end at 1.0."); 256 mLowLightAmbientBrightnessToBiasSplineStrong = null; 257 } 258 } 259 260 try { 261 mHighLightAmbientBrightnessToBiasSpline = new Spline.LinearSpline( 262 highLightAmbientBrightnesses, highLightAmbientBiases); 263 } catch (Exception e) { 264 Slog.e(TAG, "failed to create high light ambient brightness to bias spline.", e); 265 mHighLightAmbientBrightnessToBiasSpline = null; 266 } 267 if (mHighLightAmbientBrightnessToBiasSpline != null) { 268 if (mHighLightAmbientBrightnessToBiasSpline.interpolate(0.0f) != 0.0f || 269 mHighLightAmbientBrightnessToBiasSpline.interpolate(Float.POSITIVE_INFINITY) 270 != 1.0f) { 271 Slog.d(TAG, "invalid high light ambient brightness to bias spline, " 272 + "bias must begin at 0.0 and end at 1.0."); 273 mHighLightAmbientBrightnessToBiasSpline = null; 274 } 275 } 276 277 try { 278 mHighLightAmbientBrightnessToBiasSplineStrong = new Spline.LinearSpline( 279 highLightAmbientBrightnessesStrong, highLightAmbientBiasesStrong); 280 } catch (Exception e) { 281 Slog.e(TAG, "failed to create strong high light ambient brightness to bias spline.", e); 282 mHighLightAmbientBrightnessToBiasSplineStrong = null; 283 } 284 if (mHighLightAmbientBrightnessToBiasSplineStrong != null) { 285 if (mHighLightAmbientBrightnessToBiasSplineStrong.interpolate(0.0f) != 0.0f 286 || mHighLightAmbientBrightnessToBiasSplineStrong.interpolate( 287 Float.POSITIVE_INFINITY) != 1.0f) { 288 Slog.d(TAG, "invalid strong high light ambient brightness to bias spline, " 289 + "bias must begin at 0.0 and end at 1.0."); 290 mHighLightAmbientBrightnessToBiasSplineStrong = null; 291 } 292 } 293 294 if (mLowLightAmbientBrightnessToBiasSpline != null && 295 mHighLightAmbientBrightnessToBiasSpline != null) { 296 if (lowLightAmbientBrightnesses[lowLightAmbientBrightnesses.length - 1] > 297 highLightAmbientBrightnesses[0]) { 298 Slog.d(TAG, "invalid low light and high light ambient brightness to bias spline " 299 + "combination, defined domains must not intersect."); 300 mLowLightAmbientBrightnessToBiasSpline = null; 301 mHighLightAmbientBrightnessToBiasSpline = null; 302 } 303 } 304 305 if (mLowLightAmbientBrightnessToBiasSplineStrong != null 306 && mHighLightAmbientBrightnessToBiasSplineStrong != null) { 307 if (lowLightAmbientBrightnessesStrong[lowLightAmbientBrightnessesStrong.length - 1] 308 > highLightAmbientBrightnessesStrong[0]) { 309 Slog.d(TAG, 310 "invalid strong low light and high light ambient brightness to bias " 311 + "spline combination, defined domains must not intersect."); 312 mLowLightAmbientBrightnessToBiasSplineStrong = null; 313 mHighLightAmbientBrightnessToBiasSplineStrong = null; 314 } 315 } 316 317 try { 318 mAmbientToDisplayColorTemperatureSpline = new Spline.LinearSpline( 319 ambientColorTemperatures, displayColorTemperatures); 320 } catch (Exception e) { 321 Slog.e(TAG, "failed to create ambient to display color temperature spline.", e); 322 mAmbientToDisplayColorTemperatureSpline = null; 323 } 324 325 try { 326 mStrongAmbientToDisplayColorTemperatureSpline = new Spline.LinearSpline( 327 strongAmbientColorTemperatures, strongDisplayColorTemperatures); 328 } catch (Exception e) { 329 Slog.e(TAG, "Failed to create strong ambient to display color temperature spline", e); 330 } 331 332 mColorDisplayServiceInternal = LocalServices.getService(ColorDisplayServiceInternal.class); 333 } 334 335 /** 336 * Enable/disable the controller. 337 * 338 * @param enabled 339 * Whether the controller should be on/off. 340 * 341 * @return Whether the method succeeded or not. 342 */ setEnabled(boolean enabled)343 public boolean setEnabled(boolean enabled) { 344 if (enabled) { 345 return enable(); 346 } else { 347 return disable(); 348 } 349 } 350 351 /** 352 * Enable/disable the stronger adjustment option. 353 * 354 * @param enabled whether the stronger adjustment option should be turned on 355 */ setStrongModeEnabled(boolean enabled)356 public void setStrongModeEnabled(boolean enabled) { 357 mStrongModeEnabled = enabled; 358 mColorDisplayServiceInternal.setDisplayWhiteBalanceAllowed(mLightModeAllowed 359 || mStrongModeEnabled); 360 if (mEnabled) { 361 updateAmbientColorTemperature(); 362 updateDisplayColorTemperature(); 363 } 364 } 365 366 /** 367 * Set an object to call back to when the display color temperature should be updated. 368 * 369 * @param callbacks 370 * The object to call back to. 371 * 372 * @return Whether the method succeeded or not. 373 */ setCallbacks(Callbacks callbacks)374 public boolean setCallbacks(Callbacks callbacks) { 375 if (mDisplayPowerControllerCallbacks == callbacks) { 376 return false; 377 } 378 mDisplayPowerControllerCallbacks = callbacks; 379 return true; 380 } 381 382 /** 383 * Enable/disable logging. 384 * 385 * @param loggingEnabled 386 * Whether logging should be on/off. 387 * 388 * @return Whether the method succeeded or not. 389 */ setLoggingEnabled(boolean loggingEnabled)390 public boolean setLoggingEnabled(boolean loggingEnabled) { 391 if (mLoggingEnabled == loggingEnabled) { 392 return false; 393 } 394 mLoggingEnabled = loggingEnabled; 395 mBrightnessSensor.setLoggingEnabled(loggingEnabled); 396 mBrightnessFilter.setLoggingEnabled(loggingEnabled); 397 mColorTemperatureSensor.setLoggingEnabled(loggingEnabled); 398 mColorTemperatureFilter.setLoggingEnabled(loggingEnabled); 399 mThrottler.setLoggingEnabled(loggingEnabled); 400 return true; 401 } 402 403 /** 404 * Set the ambient color temperature override. 405 * 406 * This is only applied when the ambient color temperature changes or is updated (in which case 407 * it overrides the ambient color temperature estimate); in other words, it doesn't necessarily 408 * change the display color temperature immediately. 409 * 410 * @param ambientColorTemperatureOverride 411 * The ambient color temperature override. 412 * 413 * @return Whether the method succeeded or not. 414 */ setAmbientColorTemperatureOverride(float ambientColorTemperatureOverride)415 public boolean setAmbientColorTemperatureOverride(float ambientColorTemperatureOverride) { 416 if (mAmbientColorTemperatureOverride == ambientColorTemperatureOverride) { 417 return false; 418 } 419 mAmbientColorTemperatureOverride = ambientColorTemperatureOverride; 420 return true; 421 } 422 423 /** 424 * Dump the state. 425 * 426 * @param writer 427 * The writer used to dump the state. 428 */ dump(PrintWriter writer)429 public void dump(PrintWriter writer) { 430 writer.println("DisplayWhiteBalanceController"); 431 writer.println(" mLoggingEnabled=" + mLoggingEnabled); 432 writer.println(" mEnabled=" + mEnabled); 433 writer.println(" mStrongModeEnabled=" + mStrongModeEnabled); 434 writer.println(" mDisplayPowerControllerCallbacks=" + mDisplayPowerControllerCallbacks); 435 mBrightnessSensor.dump(writer); 436 mBrightnessFilter.dump(writer); 437 mColorTemperatureSensor.dump(writer); 438 mColorTemperatureFilter.dump(writer); 439 mThrottler.dump(writer); 440 writer.println(" mLowLightAmbientColorTemperature=" + mLowLightAmbientColorTemperature); 441 writer.println(" mLowLightAmbientColorTemperatureStrong=" 442 + mLowLightAmbientColorTemperatureStrong); 443 writer.println(" mHighLightAmbientColorTemperature=" + mHighLightAmbientColorTemperature); 444 writer.println(" mHighLightAmbientColorTemperatureStrong=" 445 + mHighLightAmbientColorTemperatureStrong); 446 writer.println(" mAmbientColorTemperature=" + mAmbientColorTemperature); 447 writer.println(" mPendingAmbientColorTemperature=" + mPendingAmbientColorTemperature); 448 writer.println(" mLastAmbientColorTemperature=" + mLastAmbientColorTemperature); 449 writer.println(" mAmbientColorTemperatureHistory=" + mAmbientColorTemperatureHistory); 450 writer.println(" mAmbientColorTemperatureOverride=" + mAmbientColorTemperatureOverride); 451 writer.println(" mAmbientToDisplayColorTemperatureSpline=" 452 + mAmbientToDisplayColorTemperatureSpline); 453 writer.println(" mStrongAmbientToDisplayColorTemperatureSpline=" 454 + mStrongAmbientToDisplayColorTemperatureSpline); 455 writer.println(" mLowLightAmbientBrightnessToBiasSpline=" 456 + mLowLightAmbientBrightnessToBiasSpline); 457 writer.println(" mLowLightAmbientBrightnessToBiasSplineStrong=" 458 + mLowLightAmbientBrightnessToBiasSplineStrong); 459 writer.println(" mHighLightAmbientBrightnessToBiasSpline=" 460 + mHighLightAmbientBrightnessToBiasSpline); 461 writer.println(" mHighLightAmbientBrightnessToBiasSplineStrong=" 462 + mHighLightAmbientBrightnessToBiasSplineStrong); 463 } 464 465 @Override // AmbientSensor.AmbientBrightnessSensor.Callbacks onAmbientBrightnessChanged(float value)466 public void onAmbientBrightnessChanged(float value) { 467 final long time = System.currentTimeMillis(); 468 mBrightnessFilter.addValue(time, value); 469 updateAmbientColorTemperature(); 470 } 471 472 @Override // AmbientSensor.AmbientColorTemperatureSensor.Callbacks onAmbientColorTemperatureChanged(float value)473 public void onAmbientColorTemperatureChanged(float value) { 474 final long time = System.currentTimeMillis(); 475 mColorTemperatureFilter.addValue(time, value); 476 updateAmbientColorTemperature(); 477 } 478 479 /** 480 * Updates the ambient color temperature. 481 */ updateAmbientColorTemperature()482 public void updateAmbientColorTemperature() { 483 final long time = System.currentTimeMillis(); 484 final float lowLightAmbientColorTemperature = mStrongModeEnabled 485 ? mLowLightAmbientColorTemperatureStrong : mLowLightAmbientColorTemperature; 486 final float highLightAmbientColorTemperature = mStrongModeEnabled 487 ? mHighLightAmbientColorTemperatureStrong : mHighLightAmbientColorTemperature; 488 final Spline.LinearSpline lowLightAmbientBrightnessToBiasSpline = mStrongModeEnabled 489 ? mLowLightAmbientBrightnessToBiasSplineStrong 490 : mLowLightAmbientBrightnessToBiasSpline; 491 final Spline.LinearSpline highLightAmbientBrightnessToBiasSpline = mStrongModeEnabled 492 ? mHighLightAmbientBrightnessToBiasSplineStrong 493 : mHighLightAmbientBrightnessToBiasSpline; 494 495 float ambientColorTemperature = mColorTemperatureFilter.getEstimate(time); 496 mLatestAmbientColorTemperature = ambientColorTemperature; 497 498 if (mStrongModeEnabled) { 499 if (mStrongAmbientToDisplayColorTemperatureSpline != null 500 && ambientColorTemperature != -1.0f) { 501 ambientColorTemperature = 502 mStrongAmbientToDisplayColorTemperatureSpline.interpolate( 503 ambientColorTemperature); 504 } 505 } else { 506 if (mAmbientToDisplayColorTemperatureSpline != null 507 && ambientColorTemperature != -1.0f) { 508 ambientColorTemperature = 509 mAmbientToDisplayColorTemperatureSpline.interpolate( 510 ambientColorTemperature); 511 } 512 } 513 514 float ambientBrightness = mBrightnessFilter.getEstimate(time); 515 mLatestAmbientBrightness = ambientBrightness; 516 517 if (ambientColorTemperature != -1.0f && ambientBrightness != -1.0f 518 && lowLightAmbientBrightnessToBiasSpline != null) { 519 float bias = lowLightAmbientBrightnessToBiasSpline.interpolate(ambientBrightness); 520 ambientColorTemperature = 521 bias * ambientColorTemperature + (1.0f - bias) 522 * lowLightAmbientColorTemperature; 523 mLatestLowLightBias = bias; 524 } 525 if (ambientColorTemperature != -1.0f && ambientBrightness != -1.0f 526 && highLightAmbientBrightnessToBiasSpline != null) { 527 float bias = highLightAmbientBrightnessToBiasSpline.interpolate(ambientBrightness); 528 ambientColorTemperature = 529 (1.0f - bias) * ambientColorTemperature + bias 530 * highLightAmbientColorTemperature; 531 mLatestHighLightBias = bias; 532 } 533 534 if (mAmbientColorTemperatureOverride != -1.0f) { 535 if (mLoggingEnabled) { 536 Slog.d(TAG, "override ambient color temperature: " + ambientColorTemperature 537 + " => " + mAmbientColorTemperatureOverride); 538 } 539 ambientColorTemperature = mAmbientColorTemperatureOverride; 540 } 541 542 // When the display color temperature needs to be updated, we call DisplayPowerController to 543 // call our updateColorTemperature. The reason we don't call it directly is that we want 544 // all changes to the system to happen in a predictable order in DPC's main loop 545 // (updatePowerState). 546 if (ambientColorTemperature == -1.0f || mThrottler.throttle(ambientColorTemperature)) { 547 return; 548 } 549 550 if (mLoggingEnabled) { 551 Slog.d(TAG, "pending ambient color temperature: " + ambientColorTemperature); 552 } 553 mPendingAmbientColorTemperature = ambientColorTemperature; 554 if (mDisplayPowerControllerCallbacks != null) { 555 mDisplayPowerControllerCallbacks.updateWhiteBalance(); 556 } 557 } 558 559 /** 560 * Updates the display color temperature. 561 */ updateDisplayColorTemperature()562 public void updateDisplayColorTemperature() { 563 float ambientColorTemperature = -1.0f; 564 565 // If both the pending and the current ambient color temperatures are -1, it means the DWBC 566 // was just enabled, and we use the last ambient color temperature until new sensor events 567 // give us a better estimate. 568 if (mAmbientColorTemperature == -1.0f && mPendingAmbientColorTemperature == -1.0f) { 569 ambientColorTemperature = mLastAmbientColorTemperature; 570 } 571 572 // Otherwise, we use the pending ambient color temperature, but only if it's non-trivial 573 // and different than the current one. 574 if (mPendingAmbientColorTemperature != -1.0f 575 && mPendingAmbientColorTemperature != mAmbientColorTemperature) { 576 ambientColorTemperature = mPendingAmbientColorTemperature; 577 } 578 579 if (ambientColorTemperature == -1.0f) { 580 return; 581 } 582 583 mAmbientColorTemperature = ambientColorTemperature; 584 if (mLoggingEnabled) { 585 Slog.d(TAG, "ambient color temperature: " + mAmbientColorTemperature); 586 } 587 mPendingAmbientColorTemperature = -1.0f; 588 mAmbientColorTemperatureHistory.add(mAmbientColorTemperature); 589 Slog.d(TAG, "Display cct: " + mAmbientColorTemperature 590 + " Latest ambient cct: " + mLatestAmbientColorTemperature 591 + " Latest ambient lux: " + mLatestAmbientBrightness 592 + " Latest low light bias: " + mLatestLowLightBias 593 + " Latest high light bias: " + mLatestHighLightBias); 594 mColorDisplayServiceInternal.setDisplayWhiteBalanceColorTemperature( 595 (int) mAmbientColorTemperature); 596 mLastAmbientColorTemperature = mAmbientColorTemperature; 597 } 598 599 /** 600 * Calculate the adjusted brightness, in nits, due to the DWB color adaptation 601 * 602 * @param requestedBrightnessNits brightness the framework requires to be output 603 * @return the adjusted brightness the framework needs to output to counter the drop in 604 * brightness due to DWB, or the requestedBrightnessNits if an adjustment cannot be made 605 */ calculateAdjustedBrightnessNits(float requestedBrightnessNits)606 public float calculateAdjustedBrightnessNits(float requestedBrightnessNits) { 607 float luminance = mColorDisplayServiceInternal.getDisplayWhiteBalanceLuminance(); 608 if (luminance == -1) { 609 return requestedBrightnessNits; 610 } 611 float effectiveBrightness = requestedBrightnessNits * luminance; 612 return (requestedBrightnessNits - effectiveBrightness) + requestedBrightnessNits; 613 } 614 615 /** 616 * The DisplayWhiteBalanceController decouples itself from its parent (DisplayPowerController) 617 * by providing this interface to implement (and a method to set its callbacks object), and 618 * calling these methods. 619 */ 620 public interface Callbacks { 621 622 /** 623 * Called whenever the display white-balance state has changed. 624 * 625 * Usually, this means the estimated ambient color temperature has changed enough, and the 626 * display color temperature should be updated; but it is also called if settings change. 627 */ updateWhiteBalance()628 void updateWhiteBalance(); 629 } 630 validateArguments(AmbientSensor.AmbientBrightnessSensor brightnessSensor, AmbientFilter brightnessFilter, AmbientSensor.AmbientColorTemperatureSensor colorTemperatureSensor, AmbientFilter colorTemperatureFilter, DisplayWhiteBalanceThrottler throttler)631 private void validateArguments(AmbientSensor.AmbientBrightnessSensor brightnessSensor, 632 AmbientFilter brightnessFilter, 633 AmbientSensor.AmbientColorTemperatureSensor colorTemperatureSensor, 634 AmbientFilter colorTemperatureFilter, 635 DisplayWhiteBalanceThrottler throttler) { 636 Objects.requireNonNull(brightnessSensor, "brightnessSensor must not be null"); 637 Objects.requireNonNull(brightnessFilter, "brightnessFilter must not be null"); 638 Objects.requireNonNull(colorTemperatureSensor, 639 "colorTemperatureSensor must not be null"); 640 Objects.requireNonNull(colorTemperatureFilter, 641 "colorTemperatureFilter must not be null"); 642 Objects.requireNonNull(throttler, "throttler cannot be null"); 643 } 644 enable()645 private boolean enable() { 646 if (mEnabled) { 647 return false; 648 } 649 if (mLoggingEnabled) { 650 Slog.d(TAG, "enabling"); 651 } 652 mEnabled = true; 653 mBrightnessSensor.setEnabled(true); 654 mColorTemperatureSensor.setEnabled(true); 655 return true; 656 } 657 disable()658 private boolean disable() { 659 if (!mEnabled) { 660 return false; 661 } 662 if (mLoggingEnabled) { 663 Slog.d(TAG, "disabling"); 664 } 665 mEnabled = false; 666 mBrightnessSensor.setEnabled(false); 667 mBrightnessFilter.clear(); 668 mColorTemperatureSensor.setEnabled(false); 669 mColorTemperatureFilter.clear(); 670 mThrottler.clear(); 671 mAmbientColorTemperature = -1.0f; 672 mPendingAmbientColorTemperature = -1.0f; 673 mColorDisplayServiceInternal.resetDisplayWhiteBalanceColorTemperature(); 674 return true; 675 } 676 677 } 678