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.internal.app;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.app.ActivityManager;
22 import android.content.ContentResolver;
23 import android.content.Context;
24 import android.database.ContentObserver;
25 import android.metrics.LogMaker;
26 import android.net.Uri;
27 import android.os.Handler;
28 import android.os.Looper;
29 import android.os.SystemProperties;
30 import android.provider.Settings.Secure;
31 import android.provider.Settings.System;
32 import android.util.Slog;
33 
34 import com.android.internal.R;
35 import com.android.internal.logging.MetricsLogger;
36 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
37 
38 import java.lang.annotation.Retention;
39 import java.lang.annotation.RetentionPolicy;
40 import java.time.DateTimeException;
41 import java.time.Instant;
42 import java.time.LocalDateTime;
43 import java.time.LocalTime;
44 import java.time.ZoneId;
45 import java.time.format.DateTimeParseException;
46 
47 /**
48  * Controller for managing night display and color mode settings.
49  * <p/>
50  * Night display tints your screen red at night. This makes it easier to look at your screen in
51  * dim light and may help you fall asleep more easily.
52  */
53 public final class ColorDisplayController {
54 
55     private static final String TAG = "ColorDisplayController";
56     private static final boolean DEBUG = false;
57 
58     @Retention(RetentionPolicy.SOURCE)
59     @IntDef({ AUTO_MODE_DISABLED, AUTO_MODE_CUSTOM, AUTO_MODE_TWILIGHT })
60     public @interface AutoMode {}
61 
62     /**
63      * Auto mode value to prevent Night display from being automatically activated. It can still
64      * be activated manually via {@link #setActivated(boolean)}.
65      *
66      * @see #setAutoMode(int)
67      */
68     public static final int AUTO_MODE_DISABLED = 0;
69     /**
70      * Auto mode value to automatically activate Night display at a specific start and end time.
71      *
72      * @see #setAutoMode(int)
73      * @see #setCustomStartTime(LocalTime)
74      * @see #setCustomEndTime(LocalTime)
75      */
76     public static final int AUTO_MODE_CUSTOM = 1;
77     /**
78      * Auto mode value to automatically activate Night display from sunset to sunrise.
79      *
80      * @see #setAutoMode(int)
81      */
82     public static final int AUTO_MODE_TWILIGHT = 2;
83 
84     @Retention(RetentionPolicy.SOURCE)
85     @IntDef({ COLOR_MODE_NATURAL, COLOR_MODE_BOOSTED, COLOR_MODE_SATURATED, COLOR_MODE_AUTOMATIC })
86     public @interface ColorMode {}
87 
88     /**
89      * Color mode with natural colors.
90      *
91      * @see #setColorMode(int)
92      */
93     public static final int COLOR_MODE_NATURAL = 0;
94     /**
95      * Color mode with boosted colors.
96      *
97      * @see #setColorMode(int)
98      */
99     public static final int COLOR_MODE_BOOSTED = 1;
100     /**
101      * Color mode with saturated colors.
102      *
103      * @see #setColorMode(int)
104      */
105     public static final int COLOR_MODE_SATURATED = 2;
106     /**
107      * Color mode with automatic colors.
108      *
109      * @see #setColorMode(int)
110      */
111     public static final int COLOR_MODE_AUTOMATIC = 3;
112 
113     private final Context mContext;
114     private final int mUserId;
115     private final ContentObserver mContentObserver;
116 
117     private Callback mCallback;
118     private MetricsLogger mMetricsLogger;
119 
ColorDisplayController(@onNull Context context)120     public ColorDisplayController(@NonNull Context context) {
121         this(context, ActivityManager.getCurrentUser());
122     }
123 
ColorDisplayController(@onNull Context context, int userId)124     public ColorDisplayController(@NonNull Context context, int userId) {
125         mContext = context.getApplicationContext();
126         mUserId = userId;
127 
128         mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
129             @Override
130             public void onChange(boolean selfChange, Uri uri) {
131                 super.onChange(selfChange, uri);
132 
133                 final String setting = uri == null ? null : uri.getLastPathSegment();
134                 if (setting != null) {
135                     onSettingChanged(setting);
136                 }
137             }
138         };
139     }
140 
141     /**
142      * Returns {@code true} when Night display is activated (the display is tinted red).
143      */
isActivated()144     public boolean isActivated() {
145         return Secure.getIntForUser(mContext.getContentResolver(),
146                 Secure.NIGHT_DISPLAY_ACTIVATED, 0, mUserId) == 1;
147     }
148 
149     /**
150      * Sets whether Night display should be activated. This also sets the last activated time.
151      *
152      * @param activated {@code true} if Night display should be activated
153      * @return {@code true} if the activated value was set successfully
154      */
setActivated(boolean activated)155     public boolean setActivated(boolean activated) {
156         if (isActivated() != activated) {
157             Secure.putStringForUser(mContext.getContentResolver(),
158                     Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
159                     LocalDateTime.now().toString(),
160                     mUserId);
161         }
162         return Secure.putIntForUser(mContext.getContentResolver(),
163                 Secure.NIGHT_DISPLAY_ACTIVATED, activated ? 1 : 0, mUserId);
164     }
165 
166     /**
167      * Returns the time when Night display's activation state last changed, or {@code null} if it
168      * has never been changed.
169      */
getLastActivatedTime()170     public LocalDateTime getLastActivatedTime() {
171         final ContentResolver cr = mContext.getContentResolver();
172         final String lastActivatedTime = Secure.getStringForUser(
173                 cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, mUserId);
174         if (lastActivatedTime != null) {
175             try {
176                 return LocalDateTime.parse(lastActivatedTime);
177             } catch (DateTimeParseException ignored) {}
178             // Uses the old epoch time.
179             try {
180                 return LocalDateTime.ofInstant(
181                     Instant.ofEpochMilli(Long.parseLong(lastActivatedTime)),
182                     ZoneId.systemDefault());
183             } catch (DateTimeException|NumberFormatException ignored) {}
184         }
185         return null;
186     }
187 
188     /**
189      * Returns the current auto mode value controlling when Night display will be automatically
190      * activated. One of {@link #AUTO_MODE_DISABLED}, {@link #AUTO_MODE_CUSTOM}, or
191      * {@link #AUTO_MODE_TWILIGHT}.
192      */
getAutoMode()193     public @AutoMode int getAutoMode() {
194         int autoMode = Secure.getIntForUser(mContext.getContentResolver(),
195                 Secure.NIGHT_DISPLAY_AUTO_MODE, -1, mUserId);
196         if (autoMode == -1) {
197             if (DEBUG) {
198                 Slog.d(TAG, "Using default value for setting: " + Secure.NIGHT_DISPLAY_AUTO_MODE);
199             }
200             autoMode = mContext.getResources().getInteger(
201                     R.integer.config_defaultNightDisplayAutoMode);
202         }
203 
204         if (autoMode != AUTO_MODE_DISABLED
205                 && autoMode != AUTO_MODE_CUSTOM
206                 && autoMode != AUTO_MODE_TWILIGHT) {
207             Slog.e(TAG, "Invalid autoMode: " + autoMode);
208             autoMode = AUTO_MODE_DISABLED;
209         }
210 
211         return autoMode;
212     }
213 
214     /**
215      * Returns the current auto mode value, without validation, or {@code 1} if the auto mode has
216      * never been set.
217      */
getAutoModeRaw()218     public int getAutoModeRaw() {
219         return Secure.getIntForUser(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_AUTO_MODE,
220                 -1, mUserId);
221     }
222 
223     /**
224      * Sets the current auto mode value controlling when Night display will be automatically
225      * activated. One of {@link #AUTO_MODE_DISABLED}, {@link #AUTO_MODE_CUSTOM}, or
226      * {@link #AUTO_MODE_TWILIGHT}.
227      *
228      * @param autoMode the new auto mode to use
229      * @return {@code true} if new auto mode was set successfully
230      */
setAutoMode(@utoMode int autoMode)231     public boolean setAutoMode(@AutoMode int autoMode) {
232         if (autoMode != AUTO_MODE_DISABLED
233                 && autoMode != AUTO_MODE_CUSTOM
234                 && autoMode != AUTO_MODE_TWILIGHT) {
235             throw new IllegalArgumentException("Invalid autoMode: " + autoMode);
236         }
237 
238         if (getAutoMode() != autoMode) {
239             Secure.putStringForUser(mContext.getContentResolver(),
240                     Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
241                     null,
242                     mUserId);
243             getMetricsLogger().write(new LogMaker(
244                     MetricsEvent.ACTION_NIGHT_DISPLAY_AUTO_MODE_CHANGED)
245                     .setType(MetricsEvent.TYPE_ACTION)
246                     .setSubtype(autoMode));
247         }
248 
249         return Secure.putIntForUser(mContext.getContentResolver(),
250                 Secure.NIGHT_DISPLAY_AUTO_MODE, autoMode, mUserId);
251     }
252 
253     /**
254      * Returns the local time when Night display will be automatically activated when using
255      * {@link #AUTO_MODE_CUSTOM}.
256      */
getCustomStartTime()257     public @NonNull LocalTime getCustomStartTime() {
258         int startTimeValue = Secure.getIntForUser(mContext.getContentResolver(),
259                 Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, -1, mUserId);
260         if (startTimeValue == -1) {
261             if (DEBUG) {
262                 Slog.d(TAG, "Using default value for setting: "
263                         + Secure.NIGHT_DISPLAY_CUSTOM_START_TIME);
264             }
265             startTimeValue = mContext.getResources().getInteger(
266                     R.integer.config_defaultNightDisplayCustomStartTime);
267         }
268 
269         return LocalTime.ofSecondOfDay(startTimeValue / 1000);
270     }
271 
272     /**
273      * Sets the local time when Night display will be automatically activated when using
274      * {@link #AUTO_MODE_CUSTOM}.
275      *
276      * @param startTime the local time to automatically activate Night display
277      * @return {@code true} if the new custom start time was set successfully
278      */
setCustomStartTime(@onNull LocalTime startTime)279     public boolean setCustomStartTime(@NonNull LocalTime startTime) {
280         if (startTime == null) {
281             throw new IllegalArgumentException("startTime cannot be null");
282         }
283         getMetricsLogger().write(new LogMaker(
284                 MetricsEvent.ACTION_NIGHT_DISPLAY_AUTO_MODE_CUSTOM_TIME_CHANGED)
285                 .setType(MetricsEvent.TYPE_ACTION)
286                 .setSubtype(0));
287         return Secure.putIntForUser(mContext.getContentResolver(),
288                 Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, startTime.toSecondOfDay() * 1000, mUserId);
289     }
290 
291     /**
292      * Returns the local time when Night display will be automatically deactivated when using
293      * {@link #AUTO_MODE_CUSTOM}.
294      */
getCustomEndTime()295     public @NonNull LocalTime getCustomEndTime() {
296         int endTimeValue = Secure.getIntForUser(mContext.getContentResolver(),
297                 Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, -1, mUserId);
298         if (endTimeValue == -1) {
299             if (DEBUG) {
300                 Slog.d(TAG, "Using default value for setting: "
301                         + Secure.NIGHT_DISPLAY_CUSTOM_END_TIME);
302             }
303             endTimeValue = mContext.getResources().getInteger(
304                     R.integer.config_defaultNightDisplayCustomEndTime);
305         }
306 
307         return LocalTime.ofSecondOfDay(endTimeValue / 1000);
308     }
309 
310     /**
311      * Sets the local time when Night display will be automatically deactivated when using
312      * {@link #AUTO_MODE_CUSTOM}.
313      *
314      * @param endTime the local time to automatically deactivate Night display
315      * @return {@code true} if the new custom end time was set successfully
316      */
setCustomEndTime(@onNull LocalTime endTime)317     public boolean setCustomEndTime(@NonNull LocalTime endTime) {
318         if (endTime == null) {
319             throw new IllegalArgumentException("endTime cannot be null");
320         }
321         getMetricsLogger().write(new LogMaker(
322                 MetricsEvent.ACTION_NIGHT_DISPLAY_AUTO_MODE_CUSTOM_TIME_CHANGED)
323                 .setType(MetricsEvent.TYPE_ACTION)
324                 .setSubtype(1));
325         return Secure.putIntForUser(mContext.getContentResolver(),
326                 Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.toSecondOfDay() * 1000, mUserId);
327     }
328 
329     /**
330      * Returns the color temperature (in Kelvin) to tint the display when activated.
331      */
getColorTemperature()332     public int getColorTemperature() {
333         int colorTemperature = Secure.getIntForUser(mContext.getContentResolver(),
334                 Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, -1, mUserId);
335         if (colorTemperature == -1) {
336             if (DEBUG) {
337                 Slog.d(TAG, "Using default value for setting: "
338                         + Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE);
339             }
340             colorTemperature = getDefaultColorTemperature();
341         }
342         final int minimumTemperature = getMinimumColorTemperature();
343         final int maximumTemperature = getMaximumColorTemperature();
344         if (colorTemperature < minimumTemperature) {
345             colorTemperature = minimumTemperature;
346         } else if (colorTemperature > maximumTemperature) {
347             colorTemperature = maximumTemperature;
348         }
349 
350         return colorTemperature;
351     }
352 
353     /**
354      * Sets the current temperature.
355      *
356      * @param colorTemperature the temperature, in Kelvin.
357      * @return {@code true} if new temperature was set successfully.
358      */
setColorTemperature(int colorTemperature)359     public boolean setColorTemperature(int colorTemperature) {
360         return Secure.putIntForUser(mContext.getContentResolver(),
361                 Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, colorTemperature, mUserId);
362     }
363 
364     /**
365      * Get the current color mode from system properties, or return -1.
366      *
367      * See com.android.server.display.DisplayTransformManager.
368      */
getCurrentColorModeFromSystemProperties()369     private @ColorMode int getCurrentColorModeFromSystemProperties() {
370         final int displayColorSetting = SystemProperties.getInt("persist.sys.sf.native_mode", 0);
371         if (displayColorSetting == 0) {
372             return "1.0".equals(SystemProperties.get("persist.sys.sf.color_saturation"))
373                     ? COLOR_MODE_NATURAL : COLOR_MODE_BOOSTED;
374         } else if (displayColorSetting == 1) {
375             return COLOR_MODE_SATURATED;
376         } else if (displayColorSetting == 2) {
377             return COLOR_MODE_AUTOMATIC;
378         } else {
379             return -1;
380         }
381     }
382 
isColorModeAvailable(@olorMode int colorMode)383     private boolean isColorModeAvailable(@ColorMode int colorMode) {
384         final int[] availableColorModes = mContext.getResources().getIntArray(
385                 R.array.config_availableColorModes);
386         if (availableColorModes != null) {
387             for (int mode : availableColorModes) {
388                 if (mode == colorMode) {
389                     return true;
390                 }
391             }
392         }
393         return false;
394     }
395 
396     /**
397      * Get the current color mode.
398      */
getColorMode()399     public int getColorMode() {
400         if (getAccessibilityTransformActivated()) {
401             if (isColorModeAvailable(COLOR_MODE_SATURATED)) {
402                 return COLOR_MODE_SATURATED;
403             } else if (isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
404                 return COLOR_MODE_AUTOMATIC;
405             }
406         }
407 
408         int colorMode = System.getIntForUser(mContext.getContentResolver(),
409                 System.DISPLAY_COLOR_MODE, -1, mUserId);
410         if (colorMode == -1) {
411             // There might be a system property controlling color mode that we need to respect; if
412             // not, this will set a suitable default.
413             colorMode = getCurrentColorModeFromSystemProperties();
414         }
415 
416         // This happens when a color mode is no longer available (e.g., after system update or B&R)
417         // or the device does not support any color mode.
418         if (!isColorModeAvailable(colorMode)) {
419             if (colorMode == COLOR_MODE_BOOSTED && isColorModeAvailable(COLOR_MODE_NATURAL)) {
420                 colorMode = COLOR_MODE_NATURAL;
421             } else if (colorMode == COLOR_MODE_SATURATED
422                     && isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
423                 colorMode = COLOR_MODE_AUTOMATIC;
424             } else if (colorMode == COLOR_MODE_AUTOMATIC
425                     && isColorModeAvailable(COLOR_MODE_SATURATED)) {
426                 colorMode = COLOR_MODE_SATURATED;
427             } else {
428                 colorMode = -1;
429             }
430         }
431 
432         return colorMode;
433     }
434 
435     /**
436      * Set the current color mode.
437      *
438      * @param colorMode the color mode
439      */
setColorMode(@olorMode int colorMode)440     public void setColorMode(@ColorMode int colorMode) {
441         if (!isColorModeAvailable(colorMode)) {
442             throw new IllegalArgumentException("Invalid colorMode: " + colorMode);
443         }
444         System.putIntForUser(mContext.getContentResolver(), System.DISPLAY_COLOR_MODE, colorMode,
445                 mUserId);
446     }
447 
448     /**
449      * Returns the minimum allowed color temperature (in Kelvin) to tint the display when activated.
450      */
getMinimumColorTemperature()451     public int getMinimumColorTemperature() {
452         return mContext.getResources().getInteger(
453                 R.integer.config_nightDisplayColorTemperatureMin);
454     }
455 
456     /**
457      * Returns the maximum allowed color temperature (in Kelvin) to tint the display when activated.
458      */
getMaximumColorTemperature()459     public int getMaximumColorTemperature() {
460         return mContext.getResources().getInteger(
461                 R.integer.config_nightDisplayColorTemperatureMax);
462     }
463 
464     /**
465      * Returns the default color temperature (in Kelvin) to tint the display when activated.
466      */
getDefaultColorTemperature()467     public int getDefaultColorTemperature() {
468         return mContext.getResources().getInteger(
469                 R.integer.config_nightDisplayColorTemperatureDefault);
470     }
471 
472     /**
473      * Returns true if any Accessibility color transforms are enabled.
474      */
getAccessibilityTransformActivated()475     public boolean getAccessibilityTransformActivated() {
476         final ContentResolver cr = mContext.getContentResolver();
477         return
478             Secure.getIntForUser(cr, Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
479                     0, mUserId) == 1
480             || Secure.getIntForUser(cr, Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
481                     0, mUserId) == 1;
482     }
483 
onSettingChanged(@onNull String setting)484     private void onSettingChanged(@NonNull String setting) {
485         if (DEBUG) {
486             Slog.d(TAG, "onSettingChanged: " + setting);
487         }
488 
489         if (mCallback != null) {
490             switch (setting) {
491                 case Secure.NIGHT_DISPLAY_ACTIVATED:
492                     mCallback.onActivated(isActivated());
493                     break;
494                 case Secure.NIGHT_DISPLAY_AUTO_MODE:
495                     mCallback.onAutoModeChanged(getAutoMode());
496                     break;
497                 case Secure.NIGHT_DISPLAY_CUSTOM_START_TIME:
498                     mCallback.onCustomStartTimeChanged(getCustomStartTime());
499                     break;
500                 case Secure.NIGHT_DISPLAY_CUSTOM_END_TIME:
501                     mCallback.onCustomEndTimeChanged(getCustomEndTime());
502                     break;
503                 case Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE:
504                     mCallback.onColorTemperatureChanged(getColorTemperature());
505                     break;
506                 case System.DISPLAY_COLOR_MODE:
507                     mCallback.onDisplayColorModeChanged(getColorMode());
508                     break;
509                 case Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED:
510                 case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:
511                     mCallback.onAccessibilityTransformChanged(getAccessibilityTransformActivated());
512                     break;
513             }
514         }
515     }
516 
517     /**
518      * Register a callback to be invoked whenever the Night display settings are changed.
519      */
setListener(Callback callback)520     public void setListener(Callback callback) {
521         final Callback oldCallback = mCallback;
522         if (oldCallback != callback) {
523             mCallback = callback;
524 
525             if (callback == null) {
526                 // Stop listening for changes now that there IS NOT a listener.
527                 mContext.getContentResolver().unregisterContentObserver(mContentObserver);
528             } else if (oldCallback == null) {
529                 // Start listening for changes now that there IS a listener.
530                 final ContentResolver cr = mContext.getContentResolver();
531                 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_ACTIVATED),
532                         false /* notifyForDescendants */, mContentObserver, mUserId);
533                 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_AUTO_MODE),
534                         false /* notifyForDescendants */, mContentObserver, mUserId);
535                 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_START_TIME),
536                         false /* notifyForDescendants */, mContentObserver, mUserId);
537                 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_END_TIME),
538                         false /* notifyForDescendants */, mContentObserver, mUserId);
539                 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE),
540                         false /* notifyForDescendants */, mContentObserver, mUserId);
541                 cr.registerContentObserver(System.getUriFor(System.DISPLAY_COLOR_MODE),
542                         false /* notifyForDecendants */, mContentObserver, mUserId);
543                 cr.registerContentObserver(
544                         Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
545                         false /* notifyForDecendants */, mContentObserver, mUserId);
546                 cr.registerContentObserver(
547                         Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
548                         false /* notifyForDecendants */, mContentObserver, mUserId);
549             }
550         }
551     }
552 
getMetricsLogger()553     private MetricsLogger getMetricsLogger() {
554         if (mMetricsLogger == null) {
555             mMetricsLogger = new MetricsLogger();
556         }
557         return mMetricsLogger;
558     }
559 
560     /**
561      * Returns {@code true} if Night display is supported by the device.
562      */
isAvailable(Context context)563     public static boolean isAvailable(Context context) {
564         return context.getResources().getBoolean(R.bool.config_nightDisplayAvailable);
565     }
566 
567     /**
568      * Callback invoked whenever the Night display settings are changed.
569      */
570     public interface Callback {
571         /**
572          * Callback invoked when the activated state changes.
573          *
574          * @param activated {@code true} if Night display is activated
575          */
onActivated(boolean activated)576         default void onActivated(boolean activated) {}
577         /**
578          * Callback invoked when the auto mode changes.
579          *
580          * @param autoMode the auto mode to use
581          */
onAutoModeChanged(int autoMode)582         default void onAutoModeChanged(int autoMode) {}
583         /**
584          * Callback invoked when the time to automatically activate Night display changes.
585          *
586          * @param startTime the local time to automatically activate Night display
587          */
onCustomStartTimeChanged(LocalTime startTime)588         default void onCustomStartTimeChanged(LocalTime startTime) {}
589         /**
590          * Callback invoked when the time to automatically deactivate Night display changes.
591          *
592          * @param endTime the local time to automatically deactivate Night display
593          */
onCustomEndTimeChanged(LocalTime endTime)594         default void onCustomEndTimeChanged(LocalTime endTime) {}
595 
596         /**
597          * Callback invoked when the color temperature changes.
598          *
599          * @param colorTemperature the color temperature to tint the screen
600          */
onColorTemperatureChanged(int colorTemperature)601         default void onColorTemperatureChanged(int colorTemperature) {}
602 
603         /**
604          * Callback invoked when the color mode changes.
605          *
606          * @param displayColorMode the color mode
607          */
onDisplayColorModeChanged(int displayColorMode)608         default void onDisplayColorModeChanged(int displayColorMode) {}
609 
610         /**
611          * Callback invoked when Accessibility color transforms change.
612          *
613          * @param state the state Accessibility color transforms (true of active)
614          */
onAccessibilityTransformChanged(boolean state)615         default void onAccessibilityTransformChanged(boolean state) {}
616     }
617 }
618