1 /* 2 * Copyright (C) 2016 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.color; 18 19 import static android.hardware.display.ColorDisplayManager.AUTO_MODE_CUSTOM_TIME; 20 import static android.hardware.display.ColorDisplayManager.AUTO_MODE_DISABLED; 21 import static android.hardware.display.ColorDisplayManager.AUTO_MODE_TWILIGHT; 22 import static android.hardware.display.ColorDisplayManager.COLOR_MODE_AUTOMATIC; 23 import static android.hardware.display.ColorDisplayManager.COLOR_MODE_BOOSTED; 24 import static android.hardware.display.ColorDisplayManager.COLOR_MODE_NATURAL; 25 import static android.hardware.display.ColorDisplayManager.COLOR_MODE_SATURATED; 26 import static android.hardware.display.ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MAX; 27 import static android.hardware.display.ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MIN; 28 29 import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY; 30 31 import android.Manifest; 32 import android.animation.Animator; 33 import android.animation.AnimatorListenerAdapter; 34 import android.animation.TypeEvaluator; 35 import android.animation.ValueAnimator; 36 import android.annotation.NonNull; 37 import android.annotation.Nullable; 38 import android.annotation.Size; 39 import android.annotation.UserIdInt; 40 import android.app.AlarmManager; 41 import android.content.BroadcastReceiver; 42 import android.content.ContentResolver; 43 import android.content.Context; 44 import android.content.Intent; 45 import android.content.IntentFilter; 46 import android.content.pm.PackageManager; 47 import android.content.pm.PackageManagerInternal; 48 import android.content.res.Resources; 49 import android.database.ContentObserver; 50 import android.hardware.display.ColorDisplayManager; 51 import android.hardware.display.ColorDisplayManager.AutoMode; 52 import android.hardware.display.ColorDisplayManager.ColorMode; 53 import android.hardware.display.IColorDisplayManager; 54 import android.hardware.display.Time; 55 import android.net.Uri; 56 import android.opengl.Matrix; 57 import android.os.Binder; 58 import android.os.Handler; 59 import android.os.Looper; 60 import android.os.Message; 61 import android.os.ParcelFileDescriptor; 62 import android.os.SystemProperties; 63 import android.os.UserHandle; 64 import android.provider.Settings.Secure; 65 import android.provider.Settings.System; 66 import android.util.MathUtils; 67 import android.util.Slog; 68 import android.util.SparseIntArray; 69 import android.view.Display; 70 import android.view.SurfaceControl; 71 import android.view.accessibility.AccessibilityManager; 72 import android.view.animation.AnimationUtils; 73 74 import com.android.internal.R; 75 import com.android.internal.annotations.VisibleForTesting; 76 import com.android.internal.util.DumpUtils; 77 import com.android.server.DisplayThread; 78 import com.android.server.LocalServices; 79 import com.android.server.SystemService; 80 import com.android.server.twilight.TwilightListener; 81 import com.android.server.twilight.TwilightManager; 82 import com.android.server.twilight.TwilightState; 83 84 import java.io.FileDescriptor; 85 import java.io.PrintWriter; 86 import java.lang.ref.WeakReference; 87 import java.time.DateTimeException; 88 import java.time.Instant; 89 import java.time.LocalDateTime; 90 import java.time.LocalTime; 91 import java.time.ZoneId; 92 import java.time.format.DateTimeParseException; 93 94 /** 95 * Controls the display's color transforms. 96 */ 97 public final class ColorDisplayService extends SystemService { 98 99 static final String TAG = "ColorDisplayService"; 100 101 /** 102 * The identity matrix, used if one of the given matrices is {@code null}. 103 */ 104 static final float[] MATRIX_IDENTITY = new float[16]; 105 106 static { Matrix.setIdentityM(MATRIX_IDENTITY, 0)107 Matrix.setIdentityM(MATRIX_IDENTITY, 0); 108 } 109 110 /** 111 * The transition time, in milliseconds, for Night Display to turn on/off. 112 */ 113 private static final long TRANSITION_DURATION = 3000L; 114 115 private static final int MSG_USER_CHANGED = 0; 116 private static final int MSG_SET_UP = 1; 117 private static final int MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE = 2; 118 private static final int MSG_APPLY_NIGHT_DISPLAY_ANIMATED = 3; 119 private static final int MSG_APPLY_GLOBAL_SATURATION = 4; 120 private static final int MSG_APPLY_DISPLAY_WHITE_BALANCE = 5; 121 private static final int MSG_APPLY_REDUCE_BRIGHT_COLORS = 6; 122 123 /** 124 * Return value if a setting has not been set. 125 */ 126 private static final int NOT_SET = -1; 127 128 /** 129 * Evaluator used to animate color matrix transitions. 130 */ 131 private static final ColorMatrixEvaluator COLOR_MATRIX_EVALUATOR = new ColorMatrixEvaluator(); 132 /** 133 * Matrix and offset used for converting color to grayscale. 134 */ 135 private static final float[] MATRIX_GRAYSCALE = new float[]{ 136 .2126f, .2126f, .2126f, 0f, 137 .7152f, .7152f, .7152f, 0f, 138 .0722f, .0722f, .0722f, 0f, 139 0f, 0f, 0f, 1f 140 }; 141 142 /** 143 * Matrix and offset used for luminance inversion. Represents a transform from RGB to YIQ color 144 * space, rotation around the Y axis by 180 degrees, transform back to RGB color space, and 145 * subtraction from 1. The last row represents a non-multiplied addition, see surfaceflinger's 146 * ProgramCache for full implementation details. 147 */ 148 private static final float[] MATRIX_INVERT_COLOR = new float[]{ 149 0.402f, -0.598f, -0.599f, 0f, 150 -1.174f, -0.174f, -1.175f, 0f, 151 -0.228f, -0.228f, 0.772f, 0f, 152 1f, 1f, 1f, 1f 153 }; 154 155 @VisibleForTesting 156 final DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController = 157 new DisplayWhiteBalanceTintController(); 158 private final NightDisplayTintController mNightDisplayTintController = 159 new NightDisplayTintController(); 160 private final TintController mGlobalSaturationTintController = 161 new GlobalSaturationTintController(); 162 private final ReduceBrightColorsTintController mReduceBrightColorsTintController = 163 new ReduceBrightColorsTintController(); 164 165 private final Handler mHandler; 166 167 private final AppSaturationController mAppSaturationController = new AppSaturationController(); 168 169 private int mCurrentUser = UserHandle.USER_NULL; 170 private ContentObserver mUserSetupObserver; 171 private boolean mBootCompleted; 172 173 private ContentObserver mContentObserver; 174 175 private DisplayWhiteBalanceListener mDisplayWhiteBalanceListener; 176 private ReduceBrightColorsListener mReduceBrightColorsListener; 177 178 private NightDisplayAutoMode mNightDisplayAutoMode; 179 180 /** 181 * Map of color modes -> display composition colorspace 182 */ 183 private SparseIntArray mColorModeCompositionColorSpaces = null; 184 ColorDisplayService(Context context)185 public ColorDisplayService(Context context) { 186 super(context); 187 mHandler = new TintHandler(DisplayThread.get().getLooper()); 188 } 189 190 @Override onStart()191 public void onStart() { 192 publishBinderService(Context.COLOR_DISPLAY_SERVICE, new BinderService()); 193 publishLocalService(ColorDisplayServiceInternal.class, new ColorDisplayServiceInternal()); 194 publishLocalService(DisplayTransformManager.class, new DisplayTransformManager()); 195 } 196 197 @Override onBootPhase(int phase)198 public void onBootPhase(int phase) { 199 if (phase >= PHASE_BOOT_COMPLETED) { 200 mBootCompleted = true; 201 202 // Register listeners now that boot is complete. 203 if (mCurrentUser != UserHandle.USER_NULL && mUserSetupObserver == null) { 204 mHandler.sendEmptyMessage(MSG_SET_UP); 205 } 206 } 207 } 208 209 @Override onUserStarting(@onNull TargetUser user)210 public void onUserStarting(@NonNull TargetUser user) { 211 if (mCurrentUser == UserHandle.USER_NULL) { 212 final Message message = mHandler.obtainMessage(MSG_USER_CHANGED); 213 message.arg1 = user.getUserIdentifier(); 214 mHandler.sendMessage(message); 215 } 216 } 217 218 @Override onUserSwitching(@ullable TargetUser from, @NonNull TargetUser to)219 public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) { 220 final Message message = mHandler.obtainMessage(MSG_USER_CHANGED); 221 message.arg1 = to.getUserIdentifier(); 222 mHandler.sendMessage(message); 223 } 224 225 @Override onUserStopping(@onNull TargetUser user)226 public void onUserStopping(@NonNull TargetUser user) { 227 if (mCurrentUser == user.getUserIdentifier()) { 228 final Message message = mHandler.obtainMessage(MSG_USER_CHANGED); 229 message.arg1 = UserHandle.USER_NULL; 230 mHandler.sendMessage(message); 231 } 232 } 233 onUserChanged(int userHandle)234 @VisibleForTesting void onUserChanged(int userHandle) { 235 final ContentResolver cr = getContext().getContentResolver(); 236 237 if (mCurrentUser != UserHandle.USER_NULL) { 238 if (mUserSetupObserver != null) { 239 cr.unregisterContentObserver(mUserSetupObserver); 240 mUserSetupObserver = null; 241 } else if (mBootCompleted) { 242 tearDown(); 243 } 244 } 245 246 mCurrentUser = userHandle; 247 248 if (mCurrentUser != UserHandle.USER_NULL) { 249 if (!isUserSetupCompleted(cr, mCurrentUser)) { 250 mUserSetupObserver = new ContentObserver(mHandler) { 251 @Override 252 public void onChange(boolean selfChange, Uri uri) { 253 if (isUserSetupCompleted(cr, mCurrentUser)) { 254 cr.unregisterContentObserver(this); 255 mUserSetupObserver = null; 256 257 if (mBootCompleted) { 258 setUp(); 259 } 260 } 261 } 262 }; 263 cr.registerContentObserver(Secure.getUriFor(Secure.USER_SETUP_COMPLETE), 264 false /* notifyForDescendants */, mUserSetupObserver, mCurrentUser); 265 } else if (mBootCompleted) { 266 setUp(); 267 } 268 } 269 } 270 isUserSetupCompleted(ContentResolver cr, int userHandle)271 private static boolean isUserSetupCompleted(ContentResolver cr, int userHandle) { 272 return Secure.getIntForUser(cr, Secure.USER_SETUP_COMPLETE, 0, userHandle) == 1; 273 } 274 setUpDisplayCompositionColorSpaces(Resources res)275 private void setUpDisplayCompositionColorSpaces(Resources res) { 276 mColorModeCompositionColorSpaces = null; 277 278 final int[] colorModes = res.getIntArray(R.array.config_displayCompositionColorModes); 279 if (colorModes == null) { 280 return; 281 } 282 283 final int[] compSpaces = res.getIntArray(R.array.config_displayCompositionColorSpaces); 284 if (compSpaces == null) { 285 return; 286 } 287 288 if (colorModes.length != compSpaces.length) { 289 Slog.e(TAG, "Number of composition color spaces doesn't match specified color modes"); 290 return; 291 } 292 293 mColorModeCompositionColorSpaces = new SparseIntArray(colorModes.length); 294 for (int i = 0; i < colorModes.length; i++) { 295 mColorModeCompositionColorSpaces.put(colorModes[i], compSpaces[i]); 296 } 297 } 298 setUp()299 private void setUp() { 300 Slog.d(TAG, "setUp: currentUser=" + mCurrentUser); 301 302 // Listen for external changes to any of the settings. 303 if (mContentObserver == null) { 304 mContentObserver = new ContentObserver(mHandler) { 305 @Override 306 public void onChange(boolean selfChange, Uri uri) { 307 super.onChange(selfChange, uri); 308 309 final String setting = uri == null ? null : uri.getLastPathSegment(); 310 if (setting != null) { 311 switch (setting) { 312 case Secure.NIGHT_DISPLAY_ACTIVATED: 313 final boolean activated = mNightDisplayTintController 314 .isActivatedSetting(); 315 if (mNightDisplayTintController.isActivatedStateNotSet() 316 || mNightDisplayTintController.isActivated() != activated) { 317 mNightDisplayTintController.setActivated(activated); 318 } 319 break; 320 case Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE: 321 final int temperature = mNightDisplayTintController 322 .getColorTemperatureSetting(); 323 if (mNightDisplayTintController.getColorTemperature() 324 != temperature) { 325 mNightDisplayTintController 326 .onColorTemperatureChanged(temperature); 327 } 328 break; 329 case Secure.NIGHT_DISPLAY_AUTO_MODE: 330 onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal()); 331 break; 332 case Secure.NIGHT_DISPLAY_CUSTOM_START_TIME: 333 onNightDisplayCustomStartTimeChanged( 334 getNightDisplayCustomStartTimeInternal().getLocalTime()); 335 break; 336 case Secure.NIGHT_DISPLAY_CUSTOM_END_TIME: 337 onNightDisplayCustomEndTimeChanged( 338 getNightDisplayCustomEndTimeInternal().getLocalTime()); 339 break; 340 case System.DISPLAY_COLOR_MODE: 341 onDisplayColorModeChanged(getColorModeInternal()); 342 break; 343 case Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED: 344 onAccessibilityInversionChanged(); 345 onAccessibilityActivated(); 346 break; 347 case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED: 348 onAccessibilityDaltonizerChanged(); 349 onAccessibilityActivated(); 350 break; 351 case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER: 352 onAccessibilityDaltonizerChanged(); 353 break; 354 case Secure.DISPLAY_WHITE_BALANCE_ENABLED: 355 updateDisplayWhiteBalanceStatus(); 356 break; 357 case Secure.REDUCE_BRIGHT_COLORS_ACTIVATED: 358 onReduceBrightColorsActivationChanged(/*userInitiated*/ true); 359 mHandler.sendEmptyMessage(MSG_APPLY_REDUCE_BRIGHT_COLORS); 360 break; 361 case Secure.REDUCE_BRIGHT_COLORS_LEVEL: 362 onReduceBrightColorsStrengthLevelChanged(); 363 mHandler.sendEmptyMessage(MSG_APPLY_REDUCE_BRIGHT_COLORS); 364 break; 365 } 366 } 367 } 368 }; 369 } 370 final ContentResolver cr = getContext().getContentResolver(); 371 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_ACTIVATED), 372 false /* notifyForDescendants */, mContentObserver, mCurrentUser); 373 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE), 374 false /* notifyForDescendants */, mContentObserver, mCurrentUser); 375 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_AUTO_MODE), 376 false /* notifyForDescendants */, mContentObserver, mCurrentUser); 377 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_START_TIME), 378 false /* notifyForDescendants */, mContentObserver, mCurrentUser); 379 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_END_TIME), 380 false /* notifyForDescendants */, mContentObserver, mCurrentUser); 381 cr.registerContentObserver(System.getUriFor(System.DISPLAY_COLOR_MODE), 382 false /* notifyForDescendants */, mContentObserver, mCurrentUser); 383 cr.registerContentObserver(Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED), 384 false /* notifyForDescendants */, mContentObserver, mCurrentUser); 385 cr.registerContentObserver( 386 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED), 387 false /* notifyForDescendants */, mContentObserver, mCurrentUser); 388 cr.registerContentObserver(Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER), 389 false /* notifyForDescendants */, mContentObserver, mCurrentUser); 390 cr.registerContentObserver(Secure.getUriFor(Secure.DISPLAY_WHITE_BALANCE_ENABLED), 391 false /* notifyForDescendants */, mContentObserver, mCurrentUser); 392 cr.registerContentObserver(Secure.getUriFor(Secure.REDUCE_BRIGHT_COLORS_ACTIVATED), 393 false /* notifyForDescendants */, mContentObserver, mCurrentUser); 394 cr.registerContentObserver(Secure.getUriFor(Secure.REDUCE_BRIGHT_COLORS_LEVEL), 395 false /* notifyForDescendants */, mContentObserver, mCurrentUser); 396 397 // Apply the accessibility settings first, since they override most other settings. 398 onAccessibilityInversionChanged(); 399 onAccessibilityDaltonizerChanged(); 400 401 setUpDisplayCompositionColorSpaces(getContext().getResources()); 402 403 // Set the color mode, if valid, and immediately apply the updated tint matrix based on the 404 // existing activated state. This ensures consistency of tint across the color mode change. 405 onDisplayColorModeChanged(getColorModeInternal()); 406 407 if (mNightDisplayTintController.isAvailable(getContext())) { 408 // Reset the activated state. 409 mNightDisplayTintController.setActivated(null); 410 411 // Prepare the night display color transformation matrix. 412 mNightDisplayTintController 413 .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix()); 414 mNightDisplayTintController 415 .setMatrix(mNightDisplayTintController.getColorTemperatureSetting()); 416 417 // Initialize the current auto mode. 418 onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal()); 419 420 // Force the initialization of the current saved activation state. 421 if (mNightDisplayTintController.isActivatedStateNotSet()) { 422 mNightDisplayTintController 423 .setActivated(mNightDisplayTintController.isActivatedSetting()); 424 } 425 } 426 427 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) { 428 // Prepare the display white balance transform matrix. 429 mDisplayWhiteBalanceTintController.setUp(getContext(), true /* needsLinear */); 430 431 updateDisplayWhiteBalanceStatus(); 432 } 433 434 if (mReduceBrightColorsTintController.isAvailable(getContext())) { 435 mReduceBrightColorsTintController 436 .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix()); 437 onReduceBrightColorsStrengthLevelChanged(); 438 final boolean reset = resetReduceBrightColors(); 439 if (!reset) { 440 onReduceBrightColorsActivationChanged(/*userInitiated*/ false); 441 mHandler.sendEmptyMessage(MSG_APPLY_REDUCE_BRIGHT_COLORS); 442 } 443 } 444 } 445 tearDown()446 private void tearDown() { 447 Slog.d(TAG, "tearDown: currentUser=" + mCurrentUser); 448 449 if (mContentObserver != null) { 450 getContext().getContentResolver().unregisterContentObserver(mContentObserver); 451 } 452 453 if (mNightDisplayTintController.isAvailable(getContext())) { 454 if (mNightDisplayAutoMode != null) { 455 mNightDisplayAutoMode.onStop(); 456 mNightDisplayAutoMode = null; 457 } 458 mNightDisplayTintController.endAnimator(); 459 } 460 461 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) { 462 mDisplayWhiteBalanceTintController.endAnimator(); 463 } 464 465 if (mGlobalSaturationTintController.isAvailable(getContext())) { 466 mGlobalSaturationTintController.setActivated(null); 467 } 468 469 if (mReduceBrightColorsTintController.isAvailable(getContext())) { 470 mReduceBrightColorsTintController.setActivated(null); 471 } 472 } 473 resetReduceBrightColors()474 private boolean resetReduceBrightColors() { 475 if (mCurrentUser == UserHandle.USER_NULL) { 476 return false; 477 } 478 479 final boolean isSettingActivated = Secure.getIntForUser(getContext().getContentResolver(), 480 Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 0, mCurrentUser) == 1; 481 final boolean shouldResetOnReboot = Secure.getIntForUser(getContext().getContentResolver(), 482 Secure.REDUCE_BRIGHT_COLORS_PERSIST_ACROSS_REBOOTS, 0, mCurrentUser) == 0; 483 if (isSettingActivated && mReduceBrightColorsTintController.isActivatedStateNotSet() 484 && shouldResetOnReboot) { 485 return Secure.putIntForUser(getContext().getContentResolver(), 486 Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 0, mCurrentUser); 487 } 488 return false; 489 } 490 onNightDisplayAutoModeChanged(int autoMode)491 private void onNightDisplayAutoModeChanged(int autoMode) { 492 Slog.d(TAG, "onNightDisplayAutoModeChanged: autoMode=" + autoMode); 493 494 if (mNightDisplayAutoMode != null) { 495 mNightDisplayAutoMode.onStop(); 496 mNightDisplayAutoMode = null; 497 } 498 499 if (autoMode == AUTO_MODE_CUSTOM_TIME) { 500 mNightDisplayAutoMode = new CustomNightDisplayAutoMode(); 501 } else if (autoMode == AUTO_MODE_TWILIGHT) { 502 mNightDisplayAutoMode = new TwilightNightDisplayAutoMode(); 503 } 504 505 if (mNightDisplayAutoMode != null) { 506 mNightDisplayAutoMode.onStart(); 507 } 508 } 509 onNightDisplayCustomStartTimeChanged(LocalTime startTime)510 private void onNightDisplayCustomStartTimeChanged(LocalTime startTime) { 511 Slog.d(TAG, "onNightDisplayCustomStartTimeChanged: startTime=" + startTime); 512 513 if (mNightDisplayAutoMode != null) { 514 mNightDisplayAutoMode.onCustomStartTimeChanged(startTime); 515 } 516 } 517 onNightDisplayCustomEndTimeChanged(LocalTime endTime)518 private void onNightDisplayCustomEndTimeChanged(LocalTime endTime) { 519 Slog.d(TAG, "onNightDisplayCustomEndTimeChanged: endTime=" + endTime); 520 521 if (mNightDisplayAutoMode != null) { 522 mNightDisplayAutoMode.onCustomEndTimeChanged(endTime); 523 } 524 } 525 getCompositionColorSpace(int mode)526 private int getCompositionColorSpace(int mode) { 527 if (mColorModeCompositionColorSpaces == null) { 528 return Display.COLOR_MODE_INVALID; 529 } 530 531 return mColorModeCompositionColorSpaces.get(mode, Display.COLOR_MODE_INVALID); 532 } 533 onDisplayColorModeChanged(int mode)534 private void onDisplayColorModeChanged(int mode) { 535 if (mode == NOT_SET) { 536 return; 537 } 538 539 mNightDisplayTintController.cancelAnimator(); 540 mDisplayWhiteBalanceTintController.cancelAnimator(); 541 542 if (mNightDisplayTintController.isAvailable(getContext())) { 543 mNightDisplayTintController 544 .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode)); 545 mNightDisplayTintController 546 .setMatrix(mNightDisplayTintController.getColorTemperatureSetting()); 547 } 548 549 // dtm.setColorMode() needs to be called before 550 // updateDisplayWhiteBalanceStatus(), this is because the latter calls 551 // DisplayTransformManager.needsLinearColorMatrix(), therefore it is dependent 552 // on the state of DisplayTransformManager. 553 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class); 554 dtm.setColorMode(mode, mNightDisplayTintController.getMatrix(), 555 getCompositionColorSpace(mode)); 556 557 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) { 558 updateDisplayWhiteBalanceStatus(); 559 } 560 } 561 onAccessibilityActivated()562 private void onAccessibilityActivated() { 563 onDisplayColorModeChanged(getColorModeInternal()); 564 } 565 isAccessiblityDaltonizerEnabled()566 private boolean isAccessiblityDaltonizerEnabled() { 567 return Secure.getIntForUser(getContext().getContentResolver(), 568 Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, mCurrentUser) != 0; 569 } 570 isAccessiblityInversionEnabled()571 private boolean isAccessiblityInversionEnabled() { 572 return Secure.getIntForUser(getContext().getContentResolver(), 573 Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, mCurrentUser) != 0; 574 } 575 isAccessibilityEnabled()576 private boolean isAccessibilityEnabled() { 577 return isAccessiblityDaltonizerEnabled() || isAccessiblityInversionEnabled(); 578 } 579 580 /** 581 * Apply the accessibility daltonizer transform based on the settings value. 582 */ onAccessibilityDaltonizerChanged()583 private void onAccessibilityDaltonizerChanged() { 584 if (mCurrentUser == UserHandle.USER_NULL) { 585 return; 586 } 587 final int daltonizerMode = isAccessiblityDaltonizerEnabled() 588 ? Secure.getIntForUser(getContext().getContentResolver(), 589 Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, 590 AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY, mCurrentUser) 591 : AccessibilityManager.DALTONIZER_DISABLED; 592 593 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class); 594 if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) { 595 // Monochromacy isn't supported by the native Daltonizer implementation; use grayscale. 596 dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE, 597 MATRIX_GRAYSCALE); 598 dtm.setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED); 599 } else { 600 dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE, null); 601 dtm.setDaltonizerMode(daltonizerMode); 602 } 603 } 604 605 /** 606 * Apply the accessibility inversion transform based on the settings value. 607 */ onAccessibilityInversionChanged()608 private void onAccessibilityInversionChanged() { 609 if (mCurrentUser == UserHandle.USER_NULL) { 610 return; 611 } 612 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class); 613 dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_INVERT_COLOR, 614 isAccessiblityInversionEnabled() ? MATRIX_INVERT_COLOR : null); 615 } 616 onReduceBrightColorsActivationChanged(boolean userInitiated)617 private void onReduceBrightColorsActivationChanged(boolean userInitiated) { 618 if (mCurrentUser == UserHandle.USER_NULL) { 619 return; 620 } 621 final boolean activated = Secure.getIntForUser(getContext().getContentResolver(), 622 Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 0, mCurrentUser) == 1; 623 mReduceBrightColorsTintController.setActivated(activated); 624 if (mReduceBrightColorsListener != null) { 625 mReduceBrightColorsListener.onReduceBrightColorsActivationChanged(activated, 626 userInitiated); 627 } 628 } 629 onReduceBrightColorsStrengthLevelChanged()630 private void onReduceBrightColorsStrengthLevelChanged() { 631 if (mCurrentUser == UserHandle.USER_NULL) { 632 return; 633 } 634 int strength = Secure.getIntForUser(getContext().getContentResolver(), 635 Secure.REDUCE_BRIGHT_COLORS_LEVEL, NOT_SET, mCurrentUser); 636 if (strength == NOT_SET) { 637 strength = getContext().getResources().getInteger( 638 R.integer.config_reduceBrightColorsStrengthDefault); 639 } 640 mReduceBrightColorsTintController.setMatrix(strength); 641 if (mReduceBrightColorsListener != null) { 642 mReduceBrightColorsListener.onReduceBrightColorsStrengthChanged(strength); 643 } 644 } 645 646 /** 647 * Applies current color temperature matrix, or removes it if deactivated. 648 * 649 * @param immediate {@code true} skips transition animation 650 */ applyTint(TintController tintController, boolean immediate)651 private void applyTint(TintController tintController, boolean immediate) { 652 tintController.cancelAnimator(); 653 654 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class); 655 final float[] from = dtm.getColorMatrix(tintController.getLevel()); 656 final float[] to = tintController.getMatrix(); 657 658 if (immediate) { 659 dtm.setColorMatrix(tintController.getLevel(), to); 660 } else { 661 TintValueAnimator valueAnimator = TintValueAnimator.ofMatrix(COLOR_MATRIX_EVALUATOR, 662 from == null ? MATRIX_IDENTITY : from, to); 663 tintController.setAnimator(valueAnimator); 664 valueAnimator.setDuration(TRANSITION_DURATION); 665 valueAnimator.setInterpolator(AnimationUtils.loadInterpolator( 666 getContext(), android.R.interpolator.fast_out_slow_in)); 667 valueAnimator.addUpdateListener((ValueAnimator animator) -> { 668 final float[] value = (float[]) animator.getAnimatedValue(); 669 dtm.setColorMatrix(tintController.getLevel(), value); 670 ((TintValueAnimator) animator).updateMinMaxComponents(); 671 }); 672 valueAnimator.addListener(new AnimatorListenerAdapter() { 673 674 private boolean mIsCancelled; 675 676 @Override 677 public void onAnimationCancel(Animator animator) { 678 mIsCancelled = true; 679 } 680 681 @Override 682 public void onAnimationEnd(Animator animator) { 683 TintValueAnimator t = (TintValueAnimator) animator; 684 Slog.d(TAG, tintController.getClass().getSimpleName() 685 + " Animation cancelled: " + mIsCancelled 686 + " to matrix: " + TintController.matrixToString(to, 16) 687 + " min matrix coefficients: " 688 + TintController.matrixToString(t.getMin(), 16) 689 + " max matrix coefficients: " 690 + TintController.matrixToString(t.getMax(), 16)); 691 if (!mIsCancelled) { 692 // Ensure final color matrix is set at the end of the animation. If the 693 // animation is cancelled then don't set the final color matrix so the new 694 // animator can pick up from where this one left off. 695 dtm.setColorMatrix(tintController.getLevel(), to); 696 } 697 tintController.setAnimator(null); 698 } 699 }); 700 valueAnimator.start(); 701 } 702 } 703 704 /** 705 * Returns the first date time corresponding to the local time that occurs before the provided 706 * date time. 707 * 708 * @param compareTime the LocalDateTime to compare against 709 * @return the prior LocalDateTime corresponding to this local time 710 */ 711 @VisibleForTesting getDateTimeBefore(LocalTime localTime, LocalDateTime compareTime)712 static LocalDateTime getDateTimeBefore(LocalTime localTime, LocalDateTime compareTime) { 713 final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(), 714 compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute()); 715 716 // Check if the local time has passed, if so return the same time yesterday. 717 return ldt.isAfter(compareTime) ? ldt.minusDays(1) : ldt; 718 } 719 720 /** 721 * Returns the first date time corresponding to this local time that occurs after the provided 722 * date time. 723 * 724 * @param compareTime the LocalDateTime to compare against 725 * @return the next LocalDateTime corresponding to this local time 726 */ 727 @VisibleForTesting getDateTimeAfter(LocalTime localTime, LocalDateTime compareTime)728 static LocalDateTime getDateTimeAfter(LocalTime localTime, LocalDateTime compareTime) { 729 final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(), 730 compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute()); 731 732 // Check if the local time has passed, if so return the same time tomorrow. 733 return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt; 734 } 735 736 @VisibleForTesting updateDisplayWhiteBalanceStatus()737 void updateDisplayWhiteBalanceStatus() { 738 boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated(); 739 mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled() 740 && !mNightDisplayTintController.isActivated() 741 && !isAccessibilityEnabled() 742 && DisplayTransformManager.needsLinearColorMatrix()); 743 boolean activated = mDisplayWhiteBalanceTintController.isActivated(); 744 745 if (mDisplayWhiteBalanceListener != null && oldActivated != activated) { 746 mDisplayWhiteBalanceListener.onDisplayWhiteBalanceStatusChanged(activated); 747 } 748 749 // If disabled, clear the tint. If enabled, do nothing more here and let the next 750 // temperature update set the correct tint. 751 if (!activated) { 752 mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE); 753 } 754 } 755 setDisplayWhiteBalanceSettingEnabled(boolean enabled)756 private boolean setDisplayWhiteBalanceSettingEnabled(boolean enabled) { 757 if (mCurrentUser == UserHandle.USER_NULL) { 758 return false; 759 } 760 return Secure.putIntForUser(getContext().getContentResolver(), 761 Secure.DISPLAY_WHITE_BALANCE_ENABLED, 762 enabled ? 1 : 0, mCurrentUser); 763 } 764 isDisplayWhiteBalanceSettingEnabled()765 private boolean isDisplayWhiteBalanceSettingEnabled() { 766 if (mCurrentUser == UserHandle.USER_NULL) { 767 return false; 768 } 769 return Secure.getIntForUser(getContext().getContentResolver(), 770 Secure.DISPLAY_WHITE_BALANCE_ENABLED, 771 getContext().getResources() 772 .getBoolean(R.bool.config_displayWhiteBalanceEnabledDefault) ? 1 773 : 0, 774 mCurrentUser) == 1; 775 } 776 setReduceBrightColorsActivatedInternal(boolean activated)777 private boolean setReduceBrightColorsActivatedInternal(boolean activated) { 778 if (mCurrentUser == UserHandle.USER_NULL) { 779 return false; 780 } 781 return Secure.putIntForUser(getContext().getContentResolver(), 782 Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, activated ? 1 : 0, mCurrentUser); 783 } 784 setReduceBrightColorsStrengthInternal(int strength)785 private boolean setReduceBrightColorsStrengthInternal(int strength) { 786 if (mCurrentUser == UserHandle.USER_NULL) { 787 return false; 788 } 789 return Secure.putIntForUser(getContext().getContentResolver(), 790 Secure.REDUCE_BRIGHT_COLORS_LEVEL, strength, mCurrentUser); 791 } 792 isDeviceColorManagedInternal()793 private boolean isDeviceColorManagedInternal() { 794 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class); 795 return dtm.isDeviceColorManaged(); 796 } 797 getTransformCapabilitiesInternal()798 private int getTransformCapabilitiesInternal() { 799 int availabilityFlags = ColorDisplayManager.CAPABILITY_NONE; 800 if (SurfaceControl.getProtectedContentSupport()) { 801 availabilityFlags |= ColorDisplayManager.CAPABILITY_PROTECTED_CONTENT; 802 } 803 final Resources res = getContext().getResources(); 804 if (res.getBoolean(R.bool.config_setColorTransformAccelerated)) { 805 availabilityFlags |= ColorDisplayManager.CAPABILITY_HARDWARE_ACCELERATION_GLOBAL; 806 } 807 if (res.getBoolean(R.bool.config_setColorTransformAcceleratedPerLayer)) { 808 availabilityFlags |= ColorDisplayManager.CAPABILITY_HARDWARE_ACCELERATION_PER_APP; 809 } 810 return availabilityFlags; 811 } 812 setNightDisplayAutoModeInternal(@utoMode int autoMode)813 private boolean setNightDisplayAutoModeInternal(@AutoMode int autoMode) { 814 if (getNightDisplayAutoModeInternal() != autoMode) { 815 Secure.putStringForUser(getContext().getContentResolver(), 816 Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, 817 null, 818 mCurrentUser); 819 } 820 return Secure.putIntForUser(getContext().getContentResolver(), 821 Secure.NIGHT_DISPLAY_AUTO_MODE, autoMode, mCurrentUser); 822 } 823 getNightDisplayAutoModeInternal()824 private int getNightDisplayAutoModeInternal() { 825 int autoMode = getNightDisplayAutoModeRawInternal(); 826 if (autoMode == NOT_SET) { 827 autoMode = getContext().getResources().getInteger( 828 R.integer.config_defaultNightDisplayAutoMode); 829 } 830 if (autoMode != AUTO_MODE_DISABLED 831 && autoMode != AUTO_MODE_CUSTOM_TIME 832 && autoMode != AUTO_MODE_TWILIGHT) { 833 Slog.e(TAG, "Invalid autoMode: " + autoMode); 834 autoMode = AUTO_MODE_DISABLED; 835 } 836 return autoMode; 837 } 838 getNightDisplayAutoModeRawInternal()839 private int getNightDisplayAutoModeRawInternal() { 840 if (mCurrentUser == UserHandle.USER_NULL) { 841 return NOT_SET; 842 } 843 return Secure 844 .getIntForUser(getContext().getContentResolver(), Secure.NIGHT_DISPLAY_AUTO_MODE, 845 NOT_SET, mCurrentUser); 846 } 847 getNightDisplayCustomStartTimeInternal()848 private Time getNightDisplayCustomStartTimeInternal() { 849 int startTimeValue = Secure.getIntForUser(getContext().getContentResolver(), 850 Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, NOT_SET, mCurrentUser); 851 if (startTimeValue == NOT_SET) { 852 startTimeValue = getContext().getResources().getInteger( 853 R.integer.config_defaultNightDisplayCustomStartTime); 854 } 855 return new Time(LocalTime.ofSecondOfDay(startTimeValue / 1000)); 856 } 857 setNightDisplayCustomStartTimeInternal(Time startTime)858 private boolean setNightDisplayCustomStartTimeInternal(Time startTime) { 859 return Secure.putIntForUser(getContext().getContentResolver(), 860 Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, 861 startTime.getLocalTime().toSecondOfDay() * 1000, 862 mCurrentUser); 863 } 864 getNightDisplayCustomEndTimeInternal()865 private Time getNightDisplayCustomEndTimeInternal() { 866 int endTimeValue = Secure.getIntForUser(getContext().getContentResolver(), 867 Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, NOT_SET, mCurrentUser); 868 if (endTimeValue == NOT_SET) { 869 endTimeValue = getContext().getResources().getInteger( 870 R.integer.config_defaultNightDisplayCustomEndTime); 871 } 872 return new Time(LocalTime.ofSecondOfDay(endTimeValue / 1000)); 873 } 874 setNightDisplayCustomEndTimeInternal(Time endTime)875 private boolean setNightDisplayCustomEndTimeInternal(Time endTime) { 876 return Secure.putIntForUser(getContext().getContentResolver(), 877 Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.getLocalTime().toSecondOfDay() * 1000, 878 mCurrentUser); 879 } 880 881 /** 882 * Returns the last time the night display transform activation state was changed, or {@link 883 * LocalDateTime#MIN} if night display has never been activated. 884 */ getNightDisplayLastActivatedTimeSetting()885 private LocalDateTime getNightDisplayLastActivatedTimeSetting() { 886 final ContentResolver cr = getContext().getContentResolver(); 887 final String lastActivatedTime = Secure.getStringForUser( 888 cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, getContext().getUserId()); 889 if (lastActivatedTime != null) { 890 try { 891 return LocalDateTime.parse(lastActivatedTime); 892 } catch (DateTimeParseException ignored) { 893 } 894 // Uses the old epoch time. 895 try { 896 return LocalDateTime.ofInstant( 897 Instant.ofEpochMilli(Long.parseLong(lastActivatedTime)), 898 ZoneId.systemDefault()); 899 } catch (DateTimeException | NumberFormatException ignored) { 900 } 901 } 902 return LocalDateTime.MIN; 903 } 904 setSaturationLevelInternal(int saturationLevel)905 void setSaturationLevelInternal(int saturationLevel) { 906 final Message message = mHandler.obtainMessage(MSG_APPLY_GLOBAL_SATURATION); 907 message.arg1 = saturationLevel; 908 mHandler.sendMessage(message); 909 } 910 setAppSaturationLevelInternal(String callingPackageName, String affectedPackageName, int saturationLevel)911 boolean setAppSaturationLevelInternal(String callingPackageName, 912 String affectedPackageName, int saturationLevel) { 913 return mAppSaturationController 914 .setSaturationLevel(callingPackageName, affectedPackageName, mCurrentUser, 915 saturationLevel); 916 } 917 setColorModeInternal(@olorMode int colorMode)918 private void setColorModeInternal(@ColorMode int colorMode) { 919 if (!isColorModeAvailable(colorMode)) { 920 throw new IllegalArgumentException("Invalid colorMode: " + colorMode); 921 } 922 System.putIntForUser(getContext().getContentResolver(), System.DISPLAY_COLOR_MODE, 923 colorMode, 924 mCurrentUser); 925 } 926 getColorModeInternal()927 private @ColorMode int getColorModeInternal() { 928 final ContentResolver cr = getContext().getContentResolver(); 929 if (isAccessibilityEnabled()) { 930 // There are restrictions on the available color modes combined with a11y transforms. 931 final int a11yColorMode = getContext().getResources().getInteger( 932 R.integer.config_accessibilityColorMode); 933 if (a11yColorMode >= 0) { 934 return a11yColorMode; 935 } 936 } 937 938 int colorMode = System.getIntForUser(cr, System.DISPLAY_COLOR_MODE, -1, mCurrentUser); 939 if (colorMode == -1) { 940 // There might be a system property controlling color mode that we need to respect; if 941 // not, this will set a suitable default. 942 colorMode = getCurrentColorModeFromSystemProperties(); 943 } 944 945 // This happens when a color mode is no longer available (e.g., after system update or B&R) 946 // or the device does not support any color mode. 947 if (!isColorModeAvailable(colorMode)) { 948 final int[] mappedColorModes = getContext().getResources().getIntArray( 949 R.array.config_mappedColorModes); 950 if (colorMode == COLOR_MODE_BOOSTED && mappedColorModes.length > COLOR_MODE_NATURAL 951 && isColorModeAvailable(mappedColorModes[COLOR_MODE_NATURAL])) { 952 colorMode = COLOR_MODE_NATURAL; 953 } else if (colorMode == COLOR_MODE_SATURATED 954 && mappedColorModes.length > COLOR_MODE_AUTOMATIC 955 && isColorModeAvailable(mappedColorModes[COLOR_MODE_AUTOMATIC])) { 956 colorMode = COLOR_MODE_AUTOMATIC; 957 } else if (colorMode == COLOR_MODE_AUTOMATIC 958 && mappedColorModes.length > COLOR_MODE_SATURATED 959 && isColorModeAvailable(mappedColorModes[COLOR_MODE_SATURATED])) { 960 colorMode = COLOR_MODE_SATURATED; 961 } else { 962 colorMode = -1; 963 } 964 } 965 966 return colorMode; 967 } 968 969 /** 970 * Get the current color mode from system properties, or return -1 if invalid. 971 * 972 * See {@link DisplayTransformManager} 973 */ getCurrentColorModeFromSystemProperties()974 private @ColorMode int getCurrentColorModeFromSystemProperties() { 975 final int displayColorSetting = SystemProperties.getInt("persist.sys.sf.native_mode", 0); 976 if (displayColorSetting == 0) { 977 return "1.0".equals(SystemProperties.get("persist.sys.sf.color_saturation")) 978 ? COLOR_MODE_NATURAL : COLOR_MODE_BOOSTED; 979 } else if (displayColorSetting == 1) { 980 return COLOR_MODE_SATURATED; 981 } else if (displayColorSetting == 2) { 982 return COLOR_MODE_AUTOMATIC; 983 } else if (displayColorSetting >= VENDOR_COLOR_MODE_RANGE_MIN 984 && displayColorSetting <= VENDOR_COLOR_MODE_RANGE_MAX) { 985 return displayColorSetting; 986 } else { 987 return -1; 988 } 989 } 990 isColorModeAvailable(@olorMode int colorMode)991 private boolean isColorModeAvailable(@ColorMode int colorMode) { 992 final int[] availableColorModes = getContext().getResources().getIntArray( 993 R.array.config_availableColorModes); 994 if (availableColorModes != null) { 995 for (int mode : availableColorModes) { 996 if (mode == colorMode) { 997 return true; 998 } 999 } 1000 } 1001 return false; 1002 } 1003 dumpInternal(PrintWriter pw)1004 private void dumpInternal(PrintWriter pw) { 1005 pw.println("COLOR DISPLAY MANAGER dumpsys (color_display)"); 1006 1007 pw.println("Night display:"); 1008 if (mNightDisplayTintController.isAvailable(getContext())) { 1009 pw.println(" Activated: " + mNightDisplayTintController.isActivated()); 1010 pw.println(" Color temp: " + mNightDisplayTintController.getColorTemperature()); 1011 } else { 1012 pw.println(" Not available"); 1013 } 1014 1015 pw.println("Global saturation:"); 1016 if (mGlobalSaturationTintController.isAvailable(getContext())) { 1017 pw.println(" Activated: " + mGlobalSaturationTintController.isActivated()); 1018 } else { 1019 pw.println(" Not available"); 1020 } 1021 1022 mAppSaturationController.dump(pw); 1023 1024 pw.println("Display white balance:"); 1025 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) { 1026 pw.println(" Activated: " + mDisplayWhiteBalanceTintController.isActivated()); 1027 mDisplayWhiteBalanceTintController.dump(pw); 1028 } else { 1029 pw.println(" Not available"); 1030 } 1031 1032 pw.println("Reduce bright colors:"); 1033 if (mReduceBrightColorsTintController.isAvailable(getContext())) { 1034 pw.println(" Activated: " + mReduceBrightColorsTintController.isActivated()); 1035 mReduceBrightColorsTintController.dump(pw); 1036 } else { 1037 pw.println(" Not available"); 1038 } 1039 1040 pw.println("Color mode: " + getColorModeInternal()); 1041 } 1042 1043 private abstract class NightDisplayAutoMode { 1044 onActivated(boolean activated)1045 public abstract void onActivated(boolean activated); 1046 onStart()1047 public abstract void onStart(); 1048 onStop()1049 public abstract void onStop(); 1050 onCustomStartTimeChanged(LocalTime startTime)1051 public void onCustomStartTimeChanged(LocalTime startTime) { 1052 } 1053 onCustomEndTimeChanged(LocalTime endTime)1054 public void onCustomEndTimeChanged(LocalTime endTime) { 1055 } 1056 } 1057 1058 private final class CustomNightDisplayAutoMode extends NightDisplayAutoMode implements 1059 AlarmManager.OnAlarmListener { 1060 1061 private final AlarmManager mAlarmManager; 1062 private final BroadcastReceiver mTimeChangedReceiver; 1063 1064 private LocalTime mStartTime; 1065 private LocalTime mEndTime; 1066 1067 private LocalDateTime mLastActivatedTime; 1068 CustomNightDisplayAutoMode()1069 CustomNightDisplayAutoMode() { 1070 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); 1071 mTimeChangedReceiver = new BroadcastReceiver() { 1072 @Override 1073 public void onReceive(Context context, Intent intent) { 1074 updateActivated(); 1075 } 1076 }; 1077 } 1078 updateActivated()1079 private void updateActivated() { 1080 final LocalDateTime now = LocalDateTime.now(); 1081 final LocalDateTime start = getDateTimeBefore(mStartTime, now); 1082 final LocalDateTime end = getDateTimeAfter(mEndTime, start); 1083 boolean activate = now.isBefore(end); 1084 1085 if (mLastActivatedTime != null) { 1086 // Maintain the existing activated state if within the current period. 1087 if (mLastActivatedTime.isBefore(now) 1088 && mLastActivatedTime.isAfter(start) 1089 && (mLastActivatedTime.isAfter(end) || now.isBefore(end))) { 1090 activate = mNightDisplayTintController.isActivatedSetting(); 1091 } 1092 } 1093 1094 if (mNightDisplayTintController.isActivatedStateNotSet() 1095 || (mNightDisplayTintController.isActivated() != activate)) { 1096 mNightDisplayTintController.setActivated(activate, activate ? start : end); 1097 } 1098 1099 updateNextAlarm(mNightDisplayTintController.isActivated(), now); 1100 } 1101 updateNextAlarm(@ullable Boolean activated, @NonNull LocalDateTime now)1102 private void updateNextAlarm(@Nullable Boolean activated, @NonNull LocalDateTime now) { 1103 if (activated != null) { 1104 final LocalDateTime next = activated ? getDateTimeAfter(mEndTime, now) 1105 : getDateTimeAfter(mStartTime, now); 1106 final long millis = next.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); 1107 mAlarmManager.setExact(AlarmManager.RTC, millis, TAG, this, null); 1108 } 1109 } 1110 1111 @Override onStart()1112 public void onStart() { 1113 final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_TIME_CHANGED); 1114 intentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED); 1115 getContext().registerReceiver(mTimeChangedReceiver, intentFilter); 1116 1117 mStartTime = getNightDisplayCustomStartTimeInternal().getLocalTime(); 1118 mEndTime = getNightDisplayCustomEndTimeInternal().getLocalTime(); 1119 1120 mLastActivatedTime = getNightDisplayLastActivatedTimeSetting(); 1121 1122 // Force an update to initialize state. 1123 updateActivated(); 1124 } 1125 1126 @Override onStop()1127 public void onStop() { 1128 getContext().unregisterReceiver(mTimeChangedReceiver); 1129 1130 mAlarmManager.cancel(this); 1131 mLastActivatedTime = null; 1132 } 1133 1134 @Override onActivated(boolean activated)1135 public void onActivated(boolean activated) { 1136 mLastActivatedTime = getNightDisplayLastActivatedTimeSetting(); 1137 updateNextAlarm(activated, LocalDateTime.now()); 1138 } 1139 1140 @Override onCustomStartTimeChanged(LocalTime startTime)1141 public void onCustomStartTimeChanged(LocalTime startTime) { 1142 mStartTime = startTime; 1143 mLastActivatedTime = null; 1144 updateActivated(); 1145 } 1146 1147 @Override onCustomEndTimeChanged(LocalTime endTime)1148 public void onCustomEndTimeChanged(LocalTime endTime) { 1149 mEndTime = endTime; 1150 mLastActivatedTime = null; 1151 updateActivated(); 1152 } 1153 1154 @Override onAlarm()1155 public void onAlarm() { 1156 Slog.d(TAG, "onAlarm"); 1157 updateActivated(); 1158 } 1159 } 1160 1161 private final class TwilightNightDisplayAutoMode extends NightDisplayAutoMode implements 1162 TwilightListener { 1163 1164 private final TwilightManager mTwilightManager; 1165 private LocalDateTime mLastActivatedTime; 1166 TwilightNightDisplayAutoMode()1167 TwilightNightDisplayAutoMode() { 1168 mTwilightManager = getLocalService(TwilightManager.class); 1169 } 1170 updateActivated(TwilightState state)1171 private void updateActivated(TwilightState state) { 1172 if (state == null) { 1173 // If there isn't a valid TwilightState then just keep the current activated 1174 // state. 1175 return; 1176 } 1177 1178 boolean activate = state.isNight(); 1179 if (mLastActivatedTime != null) { 1180 final LocalDateTime now = LocalDateTime.now(); 1181 final LocalDateTime sunrise = state.sunrise(); 1182 final LocalDateTime sunset = state.sunset(); 1183 // Maintain the existing activated state if within the current period. 1184 if (mLastActivatedTime.isBefore(now) && (mLastActivatedTime.isBefore(sunrise) 1185 ^ mLastActivatedTime.isBefore(sunset))) { 1186 activate = mNightDisplayTintController.isActivatedSetting(); 1187 } 1188 } 1189 1190 if (mNightDisplayTintController.isActivatedStateNotSet() || ( 1191 mNightDisplayTintController.isActivated() != activate)) { 1192 mNightDisplayTintController.setActivated(activate); 1193 } 1194 } 1195 1196 @Override onActivated(boolean activated)1197 public void onActivated(boolean activated) { 1198 mLastActivatedTime = getNightDisplayLastActivatedTimeSetting(); 1199 } 1200 1201 @Override onStart()1202 public void onStart() { 1203 mTwilightManager.registerListener(this, mHandler); 1204 mLastActivatedTime = getNightDisplayLastActivatedTimeSetting(); 1205 1206 // Force an update to initialize state. 1207 updateActivated(mTwilightManager.getLastTwilightState()); 1208 } 1209 1210 @Override onStop()1211 public void onStop() { 1212 mTwilightManager.unregisterListener(this); 1213 mLastActivatedTime = null; 1214 } 1215 1216 @Override onTwilightStateChanged(@ullable TwilightState state)1217 public void onTwilightStateChanged(@Nullable TwilightState state) { 1218 Slog.d(TAG, "onTwilightStateChanged: isNight=" 1219 + (state == null ? null : state.isNight())); 1220 updateActivated(state); 1221 } 1222 } 1223 1224 /** 1225 * Only animates matrices and saves min and max coefficients for logging. 1226 */ 1227 static class TintValueAnimator extends ValueAnimator { 1228 private float[] min; 1229 private float[] max; 1230 ofMatrix(ColorMatrixEvaluator evaluator, Object... values)1231 public static TintValueAnimator ofMatrix(ColorMatrixEvaluator evaluator, 1232 Object... values) { 1233 TintValueAnimator anim = new TintValueAnimator(); 1234 anim.setObjectValues(values); 1235 anim.setEvaluator(evaluator); 1236 if (values == null || values.length == 0) { 1237 return null; 1238 } 1239 float[] m = (float[]) values[0]; 1240 anim.min = new float[m.length]; 1241 anim.max = new float[m.length]; 1242 for (int i = 0; i < m.length; ++i) { 1243 anim.min[i] = Float.MAX_VALUE; 1244 anim.max[i] = Float.MIN_VALUE; 1245 } 1246 return anim; 1247 } 1248 updateMinMaxComponents()1249 public void updateMinMaxComponents() { 1250 float[] value = (float[]) getAnimatedValue(); 1251 if (value == null) { 1252 return; 1253 } 1254 for (int i = 0; i < value.length; ++i) { 1255 min[i] = Math.min(min[i], value[i]); 1256 max[i] = Math.max(max[i], value[i]); 1257 } 1258 } 1259 getMin()1260 public float[] getMin() { 1261 return min; 1262 } 1263 getMax()1264 public float[] getMax() { 1265 return max; 1266 } 1267 } 1268 1269 /** 1270 * Interpolates between two 4x4 color transform matrices (in column-major order). 1271 */ 1272 private static class ColorMatrixEvaluator implements TypeEvaluator<float[]> { 1273 1274 /** 1275 * Result matrix returned by {@link #evaluate(float, float[], float[])}. 1276 */ 1277 private final float[] mResultMatrix = new float[16]; 1278 1279 @Override evaluate(float fraction, float[] startValue, float[] endValue)1280 public float[] evaluate(float fraction, float[] startValue, float[] endValue) { 1281 for (int i = 0; i < mResultMatrix.length; i++) { 1282 mResultMatrix[i] = MathUtils.lerp(startValue[i], endValue[i], fraction); 1283 } 1284 return mResultMatrix; 1285 } 1286 } 1287 1288 private final class NightDisplayTintController extends TintController { 1289 1290 private final float[] mMatrix = new float[16]; 1291 private final float[] mColorTempCoefficients = new float[9]; 1292 1293 private Boolean mIsAvailable; 1294 private Integer mColorTemp; 1295 1296 /** 1297 * Set coefficients based on whether the color matrix is linear or not. 1298 */ 1299 @Override setUp(Context context, boolean needsLinear)1300 public void setUp(Context context, boolean needsLinear) { 1301 final String[] coefficients = context.getResources().getStringArray(needsLinear 1302 ? R.array.config_nightDisplayColorTemperatureCoefficients 1303 : R.array.config_nightDisplayColorTemperatureCoefficientsNative); 1304 for (int i = 0; i < 9 && i < coefficients.length; i++) { 1305 mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]); 1306 } 1307 } 1308 1309 @Override setMatrix(int cct)1310 public void setMatrix(int cct) { 1311 if (mMatrix.length != 16) { 1312 Slog.d(TAG, "The display transformation matrix must be 4x4"); 1313 return; 1314 } 1315 1316 Matrix.setIdentityM(mMatrix, 0); 1317 1318 final float squareTemperature = cct * cct; 1319 final float red = squareTemperature * mColorTempCoefficients[0] 1320 + cct * mColorTempCoefficients[1] + mColorTempCoefficients[2]; 1321 final float green = squareTemperature * mColorTempCoefficients[3] 1322 + cct * mColorTempCoefficients[4] + mColorTempCoefficients[5]; 1323 final float blue = squareTemperature * mColorTempCoefficients[6] 1324 + cct * mColorTempCoefficients[7] + mColorTempCoefficients[8]; 1325 mMatrix[0] = red; 1326 mMatrix[5] = green; 1327 mMatrix[10] = blue; 1328 } 1329 1330 @Override getMatrix()1331 public float[] getMatrix() { 1332 return isActivated() ? mMatrix : MATRIX_IDENTITY; 1333 } 1334 1335 @Override setActivated(Boolean activated)1336 public void setActivated(Boolean activated) { 1337 setActivated(activated, LocalDateTime.now()); 1338 } 1339 1340 /** 1341 * Use directly when it is important that the last activation time be exact (for example, an 1342 * automatic change). Otherwise use {@link #setActivated(Boolean)}. 1343 */ setActivated(Boolean activated, @NonNull LocalDateTime lastActivationTime)1344 public void setActivated(Boolean activated, @NonNull LocalDateTime lastActivationTime) { 1345 if (activated == null) { 1346 super.setActivated(null); 1347 return; 1348 } 1349 1350 boolean activationStateChanged = activated != isActivated(); 1351 1352 if (!isActivatedStateNotSet() && activationStateChanged) { 1353 // This is a true state change, so set this as the last activation time. 1354 Secure.putStringForUser(getContext().getContentResolver(), 1355 Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, 1356 lastActivationTime.toString(), 1357 mCurrentUser); 1358 } 1359 1360 if (isActivatedStateNotSet() || activationStateChanged) { 1361 super.setActivated(activated); 1362 if (isActivatedSetting() != activated) { 1363 Secure.putIntForUser(getContext().getContentResolver(), 1364 Secure.NIGHT_DISPLAY_ACTIVATED, 1365 activated ? 1 : 0, mCurrentUser); 1366 } 1367 onActivated(activated); 1368 } 1369 } 1370 1371 @Override getLevel()1372 public int getLevel() { 1373 return LEVEL_COLOR_MATRIX_NIGHT_DISPLAY; 1374 } 1375 1376 @Override isAvailable(Context context)1377 public boolean isAvailable(Context context) { 1378 if (mIsAvailable == null) { 1379 mIsAvailable = ColorDisplayManager.isNightDisplayAvailable(context); 1380 } 1381 return mIsAvailable; 1382 } 1383 onActivated(boolean activated)1384 private void onActivated(boolean activated) { 1385 Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display"); 1386 if (mNightDisplayAutoMode != null) { 1387 mNightDisplayAutoMode.onActivated(activated); 1388 } 1389 1390 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) { 1391 updateDisplayWhiteBalanceStatus(); 1392 } 1393 1394 mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_ANIMATED); 1395 } 1396 getColorTemperature()1397 int getColorTemperature() { 1398 return mColorTemp != null ? clampNightDisplayColorTemperature(mColorTemp) 1399 : getColorTemperatureSetting(); 1400 } 1401 setColorTemperature(int temperature)1402 boolean setColorTemperature(int temperature) { 1403 mColorTemp = temperature; 1404 final boolean success = Secure.putIntForUser(getContext().getContentResolver(), 1405 Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, temperature, mCurrentUser); 1406 onColorTemperatureChanged(temperature); 1407 return success; 1408 } 1409 onColorTemperatureChanged(int temperature)1410 void onColorTemperatureChanged(int temperature) { 1411 setMatrix(temperature); 1412 mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE); 1413 } 1414 isActivatedSetting()1415 boolean isActivatedSetting() { 1416 if (mCurrentUser == UserHandle.USER_NULL) { 1417 return false; 1418 } 1419 return Secure.getIntForUser(getContext().getContentResolver(), 1420 Secure.NIGHT_DISPLAY_ACTIVATED, 0, mCurrentUser) == 1; 1421 } 1422 getColorTemperatureSetting()1423 int getColorTemperatureSetting() { 1424 if (mCurrentUser == UserHandle.USER_NULL) { 1425 return NOT_SET; 1426 } 1427 return clampNightDisplayColorTemperature(Secure.getIntForUser( 1428 getContext().getContentResolver(), Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, 1429 NOT_SET, 1430 mCurrentUser)); 1431 } 1432 clampNightDisplayColorTemperature(int colorTemperature)1433 private int clampNightDisplayColorTemperature(int colorTemperature) { 1434 if (colorTemperature == NOT_SET) { 1435 colorTemperature = getContext().getResources().getInteger( 1436 R.integer.config_nightDisplayColorTemperatureDefault); 1437 } 1438 final int minimumTemperature = ColorDisplayManager 1439 .getMinimumColorTemperature(getContext()); 1440 final int maximumTemperature = ColorDisplayManager 1441 .getMaximumColorTemperature(getContext()); 1442 if (colorTemperature < minimumTemperature) { 1443 colorTemperature = minimumTemperature; 1444 } else if (colorTemperature > maximumTemperature) { 1445 colorTemperature = maximumTemperature; 1446 } 1447 1448 return colorTemperature; 1449 } 1450 } 1451 1452 /** 1453 * Local service that allows color transforms to be enabled from other system services. 1454 */ 1455 public final class ColorDisplayServiceInternal { 1456 1457 /** 1458 * Set the current CCT value for the display white balance transform, and if the transform 1459 * is enabled, apply it. 1460 * 1461 * @param cct the color temperature in Kelvin. 1462 */ setDisplayWhiteBalanceColorTemperature(int cct)1463 public boolean setDisplayWhiteBalanceColorTemperature(int cct) { 1464 // Update the transform matrix even if it can't be applied. 1465 mDisplayWhiteBalanceTintController.setMatrix(cct); 1466 1467 if (mDisplayWhiteBalanceTintController.isActivated()) { 1468 mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE); 1469 return true; 1470 } 1471 return false; 1472 } 1473 1474 /** 1475 * Reset the CCT value for the display white balance transform to its default value. 1476 */ resetDisplayWhiteBalanceColorTemperature()1477 public boolean resetDisplayWhiteBalanceColorTemperature() { 1478 int temperatureDefault = getContext().getResources() 1479 .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault); 1480 Slog.d(TAG, "resetDisplayWhiteBalanceColorTemperature: " + temperatureDefault); 1481 return setDisplayWhiteBalanceColorTemperature(temperatureDefault); 1482 } 1483 1484 /** 1485 * Sets the listener and returns whether display white balance is currently enabled. 1486 */ setDisplayWhiteBalanceListener(DisplayWhiteBalanceListener listener)1487 public boolean setDisplayWhiteBalanceListener(DisplayWhiteBalanceListener listener) { 1488 mDisplayWhiteBalanceListener = listener; 1489 return mDisplayWhiteBalanceTintController.isActivated(); 1490 } 1491 1492 /** 1493 * Returns whether Display white balance is currently enabled. 1494 */ isDisplayWhiteBalanceEnabled()1495 public boolean isDisplayWhiteBalanceEnabled() { 1496 return isDisplayWhiteBalanceSettingEnabled(); 1497 } 1498 1499 /** 1500 * Sets the listener and returns whether reduce bright colors is currently enabled. 1501 */ setReduceBrightColorsListener(ReduceBrightColorsListener listener)1502 public boolean setReduceBrightColorsListener(ReduceBrightColorsListener listener) { 1503 mReduceBrightColorsListener = listener; 1504 return mReduceBrightColorsTintController.isActivated(); 1505 } 1506 1507 /** 1508 * Returns whether reduce bright colors is currently active. 1509 */ isReduceBrightColorsActivated()1510 public boolean isReduceBrightColorsActivated() { 1511 return mReduceBrightColorsTintController.isActivated(); 1512 } 1513 1514 /** 1515 * Gets the computed brightness, in nits, when the reduce bright colors feature is applied 1516 * at the current strength. 1517 * 1518 * @hide 1519 */ getReduceBrightColorsAdjustedBrightnessNits(float nits)1520 public float getReduceBrightColorsAdjustedBrightnessNits(float nits) { 1521 return mReduceBrightColorsTintController.getAdjustedBrightness(nits); 1522 } 1523 1524 /** 1525 * Adds a {@link WeakReference<ColorTransformController>} for a newly started activity, and 1526 * invokes {@link ColorTransformController#applyAppSaturation(float[], float[])} if needed. 1527 */ attachColorTransformController(String packageName, @UserIdInt int userId, WeakReference<ColorTransformController> controller)1528 public boolean attachColorTransformController(String packageName, @UserIdInt int userId, 1529 WeakReference<ColorTransformController> controller) { 1530 return mAppSaturationController 1531 .addColorTransformController(packageName, userId, controller); 1532 } 1533 } 1534 1535 /** 1536 * Listener for changes in display white balance status. 1537 */ 1538 public interface DisplayWhiteBalanceListener { 1539 1540 /** 1541 * Notify that the display white balance status has changed, either due to preemption by 1542 * another transform or the feature being turned off. 1543 */ onDisplayWhiteBalanceStatusChanged(boolean activated)1544 void onDisplayWhiteBalanceStatusChanged(boolean activated); 1545 } 1546 1547 /** 1548 * Listener for changes in reduce bright colors status. 1549 */ 1550 public interface ReduceBrightColorsListener { 1551 1552 /** 1553 * Notify that the reduce bright colors activation status has changed. 1554 */ onReduceBrightColorsActivationChanged(boolean activated, boolean userInitiated)1555 void onReduceBrightColorsActivationChanged(boolean activated, boolean userInitiated); 1556 1557 /** 1558 * Notify that the reduce bright colors strength has changed. 1559 */ onReduceBrightColorsStrengthChanged(int strength)1560 void onReduceBrightColorsStrengthChanged(int strength); 1561 } 1562 1563 private final class TintHandler extends Handler { 1564 TintHandler(Looper looper)1565 private TintHandler(Looper looper) { 1566 super(looper, null, true /* async */); 1567 } 1568 1569 @Override handleMessage(Message msg)1570 public void handleMessage(Message msg) { 1571 switch (msg.what) { 1572 case MSG_USER_CHANGED: 1573 onUserChanged(msg.arg1); 1574 break; 1575 case MSG_SET_UP: 1576 setUp(); 1577 break; 1578 case MSG_APPLY_GLOBAL_SATURATION: 1579 mGlobalSaturationTintController.setMatrix(msg.arg1); 1580 applyTint(mGlobalSaturationTintController, false); 1581 break; 1582 case MSG_APPLY_REDUCE_BRIGHT_COLORS: 1583 applyTint(mReduceBrightColorsTintController, true); 1584 break; 1585 case MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE: 1586 applyTint(mNightDisplayTintController, true); 1587 break; 1588 case MSG_APPLY_NIGHT_DISPLAY_ANIMATED: 1589 applyTint(mNightDisplayTintController, false); 1590 break; 1591 case MSG_APPLY_DISPLAY_WHITE_BALANCE: 1592 applyTint(mDisplayWhiteBalanceTintController, false); 1593 break; 1594 } 1595 } 1596 } 1597 1598 /** 1599 * Interface for applying transforms to a given AppWindow. 1600 */ 1601 public interface ColorTransformController { 1602 1603 /** 1604 * Apply the given saturation (grayscale) matrix to the associated AppWindow. 1605 */ applyAppSaturation(@ize9) float[] matrix, @Size(3) float[] translation)1606 void applyAppSaturation(@Size(9) float[] matrix, @Size(3) float[] translation); 1607 } 1608 1609 @VisibleForTesting 1610 final class BinderService extends IColorDisplayManager.Stub { 1611 1612 @Override setColorMode(int colorMode)1613 public void setColorMode(int colorMode) { 1614 getContext().enforceCallingOrSelfPermission( 1615 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, 1616 "Permission required to set display color mode"); 1617 final long token = Binder.clearCallingIdentity(); 1618 try { 1619 setColorModeInternal(colorMode); 1620 } finally { 1621 Binder.restoreCallingIdentity(token); 1622 } 1623 } 1624 1625 @Override getColorMode()1626 public int getColorMode() { 1627 final long token = Binder.clearCallingIdentity(); 1628 try { 1629 return getColorModeInternal(); 1630 } finally { 1631 Binder.restoreCallingIdentity(token); 1632 } 1633 } 1634 1635 @Override isDeviceColorManaged()1636 public boolean isDeviceColorManaged() { 1637 final long token = Binder.clearCallingIdentity(); 1638 try { 1639 return isDeviceColorManagedInternal(); 1640 } finally { 1641 Binder.restoreCallingIdentity(token); 1642 } 1643 } 1644 1645 @Override setSaturationLevel(int level)1646 public boolean setSaturationLevel(int level) { 1647 final boolean hasTransformsPermission = getContext() 1648 .checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) 1649 == PackageManager.PERMISSION_GRANTED; 1650 final boolean hasLegacyPermission = getContext() 1651 .checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION) 1652 == PackageManager.PERMISSION_GRANTED; 1653 if (!hasTransformsPermission && !hasLegacyPermission) { 1654 throw new SecurityException("Permission required to set display saturation level"); 1655 } 1656 final long token = Binder.clearCallingIdentity(); 1657 try { 1658 setSaturationLevelInternal(level); 1659 } finally { 1660 Binder.restoreCallingIdentity(token); 1661 } 1662 return true; 1663 } 1664 1665 @Override isSaturationActivated()1666 public boolean isSaturationActivated() { 1667 getContext().enforceCallingPermission( 1668 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, 1669 "Permission required to get display saturation level"); 1670 final long token = Binder.clearCallingIdentity(); 1671 try { 1672 return !mGlobalSaturationTintController.isActivatedStateNotSet() 1673 && mGlobalSaturationTintController.isActivated(); 1674 } finally { 1675 Binder.restoreCallingIdentity(token); 1676 } 1677 } 1678 1679 @Override setAppSaturationLevel(String packageName, int level)1680 public boolean setAppSaturationLevel(String packageName, int level) { 1681 getContext().enforceCallingPermission( 1682 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, 1683 "Permission required to set display saturation level"); 1684 final String callingPackageName = LocalServices.getService(PackageManagerInternal.class) 1685 .getNameForUid(Binder.getCallingUid()); 1686 final long token = Binder.clearCallingIdentity(); 1687 try { 1688 return setAppSaturationLevelInternal(callingPackageName, packageName, level); 1689 } finally { 1690 Binder.restoreCallingIdentity(token); 1691 } 1692 } 1693 getTransformCapabilities()1694 public int getTransformCapabilities() { 1695 getContext().enforceCallingPermission( 1696 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, 1697 "Permission required to query transform capabilities"); 1698 final long token = Binder.clearCallingIdentity(); 1699 try { 1700 return getTransformCapabilitiesInternal(); 1701 } finally { 1702 Binder.restoreCallingIdentity(token); 1703 } 1704 } 1705 1706 @Override setNightDisplayActivated(boolean activated)1707 public boolean setNightDisplayActivated(boolean activated) { 1708 getContext().enforceCallingOrSelfPermission( 1709 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, 1710 "Permission required to set night display activated"); 1711 final long token = Binder.clearCallingIdentity(); 1712 try { 1713 mNightDisplayTintController.setActivated(activated); 1714 return true; 1715 } finally { 1716 Binder.restoreCallingIdentity(token); 1717 } 1718 } 1719 1720 @Override isNightDisplayActivated()1721 public boolean isNightDisplayActivated() { 1722 final long token = Binder.clearCallingIdentity(); 1723 try { 1724 return mNightDisplayTintController.isActivated(); 1725 } finally { 1726 Binder.restoreCallingIdentity(token); 1727 } 1728 } 1729 1730 @Override setNightDisplayColorTemperature(int temperature)1731 public boolean setNightDisplayColorTemperature(int temperature) { 1732 getContext().enforceCallingOrSelfPermission( 1733 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, 1734 "Permission required to set night display temperature"); 1735 final long token = Binder.clearCallingIdentity(); 1736 try { 1737 return mNightDisplayTintController.setColorTemperature(temperature); 1738 } finally { 1739 Binder.restoreCallingIdentity(token); 1740 } 1741 } 1742 1743 @Override getNightDisplayColorTemperature()1744 public int getNightDisplayColorTemperature() { 1745 final long token = Binder.clearCallingIdentity(); 1746 try { 1747 return mNightDisplayTintController.getColorTemperature(); 1748 } finally { 1749 Binder.restoreCallingIdentity(token); 1750 } 1751 } 1752 1753 @Override setNightDisplayAutoMode(int autoMode)1754 public boolean setNightDisplayAutoMode(int autoMode) { 1755 getContext().enforceCallingOrSelfPermission( 1756 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, 1757 "Permission required to set night display auto mode"); 1758 final long token = Binder.clearCallingIdentity(); 1759 try { 1760 return setNightDisplayAutoModeInternal(autoMode); 1761 } finally { 1762 Binder.restoreCallingIdentity(token); 1763 } 1764 } 1765 1766 @Override getNightDisplayAutoMode()1767 public int getNightDisplayAutoMode() { 1768 getContext().enforceCallingOrSelfPermission( 1769 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, 1770 "Permission required to get night display auto mode"); 1771 final long token = Binder.clearCallingIdentity(); 1772 try { 1773 return getNightDisplayAutoModeInternal(); 1774 } finally { 1775 Binder.restoreCallingIdentity(token); 1776 } 1777 } 1778 1779 @Override getNightDisplayAutoModeRaw()1780 public int getNightDisplayAutoModeRaw() { 1781 final long token = Binder.clearCallingIdentity(); 1782 try { 1783 return getNightDisplayAutoModeRawInternal(); 1784 } finally { 1785 Binder.restoreCallingIdentity(token); 1786 } 1787 } 1788 1789 @Override setNightDisplayCustomStartTime(Time startTime)1790 public boolean setNightDisplayCustomStartTime(Time startTime) { 1791 getContext().enforceCallingOrSelfPermission( 1792 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, 1793 "Permission required to set night display custom start time"); 1794 final long token = Binder.clearCallingIdentity(); 1795 try { 1796 return setNightDisplayCustomStartTimeInternal(startTime); 1797 } finally { 1798 Binder.restoreCallingIdentity(token); 1799 } 1800 } 1801 1802 @Override getNightDisplayCustomStartTime()1803 public Time getNightDisplayCustomStartTime() { 1804 final long token = Binder.clearCallingIdentity(); 1805 try { 1806 return getNightDisplayCustomStartTimeInternal(); 1807 } finally { 1808 Binder.restoreCallingIdentity(token); 1809 } 1810 } 1811 1812 @Override setNightDisplayCustomEndTime(Time endTime)1813 public boolean setNightDisplayCustomEndTime(Time endTime) { 1814 getContext().enforceCallingOrSelfPermission( 1815 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, 1816 "Permission required to set night display custom end time"); 1817 final long token = Binder.clearCallingIdentity(); 1818 try { 1819 return setNightDisplayCustomEndTimeInternal(endTime); 1820 } finally { 1821 Binder.restoreCallingIdentity(token); 1822 } 1823 } 1824 1825 @Override getNightDisplayCustomEndTime()1826 public Time getNightDisplayCustomEndTime() { 1827 final long token = Binder.clearCallingIdentity(); 1828 try { 1829 return getNightDisplayCustomEndTimeInternal(); 1830 } finally { 1831 Binder.restoreCallingIdentity(token); 1832 } 1833 } 1834 1835 @Override setDisplayWhiteBalanceEnabled(boolean enabled)1836 public boolean setDisplayWhiteBalanceEnabled(boolean enabled) { 1837 getContext().enforceCallingOrSelfPermission( 1838 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, 1839 "Permission required to set night display activated"); 1840 final long token = Binder.clearCallingIdentity(); 1841 try { 1842 return setDisplayWhiteBalanceSettingEnabled(enabled); 1843 } finally { 1844 Binder.restoreCallingIdentity(token); 1845 } 1846 } 1847 1848 @Override isDisplayWhiteBalanceEnabled()1849 public boolean isDisplayWhiteBalanceEnabled() { 1850 final long token = Binder.clearCallingIdentity(); 1851 try { 1852 return isDisplayWhiteBalanceSettingEnabled(); 1853 } finally { 1854 Binder.restoreCallingIdentity(token); 1855 } 1856 } 1857 1858 @Override isReduceBrightColorsActivated()1859 public boolean isReduceBrightColorsActivated() { 1860 final long token = Binder.clearCallingIdentity(); 1861 try { 1862 return mReduceBrightColorsTintController.isActivated(); 1863 } finally { 1864 Binder.restoreCallingIdentity(token); 1865 } 1866 } 1867 1868 @Override setReduceBrightColorsActivated(boolean activated)1869 public boolean setReduceBrightColorsActivated(boolean activated) { 1870 getContext().enforceCallingOrSelfPermission( 1871 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, 1872 "Permission required to set reduce bright colors activation state"); 1873 final long token = Binder.clearCallingIdentity(); 1874 try { 1875 return setReduceBrightColorsActivatedInternal(activated); 1876 } finally { 1877 Binder.restoreCallingIdentity(token); 1878 } 1879 } 1880 1881 @Override getReduceBrightColorsStrength()1882 public int getReduceBrightColorsStrength() { 1883 final long token = Binder.clearCallingIdentity(); 1884 try { 1885 return mReduceBrightColorsTintController.getStrength(); 1886 } finally { 1887 Binder.restoreCallingIdentity(token); 1888 } 1889 } 1890 1891 @Override getReduceBrightColorsOffsetFactor()1892 public float getReduceBrightColorsOffsetFactor() { 1893 final long token = Binder.clearCallingIdentity(); 1894 try { 1895 return mReduceBrightColorsTintController.getOffsetFactor(); 1896 } finally { 1897 Binder.restoreCallingIdentity(token); 1898 } 1899 } 1900 1901 @Override setReduceBrightColorsStrength(int strength)1902 public boolean setReduceBrightColorsStrength(int strength) { 1903 getContext().enforceCallingOrSelfPermission( 1904 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, 1905 "Permission required to set reduce bright colors strength"); 1906 final long token = Binder.clearCallingIdentity(); 1907 try { 1908 return setReduceBrightColorsStrengthInternal(strength); 1909 } finally { 1910 Binder.restoreCallingIdentity(token); 1911 } 1912 } 1913 1914 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)1915 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1916 if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) { 1917 return; 1918 } 1919 1920 final long token = Binder.clearCallingIdentity(); 1921 try { 1922 dumpInternal(pw); 1923 } finally { 1924 Binder.restoreCallingIdentity(token); 1925 } 1926 } 1927 1928 @Override handleShellCommand(ParcelFileDescriptor in, ParcelFileDescriptor out, ParcelFileDescriptor err, String[] args)1929 public int handleShellCommand(ParcelFileDescriptor in, 1930 ParcelFileDescriptor out, ParcelFileDescriptor err, String[] args) { 1931 getContext().enforceCallingOrSelfPermission( 1932 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS, 1933 "Permission required to use ADB color transform commands"); 1934 final long token = Binder.clearCallingIdentity(); 1935 try { 1936 return new ColorDisplayShellCommand(ColorDisplayService.this) 1937 .exec(this, in.getFileDescriptor(), out.getFileDescriptor(), 1938 err.getFileDescriptor(), 1939 args); 1940 } finally { 1941 Binder.restoreCallingIdentity(token); 1942 } 1943 } 1944 } 1945 } 1946