blob: 7dd3b363810d8c27c11384119abc15d6b158b881 [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.server.display;
18
Christine Franks83cc5412018-07-03 14:46:07 -070019import static android.hardware.display.ColorDisplayManager.AUTO_MODE_CUSTOM_TIME;
20import static android.hardware.display.ColorDisplayManager.AUTO_MODE_DISABLED;
21import static android.hardware.display.ColorDisplayManager.AUTO_MODE_TWILIGHT;
Christine Franksd154fe52019-01-04 17:17:45 -080022import static android.hardware.display.ColorDisplayManager.COLOR_MODE_AUTOMATIC;
23import static android.hardware.display.ColorDisplayManager.COLOR_MODE_BOOSTED;
24import static android.hardware.display.ColorDisplayManager.COLOR_MODE_NATURAL;
25import static android.hardware.display.ColorDisplayManager.COLOR_MODE_SATURATED;
Christine Franksa4ed3762019-01-24 15:37:04 -080026
Christine Franks245ffd42018-11-16 13:45:14 -080027import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
Christine Franks39b03112018-07-03 14:46:07 -070028import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
Christine Franks09c229e2018-12-14 10:37:40 -080029import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_SATURATION;
Christine Franks39b03112018-07-03 14:46:07 -070030
Christine Franks09c229e2018-12-14 10:37:40 -080031import android.Manifest;
Justin Klaassen639214e2016-07-14 21:00:06 -070032import android.animation.Animator;
33import android.animation.AnimatorListenerAdapter;
34import android.animation.TypeEvaluator;
35import android.animation.ValueAnimator;
Justin Klaassen4346f632016-08-08 15:01:47 -070036import android.annotation.NonNull;
Justin Klaassen908b86c2016-08-08 09:18:42 -070037import android.annotation.Nullable;
Christine Franksf3529b22019-01-03 13:20:17 -080038import android.annotation.Size;
Christine Franks55194dc2019-01-15 13:47:06 -080039import android.annotation.UserIdInt;
Justin Klaassen911e8892016-06-21 18:24:24 -070040import android.app.AlarmManager;
41import android.content.BroadcastReceiver;
42import android.content.ContentResolver;
43import android.content.Context;
44import android.content.Intent;
45import android.content.IntentFilter;
Christine Franks09c229e2018-12-14 10:37:40 -080046import android.content.pm.PackageManager;
Daniel Solomon8b72c5b2018-11-25 11:07:13 -080047import android.content.res.Resources;
Justin Klaassen2696d992016-07-11 21:26:46 -070048import android.database.ContentObserver;
Daniel Solomon8b72c5b2018-11-25 11:07:13 -080049import android.graphics.ColorSpace;
Christine Franksf3529b22019-01-03 13:20:17 -080050import android.hardware.display.ColorDisplayManager;
Christine Franks83cc5412018-07-03 14:46:07 -070051import android.hardware.display.ColorDisplayManager.AutoMode;
Christine Franksd154fe52019-01-04 17:17:45 -080052import android.hardware.display.ColorDisplayManager.ColorMode;
Christine Franks39b03112018-07-03 14:46:07 -070053import android.hardware.display.IColorDisplayManager;
Christine Franks83cc5412018-07-03 14:46:07 -070054import android.hardware.display.Time;
Justin Klaassen2696d992016-07-11 21:26:46 -070055import android.net.Uri;
Justin Klaassen639214e2016-07-14 21:00:06 -070056import android.opengl.Matrix;
Christine Franks39b03112018-07-03 14:46:07 -070057import android.os.Binder;
Justin Klaassen911e8892016-06-21 18:24:24 -070058import android.os.Handler;
Daniel Solomona4ab5672019-01-22 19:35:55 -080059import android.os.IBinder;
Justin Klaassen911e8892016-06-21 18:24:24 -070060import android.os.Looper;
Christine Franks09c229e2018-12-14 10:37:40 -080061import android.os.Message;
Christine Franksd154fe52019-01-04 17:17:45 -080062import android.os.SystemProperties;
Justin Klaassen911e8892016-06-21 18:24:24 -070063import android.os.UserHandle;
64import android.provider.Settings.Secure;
Christine Franks57fdde82018-07-03 14:46:07 -070065import android.provider.Settings.System;
Justin Klaassen639214e2016-07-14 21:00:06 -070066import android.util.MathUtils;
Justin Klaassen911e8892016-06-21 18:24:24 -070067import android.util.Slog;
Christine Franks55194dc2019-01-15 13:47:06 -080068import android.view.SurfaceControl;
Christine Franksa4ed3762019-01-24 15:37:04 -080069import android.view.SurfaceControl.DisplayPrimaries;
Christine Franks9114f462019-01-04 11:27:30 -080070import android.view.accessibility.AccessibilityManager;
Justin Klaassen639214e2016-07-14 21:00:06 -070071import android.view.animation.AnimationUtils;
Daniel Solomona4ab5672019-01-22 19:35:55 -080072
Christine Franks39b03112018-07-03 14:46:07 -070073import com.android.internal.R;
Christine Franks57fdde82018-07-03 14:46:07 -070074import com.android.internal.annotations.VisibleForTesting;
Christine Franksf3529b22019-01-03 13:20:17 -080075import com.android.internal.util.DumpUtils;
Christine Franks57fdde82018-07-03 14:46:07 -070076import com.android.server.DisplayThread;
Justin Klaassen911e8892016-06-21 18:24:24 -070077import com.android.server.SystemService;
78import com.android.server.twilight.TwilightListener;
79import com.android.server.twilight.TwilightManager;
80import com.android.server.twilight.TwilightState;
Christine Franksa4ed3762019-01-24 15:37:04 -080081
Christine Franksf3529b22019-01-03 13:20:17 -080082import java.io.FileDescriptor;
Daniel Solomon8b72c5b2018-11-25 11:07:13 -080083import java.io.PrintWriter;
Christine Franksf3529b22019-01-03 13:20:17 -080084import java.lang.ref.WeakReference;
Christine Franks57fdde82018-07-03 14:46:07 -070085import java.time.DateTimeException;
86import java.time.Instant;
Christine Franks03213462017-08-25 13:57:26 -070087import java.time.LocalDateTime;
88import java.time.LocalTime;
89import java.time.ZoneId;
Christine Franks57fdde82018-07-03 14:46:07 -070090import java.time.format.DateTimeParseException;
Christine Franks09c229e2018-12-14 10:37:40 -080091import java.util.Arrays;
Christine Franks8ad71492017-10-24 19:04:22 -070092
Justin Klaassen911e8892016-06-21 18:24:24 -070093/**
Christine Franks39b03112018-07-03 14:46:07 -070094 * Controls the display's color transforms.
Justin Klaassen911e8892016-06-21 18:24:24 -070095 */
Christine Franks57fdde82018-07-03 14:46:07 -070096public final class ColorDisplayService extends SystemService {
Justin Klaassen911e8892016-06-21 18:24:24 -070097
Christine Franks5397f032017-11-01 18:35:16 -070098 private static final String TAG = "ColorDisplayService";
Justin Klaassen911e8892016-06-21 18:24:24 -070099
100 /**
Christine Franks7b83b4282017-01-18 14:55:00 -0800101 * The transition time, in milliseconds, for Night Display to turn on/off.
102 */
103 private static final long TRANSITION_DURATION = 3000L;
104
105 /**
Justin Klaassen639214e2016-07-14 21:00:06 -0700106 * The identity matrix, used if one of the given matrices is {@code null}.
107 */
108 private static final float[] MATRIX_IDENTITY = new float[16];
Christine Franks57fdde82018-07-03 14:46:07 -0700109
Justin Klaassen639214e2016-07-14 21:00:06 -0700110 static {
111 Matrix.setIdentityM(MATRIX_IDENTITY, 0);
112 }
113
Christine Franks09c229e2018-12-14 10:37:40 -0800114 private static final int MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE = 0;
115 private static final int MSG_APPLY_NIGHT_DISPLAY_ANIMATED = 1;
116 private static final int MSG_APPLY_GLOBAL_SATURATION = 2;
Christine Franksc7fb9452019-02-04 08:45:33 -0800117 private static final int MSG_APPLY_DISPLAY_WHITE_BALANCE = 3;
Christine Franks09c229e2018-12-14 10:37:40 -0800118
Justin Klaassen639214e2016-07-14 21:00:06 -0700119 /**
Christine Franks83cc5412018-07-03 14:46:07 -0700120 * Return value if a setting has not been set.
121 */
122 private static final int NOT_SET = -1;
123
124 /**
Justin Klaassen639214e2016-07-14 21:00:06 -0700125 * Evaluator used to animate color matrix transitions.
126 */
127 private static final ColorMatrixEvaluator COLOR_MATRIX_EVALUATOR = new ColorMatrixEvaluator();
128
Christine Franks83cc5412018-07-03 14:46:07 -0700129 private final NightDisplayTintController mNightDisplayTintController =
130 new NightDisplayTintController();
Christine Franks245ffd42018-11-16 13:45:14 -0800131
Long Ling1d3f1892019-02-06 12:34:02 -0800132 @VisibleForTesting
133 final DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController =
134 new DisplayWhiteBalanceTintController();
Christine Franks245ffd42018-11-16 13:45:14 -0800135
Christine Franks09c229e2018-12-14 10:37:40 -0800136 private final TintController mGlobalSaturationTintController = new TintController() {
137
138 private float[] mMatrixGlobalSaturation = new float[16];
139
140 @Override
141 public void setUp(Context context, boolean needsLinear) {
142 }
143
144 @Override
145 public float[] getMatrix() {
146 return Arrays.copyOf(mMatrixGlobalSaturation, mMatrixGlobalSaturation.length);
147 }
148
149 @Override
150 public void setMatrix(int saturationLevel) {
151 if (saturationLevel < 0) {
152 saturationLevel = 0;
153 } else if (saturationLevel > 100) {
154 saturationLevel = 100;
155 }
156 Slog.d(TAG, "Setting saturation level: " + saturationLevel);
157
158 if (saturationLevel == 100) {
Christine Franks6d21d342019-02-07 15:09:03 -0800159 setActivated(false);
Christine Franks09c229e2018-12-14 10:37:40 -0800160 Matrix.setIdentityM(mMatrixGlobalSaturation, 0);
161 } else {
Christine Franks6d21d342019-02-07 15:09:03 -0800162 setActivated(true);
Christine Franks09c229e2018-12-14 10:37:40 -0800163 float saturation = saturationLevel * 0.1f;
164 float desaturation = 1.0f - saturation;
165 float[] luminance = {0.231f * desaturation, 0.715f * desaturation,
Christine Franks83cc5412018-07-03 14:46:07 -0700166 0.072f * desaturation};
Christine Franks09c229e2018-12-14 10:37:40 -0800167 mMatrixGlobalSaturation[0] = luminance[0] + saturation;
168 mMatrixGlobalSaturation[1] = luminance[0];
169 mMatrixGlobalSaturation[2] = luminance[0];
170 mMatrixGlobalSaturation[4] = luminance[1];
171 mMatrixGlobalSaturation[5] = luminance[1] + saturation;
172 mMatrixGlobalSaturation[6] = luminance[1];
173 mMatrixGlobalSaturation[8] = luminance[2];
174 mMatrixGlobalSaturation[9] = luminance[2];
175 mMatrixGlobalSaturation[10] = luminance[2] + saturation;
176 }
177 }
178
179 @Override
180 public int getLevel() {
181 return LEVEL_COLOR_MATRIX_SATURATION;
182 }
Christine Franksa4ed3762019-01-24 15:37:04 -0800183
184 @Override
185 public boolean isAvailable(Context context) {
186 return ColorDisplayManager.isColorTransformAccelerated(context);
187 }
Christine Franks09c229e2018-12-14 10:37:40 -0800188 };
189
Christine Franks9114f462019-01-04 11:27:30 -0800190 /**
191 * Matrix and offset used for converting color to grayscale.
192 */
193 private static final float[] MATRIX_GRAYSCALE = new float[]{
194 .2126f, .2126f, .2126f, 0f,
195 .7152f, .7152f, .7152f, 0f,
196 .0722f, .0722f, .0722f, 0f,
197 0f, 0f, 0f, 1f
198 };
199
200 /**
201 * Matrix and offset used for luminance inversion. Represents a transform from RGB to YIQ color
202 * space, rotation around the Y axis by 180 degrees, transform back to RGB color space, and
203 * subtraction from 1. The last row represents a non-multiplied addition, see surfaceflinger's
204 * ProgramCache for full implementation details.
205 */
Christine Franksd154fe52019-01-04 17:17:45 -0800206 private static final float[] MATRIX_INVERT_COLOR = new float[]{
Christine Franks9114f462019-01-04 11:27:30 -0800207 0.402f, -0.598f, -0.599f, 0f,
208 -1.174f, -0.174f, -1.175f, 0f,
209 -0.228f, -0.228f, 0.772f, 0f,
210 1f, 1f, 1f, 1f
211 };
212
Justin Klaassen2696d992016-07-11 21:26:46 -0700213 private final Handler mHandler;
214
Christine Franksf3529b22019-01-03 13:20:17 -0800215 private final AppSaturationController mAppSaturationController = new AppSaturationController();
216
Justin Klaassen911e8892016-06-21 18:24:24 -0700217 private int mCurrentUser = UserHandle.USER_NULL;
Justin Klaassen2696d992016-07-11 21:26:46 -0700218 private ContentObserver mUserSetupObserver;
Justin Klaassen911e8892016-06-21 18:24:24 -0700219 private boolean mBootCompleted;
220
Christine Franks57fdde82018-07-03 14:46:07 -0700221 private ContentObserver mContentObserver;
Christine Franks57fdde82018-07-03 14:46:07 -0700222
Christine Franks245ffd42018-11-16 13:45:14 -0800223 private DisplayWhiteBalanceListener mDisplayWhiteBalanceListener;
224
Christine Franks57fdde82018-07-03 14:46:07 -0700225 private NightDisplayAutoMode mNightDisplayAutoMode;
Justin Klaassen911e8892016-06-21 18:24:24 -0700226
Christine Franks5397f032017-11-01 18:35:16 -0700227 public ColorDisplayService(Context context) {
Justin Klaassen911e8892016-06-21 18:24:24 -0700228 super(context);
Christine Franks83cc5412018-07-03 14:46:07 -0700229 mHandler = new TintHandler(DisplayThread.get().getLooper());
Justin Klaassen911e8892016-06-21 18:24:24 -0700230 }
231
232 @Override
233 public void onStart() {
Christine Franks39b03112018-07-03 14:46:07 -0700234 publishBinderService(Context.COLOR_DISPLAY_SERVICE, new BinderService());
Christine Franks245ffd42018-11-16 13:45:14 -0800235 publishLocalService(ColorDisplayServiceInternal.class, new ColorDisplayServiceInternal());
Justin Klaassen911e8892016-06-21 18:24:24 -0700236 }
237
238 @Override
Justin Klaassen2696d992016-07-11 21:26:46 -0700239 public void onBootPhase(int phase) {
Christine Frankse5bb03e2017-02-10 17:36:10 -0800240 if (phase >= PHASE_BOOT_COMPLETED) {
Justin Klaassen2696d992016-07-11 21:26:46 -0700241 mBootCompleted = true;
242
243 // Register listeners now that boot is complete.
244 if (mCurrentUser != UserHandle.USER_NULL && mUserSetupObserver == null) {
245 setUp();
246 }
247 }
248 }
249
250 @Override
Justin Klaassen911e8892016-06-21 18:24:24 -0700251 public void onStartUser(int userHandle) {
252 super.onStartUser(userHandle);
253
Justin Klaassen911e8892016-06-21 18:24:24 -0700254 if (mCurrentUser == UserHandle.USER_NULL) {
Justin Klaassen2696d992016-07-11 21:26:46 -0700255 onUserChanged(userHandle);
Justin Klaassen911e8892016-06-21 18:24:24 -0700256 }
257 }
258
259 @Override
260 public void onSwitchUser(int userHandle) {
261 super.onSwitchUser(userHandle);
262
Justin Klaassen2696d992016-07-11 21:26:46 -0700263 onUserChanged(userHandle);
Justin Klaassen911e8892016-06-21 18:24:24 -0700264 }
265
266 @Override
267 public void onStopUser(int userHandle) {
268 super.onStopUser(userHandle);
269
Justin Klaassen911e8892016-06-21 18:24:24 -0700270 if (mCurrentUser == userHandle) {
Justin Klaassen2696d992016-07-11 21:26:46 -0700271 onUserChanged(UserHandle.USER_NULL);
Justin Klaassen911e8892016-06-21 18:24:24 -0700272 }
273 }
274
Justin Klaassen2696d992016-07-11 21:26:46 -0700275 private void onUserChanged(int userHandle) {
276 final ContentResolver cr = getContext().getContentResolver();
Justin Klaassen911e8892016-06-21 18:24:24 -0700277
Justin Klaassen2696d992016-07-11 21:26:46 -0700278 if (mCurrentUser != UserHandle.USER_NULL) {
279 if (mUserSetupObserver != null) {
280 cr.unregisterContentObserver(mUserSetupObserver);
281 mUserSetupObserver = null;
282 } else if (mBootCompleted) {
283 tearDown();
284 }
285 }
286
287 mCurrentUser = userHandle;
288
289 if (mCurrentUser != UserHandle.USER_NULL) {
290 if (!isUserSetupCompleted(cr, mCurrentUser)) {
291 mUserSetupObserver = new ContentObserver(mHandler) {
292 @Override
293 public void onChange(boolean selfChange, Uri uri) {
294 if (isUserSetupCompleted(cr, mCurrentUser)) {
295 cr.unregisterContentObserver(this);
296 mUserSetupObserver = null;
297
298 if (mBootCompleted) {
299 setUp();
300 }
301 }
302 }
303 };
304 cr.registerContentObserver(Secure.getUriFor(Secure.USER_SETUP_COMPLETE),
Christine Franks39b03112018-07-03 14:46:07 -0700305 false /* notifyForDescendants */, mUserSetupObserver, mCurrentUser);
Justin Klaassen2696d992016-07-11 21:26:46 -0700306 } else if (mBootCompleted) {
307 setUp();
Justin Klaassen911e8892016-06-21 18:24:24 -0700308 }
309 }
310 }
311
Justin Klaassen2696d992016-07-11 21:26:46 -0700312 private static boolean isUserSetupCompleted(ContentResolver cr, int userHandle) {
313 return Secure.getIntForUser(cr, Secure.USER_SETUP_COMPLETE, 0, userHandle) == 1;
314 }
315
316 private void setUp() {
Justin Klaassenec8837a2016-08-23 12:04:42 -0700317 Slog.d(TAG, "setUp: currentUser=" + mCurrentUser);
318
Christine Franks57fdde82018-07-03 14:46:07 -0700319 // Listen for external changes to any of the settings.
320 if (mContentObserver == null) {
321 mContentObserver = new ContentObserver(new Handler(DisplayThread.get().getLooper())) {
322 @Override
323 public void onChange(boolean selfChange, Uri uri) {
324 super.onChange(selfChange, uri);
325
326 final String setting = uri == null ? null : uri.getLastPathSegment();
327 if (setting != null) {
328 switch (setting) {
329 case Secure.NIGHT_DISPLAY_ACTIVATED:
Christine Franks78a4dd42019-02-08 11:09:30 -0800330 final boolean activated = mNightDisplayTintController
331 .isActivatedSetting();
Christine Franks83cc5412018-07-03 14:46:07 -0700332 if (mNightDisplayTintController.isActivatedStateNotSet()
333 || mNightDisplayTintController.isActivated() != activated) {
Christine Franks78a4dd42019-02-08 11:09:30 -0800334 mNightDisplayTintController.setActivated(activated);
Christine Franks83cc5412018-07-03 14:46:07 -0700335 }
Christine Franks57fdde82018-07-03 14:46:07 -0700336 break;
337 case Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE:
Christine Franks78a4dd42019-02-08 11:09:30 -0800338 final int temperature = mNightDisplayTintController
339 .getColorTemperatureSetting();
Christine Franks83cc5412018-07-03 14:46:07 -0700340 if (mNightDisplayTintController.getColorTemperature()
341 != temperature) {
342 mNightDisplayTintController
343 .onColorTemperatureChanged(temperature);
344 }
Christine Franks57fdde82018-07-03 14:46:07 -0700345 break;
346 case Secure.NIGHT_DISPLAY_AUTO_MODE:
Christine Franks83cc5412018-07-03 14:46:07 -0700347 onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal());
Christine Franks57fdde82018-07-03 14:46:07 -0700348 break;
349 case Secure.NIGHT_DISPLAY_CUSTOM_START_TIME:
350 onNightDisplayCustomStartTimeChanged(
Christine Franks83cc5412018-07-03 14:46:07 -0700351 getNightDisplayCustomStartTimeInternal().getLocalTime());
Christine Franks57fdde82018-07-03 14:46:07 -0700352 break;
353 case Secure.NIGHT_DISPLAY_CUSTOM_END_TIME:
354 onNightDisplayCustomEndTimeChanged(
Christine Franks83cc5412018-07-03 14:46:07 -0700355 getNightDisplayCustomEndTimeInternal().getLocalTime());
Christine Franks57fdde82018-07-03 14:46:07 -0700356 break;
357 case System.DISPLAY_COLOR_MODE:
Christine Franks71e003e2019-01-24 14:40:20 -0800358 onDisplayColorModeChanged(getColorModeInternal());
Christine Franks57fdde82018-07-03 14:46:07 -0700359 break;
Christine Franks57fdde82018-07-03 14:46:07 -0700360 case Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED:
Christine Franks9114f462019-01-04 11:27:30 -0800361 onAccessibilityInversionChanged();
362 onAccessibilityActivated();
363 break;
364 case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:
365 onAccessibilityDaltonizerChanged();
366 onAccessibilityActivated();
367 break;
368 case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER:
369 onAccessibilityDaltonizerChanged();
Christine Franks57fdde82018-07-03 14:46:07 -0700370 break;
Christine Franks245ffd42018-11-16 13:45:14 -0800371 case Secure.DISPLAY_WHITE_BALANCE_ENABLED:
Daniel Solomon8b72c5b2018-11-25 11:07:13 -0800372 updateDisplayWhiteBalanceStatus();
Christine Franks245ffd42018-11-16 13:45:14 -0800373 break;
Christine Franks57fdde82018-07-03 14:46:07 -0700374 }
375 }
376 }
377 };
378 }
379 final ContentResolver cr = getContext().getContentResolver();
380 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_ACTIVATED),
381 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
382 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE),
383 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
384 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_AUTO_MODE),
385 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
386 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_START_TIME),
387 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
388 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_END_TIME),
389 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
390 cr.registerContentObserver(System.getUriFor(System.DISPLAY_COLOR_MODE),
391 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
392 cr.registerContentObserver(
393 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
394 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
395 cr.registerContentObserver(
396 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
397 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
Christine Franks9114f462019-01-04 11:27:30 -0800398 cr.registerContentObserver(
399 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
400 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
Christine Franks245ffd42018-11-16 13:45:14 -0800401 cr.registerContentObserver(Secure.getUriFor(Secure.DISPLAY_WHITE_BALANCE_ENABLED),
402 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
Justin Klaassen911e8892016-06-21 18:24:24 -0700403
Christine Frankscf388c22018-05-15 15:48:10 -0700404 // Set the color mode, if valid, and immediately apply the updated tint matrix based on the
405 // existing activated state. This ensures consistency of tint across the color mode change.
Christine Franks71e003e2019-01-24 14:40:20 -0800406 onDisplayColorModeChanged(getColorModeInternal());
Christine Frankscf388c22018-05-15 15:48:10 -0700407
Christine Franksa4ed3762019-01-24 15:37:04 -0800408 if (mNightDisplayTintController.isAvailable(getContext())) {
Christine Franks245ffd42018-11-16 13:45:14 -0800409 // Reset the activated state.
410 mNightDisplayTintController.setActivated(null);
Christine Frankscf388c22018-05-15 15:48:10 -0700411
Christine Franks245ffd42018-11-16 13:45:14 -0800412 // Prepare the night display color transformation matrix.
413 mNightDisplayTintController
414 .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
Christine Franks78a4dd42019-02-08 11:09:30 -0800415 mNightDisplayTintController
416 .setMatrix(mNightDisplayTintController.getColorTemperatureSetting());
Christine Franks8ad71492017-10-24 19:04:22 -0700417
Christine Franks245ffd42018-11-16 13:45:14 -0800418 // Initialize the current auto mode.
Christine Franks83cc5412018-07-03 14:46:07 -0700419 onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal());
Christine Franks6418d0b2017-02-13 09:48:00 -0800420
Christine Franks83cc5412018-07-03 14:46:07 -0700421 // Force the initialization of the current saved activation state.
Christine Franks245ffd42018-11-16 13:45:14 -0800422 if (mNightDisplayTintController.isActivatedStateNotSet()) {
Christine Franks78a4dd42019-02-08 11:09:30 -0800423 mNightDisplayTintController
424 .setActivated(mNightDisplayTintController.isActivatedSetting());
Christine Franks245ffd42018-11-16 13:45:14 -0800425 }
426 }
Justin Klaassen911e8892016-06-21 18:24:24 -0700427
Christine Franksa4ed3762019-01-24 15:37:04 -0800428 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
Christine Franks245ffd42018-11-16 13:45:14 -0800429 // Prepare the display white balance transform matrix.
Daniel Solomon8b72c5b2018-11-25 11:07:13 -0800430 mDisplayWhiteBalanceTintController.setUp(getContext(), true /* needsLinear */);
Christine Franks245ffd42018-11-16 13:45:14 -0800431
Daniel Solomon8b72c5b2018-11-25 11:07:13 -0800432 updateDisplayWhiteBalanceStatus();
Justin Klaassen911e8892016-06-21 18:24:24 -0700433 }
434 }
435
Justin Klaassen2696d992016-07-11 21:26:46 -0700436 private void tearDown() {
Justin Klaassenec8837a2016-08-23 12:04:42 -0700437 Slog.d(TAG, "tearDown: currentUser=" + mCurrentUser);
438
Christine Franks57fdde82018-07-03 14:46:07 -0700439 getContext().getContentResolver().unregisterContentObserver(mContentObserver);
440
Christine Franksa4ed3762019-01-24 15:37:04 -0800441 if (mNightDisplayTintController.isAvailable(getContext())) {
Christine Franks245ffd42018-11-16 13:45:14 -0800442 if (mNightDisplayAutoMode != null) {
443 mNightDisplayAutoMode.onStop();
444 mNightDisplayAutoMode = null;
445 }
446 mNightDisplayTintController.endAnimator();
Justin Klaassen911e8892016-06-21 18:24:24 -0700447 }
448
Christine Franksa4ed3762019-01-24 15:37:04 -0800449 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
Christine Franks245ffd42018-11-16 13:45:14 -0800450 mDisplayWhiteBalanceTintController.endAnimator();
Justin Klaassen639214e2016-07-14 21:00:06 -0700451 }
Christine Franks6d21d342019-02-07 15:09:03 -0800452
453 if (mGlobalSaturationTintController.isAvailable(getContext())) {
454 mGlobalSaturationTintController.setActivated(null);
455 }
Justin Klaassen911e8892016-06-21 18:24:24 -0700456 }
457
Christine Franks57fdde82018-07-03 14:46:07 -0700458 private void onNightDisplayAutoModeChanged(int autoMode) {
459 Slog.d(TAG, "onNightDisplayAutoModeChanged: autoMode=" + autoMode);
Justin Klaassenec8837a2016-08-23 12:04:42 -0700460
Christine Franks57fdde82018-07-03 14:46:07 -0700461 if (mNightDisplayAutoMode != null) {
462 mNightDisplayAutoMode.onStop();
463 mNightDisplayAutoMode = null;
Justin Klaassen911e8892016-06-21 18:24:24 -0700464 }
465
Christine Franks83cc5412018-07-03 14:46:07 -0700466 if (autoMode == AUTO_MODE_CUSTOM_TIME) {
Christine Franks57fdde82018-07-03 14:46:07 -0700467 mNightDisplayAutoMode = new CustomNightDisplayAutoMode();
Christine Franks83cc5412018-07-03 14:46:07 -0700468 } else if (autoMode == AUTO_MODE_TWILIGHT) {
Christine Franks57fdde82018-07-03 14:46:07 -0700469 mNightDisplayAutoMode = new TwilightNightDisplayAutoMode();
Justin Klaassen911e8892016-06-21 18:24:24 -0700470 }
471
Christine Franks57fdde82018-07-03 14:46:07 -0700472 if (mNightDisplayAutoMode != null) {
473 mNightDisplayAutoMode.onStart();
Justin Klaassen911e8892016-06-21 18:24:24 -0700474 }
475 }
476
Christine Franks57fdde82018-07-03 14:46:07 -0700477 private void onNightDisplayCustomStartTimeChanged(LocalTime startTime) {
478 Slog.d(TAG, "onNightDisplayCustomStartTimeChanged: startTime=" + startTime);
Justin Klaassenec8837a2016-08-23 12:04:42 -0700479
Christine Franks57fdde82018-07-03 14:46:07 -0700480 if (mNightDisplayAutoMode != null) {
481 mNightDisplayAutoMode.onCustomStartTimeChanged(startTime);
Justin Klaassen911e8892016-06-21 18:24:24 -0700482 }
483 }
484
Christine Franks57fdde82018-07-03 14:46:07 -0700485 private void onNightDisplayCustomEndTimeChanged(LocalTime endTime) {
486 Slog.d(TAG, "onNightDisplayCustomEndTimeChanged: endTime=" + endTime);
Justin Klaassenec8837a2016-08-23 12:04:42 -0700487
Christine Franks57fdde82018-07-03 14:46:07 -0700488 if (mNightDisplayAutoMode != null) {
489 mNightDisplayAutoMode.onCustomEndTimeChanged(endTime);
Justin Klaassen911e8892016-06-21 18:24:24 -0700490 }
491 }
492
Christine Franks57fdde82018-07-03 14:46:07 -0700493 private void onDisplayColorModeChanged(int mode) {
Christine Franks83cc5412018-07-03 14:46:07 -0700494 if (mode == NOT_SET) {
Christine Frankscf388c22018-05-15 15:48:10 -0700495 return;
496 }
497
Christine Franks245ffd42018-11-16 13:45:14 -0800498 mNightDisplayTintController.cancelAnimator();
499 mDisplayWhiteBalanceTintController.cancelAnimator();
500
Christine Franksa4ed3762019-01-24 15:37:04 -0800501 if (mNightDisplayTintController.isAvailable(getContext())) {
502 mNightDisplayTintController
503 .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
Christine Franks78a4dd42019-02-08 11:09:30 -0800504 mNightDisplayTintController
505 .setMatrix(mNightDisplayTintController.getColorTemperatureSetting());
Christine Franksa4ed3762019-01-24 15:37:04 -0800506 }
Christine Franks245ffd42018-11-16 13:45:14 -0800507
Daniel Solomon8b72c5b2018-11-25 11:07:13 -0800508 updateDisplayWhiteBalanceStatus();
Christine Franks8ad71492017-10-24 19:04:22 -0700509
Christine Franks218e6562017-11-27 10:20:14 -0800510 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
Christine Franks245ffd42018-11-16 13:45:14 -0800511 dtm.setColorMode(mode, mNightDisplayTintController.getMatrix());
Christine Franks8ad71492017-10-24 19:04:22 -0700512 }
513
Christine Franks9114f462019-01-04 11:27:30 -0800514 private void onAccessibilityActivated() {
Christine Franks71e003e2019-01-24 14:40:20 -0800515 onDisplayColorModeChanged(getColorModeInternal());
Daniel Solomon317a3572018-03-30 18:36:37 -0700516 }
517
Christine Franks9114f462019-01-04 11:27:30 -0800518 /**
519 * Apply the accessibility daltonizer transform based on the settings value.
520 */
521 private void onAccessibilityDaltonizerChanged() {
522 final boolean enabled = Secure.getIntForUser(getContext().getContentResolver(),
523 Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, mCurrentUser) != 0;
524 final int daltonizerMode = enabled ? Secure.getIntForUser(getContext().getContentResolver(),
525 Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
526 AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY, mCurrentUser)
527 : AccessibilityManager.DALTONIZER_DISABLED;
528
529 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
530 if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) {
531 // Monochromacy isn't supported by the native Daltonizer implementation; use grayscale.
532 dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE,
533 MATRIX_GRAYSCALE);
534 dtm.setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
535 } else {
536 dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE, null);
537 dtm.setDaltonizerMode(daltonizerMode);
538 }
539 }
540
541 /**
542 * Apply the accessibility inversion transform based on the settings value.
543 */
544 private void onAccessibilityInversionChanged() {
545 final boolean enabled = Secure.getIntForUser(getContext().getContentResolver(),
546 Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, mCurrentUser) != 0;
547 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
548 dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_INVERT_COLOR,
549 enabled ? MATRIX_INVERT_COLOR : null);
550 }
Christine Franks8ad71492017-10-24 19:04:22 -0700551
Christine Franks6418d0b2017-02-13 09:48:00 -0800552 /**
553 * Applies current color temperature matrix, or removes it if deactivated.
554 *
555 * @param immediate {@code true} skips transition animation
556 */
Christine Franks245ffd42018-11-16 13:45:14 -0800557 private void applyTint(TintController tintController, boolean immediate) {
558 tintController.cancelAnimator();
Christine Franks6418d0b2017-02-13 09:48:00 -0800559
Christine Franks6418d0b2017-02-13 09:48:00 -0800560 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
Christine Franks245ffd42018-11-16 13:45:14 -0800561 final float[] from = dtm.getColorMatrix(tintController.getLevel());
562 final float[] to = tintController.getMatrix();
Christine Franks6418d0b2017-02-13 09:48:00 -0800563
564 if (immediate) {
Christine Franks245ffd42018-11-16 13:45:14 -0800565 dtm.setColorMatrix(tintController.getLevel(), to);
Christine Franks6418d0b2017-02-13 09:48:00 -0800566 } else {
Christine Franks245ffd42018-11-16 13:45:14 -0800567 tintController.setAnimator(ValueAnimator.ofObject(COLOR_MATRIX_EVALUATOR,
568 from == null ? MATRIX_IDENTITY : from, to));
569 tintController.getAnimator().setDuration(TRANSITION_DURATION);
570 tintController.getAnimator().setInterpolator(AnimationUtils.loadInterpolator(
Christine Franks6418d0b2017-02-13 09:48:00 -0800571 getContext(), android.R.interpolator.fast_out_slow_in));
Christine Franks245ffd42018-11-16 13:45:14 -0800572 tintController.getAnimator().addUpdateListener((ValueAnimator animator) -> {
573 final float[] value = (float[]) animator.getAnimatedValue();
574 dtm.setColorMatrix(tintController.getLevel(), value);
Christine Franks6418d0b2017-02-13 09:48:00 -0800575 });
Christine Franks245ffd42018-11-16 13:45:14 -0800576 tintController.getAnimator().addListener(new AnimatorListenerAdapter() {
Christine Franks6418d0b2017-02-13 09:48:00 -0800577
578 private boolean mIsCancelled;
579
580 @Override
581 public void onAnimationCancel(Animator animator) {
582 mIsCancelled = true;
583 }
584
585 @Override
586 public void onAnimationEnd(Animator animator) {
587 if (!mIsCancelled) {
588 // Ensure final color matrix is set at the end of the animation. If the
589 // animation is cancelled then don't set the final color matrix so the new
590 // animator can pick up from where this one left off.
Christine Franks245ffd42018-11-16 13:45:14 -0800591 dtm.setColorMatrix(tintController.getLevel(), to);
Christine Franks6418d0b2017-02-13 09:48:00 -0800592 }
Christine Franks245ffd42018-11-16 13:45:14 -0800593 tintController.setAnimator(null);
Christine Franks6418d0b2017-02-13 09:48:00 -0800594 }
595 });
Christine Franks245ffd42018-11-16 13:45:14 -0800596 tintController.getAnimator().start();
Christine Franks6418d0b2017-02-13 09:48:00 -0800597 }
598 }
599
600 /**
Christine Franks39b03112018-07-03 14:46:07 -0700601 * Returns the first date time corresponding to the local time that occurs before the provided
602 * date time.
Christine Franks03213462017-08-25 13:57:26 -0700603 *
604 * @param compareTime the LocalDateTime to compare against
605 * @return the prior LocalDateTime corresponding to this local time
606 */
Christine Franks57fdde82018-07-03 14:46:07 -0700607 @VisibleForTesting
608 static LocalDateTime getDateTimeBefore(LocalTime localTime, LocalDateTime compareTime) {
Christine Franks03213462017-08-25 13:57:26 -0700609 final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
610 compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());
611
612 // Check if the local time has passed, if so return the same time yesterday.
613 return ldt.isAfter(compareTime) ? ldt.minusDays(1) : ldt;
614 }
615
616 /**
Christine Franks39b03112018-07-03 14:46:07 -0700617 * Returns the first date time corresponding to this local time that occurs after the provided
618 * date time.
Christine Franks03213462017-08-25 13:57:26 -0700619 *
620 * @param compareTime the LocalDateTime to compare against
621 * @return the next LocalDateTime corresponding to this local time
622 */
Christine Franks57fdde82018-07-03 14:46:07 -0700623 @VisibleForTesting
624 static LocalDateTime getDateTimeAfter(LocalTime localTime, LocalDateTime compareTime) {
Christine Franks03213462017-08-25 13:57:26 -0700625 final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
626 compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());
627
628 // Check if the local time has passed, if so return the same time tomorrow.
629 return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
630 }
631
Long Ling1d3f1892019-02-06 12:34:02 -0800632 @VisibleForTesting
633 void updateDisplayWhiteBalanceStatus() {
Daniel Solomon8b72c5b2018-11-25 11:07:13 -0800634 boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated();
635 mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled() &&
636 !mNightDisplayTintController.isActivated() &&
637 DisplayTransformManager.needsLinearColorMatrix());
638 boolean activated = mDisplayWhiteBalanceTintController.isActivated();
639
640 if (mDisplayWhiteBalanceListener != null && oldActivated != activated) {
641 mDisplayWhiteBalanceListener.onDisplayWhiteBalanceStatusChanged(activated);
Christine Franks245ffd42018-11-16 13:45:14 -0800642 }
Daniel Solomon86508f82019-01-18 19:01:02 -0800643
644 // If disabled, clear the tint. If enabled, do nothing more here and let the next
645 // temperature update set the correct tint.
646 if (!activated) {
Christine Franksc7fb9452019-02-04 08:45:33 -0800647 mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE);
Daniel Solomon86508f82019-01-18 19:01:02 -0800648 }
Christine Franks245ffd42018-11-16 13:45:14 -0800649 }
650
651 private boolean isDisplayWhiteBalanceSettingEnabled() {
652 return Secure.getIntForUser(getContext().getContentResolver(),
653 Secure.DISPLAY_WHITE_BALANCE_ENABLED, 0, mCurrentUser) == 1;
654 }
655
Christine Franks39b03112018-07-03 14:46:07 -0700656 private boolean isDeviceColorManagedInternal() {
657 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
658 return dtm.isDeviceColorManaged();
659 }
660
Christine Franks55194dc2019-01-15 13:47:06 -0800661 private int getTransformCapabilitiesInternal() {
662 int availabilityFlags = ColorDisplayManager.CAPABILITY_NONE;
663 if (SurfaceControl.getProtectedContentSupport()) {
664 availabilityFlags |= ColorDisplayManager.CAPABILITY_PROTECTED_CONTENT;
665 }
666 final Resources res = getContext().getResources();
667 if (res.getBoolean(R.bool.config_setColorTransformAccelerated)) {
668 availabilityFlags |= ColorDisplayManager.CAPABILITY_HARDWARE_ACCELERATION_GLOBAL;
669 }
670 if (res.getBoolean(R.bool.config_setColorTransformAcceleratedPerLayer)) {
671 availabilityFlags |= ColorDisplayManager.CAPABILITY_HARDWARE_ACCELERATION_PER_APP;
672 }
673 return availabilityFlags;
674 }
675
Christine Franks83cc5412018-07-03 14:46:07 -0700676 private boolean setNightDisplayAutoModeInternal(@AutoMode int autoMode) {
677 if (getNightDisplayAutoModeInternal() != autoMode) {
678 Secure.putStringForUser(getContext().getContentResolver(),
679 Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
680 null,
681 mCurrentUser);
682 }
683 return Secure.putIntForUser(getContext().getContentResolver(),
684 Secure.NIGHT_DISPLAY_AUTO_MODE, autoMode, mCurrentUser);
685 }
686
687 private int getNightDisplayAutoModeInternal() {
688 int autoMode = getNightDisplayAutoModeRawInternal();
689 if (autoMode == NOT_SET) {
690 autoMode = getContext().getResources().getInteger(
691 R.integer.config_defaultNightDisplayAutoMode);
692 }
693 if (autoMode != AUTO_MODE_DISABLED
694 && autoMode != AUTO_MODE_CUSTOM_TIME
695 && autoMode != AUTO_MODE_TWILIGHT) {
696 Slog.e(TAG, "Invalid autoMode: " + autoMode);
697 autoMode = AUTO_MODE_DISABLED;
698 }
699 return autoMode;
700 }
701
702 private int getNightDisplayAutoModeRawInternal() {
703 return Secure
704 .getIntForUser(getContext().getContentResolver(), Secure.NIGHT_DISPLAY_AUTO_MODE,
705 NOT_SET, mCurrentUser);
706 }
707
708 private Time getNightDisplayCustomStartTimeInternal() {
709 int startTimeValue = Secure.getIntForUser(getContext().getContentResolver(),
710 Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, NOT_SET, mCurrentUser);
711 if (startTimeValue == NOT_SET) {
712 startTimeValue = getContext().getResources().getInteger(
713 R.integer.config_defaultNightDisplayCustomStartTime);
714 }
715 return new Time(LocalTime.ofSecondOfDay(startTimeValue / 1000));
716 }
717
718 private boolean setNightDisplayCustomStartTimeInternal(Time startTime) {
719 return Secure.putIntForUser(getContext().getContentResolver(),
720 Secure.NIGHT_DISPLAY_CUSTOM_START_TIME,
721 startTime.getLocalTime().toSecondOfDay() * 1000,
722 mCurrentUser);
723 }
724
725 private Time getNightDisplayCustomEndTimeInternal() {
726 int endTimeValue = Secure.getIntForUser(getContext().getContentResolver(),
727 Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, NOT_SET, mCurrentUser);
728 if (endTimeValue == NOT_SET) {
729 endTimeValue = getContext().getResources().getInteger(
730 R.integer.config_defaultNightDisplayCustomEndTime);
731 }
732 return new Time(LocalTime.ofSecondOfDay(endTimeValue / 1000));
733 }
734
735 private boolean setNightDisplayCustomEndTimeInternal(Time endTime) {
736 return Secure.putIntForUser(getContext().getContentResolver(),
737 Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.getLocalTime().toSecondOfDay() * 1000,
738 mCurrentUser);
739 }
740
Christine Franks57fdde82018-07-03 14:46:07 -0700741 /**
742 * Returns the last time the night display transform activation state was changed, or {@link
743 * LocalDateTime#MIN} if night display has never been activated.
744 */
Christine Franks245ffd42018-11-16 13:45:14 -0800745 private LocalDateTime getNightDisplayLastActivatedTimeSetting() {
Christine Franks57fdde82018-07-03 14:46:07 -0700746 final ContentResolver cr = getContext().getContentResolver();
747 final String lastActivatedTime = Secure.getStringForUser(
748 cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, getContext().getUserId());
749 if (lastActivatedTime != null) {
750 try {
751 return LocalDateTime.parse(lastActivatedTime);
752 } catch (DateTimeParseException ignored) {
753 }
754 // Uses the old epoch time.
755 try {
756 return LocalDateTime.ofInstant(
757 Instant.ofEpochMilli(Long.parseLong(lastActivatedTime)),
758 ZoneId.systemDefault());
759 } catch (DateTimeException | NumberFormatException ignored) {
760 }
761 }
762 return LocalDateTime.MIN;
763 }
764
Christine Franksf3529b22019-01-03 13:20:17 -0800765 private boolean setAppSaturationLevelInternal(String packageName, int saturationLevel) {
766 return mAppSaturationController
767 .setSaturationLevel(packageName, mCurrentUser, saturationLevel);
768 }
769
Christine Franksd154fe52019-01-04 17:17:45 -0800770 private void setColorModeInternal(@ColorMode int colorMode) {
771 if (!isColorModeAvailable(colorMode)) {
772 throw new IllegalArgumentException("Invalid colorMode: " + colorMode);
773 }
774 System.putIntForUser(getContext().getContentResolver(), System.DISPLAY_COLOR_MODE,
775 colorMode,
776 mCurrentUser);
777 }
778
Christine Franks71e003e2019-01-24 14:40:20 -0800779 private @ColorMode int getColorModeInternal() {
Christine Franksd154fe52019-01-04 17:17:45 -0800780 final ContentResolver cr = getContext().getContentResolver();
781 if (Secure.getIntForUser(cr, Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
782 0, mCurrentUser) == 1
783 || Secure.getIntForUser(cr, Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
784 0, mCurrentUser) == 1) {
785 // There are restrictions on the available color modes combined with a11y transforms.
786 if (isColorModeAvailable(COLOR_MODE_SATURATED)) {
787 return COLOR_MODE_SATURATED;
788 } else if (isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
789 return COLOR_MODE_AUTOMATIC;
790 }
791 }
792
793 int colorMode = System.getIntForUser(cr, System.DISPLAY_COLOR_MODE, -1, mCurrentUser);
794 if (colorMode == -1) {
795 // There might be a system property controlling color mode that we need to respect; if
796 // not, this will set a suitable default.
797 colorMode = getCurrentColorModeFromSystemProperties();
798 }
799
800 // This happens when a color mode is no longer available (e.g., after system update or B&R)
801 // or the device does not support any color mode.
802 if (!isColorModeAvailable(colorMode)) {
803 if (colorMode == COLOR_MODE_BOOSTED && isColorModeAvailable(COLOR_MODE_NATURAL)) {
804 colorMode = COLOR_MODE_NATURAL;
805 } else if (colorMode == COLOR_MODE_SATURATED
806 && isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
807 colorMode = COLOR_MODE_AUTOMATIC;
808 } else if (colorMode == COLOR_MODE_AUTOMATIC
809 && isColorModeAvailable(COLOR_MODE_SATURATED)) {
810 colorMode = COLOR_MODE_SATURATED;
811 } else {
812 colorMode = -1;
813 }
814 }
815
816 return colorMode;
817 }
818
819 /**
820 * Get the current color mode from system properties, or return -1 if invalid.
821 *
822 * See {@link com.android.server.display.DisplayTransformManager}
823 */
Christine Franks78a4dd42019-02-08 11:09:30 -0800824 private @ColorMode int getCurrentColorModeFromSystemProperties() {
Christine Franksd154fe52019-01-04 17:17:45 -0800825 final int displayColorSetting = SystemProperties.getInt("persist.sys.sf.native_mode", 0);
826 if (displayColorSetting == 0) {
827 return "1.0".equals(SystemProperties.get("persist.sys.sf.color_saturation"))
828 ? COLOR_MODE_NATURAL : COLOR_MODE_BOOSTED;
829 } else if (displayColorSetting == 1) {
830 return COLOR_MODE_SATURATED;
831 } else if (displayColorSetting == 2) {
832 return COLOR_MODE_AUTOMATIC;
833 } else {
834 return -1;
835 }
836 }
837
838 private boolean isColorModeAvailable(@ColorMode int colorMode) {
839 final int[] availableColorModes = getContext().getResources().getIntArray(
840 R.array.config_availableColorModes);
841 if (availableColorModes != null) {
842 for (int mode : availableColorModes) {
843 if (mode == colorMode) {
844 return true;
845 }
846 }
847 }
848 return false;
849 }
850
Christine Franksf3529b22019-01-03 13:20:17 -0800851 private void dumpInternal(PrintWriter pw) {
852 pw.println("COLOR DISPLAY MANAGER dumpsys (color_display)");
Christine Franksa4ed3762019-01-24 15:37:04 -0800853
Christine Franksf3529b22019-01-03 13:20:17 -0800854 pw.println("Night Display:");
Christine Franksa4ed3762019-01-24 15:37:04 -0800855 if (mNightDisplayTintController.isAvailable(getContext())) {
Christine Franksf3529b22019-01-03 13:20:17 -0800856 pw.println(" Activated: " + mNightDisplayTintController.isActivated());
Christine Franksa4ed3762019-01-24 15:37:04 -0800857 pw.println(" Color temp: " + mNightDisplayTintController.getColorTemperature());
Christine Franksf3529b22019-01-03 13:20:17 -0800858 } else {
859 pw.println(" Not available");
860 }
Christine Franksa4ed3762019-01-24 15:37:04 -0800861
862 pw.println("Global saturation:");
863 if (mGlobalSaturationTintController.isAvailable(getContext())) {
864 pw.println(" Activated: " + mGlobalSaturationTintController.isActivated());
865 } else {
866 pw.println(" Not available");
867 }
868
Christine Franksf3529b22019-01-03 13:20:17 -0800869 mAppSaturationController.dump(pw);
Christine Franksa4ed3762019-01-24 15:37:04 -0800870
871 pw.println("Display white balance:");
872 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
873 pw.println(" Activated: " + mDisplayWhiteBalanceTintController.isActivated());
Long Ling1d3f1892019-02-06 12:34:02 -0800874 mDisplayWhiteBalanceTintController.dump(pw);
Christine Franksa4ed3762019-01-24 15:37:04 -0800875 } else {
876 pw.println(" Not available");
877 }
878
879 pw.println("Color mode: " + getColorModeInternal());
Christine Franksf3529b22019-01-03 13:20:17 -0800880 }
881
Christine Franks57fdde82018-07-03 14:46:07 -0700882 private abstract class NightDisplayAutoMode {
883
884 public abstract void onActivated(boolean activated);
885
Justin Klaassen911e8892016-06-21 18:24:24 -0700886 public abstract void onStart();
Christine Frankse5bb03e2017-02-10 17:36:10 -0800887
Justin Klaassen911e8892016-06-21 18:24:24 -0700888 public abstract void onStop();
Christine Franks57fdde82018-07-03 14:46:07 -0700889
890 public void onCustomStartTimeChanged(LocalTime startTime) {
891 }
892
893 public void onCustomEndTimeChanged(LocalTime endTime) {
894 }
Justin Klaassen911e8892016-06-21 18:24:24 -0700895 }
896
Christine Franks57fdde82018-07-03 14:46:07 -0700897 private final class CustomNightDisplayAutoMode extends NightDisplayAutoMode implements
898 AlarmManager.OnAlarmListener {
Justin Klaassen911e8892016-06-21 18:24:24 -0700899
900 private final AlarmManager mAlarmManager;
901 private final BroadcastReceiver mTimeChangedReceiver;
902
Christine Franks03213462017-08-25 13:57:26 -0700903 private LocalTime mStartTime;
904 private LocalTime mEndTime;
Justin Klaassen911e8892016-06-21 18:24:24 -0700905
Christine Franks03213462017-08-25 13:57:26 -0700906 private LocalDateTime mLastActivatedTime;
Justin Klaassen911e8892016-06-21 18:24:24 -0700907
Christine Franks57fdde82018-07-03 14:46:07 -0700908 CustomNightDisplayAutoMode() {
Justin Klaassen911e8892016-06-21 18:24:24 -0700909 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
910 mTimeChangedReceiver = new BroadcastReceiver() {
911 @Override
912 public void onReceive(Context context, Intent intent) {
913 updateActivated();
914 }
915 };
916 }
917
918 private void updateActivated() {
Christine Franks03213462017-08-25 13:57:26 -0700919 final LocalDateTime now = LocalDateTime.now();
920 final LocalDateTime start = getDateTimeBefore(mStartTime, now);
921 final LocalDateTime end = getDateTimeAfter(mEndTime, start);
922 boolean activate = now.isBefore(end);
Justin Klaassen911e8892016-06-21 18:24:24 -0700923
Christine Frankse5bb03e2017-02-10 17:36:10 -0800924 if (mLastActivatedTime != null) {
Christine Frankse5bb03e2017-02-10 17:36:10 -0800925 // Maintain the existing activated state if within the current period.
Christine Franks03213462017-08-25 13:57:26 -0700926 if (mLastActivatedTime.isBefore(now) && mLastActivatedTime.isAfter(start)
927 && (mLastActivatedTime.isAfter(end) || now.isBefore(end))) {
Christine Franks78a4dd42019-02-08 11:09:30 -0800928 activate = mNightDisplayTintController.isActivatedSetting();
Justin Klaassen911e8892016-06-21 18:24:24 -0700929 }
930 }
931
Christine Franks245ffd42018-11-16 13:45:14 -0800932 if (mNightDisplayTintController.isActivatedStateNotSet() || (
933 mNightDisplayTintController.isActivated() != activate)) {
Christine Franks83cc5412018-07-03 14:46:07 -0700934 mNightDisplayTintController.setActivated(activate);
Justin Klaassen911e8892016-06-21 18:24:24 -0700935 }
Christine Franks03213462017-08-25 13:57:26 -0700936
Christine Franks245ffd42018-11-16 13:45:14 -0800937 updateNextAlarm(mNightDisplayTintController.isActivated(), now);
Justin Klaassen911e8892016-06-21 18:24:24 -0700938 }
939
Christine Franks03213462017-08-25 13:57:26 -0700940 private void updateNextAlarm(@Nullable Boolean activated, @NonNull LocalDateTime now) {
Justin Klaassen4346f632016-08-08 15:01:47 -0700941 if (activated != null) {
Christine Franks03213462017-08-25 13:57:26 -0700942 final LocalDateTime next = activated ? getDateTimeAfter(mEndTime, now)
943 : getDateTimeAfter(mStartTime, now);
944 final long millis = next.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
945 mAlarmManager.setExact(AlarmManager.RTC, millis, TAG, this, null);
Justin Klaassen911e8892016-06-21 18:24:24 -0700946 }
947 }
948
949 @Override
950 public void onStart() {
951 final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_TIME_CHANGED);
952 intentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
953 getContext().registerReceiver(mTimeChangedReceiver, intentFilter);
954
Christine Franks83cc5412018-07-03 14:46:07 -0700955 mStartTime = getNightDisplayCustomStartTimeInternal().getLocalTime();
956 mEndTime = getNightDisplayCustomEndTimeInternal().getLocalTime();
Justin Klaassen911e8892016-06-21 18:24:24 -0700957
Christine Franks57fdde82018-07-03 14:46:07 -0700958 mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
Christine Frankse5bb03e2017-02-10 17:36:10 -0800959
Justin Klaassen911e8892016-06-21 18:24:24 -0700960 // Force an update to initialize state.
961 updateActivated();
962 }
963
964 @Override
965 public void onStop() {
966 getContext().unregisterReceiver(mTimeChangedReceiver);
967
968 mAlarmManager.cancel(this);
969 mLastActivatedTime = null;
970 }
971
972 @Override
973 public void onActivated(boolean activated) {
Christine Franks57fdde82018-07-03 14:46:07 -0700974 mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
Christine Franks03213462017-08-25 13:57:26 -0700975 updateNextAlarm(activated, LocalDateTime.now());
Justin Klaassen911e8892016-06-21 18:24:24 -0700976 }
977
978 @Override
Christine Franks03213462017-08-25 13:57:26 -0700979 public void onCustomStartTimeChanged(LocalTime startTime) {
Justin Klaassen911e8892016-06-21 18:24:24 -0700980 mStartTime = startTime;
981 mLastActivatedTime = null;
982 updateActivated();
983 }
984
985 @Override
Christine Franks03213462017-08-25 13:57:26 -0700986 public void onCustomEndTimeChanged(LocalTime endTime) {
Justin Klaassen911e8892016-06-21 18:24:24 -0700987 mEndTime = endTime;
988 mLastActivatedTime = null;
989 updateActivated();
990 }
991
992 @Override
993 public void onAlarm() {
Justin Klaassenec8837a2016-08-23 12:04:42 -0700994 Slog.d(TAG, "onAlarm");
Justin Klaassen911e8892016-06-21 18:24:24 -0700995 updateActivated();
996 }
997 }
998
Christine Franks57fdde82018-07-03 14:46:07 -0700999 private final class TwilightNightDisplayAutoMode extends NightDisplayAutoMode implements
1000 TwilightListener {
Justin Klaassen911e8892016-06-21 18:24:24 -07001001
1002 private final TwilightManager mTwilightManager;
Christine Franks57fdde82018-07-03 14:46:07 -07001003 private LocalDateTime mLastActivatedTime;
Justin Klaassen911e8892016-06-21 18:24:24 -07001004
Christine Franks57fdde82018-07-03 14:46:07 -07001005 TwilightNightDisplayAutoMode() {
Justin Klaassen911e8892016-06-21 18:24:24 -07001006 mTwilightManager = getLocalService(TwilightManager.class);
Justin Klaassen911e8892016-06-21 18:24:24 -07001007 }
1008
Justin Klaassen908b86c2016-08-08 09:18:42 -07001009 private void updateActivated(TwilightState state) {
Justin Klaassen3da4c442017-05-05 15:19:33 -07001010 if (state == null) {
1011 // If there isn't a valid TwilightState then just keep the current activated
1012 // state.
1013 return;
1014 }
1015
1016 boolean activate = state.isNight();
Christine Franks57fdde82018-07-03 14:46:07 -07001017 if (mLastActivatedTime != null) {
Christine Franks03213462017-08-25 13:57:26 -07001018 final LocalDateTime now = LocalDateTime.now();
1019 final LocalDateTime sunrise = state.sunrise();
1020 final LocalDateTime sunset = state.sunset();
Christine Frankse5bb03e2017-02-10 17:36:10 -08001021 // Maintain the existing activated state if within the current period.
Christine Franks57fdde82018-07-03 14:46:07 -07001022 if (mLastActivatedTime.isBefore(now) && (mLastActivatedTime.isBefore(sunrise)
1023 ^ mLastActivatedTime.isBefore(sunset))) {
Christine Franks78a4dd42019-02-08 11:09:30 -08001024 activate = mNightDisplayTintController.isActivatedSetting();
Justin Klaassen911e8892016-06-21 18:24:24 -07001025 }
1026 }
Justin Klaassen908b86c2016-08-08 09:18:42 -07001027
Christine Franks245ffd42018-11-16 13:45:14 -08001028 if (mNightDisplayTintController.isActivatedStateNotSet() || (
1029 mNightDisplayTintController.isActivated() != activate)) {
Christine Franks83cc5412018-07-03 14:46:07 -07001030 mNightDisplayTintController.setActivated(activate);
Justin Klaassen908b86c2016-08-08 09:18:42 -07001031 }
Justin Klaassen911e8892016-06-21 18:24:24 -07001032 }
1033
1034 @Override
Christine Franks57fdde82018-07-03 14:46:07 -07001035 public void onActivated(boolean activated) {
1036 mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
1037 }
1038
1039 @Override
Justin Klaassen911e8892016-06-21 18:24:24 -07001040 public void onStart() {
1041 mTwilightManager.registerListener(this, mHandler);
Christine Franks57fdde82018-07-03 14:46:07 -07001042 mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
Justin Klaassen911e8892016-06-21 18:24:24 -07001043
1044 // Force an update to initialize state.
Justin Klaassen908b86c2016-08-08 09:18:42 -07001045 updateActivated(mTwilightManager.getLastTwilightState());
Justin Klaassen911e8892016-06-21 18:24:24 -07001046 }
1047
1048 @Override
1049 public void onStop() {
1050 mTwilightManager.unregisterListener(this);
Christine Franks57fdde82018-07-03 14:46:07 -07001051 mLastActivatedTime = null;
Justin Klaassen908b86c2016-08-08 09:18:42 -07001052 }
1053
1054 @Override
1055 public void onTwilightStateChanged(@Nullable TwilightState state) {
Justin Klaassenec8837a2016-08-23 12:04:42 -07001056 Slog.d(TAG, "onTwilightStateChanged: isNight="
1057 + (state == null ? null : state.isNight()));
Justin Klaassen908b86c2016-08-08 09:18:42 -07001058 updateActivated(state);
Justin Klaassen911e8892016-06-21 18:24:24 -07001059 }
1060 }
Justin Klaassen639214e2016-07-14 21:00:06 -07001061
1062 /**
1063 * Interpolates between two 4x4 color transform matrices (in column-major order).
1064 */
1065 private static class ColorMatrixEvaluator implements TypeEvaluator<float[]> {
1066
1067 /**
1068 * Result matrix returned by {@link #evaluate(float, float[], float[])}.
1069 */
1070 private final float[] mResultMatrix = new float[16];
1071
1072 @Override
1073 public float[] evaluate(float fraction, float[] startValue, float[] endValue) {
1074 for (int i = 0; i < mResultMatrix.length; i++) {
1075 mResultMatrix[i] = MathUtils.lerp(startValue[i], endValue[i], fraction);
1076 }
1077 return mResultMatrix;
1078 }
1079 }
Christine Franks39b03112018-07-03 14:46:07 -07001080
Christine Franks245ffd42018-11-16 13:45:14 -08001081 private abstract static class TintController {
1082
1083 private ValueAnimator mAnimator;
1084 private Boolean mIsActivated;
1085
1086 public ValueAnimator getAnimator() {
1087 return mAnimator;
1088 }
1089
1090 public void setAnimator(ValueAnimator animator) {
1091 mAnimator = animator;
1092 }
1093
1094 /**
1095 * Cancel the animator if it's still running.
1096 */
1097 public void cancelAnimator() {
1098 if (mAnimator != null) {
1099 mAnimator.cancel();
1100 }
1101 }
1102
1103 /**
1104 * End the animator if it's still running, jumping to the end state.
1105 */
1106 public void endAnimator() {
1107 if (mAnimator != null) {
1108 mAnimator.end();
1109 mAnimator = null;
1110 }
1111 }
1112
1113 public void setActivated(Boolean isActivated) {
1114 mIsActivated = isActivated;
1115 }
1116
1117 public boolean isActivated() {
1118 return mIsActivated != null && mIsActivated;
1119 }
1120
1121 public boolean isActivatedStateNotSet() {
1122 return mIsActivated == null;
1123 }
1124
1125 /**
Daniel Solomon8b72c5b2018-11-25 11:07:13 -08001126 * Dump debug information.
1127 */
1128 public void dump(PrintWriter pw) {
1129 }
1130
1131 /**
Christine Franks245ffd42018-11-16 13:45:14 -08001132 * Set up any constants needed for computing the matrix.
1133 */
1134 public abstract void setUp(Context context, boolean needsLinear);
1135
1136 /**
1137 * Sets the 4x4 matrix to apply.
1138 */
1139 public abstract void setMatrix(int value);
1140
1141 /**
1142 * Get the 4x4 matrix to apply.
1143 */
1144 public abstract float[] getMatrix();
1145
1146 /**
1147 * Get the color transform level to apply the matrix.
1148 */
1149 public abstract int getLevel();
Christine Franksa4ed3762019-01-24 15:37:04 -08001150
1151 /**
1152 * Returns whether or not this transform type is available on this device.
1153 */
1154 public abstract boolean isAvailable(Context context);
Christine Franks245ffd42018-11-16 13:45:14 -08001155 }
1156
Christine Franks83cc5412018-07-03 14:46:07 -07001157 private final class NightDisplayTintController extends TintController {
1158
Christine Franksa4ed3762019-01-24 15:37:04 -08001159 private final float[] mMatrix = new float[16];
Christine Franks83cc5412018-07-03 14:46:07 -07001160 private final float[] mColorTempCoefficients = new float[9];
Christine Franksa4ed3762019-01-24 15:37:04 -08001161
1162 private Boolean mIsAvailable;
Christine Franks83cc5412018-07-03 14:46:07 -07001163 private Integer mColorTemp;
1164
1165 /**
1166 * Set coefficients based on whether the color matrix is linear or not.
1167 */
1168 @Override
1169 public void setUp(Context context, boolean needsLinear) {
1170 final String[] coefficients = context.getResources().getStringArray(needsLinear
1171 ? R.array.config_nightDisplayColorTemperatureCoefficients
1172 : R.array.config_nightDisplayColorTemperatureCoefficientsNative);
1173 for (int i = 0; i < 9 && i < coefficients.length; i++) {
1174 mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]);
1175 }
1176 }
1177
1178 @Override
1179 public void setMatrix(int cct) {
1180 if (mMatrix.length != 16) {
1181 Slog.d(TAG, "The display transformation matrix must be 4x4");
1182 return;
1183 }
1184
1185 Matrix.setIdentityM(mMatrix, 0);
1186
1187 final float squareTemperature = cct * cct;
1188 final float red = squareTemperature * mColorTempCoefficients[0]
1189 + cct * mColorTempCoefficients[1] + mColorTempCoefficients[2];
1190 final float green = squareTemperature * mColorTempCoefficients[3]
1191 + cct * mColorTempCoefficients[4] + mColorTempCoefficients[5];
1192 final float blue = squareTemperature * mColorTempCoefficients[6]
1193 + cct * mColorTempCoefficients[7] + mColorTempCoefficients[8];
1194 mMatrix[0] = red;
1195 mMatrix[5] = green;
1196 mMatrix[10] = blue;
1197 }
1198
1199 @Override
1200 public float[] getMatrix() {
1201 return isActivated() ? mMatrix : MATRIX_IDENTITY;
1202 }
1203
1204 @Override
1205 public void setActivated(Boolean activated) {
1206 if (activated == null) {
1207 super.setActivated(null);
1208 return;
1209 }
1210
1211 boolean activationStateChanged = activated != isActivated();
1212
1213 if (!isActivatedStateNotSet() && activationStateChanged) {
1214 // This is a true state change, so set this as the last activation time.
1215 Secure.putStringForUser(getContext().getContentResolver(),
1216 Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
1217 LocalDateTime.now().toString(),
1218 mCurrentUser);
1219 }
1220
1221 if (isActivatedStateNotSet() || activationStateChanged) {
1222 super.setActivated(activated);
Christine Franks78a4dd42019-02-08 11:09:30 -08001223 if (isActivatedSetting() != activated) {
1224 Secure.putIntForUser(getContext().getContentResolver(),
1225 Secure.NIGHT_DISPLAY_ACTIVATED,
1226 activated ? 1 : 0, mCurrentUser);
1227 }
Christine Franks83cc5412018-07-03 14:46:07 -07001228 onActivated(activated);
1229 }
1230 }
1231
1232 @Override
1233 public int getLevel() {
1234 return LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
1235 }
1236
Christine Franksa4ed3762019-01-24 15:37:04 -08001237 @Override
1238 public boolean isAvailable(Context context) {
1239 if (mIsAvailable == null) {
1240 mIsAvailable = ColorDisplayManager.isNightDisplayAvailable(context);
1241 }
1242 return mIsAvailable;
1243 }
1244
Christine Franks78a4dd42019-02-08 11:09:30 -08001245 private void onActivated(boolean activated) {
Christine Franks83cc5412018-07-03 14:46:07 -07001246 Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display");
1247 if (mNightDisplayAutoMode != null) {
1248 mNightDisplayAutoMode.onActivated(activated);
1249 }
1250
Christine Franksa4ed3762019-01-24 15:37:04 -08001251 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
Christine Franks83cc5412018-07-03 14:46:07 -07001252 updateDisplayWhiteBalanceStatus();
1253 }
1254
1255 mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_ANIMATED);
1256 }
1257
1258 int getColorTemperature() {
1259 return mColorTemp != null ? clampNightDisplayColorTemperature(mColorTemp)
Christine Franks78a4dd42019-02-08 11:09:30 -08001260 : getColorTemperatureSetting();
Christine Franks83cc5412018-07-03 14:46:07 -07001261 }
1262
1263 boolean setColorTemperature(int temperature) {
1264 mColorTemp = temperature;
1265 final boolean success = Secure.putIntForUser(getContext().getContentResolver(),
1266 Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, temperature, mCurrentUser);
1267 onColorTemperatureChanged(temperature);
1268 return success;
1269 }
1270
1271 void onColorTemperatureChanged(int temperature) {
1272 setMatrix(temperature);
1273 mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE);
1274 }
Christine Franks78a4dd42019-02-08 11:09:30 -08001275
1276 boolean isActivatedSetting() {
1277 return Secure.getIntForUser(getContext().getContentResolver(),
1278 Secure.NIGHT_DISPLAY_ACTIVATED, 0, mCurrentUser) == 1;
1279 }
1280
1281 int getColorTemperatureSetting() {
1282 return clampNightDisplayColorTemperature(Secure.getIntForUser(
1283 getContext().getContentResolver(), Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE,
1284 NOT_SET,
1285 mCurrentUser));
1286 }
1287
1288 private int clampNightDisplayColorTemperature(int colorTemperature) {
1289 if (colorTemperature == NOT_SET) {
1290 colorTemperature = getContext().getResources().getInteger(
1291 R.integer.config_nightDisplayColorTemperatureDefault);
1292 }
1293 final int minimumTemperature = ColorDisplayManager
1294 .getMinimumColorTemperature(getContext());
1295 final int maximumTemperature = ColorDisplayManager
1296 .getMaximumColorTemperature(getContext());
1297 if (colorTemperature < minimumTemperature) {
1298 colorTemperature = minimumTemperature;
1299 } else if (colorTemperature > maximumTemperature) {
1300 colorTemperature = maximumTemperature;
1301 }
1302
1303 return colorTemperature;
1304 }
Christine Franks83cc5412018-07-03 14:46:07 -07001305 }
1306
Long Ling1d3f1892019-02-06 12:34:02 -08001307 final class DisplayWhiteBalanceTintController extends TintController {
1308 // Three chromaticity coordinates per color: X, Y, and Z
1309 private final int NUM_VALUES_PER_PRIMARY = 3;
1310 // Four colors: red, green, blue, and white
1311 private final int NUM_DISPLAY_PRIMARIES_VALS = 4 * NUM_VALUES_PER_PRIMARY;
1312
1313 private final Object mLock = new Object();
1314 @VisibleForTesting
1315 int mTemperatureMin;
1316 @VisibleForTesting
1317 int mTemperatureMax;
1318 private int mTemperatureDefault;
1319 private float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
1320 @VisibleForTesting
1321 ColorSpace.Rgb mDisplayColorSpaceRGB;
1322 private float[] mChromaticAdaptationMatrix;
1323 @VisibleForTesting
1324 int mCurrentColorTemperature;
1325 private float[] mCurrentColorTemperatureXYZ;
1326 private boolean mSetUp = false;
1327 private float[] mMatrixDisplayWhiteBalance = new float[16];
1328 private Boolean mIsAvailable;
1329
1330 @Override
1331 public void setUp(Context context, boolean needsLinear) {
1332 mSetUp = false;
1333 final Resources res = context.getResources();
1334
1335 ColorSpace.Rgb displayColorSpaceRGB = getDisplayColorSpaceFromSurfaceControl();
1336 if (displayColorSpaceRGB == null) {
1337 Slog.w(TAG, "Failed to get display color space from SurfaceControl, trying res");
1338 displayColorSpaceRGB = getDisplayColorSpaceFromResources(res);
1339 if (displayColorSpaceRGB == null) {
1340 Slog.e(TAG, "Failed to get display color space from resources");
1341 return;
1342 }
1343 }
1344
1345 final String[] nominalWhiteValues = res.getStringArray(
1346 R.array.config_displayWhiteBalanceDisplayNominalWhite);
1347 float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
1348 for (int i = 0; i < nominalWhiteValues.length; i++) {
1349 displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]);
1350 }
1351
1352 final int colorTemperatureMin = res.getInteger(
1353 R.integer.config_displayWhiteBalanceColorTemperatureMin);
1354 if (colorTemperatureMin <= 0) {
1355 Slog.e(TAG, "Display white balance minimum temperature must be greater than 0");
1356 return;
1357 }
1358
1359 final int colorTemperatureMax = res.getInteger(
1360 R.integer.config_displayWhiteBalanceColorTemperatureMax);
1361 if (colorTemperatureMax < colorTemperatureMin) {
1362 Slog.e(TAG, "Display white balance max temp must be greater or equal to min");
1363 return;
1364 }
1365
1366 final int colorTemperature = res.getInteger(
1367 R.integer.config_displayWhiteBalanceColorTemperatureDefault);
1368
1369 synchronized (mLock) {
1370 mDisplayColorSpaceRGB = displayColorSpaceRGB;
1371 mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ;
1372 mTemperatureMin = colorTemperatureMin;
1373 mTemperatureMax = colorTemperatureMax;
1374 mTemperatureDefault = colorTemperature;
1375 mSetUp = true;
1376 }
1377
1378 setMatrix(mTemperatureDefault);
1379 }
1380
1381 @Override
1382 public float[] getMatrix() {
1383 return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
1384 }
1385
1386 @Override
1387 public void setMatrix(int cct) {
1388 if (!mSetUp) {
1389 Slog.w(TAG, "Can't set display white balance temperature: uninitialized");
1390 return;
1391 }
1392
1393 if (cct < mTemperatureMin) {
1394 Slog.w(TAG, "Requested display color temperature is below allowed minimum");
1395 cct = mTemperatureMin;
1396 } else if (cct > mTemperatureMax) {
1397 Slog.w(TAG, "Requested display color temperature is above allowed maximum");
1398 cct = mTemperatureMax;
1399 }
1400
1401 Slog.d(TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct);
1402
1403 synchronized (mLock) {
1404 mCurrentColorTemperature = cct;
1405
1406 // Adapt the display's nominal white point to match the requested CCT value
1407 mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct);
1408
1409 mChromaticAdaptationMatrix =
1410 ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
1411 mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
1412
1413 // Convert the adaptation matrix to RGB space
1414 float[] result = ColorSpace.mul3x3(mChromaticAdaptationMatrix,
1415 mDisplayColorSpaceRGB.getTransform());
1416 result = ColorSpace.mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
1417
1418 // Normalize the transform matrix to peak white value in RGB space
1419 final float adaptedMaxR = result[0] + result[3] + result[6];
1420 final float adaptedMaxG = result[1] + result[4] + result[7];
1421 final float adaptedMaxB = result[2] + result[5] + result[8];
1422 final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
1423 for (int i = 0; i < result.length; i++) {
1424 result[i] /= denum;
1425 }
1426
1427 Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
1428 java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
1429 java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
1430 java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
1431 }
1432 }
1433
1434 @Override
1435 public int getLevel() {
1436 return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
1437 }
1438
1439 @Override
1440 public boolean isAvailable(Context context) {
1441 if (mIsAvailable == null) {
1442 mIsAvailable = ColorDisplayManager.isDisplayWhiteBalanceAvailable(context);
1443 }
1444 return mIsAvailable;
1445 }
1446
1447 /**
1448 * Format a given matrix into a string.
1449 *
1450 * @param matrix the matrix to format
1451 * @param cols number of columns in the matrix
1452 */
1453 private String matrixToString(float[] matrix, int cols) {
1454 if (matrix == null || cols <= 0) {
1455 Slog.e(TAG, "Invalid arguments when formatting matrix to string");
1456 return "";
1457 }
1458
1459 StringBuilder sb = new StringBuilder("");
1460 for (int i = 0; i < matrix.length; i++) {
1461 if (i % cols == 0) {
1462 sb.append("\n ");
1463 }
1464 sb.append(String.format("%9.6f ", matrix[i]));
1465 }
1466 return sb.toString();
1467 }
1468
1469 @Override
1470 public void dump(PrintWriter pw) {
1471 synchronized (mLock) {
1472 pw.println(" mSetUp = " + mSetUp);
1473 if (!mSetUp) {
1474 return;
1475 }
1476
1477 pw.println(" mTemperatureMin = " + mTemperatureMin);
1478 pw.println(" mTemperatureMax = " + mTemperatureMax);
1479 pw.println(" mTemperatureDefault = " + mTemperatureDefault);
1480 pw.println(" mCurrentColorTemperature = " + mCurrentColorTemperature);
1481 pw.println(" mCurrentColorTemperatureXYZ = " +
1482 matrixToString(mCurrentColorTemperatureXYZ, 3));
1483 pw.println(" mDisplayColorSpaceRGB RGB-to-XYZ = " +
1484 matrixToString(mDisplayColorSpaceRGB.getTransform(), 3));
1485 pw.println(" mChromaticAdaptationMatrix = " +
1486 matrixToString(mChromaticAdaptationMatrix, 3));
1487 pw.println(" mDisplayColorSpaceRGB XYZ-to-RGB = " +
1488 matrixToString(mDisplayColorSpaceRGB.getInverseTransform(), 3));
1489 pw.println(" mMatrixDisplayWhiteBalance = " +
1490 matrixToString(mMatrixDisplayWhiteBalance, 4));
1491 }
1492 }
1493
1494 private ColorSpace.Rgb makeRgbColorSpaceFromXYZ(float[] redGreenBlueXYZ, float[] whiteXYZ) {
1495 return new ColorSpace.Rgb(
1496 "Display Color Space",
1497 redGreenBlueXYZ,
1498 whiteXYZ,
1499 2.2f // gamma, unused for display white balance
1500 );
1501 }
1502
1503 private ColorSpace.Rgb getDisplayColorSpaceFromSurfaceControl() {
1504 final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
1505 if (displayToken == null) {
1506 return null;
1507 }
1508
1509 DisplayPrimaries primaries = SurfaceControl.getDisplayNativePrimaries(displayToken);
1510 if (primaries == null || primaries.red == null || primaries.green == null ||
1511 primaries.blue == null || primaries.white == null) {
1512 return null;
1513 }
1514
1515 return makeRgbColorSpaceFromXYZ(
1516 new float[] {
1517 primaries.red.X, primaries.red.Y, primaries.red.Z,
1518 primaries.green.X, primaries.green.Y, primaries.green.Z,
1519 primaries.blue.X, primaries.blue.Y, primaries.blue.Z,
1520 },
1521 new float[] { primaries.white.X, primaries.white.Y, primaries.white.Z }
1522 );
1523 }
1524
1525 private ColorSpace.Rgb getDisplayColorSpaceFromResources(Resources res) {
1526 final String[] displayPrimariesValues = res.getStringArray(
1527 R.array.config_displayWhiteBalanceDisplayPrimaries);
1528 float[] displayRedGreenBlueXYZ =
1529 new float[NUM_DISPLAY_PRIMARIES_VALS - NUM_VALUES_PER_PRIMARY];
1530 float[] displayWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
1531
1532 for (int i = 0; i < displayRedGreenBlueXYZ.length; i++) {
1533 displayRedGreenBlueXYZ[i] = Float.parseFloat(displayPrimariesValues[i]);
1534 }
1535
1536 for (int i = 0; i < displayWhiteXYZ.length; i++) {
1537 displayWhiteXYZ[i] = Float.parseFloat(
1538 displayPrimariesValues[displayRedGreenBlueXYZ.length + i]);
1539 }
1540
1541 return makeRgbColorSpaceFromXYZ(displayRedGreenBlueXYZ, displayWhiteXYZ);
1542 }
1543 };
1544
Christine Franks245ffd42018-11-16 13:45:14 -08001545 /**
1546 * Local service that allows color transforms to be enabled from other system services.
1547 */
1548 public final class ColorDisplayServiceInternal {
1549
1550 /**
1551 * Set the current CCT value for the display white balance transform, and if the transform
1552 * is enabled, apply it.
1553 *
1554 * @param cct the color temperature in Kelvin.
1555 */
1556 public boolean setDisplayWhiteBalanceColorTemperature(int cct) {
1557 // Update the transform matrix even if it can't be applied.
Christine Franks245ffd42018-11-16 13:45:14 -08001558 mDisplayWhiteBalanceTintController.setMatrix(cct);
1559
1560 if (mDisplayWhiteBalanceTintController.isActivated()) {
Christine Franksc7fb9452019-02-04 08:45:33 -08001561 mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE);
Christine Franks245ffd42018-11-16 13:45:14 -08001562 return true;
1563 }
1564 return false;
1565 }
1566
1567 /**
1568 * Sets the listener and returns whether display white balance is currently enabled.
1569 */
1570 public boolean setDisplayWhiteBalanceListener(DisplayWhiteBalanceListener listener) {
1571 mDisplayWhiteBalanceListener = listener;
1572 return mDisplayWhiteBalanceTintController.isActivated();
1573 }
Daniel Solomon8b72c5b2018-11-25 11:07:13 -08001574
1575 public void dump(PrintWriter pw) {
1576 mDisplayWhiteBalanceTintController.dump(pw);
1577 }
Christine Franksf3529b22019-01-03 13:20:17 -08001578
1579 /**
1580 * Adds a {@link WeakReference<ColorTransformController>} for a newly started activity, and
1581 * invokes {@link ColorTransformController#applyAppSaturation(float[], float[])} if needed.
1582 */
Christine Franks55194dc2019-01-15 13:47:06 -08001583 public boolean attachColorTransformController(String packageName, @UserIdInt int userId,
Christine Franksf3529b22019-01-03 13:20:17 -08001584 WeakReference<ColorTransformController> controller) {
1585 return mAppSaturationController
Christine Franks55194dc2019-01-15 13:47:06 -08001586 .addColorTransformController(packageName, userId, controller);
Christine Franksf3529b22019-01-03 13:20:17 -08001587 }
Christine Franks245ffd42018-11-16 13:45:14 -08001588 }
1589
1590 /**
1591 * Listener for changes in display white balance status.
1592 */
1593 public interface DisplayWhiteBalanceListener {
1594
1595 /**
1596 * Notify that the display white balance status has changed, either due to preemption by
1597 * another transform or the feature being turned off.
1598 */
1599 void onDisplayWhiteBalanceStatusChanged(boolean enabled);
1600 }
1601
Christine Franks09c229e2018-12-14 10:37:40 -08001602 private final class TintHandler extends Handler {
1603
Christine Franks83cc5412018-07-03 14:46:07 -07001604 private TintHandler(Looper looper) {
Christine Franks09c229e2018-12-14 10:37:40 -08001605 super(looper, null, true /* async */);
1606 }
1607
1608 @Override
1609 public void handleMessage(Message msg) {
1610 switch (msg.what) {
1611 case MSG_APPLY_GLOBAL_SATURATION:
1612 mGlobalSaturationTintController.setMatrix(msg.arg1);
1613 applyTint(mGlobalSaturationTintController, false);
1614 break;
Christine Franks83cc5412018-07-03 14:46:07 -07001615 case MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE:
1616 applyTint(mNightDisplayTintController, true);
1617 break;
1618 case MSG_APPLY_NIGHT_DISPLAY_ANIMATED:
1619 applyTint(mNightDisplayTintController, false);
1620 break;
Christine Franksc7fb9452019-02-04 08:45:33 -08001621 case MSG_APPLY_DISPLAY_WHITE_BALANCE:
1622 applyTint(mDisplayWhiteBalanceTintController, false);
1623 break;
Christine Franks09c229e2018-12-14 10:37:40 -08001624 }
1625 }
1626 }
1627
Christine Franksf3529b22019-01-03 13:20:17 -08001628 /**
1629 * Interface for applying transforms to a given AppWindow.
1630 */
1631 public interface ColorTransformController {
1632
Christine Franksd154fe52019-01-04 17:17:45 -08001633 /**
1634 * Apply the given saturation (grayscale) matrix to the associated AppWindow.
1635 */
Christine Franksf3529b22019-01-03 13:20:17 -08001636 void applyAppSaturation(@Size(9) float[] matrix, @Size(3) float[] translation);
1637 }
1638
Christine Franks83cc5412018-07-03 14:46:07 -07001639 @VisibleForTesting
1640 final class BinderService extends IColorDisplayManager.Stub {
Christine Franks57fdde82018-07-03 14:46:07 -07001641
Christine Franks39b03112018-07-03 14:46:07 -07001642 @Override
Christine Franksd154fe52019-01-04 17:17:45 -08001643 public void setColorMode(int colorMode) {
1644 getContext().enforceCallingOrSelfPermission(
1645 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1646 "Permission required to set display color mode");
1647 final long token = Binder.clearCallingIdentity();
1648 try {
1649 setColorModeInternal(colorMode);
1650 } finally {
1651 Binder.restoreCallingIdentity(token);
1652 }
1653 }
1654
1655 @Override
1656 public int getColorMode() {
1657 final long token = Binder.clearCallingIdentity();
1658 try {
1659 return getColorModeInternal();
1660 } finally {
1661 Binder.restoreCallingIdentity(token);
1662 }
1663 }
1664
1665 @Override
Christine Franks39b03112018-07-03 14:46:07 -07001666 public boolean isDeviceColorManaged() {
1667 final long token = Binder.clearCallingIdentity();
1668 try {
1669 return isDeviceColorManagedInternal();
1670 } finally {
1671 Binder.restoreCallingIdentity(token);
1672 }
1673 }
Christine Franks09c229e2018-12-14 10:37:40 -08001674
1675 @Override
1676 public boolean setSaturationLevel(int level) {
1677 final boolean hasTransformsPermission = getContext()
1678 .checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
1679 == PackageManager.PERMISSION_GRANTED;
1680 final boolean hasLegacyPermission = getContext()
1681 .checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION)
1682 == PackageManager.PERMISSION_GRANTED;
1683 if (!hasTransformsPermission && !hasLegacyPermission) {
1684 throw new SecurityException("Permission required to set display saturation level");
1685 }
1686 final long token = Binder.clearCallingIdentity();
1687 try {
1688 final Message message = mHandler.obtainMessage(MSG_APPLY_GLOBAL_SATURATION);
1689 message.arg1 = level;
1690 mHandler.sendMessage(message);
1691 } finally {
1692 Binder.restoreCallingIdentity(token);
1693 }
1694 return true;
1695 }
Christine Franksf3529b22019-01-03 13:20:17 -08001696
1697 @Override
Christine Franks6d21d342019-02-07 15:09:03 -08001698 public boolean isSaturationActivated() {
1699 getContext().enforceCallingPermission(
1700 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1701 "Permission required to get display saturation level");
1702 final long token = Binder.clearCallingIdentity();
1703 try {
1704 return !mGlobalSaturationTintController.isActivatedStateNotSet()
1705 && mGlobalSaturationTintController.isActivated();
1706 } finally {
1707 Binder.restoreCallingIdentity(token);
1708 }
1709 }
1710
1711 @Override
Christine Franksf3529b22019-01-03 13:20:17 -08001712 public boolean setAppSaturationLevel(String packageName, int level) {
1713 getContext().enforceCallingPermission(
1714 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1715 "Permission required to set display saturation level");
1716 final long token = Binder.clearCallingIdentity();
1717 try {
1718 return setAppSaturationLevelInternal(packageName, level);
1719 } finally {
1720 Binder.restoreCallingIdentity(token);
1721 }
1722 }
1723
Christine Franks55194dc2019-01-15 13:47:06 -08001724 public int getTransformCapabilities() {
1725 getContext().enforceCallingPermission(
1726 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1727 "Permission required to query transform capabilities");
1728 final long token = Binder.clearCallingIdentity();
1729 try {
1730 return getTransformCapabilitiesInternal();
1731 } finally {
1732 Binder.restoreCallingIdentity(token);
1733 }
1734 }
1735
Christine Franksf3529b22019-01-03 13:20:17 -08001736 @Override
Christine Franks83cc5412018-07-03 14:46:07 -07001737 public boolean setNightDisplayActivated(boolean activated) {
1738 getContext().enforceCallingOrSelfPermission(
1739 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1740 "Permission required to set night display activated");
1741 final long token = Binder.clearCallingIdentity();
1742 try {
1743 mNightDisplayTintController.setActivated(activated);
1744 return true;
1745 } finally {
1746 Binder.restoreCallingIdentity(token);
1747 }
1748 }
1749
1750 @Override
1751 public boolean isNightDisplayActivated() {
1752 final long token = Binder.clearCallingIdentity();
1753 try {
1754 return mNightDisplayTintController.isActivated();
1755 } finally {
1756 Binder.restoreCallingIdentity(token);
1757 }
1758 }
1759
1760 @Override
1761 public boolean setNightDisplayColorTemperature(int temperature) {
1762 getContext().enforceCallingOrSelfPermission(
1763 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1764 "Permission required to set night display temperature");
1765 final long token = Binder.clearCallingIdentity();
1766 try {
1767 return mNightDisplayTintController.setColorTemperature(temperature);
1768 } finally {
1769 Binder.restoreCallingIdentity(token);
1770 }
1771 }
1772
1773 @Override
1774 public int getNightDisplayColorTemperature() {
1775 final long token = Binder.clearCallingIdentity();
1776 try {
1777 return mNightDisplayTintController.getColorTemperature();
1778 } finally {
1779 Binder.restoreCallingIdentity(token);
1780 }
1781 }
1782
1783 @Override
1784 public boolean setNightDisplayAutoMode(int autoMode) {
1785 getContext().enforceCallingOrSelfPermission(
1786 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1787 "Permission required to set night display auto mode");
1788 final long token = Binder.clearCallingIdentity();
1789 try {
1790 return setNightDisplayAutoModeInternal(autoMode);
1791 } finally {
1792 Binder.restoreCallingIdentity(token);
1793 }
1794 }
1795
1796 @Override
1797 public int getNightDisplayAutoMode() {
1798 getContext().enforceCallingOrSelfPermission(
1799 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1800 "Permission required to get night display auto mode");
1801 final long token = Binder.clearCallingIdentity();
1802 try {
1803 return getNightDisplayAutoModeInternal();
1804 } finally {
1805 Binder.restoreCallingIdentity(token);
1806 }
1807 }
1808
1809 @Override
1810 public int getNightDisplayAutoModeRaw() {
1811 final long token = Binder.clearCallingIdentity();
1812 try {
1813 return getNightDisplayAutoModeRawInternal();
1814 } finally {
1815 Binder.restoreCallingIdentity(token);
1816 }
1817 }
1818
1819 @Override
1820 public boolean setNightDisplayCustomStartTime(Time startTime) {
1821 getContext().enforceCallingOrSelfPermission(
1822 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1823 "Permission required to set night display custom start time");
1824 final long token = Binder.clearCallingIdentity();
1825 try {
1826 return setNightDisplayCustomStartTimeInternal(startTime);
1827 } finally {
1828 Binder.restoreCallingIdentity(token);
1829 }
1830 }
1831
1832 @Override
1833 public Time getNightDisplayCustomStartTime() {
1834 final long token = Binder.clearCallingIdentity();
1835 try {
1836 return getNightDisplayCustomStartTimeInternal();
1837 } finally {
1838 Binder.restoreCallingIdentity(token);
1839 }
1840 }
1841
1842 @Override
1843 public boolean setNightDisplayCustomEndTime(Time endTime) {
1844 getContext().enforceCallingOrSelfPermission(
1845 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1846 "Permission required to set night display custom end time");
1847 final long token = Binder.clearCallingIdentity();
1848 try {
1849 return setNightDisplayCustomEndTimeInternal(endTime);
1850 } finally {
1851 Binder.restoreCallingIdentity(token);
1852 }
1853 }
1854
1855 @Override
1856 public Time getNightDisplayCustomEndTime() {
1857 final long token = Binder.clearCallingIdentity();
1858 try {
1859 return getNightDisplayCustomEndTimeInternal();
1860 } finally {
1861 Binder.restoreCallingIdentity(token);
1862 }
1863 }
1864
1865 @Override
Christine Franksf3529b22019-01-03 13:20:17 -08001866 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Christine Franksd154fe52019-01-04 17:17:45 -08001867 if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
1868 return;
1869 }
Christine Franksf3529b22019-01-03 13:20:17 -08001870
1871 final long token = Binder.clearCallingIdentity();
1872 try {
1873 dumpInternal(pw);
1874 } finally {
1875 Binder.restoreCallingIdentity(token);
1876 }
1877 }
Christine Franks39b03112018-07-03 14:46:07 -07001878 }
Justin Klaassen911e8892016-06-21 18:24:24 -07001879}