blob: f1539eeb1260e713ab38c26989d5b30fc48409c7 [file] [log] [blame]
Justin Klaassen911e8892016-06-21 18:24:24 -07001/*
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
17package com.android.internal.app;
18
19import android.annotation.IntDef;
20import android.annotation.NonNull;
Christine Franks69c2d1d2017-01-23 14:45:29 -080021import android.app.ActivityManager;
Justin Klaassen911e8892016-06-21 18:24:24 -070022import android.content.ContentResolver;
23import android.content.Context;
24import android.database.ContentObserver;
Christine Franks8ad6f6d2017-12-13 18:40:43 -080025import android.metrics.LogMaker;
Justin Klaassen911e8892016-06-21 18:24:24 -070026import android.net.Uri;
27import android.os.Handler;
28import android.os.Looper;
Christine Franks17947172017-10-30 16:22:37 -070029import android.os.SystemProperties;
Justin Klaassen911e8892016-06-21 18:24:24 -070030import android.provider.Settings.Secure;
Christine Franks8ad71492017-10-24 19:04:22 -070031import android.provider.Settings.System;
Justin Klaassen911e8892016-06-21 18:24:24 -070032import android.util.Slog;
33
34import com.android.internal.R;
Christine Franks8ad6f6d2017-12-13 18:40:43 -080035import com.android.internal.logging.MetricsLogger;
36import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Justin Klaassen911e8892016-06-21 18:24:24 -070037
38import java.lang.annotation.Retention;
39import java.lang.annotation.RetentionPolicy;
Christine Franks03213462017-08-25 13:57:26 -070040import java.time.DateTimeException;
41import java.time.Instant;
42import java.time.LocalDateTime;
43import java.time.LocalTime;
44import java.time.ZoneId;
45import java.time.format.DateTimeParseException;
Justin Klaassen911e8892016-06-21 18:24:24 -070046
47/**
Christine Franks5397f032017-11-01 18:35:16 -070048 * Controller for managing night display and color mode settings.
Justin Klaassen911e8892016-06-21 18:24:24 -070049 * <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 */
Christine Franks5397f032017-11-01 18:35:16 -070053public final class ColorDisplayController {
Justin Klaassen911e8892016-06-21 18:24:24 -070054
Christine Franks5397f032017-11-01 18:35:16 -070055 private static final String TAG = "ColorDisplayController";
Justin Klaassen911e8892016-06-21 18:24:24 -070056 private static final boolean DEBUG = false;
57
Justin Klaassen911e8892016-06-21 18:24:24 -070058 @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
Christine Franks8ad71492017-10-24 19:04:22 -070084 @Retention(RetentionPolicy.SOURCE)
85 @IntDef({ COLOR_MODE_NATURAL, COLOR_MODE_BOOSTED, COLOR_MODE_SATURATED })
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
Christine Franks17947172017-10-30 16:22:37 -0700107 /**
108 * See com.android.server.display.DisplayTransformManager.
109 */
110 private static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation";
111 private static final String PERSISTENT_PROPERTY_NATIVE_MODE = "persist.sys.sf.native_mode";
112
Justin Klaassen911e8892016-06-21 18:24:24 -0700113 private final Context mContext;
114 private final int mUserId;
Justin Klaassen911e8892016-06-21 18:24:24 -0700115 private final ContentObserver mContentObserver;
116
117 private Callback mCallback;
Christine Franks8ad6f6d2017-12-13 18:40:43 -0800118 private MetricsLogger mMetricsLogger;
Justin Klaassen911e8892016-06-21 18:24:24 -0700119
Christine Franks5397f032017-11-01 18:35:16 -0700120 public ColorDisplayController(@NonNull Context context) {
Christine Franks69c2d1d2017-01-23 14:45:29 -0800121 this(context, ActivityManager.getCurrentUser());
Justin Klaassen911e8892016-06-21 18:24:24 -0700122 }
123
Christine Franks5397f032017-11-01 18:35:16 -0700124 public ColorDisplayController(@NonNull Context context, int userId) {
Justin Klaassen911e8892016-06-21 18:24:24 -0700125 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 */
144 public boolean isActivated() {
145 return Secure.getIntForUser(mContext.getContentResolver(),
146 Secure.NIGHT_DISPLAY_ACTIVATED, 0, mUserId) == 1;
147 }
148
149 /**
Christine Franks1454eae2017-05-31 10:52:22 -0700150 * Sets whether Night display should be activated. This also sets the last activated time.
Justin Klaassen911e8892016-06-21 18:24:24 -0700151 *
152 * @param activated {@code true} if Night display should be activated
153 * @return {@code true} if the activated value was set successfully
154 */
155 public boolean setActivated(boolean activated) {
Christine Franks1454eae2017-05-31 10:52:22 -0700156 if (isActivated() != activated) {
Christine Franks03213462017-08-25 13:57:26 -0700157 Secure.putStringForUser(mContext.getContentResolver(),
158 Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
159 LocalDateTime.now().toString(),
Christine Franks1454eae2017-05-31 10:52:22 -0700160 mUserId);
161 }
Justin Klaassen911e8892016-06-21 18:24:24 -0700162 return Secure.putIntForUser(mContext.getContentResolver(),
163 Secure.NIGHT_DISPLAY_ACTIVATED, activated ? 1 : 0, mUserId);
164 }
165
166 /**
Christine Franks1454eae2017-05-31 10:52:22 -0700167 * Returns the time when Night display's activation state last changed, or {@code null} if it
168 * has never been changed.
169 */
Christine Franks03213462017-08-25 13:57:26 -0700170 public LocalDateTime getLastActivatedTime() {
Christine Franks1454eae2017-05-31 10:52:22 -0700171 final ContentResolver cr = mContext.getContentResolver();
Christine Franks03213462017-08-25 13:57:26 -0700172 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) {}
Christine Franks1454eae2017-05-31 10:52:22 -0700184 }
Christine Franks03213462017-08-25 13:57:26 -0700185 return null;
Christine Franks1454eae2017-05-31 10:52:22 -0700186 }
187
188 /**
Justin Klaassen911e8892016-06-21 18:24:24 -0700189 * 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 */
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 /**
Christine Franks8ad6f6d2017-12-13 18:40:43 -0800215 * Returns the current auto mode value, without validation, or {@code 1} if the auto mode has
216 * never been set.
217 */
218 public int getAutoModeRaw() {
219 return Secure.getIntForUser(mContext.getContentResolver(), Secure.NIGHT_DISPLAY_AUTO_MODE,
220 -1, mUserId);
221 }
222
223 /**
Justin Klaassen911e8892016-06-21 18:24:24 -0700224 * 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 */
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
Justin Klaassen4bcc06f2017-06-20 10:08:50 -0700238 if (getAutoMode() != autoMode) {
Christine Franks03213462017-08-25 13:57:26 -0700239 Secure.putStringForUser(mContext.getContentResolver(),
240 Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
241 null,
242 mUserId);
Christine Franks8ad6f6d2017-12-13 18:40:43 -0800243 getMetricsLogger().write(new LogMaker(
244 MetricsEvent.ACTION_NIGHT_DISPLAY_AUTO_MODE_CHANGED)
245 .setType(MetricsEvent.TYPE_ACTION)
246 .setSubtype(autoMode));
Justin Klaassen4bcc06f2017-06-20 10:08:50 -0700247 }
Christine Franks8ad6f6d2017-12-13 18:40:43 -0800248
Justin Klaassen911e8892016-06-21 18:24:24 -0700249 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 */
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
Christine Franks03213462017-08-25 13:57:26 -0700269 return LocalTime.ofSecondOfDay(startTimeValue / 1000);
Justin Klaassen911e8892016-06-21 18:24:24 -0700270 }
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 */
279 public boolean setCustomStartTime(@NonNull LocalTime startTime) {
280 if (startTime == null) {
281 throw new IllegalArgumentException("startTime cannot be null");
282 }
Christine Franks8ad6f6d2017-12-13 18:40:43 -0800283 getMetricsLogger().write(new LogMaker(
284 MetricsEvent.ACTION_NIGHT_DISPLAY_AUTO_MODE_CUSTOM_TIME_CHANGED)
285 .setType(MetricsEvent.TYPE_ACTION)
286 .setSubtype(0));
Justin Klaassen911e8892016-06-21 18:24:24 -0700287 return Secure.putIntForUser(mContext.getContentResolver(),
Christine Franks03213462017-08-25 13:57:26 -0700288 Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, startTime.toSecondOfDay() * 1000, mUserId);
Justin Klaassen911e8892016-06-21 18:24:24 -0700289 }
290
291 /**
292 * Returns the local time when Night display will be automatically deactivated when using
293 * {@link #AUTO_MODE_CUSTOM}.
294 */
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
Christine Franks03213462017-08-25 13:57:26 -0700307 return LocalTime.ofSecondOfDay(endTimeValue / 1000);
Justin Klaassen911e8892016-06-21 18:24:24 -0700308 }
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 */
317 public boolean setCustomEndTime(@NonNull LocalTime endTime) {
318 if (endTime == null) {
319 throw new IllegalArgumentException("endTime cannot be null");
320 }
Christine Franks8ad6f6d2017-12-13 18:40:43 -0800321 getMetricsLogger().write(new LogMaker(
322 MetricsEvent.ACTION_NIGHT_DISPLAY_AUTO_MODE_CUSTOM_TIME_CHANGED)
323 .setType(MetricsEvent.TYPE_ACTION)
324 .setSubtype(1));
Justin Klaassen911e8892016-06-21 18:24:24 -0700325 return Secure.putIntForUser(mContext.getContentResolver(),
Christine Franks03213462017-08-25 13:57:26 -0700326 Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.toSecondOfDay() * 1000, mUserId);
Justin Klaassen911e8892016-06-21 18:24:24 -0700327 }
328
Christine Franks6418d0b2017-02-13 09:48:00 -0800329 /**
330 * Returns the color temperature (in Kelvin) to tint the display when activated.
331 */
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 */
359 public boolean setColorTemperature(int colorTemperature) {
360 return Secure.putIntForUser(mContext.getContentResolver(),
361 Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, colorTemperature, mUserId);
362 }
363
364 /**
Christine Franks8ad71492017-10-24 19:04:22 -0700365 * Get the current color mode.
366 */
367 public int getColorMode() {
Daniel Solomon317a3572018-03-30 18:36:37 -0700368 if (getAccessibilityTransformActivated()) {
369 return COLOR_MODE_SATURATED;
370 }
371
Christine Franks8ad71492017-10-24 19:04:22 -0700372 final int colorMode = System.getIntForUser(mContext.getContentResolver(),
Christine Franks17947172017-10-30 16:22:37 -0700373 System.DISPLAY_COLOR_MODE, -1, mUserId);
Christine Franks8ad71492017-10-24 19:04:22 -0700374 if (colorMode < COLOR_MODE_NATURAL || colorMode > COLOR_MODE_SATURATED) {
Christine Franks17947172017-10-30 16:22:37 -0700375 // There still might be a legacy system property controlling color mode that we need to
376 // respect.
377 if ("1".equals(SystemProperties.get(PERSISTENT_PROPERTY_NATIVE_MODE))) {
378 return COLOR_MODE_SATURATED;
379 }
380 return "1.0".equals(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION))
381 ? COLOR_MODE_NATURAL : COLOR_MODE_BOOSTED;
Christine Franks8ad71492017-10-24 19:04:22 -0700382 }
383 return colorMode;
384 }
385
386 /**
387 * Set the current color mode.
388 *
389 * @param colorMode the color mode
390 */
391 public void setColorMode(@ColorMode int colorMode) {
392 if (colorMode < COLOR_MODE_NATURAL || colorMode > COLOR_MODE_SATURATED) {
393 throw new IllegalArgumentException("Invalid colorMode: " + colorMode);
394 }
395 System.putIntForUser(mContext.getContentResolver(), System.DISPLAY_COLOR_MODE, colorMode,
396 mUserId);
397 }
398
399 /**
Christine Franks6418d0b2017-02-13 09:48:00 -0800400 * Returns the minimum allowed color temperature (in Kelvin) to tint the display when activated.
401 */
402 public int getMinimumColorTemperature() {
403 return mContext.getResources().getInteger(
404 R.integer.config_nightDisplayColorTemperatureMin);
405 }
406
407 /**
408 * Returns the maximum allowed color temperature (in Kelvin) to tint the display when activated.
409 */
410 public int getMaximumColorTemperature() {
411 return mContext.getResources().getInteger(
412 R.integer.config_nightDisplayColorTemperatureMax);
413 }
414
415 /**
416 * Returns the default color temperature (in Kelvin) to tint the display when activated.
417 */
418 public int getDefaultColorTemperature() {
419 return mContext.getResources().getInteger(
420 R.integer.config_nightDisplayColorTemperatureDefault);
421 }
422
Daniel Solomon317a3572018-03-30 18:36:37 -0700423 /**
424 * Returns true if any Accessibility color transforms are enabled.
425 */
426 public boolean getAccessibilityTransformActivated() {
427 final ContentResolver cr = mContext.getContentResolver();
428 return
429 Secure.getIntForUser(cr, Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
430 0, mUserId) == 1
431 || Secure.getIntForUser(cr, Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
432 0, mUserId) == 1;
433 }
434
Justin Klaassen911e8892016-06-21 18:24:24 -0700435 private void onSettingChanged(@NonNull String setting) {
436 if (DEBUG) {
437 Slog.d(TAG, "onSettingChanged: " + setting);
438 }
439
440 if (mCallback != null) {
441 switch (setting) {
442 case Secure.NIGHT_DISPLAY_ACTIVATED:
443 mCallback.onActivated(isActivated());
444 break;
445 case Secure.NIGHT_DISPLAY_AUTO_MODE:
446 mCallback.onAutoModeChanged(getAutoMode());
447 break;
448 case Secure.NIGHT_DISPLAY_CUSTOM_START_TIME:
449 mCallback.onCustomStartTimeChanged(getCustomStartTime());
450 break;
451 case Secure.NIGHT_DISPLAY_CUSTOM_END_TIME:
452 mCallback.onCustomEndTimeChanged(getCustomEndTime());
453 break;
Christine Franks6418d0b2017-02-13 09:48:00 -0800454 case Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE:
455 mCallback.onColorTemperatureChanged(getColorTemperature());
456 break;
Christine Franks8ad71492017-10-24 19:04:22 -0700457 case System.DISPLAY_COLOR_MODE:
458 mCallback.onDisplayColorModeChanged(getColorMode());
459 break;
Daniel Solomon317a3572018-03-30 18:36:37 -0700460 case Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED:
461 case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:
462 mCallback.onAccessibilityTransformChanged(getAccessibilityTransformActivated());
463 break;
Justin Klaassen911e8892016-06-21 18:24:24 -0700464 }
465 }
466 }
467
468 /**
469 * Register a callback to be invoked whenever the Night display settings are changed.
470 */
471 public void setListener(Callback callback) {
472 final Callback oldCallback = mCallback;
473 if (oldCallback != callback) {
474 mCallback = callback;
475
476 if (callback == null) {
477 // Stop listening for changes now that there IS NOT a listener.
478 mContext.getContentResolver().unregisterContentObserver(mContentObserver);
479 } else if (oldCallback == null) {
480 // Start listening for changes now that there IS a listener.
481 final ContentResolver cr = mContext.getContentResolver();
482 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_ACTIVATED),
483 false /* notifyForDescendants */, mContentObserver, mUserId);
484 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_AUTO_MODE),
485 false /* notifyForDescendants */, mContentObserver, mUserId);
486 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_START_TIME),
487 false /* notifyForDescendants */, mContentObserver, mUserId);
488 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_END_TIME),
489 false /* notifyForDescendants */, mContentObserver, mUserId);
Christine Franks6418d0b2017-02-13 09:48:00 -0800490 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE),
491 false /* notifyForDescendants */, mContentObserver, mUserId);
Christine Franks8ad71492017-10-24 19:04:22 -0700492 cr.registerContentObserver(System.getUriFor(System.DISPLAY_COLOR_MODE),
493 false /* notifyForDecendants */, mContentObserver, mUserId);
Daniel Solomon317a3572018-03-30 18:36:37 -0700494 cr.registerContentObserver(
495 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
496 false /* notifyForDecendants */, mContentObserver, mUserId);
497 cr.registerContentObserver(
498 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
499 false /* notifyForDecendants */, mContentObserver, mUserId);
Justin Klaassen911e8892016-06-21 18:24:24 -0700500 }
501 }
502 }
503
Christine Franks8ad6f6d2017-12-13 18:40:43 -0800504 private MetricsLogger getMetricsLogger() {
505 if (mMetricsLogger == null) {
506 mMetricsLogger = new MetricsLogger();
507 }
508 return mMetricsLogger;
509 }
510
Justin Klaassen911e8892016-06-21 18:24:24 -0700511 /**
512 * Returns {@code true} if Night display is supported by the device.
513 */
514 public static boolean isAvailable(Context context) {
515 return context.getResources().getBoolean(R.bool.config_nightDisplayAvailable);
516 }
517
518 /**
Justin Klaassen911e8892016-06-21 18:24:24 -0700519 * Callback invoked whenever the Night display settings are changed.
520 */
521 public interface Callback {
522 /**
523 * Callback invoked when the activated state changes.
524 *
525 * @param activated {@code true} if Night display is activated
526 */
527 default void onActivated(boolean activated) {}
528 /**
529 * Callback invoked when the auto mode changes.
530 *
531 * @param autoMode the auto mode to use
532 */
533 default void onAutoModeChanged(int autoMode) {}
534 /**
535 * Callback invoked when the time to automatically activate Night display changes.
536 *
537 * @param startTime the local time to automatically activate Night display
538 */
539 default void onCustomStartTimeChanged(LocalTime startTime) {}
540 /**
541 * Callback invoked when the time to automatically deactivate Night display changes.
542 *
543 * @param endTime the local time to automatically deactivate Night display
544 */
545 default void onCustomEndTimeChanged(LocalTime endTime) {}
Christine Franks6418d0b2017-02-13 09:48:00 -0800546
547 /**
548 * Callback invoked when the color temperature changes.
549 *
550 * @param colorTemperature the color temperature to tint the screen
551 */
552 default void onColorTemperatureChanged(int colorTemperature) {}
Christine Franks8ad71492017-10-24 19:04:22 -0700553
554 /**
555 * Callback invoked when the color mode changes.
556 *
557 * @param displayColorMode the color mode
558 */
559 default void onDisplayColorModeChanged(int displayColorMode) {}
Daniel Solomon317a3572018-03-30 18:36:37 -0700560
561 /**
562 * Callback invoked when Accessibility color transforms change.
563 *
564 * @param state the state Accessibility color transforms (true of active)
565 */
566 default void onAccessibilityTransformChanged(boolean state) {}
Justin Klaassen911e8892016-06-21 18:24:24 -0700567 }
568}