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("------------------------------"); 432 writer.println(" mLoggingEnabled=" + mLoggingEnabled); 433 writer.println(" mEnabled=" + mEnabled); 434 writer.println(" mStrongModeEnabled=" + mStrongModeEnabled); 435 writer.println(" mDisplayPowerControllerCallbacks=" + mDisplayPowerControllerCallbacks); 436 mBrightnessSensor.dump(writer); 437 mBrightnessFilter.dump(writer); 438 mColorTemperatureSensor.dump(writer); 439 mColorTemperatureFilter.dump(writer); 440 mThrottler.dump(writer); 441 writer.println(" mLowLightAmbientColorTemperature=" + mLowLightAmbientColorTemperature); 442 writer.println(" mLowLightAmbientColorTemperatureStrong=" 443 + mLowLightAmbientColorTemperatureStrong); 444 writer.println(" mHighLightAmbientColorTemperature=" + mHighLightAmbientColorTemperature); 445 writer.println(" mHighLightAmbientColorTemperatureStrong=" 446 + mHighLightAmbientColorTemperatureStrong); 447 writer.println(" mAmbientColorTemperature=" + mAmbientColorTemperature); 448 writer.println(" mPendingAmbientColorTemperature=" + mPendingAmbientColorTemperature); 449 writer.println(" mLastAmbientColorTemperature=" + mLastAmbientColorTemperature); 450 writer.println(" mAmbientColorTemperatureHistory=" + mAmbientColorTemperatureHistory); 451 writer.println(" mAmbientColorTemperatureOverride=" + mAmbientColorTemperatureOverride); 452 writer.println(" mAmbientToDisplayColorTemperatureSpline=" 453 + mAmbientToDisplayColorTemperatureSpline); 454 writer.println(" mStrongAmbientToDisplayColorTemperatureSpline=" 455 + mStrongAmbientToDisplayColorTemperatureSpline); 456 writer.println(" mLowLightAmbientBrightnessToBiasSpline=" 457 + mLowLightAmbientBrightnessToBiasSpline); 458 writer.println(" mLowLightAmbientBrightnessToBiasSplineStrong=" 459 + mLowLightAmbientBrightnessToBiasSplineStrong); 460 writer.println(" mHighLightAmbientBrightnessToBiasSpline=" 461 + mHighLightAmbientBrightnessToBiasSpline); 462 writer.println(" mHighLightAmbientBrightnessToBiasSplineStrong=" 463 + mHighLightAmbientBrightnessToBiasSplineStrong); 464 } 465 466 @Override // AmbientSensor.AmbientBrightnessSensor.Callbacks onAmbientBrightnessChanged(float value)467 public void onAmbientBrightnessChanged(float value) { 468 final long time = System.currentTimeMillis(); 469 mBrightnessFilter.addValue(time, value); 470 updateAmbientColorTemperature(); 471 } 472 473 @Override // AmbientSensor.AmbientColorTemperatureSensor.Callbacks onAmbientColorTemperatureChanged(float value)474 public void onAmbientColorTemperatureChanged(float value) { 475 final long time = System.currentTimeMillis(); 476 mColorTemperatureFilter.addValue(time, value); 477 updateAmbientColorTemperature(); 478 } 479 480 /** 481 * Updates the ambient color temperature. 482 */ updateAmbientColorTemperature()483 public void updateAmbientColorTemperature() { 484 final long time = System.currentTimeMillis(); 485 final float lowLightAmbientColorTemperature = mStrongModeEnabled 486 ? mLowLightAmbientColorTemperatureStrong : mLowLightAmbientColorTemperature; 487 final float highLightAmbientColorTemperature = mStrongModeEnabled 488 ? mHighLightAmbientColorTemperatureStrong : mHighLightAmbientColorTemperature; 489 final Spline.LinearSpline lowLightAmbientBrightnessToBiasSpline = mStrongModeEnabled 490 ? mLowLightAmbientBrightnessToBiasSplineStrong 491 : mLowLightAmbientBrightnessToBiasSpline; 492 final Spline.LinearSpline highLightAmbientBrightnessToBiasSpline = mStrongModeEnabled 493 ? mHighLightAmbientBrightnessToBiasSplineStrong 494 : mHighLightAmbientBrightnessToBiasSpline; 495 496 float ambientColorTemperature = mColorTemperatureFilter.getEstimate(time); 497 mLatestAmbientColorTemperature = ambientColorTemperature; 498 499 if (mStrongModeEnabled) { 500 if (mStrongAmbientToDisplayColorTemperatureSpline != null 501 && ambientColorTemperature != -1.0f) { 502 ambientColorTemperature = 503 mStrongAmbientToDisplayColorTemperatureSpline.interpolate( 504 ambientColorTemperature); 505 } 506 } else { 507 if (mAmbientToDisplayColorTemperatureSpline != null 508 && ambientColorTemperature != -1.0f) { 509 ambientColorTemperature = 510 mAmbientToDisplayColorTemperatureSpline.interpolate( 511 ambientColorTemperature); 512 } 513 } 514 515 float ambientBrightness = mBrightnessFilter.getEstimate(time); 516 mLatestAmbientBrightness = ambientBrightness; 517 518 if (ambientColorTemperature != -1.0f && ambientBrightness != -1.0f 519 && lowLightAmbientBrightnessToBiasSpline != null) { 520 float bias = lowLightAmbientBrightnessToBiasSpline.interpolate(ambientBrightness); 521 ambientColorTemperature = 522 bias * ambientColorTemperature + (1.0f - bias) 523 * lowLightAmbientColorTemperature; 524 mLatestLowLightBias = bias; 525 } 526 if (ambientColorTemperature != -1.0f && ambientBrightness != -1.0f 527 && highLightAmbientBrightnessToBiasSpline != null) { 528 float bias = highLightAmbientBrightnessToBiasSpline.interpolate(ambientBrightness); 529 ambientColorTemperature = 530 (1.0f - bias) * ambientColorTemperature + bias 531 * highLightAmbientColorTemperature; 532 mLatestHighLightBias = bias; 533 } 534 535 if (mAmbientColorTemperatureOverride != -1.0f) { 536 if (mLoggingEnabled) { 537 Slog.d(TAG, "override ambient color temperature: " + ambientColorTemperature 538 + " => " + mAmbientColorTemperatureOverride); 539 } 540 ambientColorTemperature = mAmbientColorTemperatureOverride; 541 } 542 543 // When the display color temperature needs to be updated, we call DisplayPowerController to 544 // call our updateColorTemperature. The reason we don't call it directly is that we want 545 // all changes to the system to happen in a predictable order in DPC's main loop 546 // (updatePowerState). 547 if (ambientColorTemperature == -1.0f || mThrottler.throttle(ambientColorTemperature)) { 548 return; 549 } 550 551 if (mLoggingEnabled) { 552 Slog.d(TAG, "pending ambient color temperature: " + ambientColorTemperature); 553 } 554 mPendingAmbientColorTemperature = ambientColorTemperature; 555 if (mDisplayPowerControllerCallbacks != null) { 556 mDisplayPowerControllerCallbacks.updateWhiteBalance(); 557 } 558 } 559 560 /** 561 * Updates the display color temperature. 562 */ updateDisplayColorTemperature()563 public void updateDisplayColorTemperature() { 564 float ambientColorTemperature = -1.0f; 565 566 // If both the pending and the current ambient color temperatures are -1, it means the DWBC 567 // was just enabled, and we use the last ambient color temperature until new sensor events 568 // give us a better estimate. 569 if (mAmbientColorTemperature == -1.0f && mPendingAmbientColorTemperature == -1.0f) { 570 ambientColorTemperature = mLastAmbientColorTemperature; 571 } 572 573 // Otherwise, we use the pending ambient color temperature, but only if it's non-trivial 574 // and different than the current one. 575 if (mPendingAmbientColorTemperature != -1.0f 576 && mPendingAmbientColorTemperature != mAmbientColorTemperature) { 577 ambientColorTemperature = mPendingAmbientColorTemperature; 578 } 579 580 if (ambientColorTemperature == -1.0f) { 581 return; 582 } 583 584 mAmbientColorTemperature = ambientColorTemperature; 585 if (mLoggingEnabled) { 586 Slog.d(TAG, "ambient color temperature: " + mAmbientColorTemperature); 587 } 588 mPendingAmbientColorTemperature = -1.0f; 589 mAmbientColorTemperatureHistory.add(mAmbientColorTemperature); 590 Slog.d(TAG, "Display cct: " + mAmbientColorTemperature 591 + " Latest ambient cct: " + mLatestAmbientColorTemperature 592 + " Latest ambient lux: " + mLatestAmbientBrightness 593 + " Latest low light bias: " + mLatestLowLightBias 594 + " Latest high light bias: " + mLatestHighLightBias); 595 mColorDisplayServiceInternal.setDisplayWhiteBalanceColorTemperature( 596 (int) mAmbientColorTemperature); 597 mLastAmbientColorTemperature = mAmbientColorTemperature; 598 } 599 600 /** 601 * Calculate the adjusted brightness, in nits, due to the DWB color adaptation 602 * 603 * @param requestedBrightnessNits brightness the framework requires to be output 604 * @return the adjusted brightness the framework needs to output to counter the drop in 605 * brightness due to DWB, or the requestedBrightnessNits if an adjustment cannot be made 606 */ calculateAdjustedBrightnessNits(float requestedBrightnessNits)607 public float calculateAdjustedBrightnessNits(float requestedBrightnessNits) { 608 float luminance = mColorDisplayServiceInternal.getDisplayWhiteBalanceLuminance(); 609 if (luminance == -1) { 610 return requestedBrightnessNits; 611 } 612 float effectiveBrightness = requestedBrightnessNits * luminance; 613 return (requestedBrightnessNits - effectiveBrightness) + requestedBrightnessNits; 614 } 615 616 /** 617 * The DisplayWhiteBalanceController decouples itself from its parent (DisplayPowerController) 618 * by providing this interface to implement (and a method to set its callbacks object), and 619 * calling these methods. 620 */ 621 public interface Callbacks { 622 623 /** 624 * Called whenever the display white-balance state has changed. 625 * 626 * Usually, this means the estimated ambient color temperature has changed enough, and the 627 * display color temperature should be updated; but it is also called if settings change. 628 */ updateWhiteBalance()629 void updateWhiteBalance(); 630 } 631 validateArguments(AmbientSensor.AmbientBrightnessSensor brightnessSensor, AmbientFilter brightnessFilter, AmbientSensor.AmbientColorTemperatureSensor colorTemperatureSensor, AmbientFilter colorTemperatureFilter, DisplayWhiteBalanceThrottler throttler)632 private void validateArguments(AmbientSensor.AmbientBrightnessSensor brightnessSensor, 633 AmbientFilter brightnessFilter, 634 AmbientSensor.AmbientColorTemperatureSensor colorTemperatureSensor, 635 AmbientFilter colorTemperatureFilter, 636 DisplayWhiteBalanceThrottler throttler) { 637 Objects.requireNonNull(brightnessSensor, "brightnessSensor must not be null"); 638 Objects.requireNonNull(brightnessFilter, "brightnessFilter must not be null"); 639 Objects.requireNonNull(colorTemperatureSensor, 640 "colorTemperatureSensor must not be null"); 641 Objects.requireNonNull(colorTemperatureFilter, 642 "colorTemperatureFilter must not be null"); 643 Objects.requireNonNull(throttler, "throttler cannot be null"); 644 } 645 enable()646 private boolean enable() { 647 if (mEnabled) { 648 return false; 649 } 650 if (mLoggingEnabled) { 651 Slog.d(TAG, "enabling"); 652 } 653 mEnabled = true; 654 mBrightnessSensor.setEnabled(true); 655 mColorTemperatureSensor.setEnabled(true); 656 return true; 657 } 658 disable()659 private boolean disable() { 660 if (!mEnabled) { 661 return false; 662 } 663 if (mLoggingEnabled) { 664 Slog.d(TAG, "disabling"); 665 } 666 mEnabled = false; 667 mBrightnessSensor.setEnabled(false); 668 mBrightnessFilter.clear(); 669 mColorTemperatureSensor.setEnabled(false); 670 mColorTemperatureFilter.clear(); 671 mThrottler.clear(); 672 mAmbientColorTemperature = -1.0f; 673 mPendingAmbientColorTemperature = -1.0f; 674 mColorDisplayServiceInternal.resetDisplayWhiteBalanceColorTemperature(); 675 return true; 676 } 677 678 } 679