blob: 45567e5a34cbf00e96fc1636ff7e71c5a5ed4db7 [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
Christine Franks0ada2772019-02-25 13:54:57 -080017package com.android.server.display.color;
Justin Klaassen911e8892016-06-21 18:24:24 -070018
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 Franks0ada2772019-02-25 13:54:57 -080027import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
28import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
29import static com.android.server.display.color.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());
Christine Franks0ada2772019-02-25 13:54:57 -0800236 publishLocalService(DisplayTransformManager.class, new DisplayTransformManager());
Justin Klaassen911e8892016-06-21 18:24:24 -0700237 }
238
239 @Override
Justin Klaassen2696d992016-07-11 21:26:46 -0700240 public void onBootPhase(int phase) {
Christine Frankse5bb03e2017-02-10 17:36:10 -0800241 if (phase >= PHASE_BOOT_COMPLETED) {
Justin Klaassen2696d992016-07-11 21:26:46 -0700242 mBootCompleted = true;
243
244 // Register listeners now that boot is complete.
245 if (mCurrentUser != UserHandle.USER_NULL && mUserSetupObserver == null) {
246 setUp();
247 }
248 }
249 }
250
251 @Override
Justin Klaassen911e8892016-06-21 18:24:24 -0700252 public void onStartUser(int userHandle) {
253 super.onStartUser(userHandle);
254
Justin Klaassen911e8892016-06-21 18:24:24 -0700255 if (mCurrentUser == UserHandle.USER_NULL) {
Justin Klaassen2696d992016-07-11 21:26:46 -0700256 onUserChanged(userHandle);
Justin Klaassen911e8892016-06-21 18:24:24 -0700257 }
258 }
259
260 @Override
261 public void onSwitchUser(int userHandle) {
262 super.onSwitchUser(userHandle);
263
Justin Klaassen2696d992016-07-11 21:26:46 -0700264 onUserChanged(userHandle);
Justin Klaassen911e8892016-06-21 18:24:24 -0700265 }
266
267 @Override
268 public void onStopUser(int userHandle) {
269 super.onStopUser(userHandle);
270
Justin Klaassen911e8892016-06-21 18:24:24 -0700271 if (mCurrentUser == userHandle) {
Justin Klaassen2696d992016-07-11 21:26:46 -0700272 onUserChanged(UserHandle.USER_NULL);
Justin Klaassen911e8892016-06-21 18:24:24 -0700273 }
274 }
275
Justin Klaassen2696d992016-07-11 21:26:46 -0700276 private void onUserChanged(int userHandle) {
277 final ContentResolver cr = getContext().getContentResolver();
Justin Klaassen911e8892016-06-21 18:24:24 -0700278
Justin Klaassen2696d992016-07-11 21:26:46 -0700279 if (mCurrentUser != UserHandle.USER_NULL) {
280 if (mUserSetupObserver != null) {
281 cr.unregisterContentObserver(mUserSetupObserver);
282 mUserSetupObserver = null;
283 } else if (mBootCompleted) {
284 tearDown();
285 }
286 }
287
288 mCurrentUser = userHandle;
289
290 if (mCurrentUser != UserHandle.USER_NULL) {
291 if (!isUserSetupCompleted(cr, mCurrentUser)) {
292 mUserSetupObserver = new ContentObserver(mHandler) {
293 @Override
294 public void onChange(boolean selfChange, Uri uri) {
295 if (isUserSetupCompleted(cr, mCurrentUser)) {
296 cr.unregisterContentObserver(this);
297 mUserSetupObserver = null;
298
299 if (mBootCompleted) {
300 setUp();
301 }
302 }
303 }
304 };
305 cr.registerContentObserver(Secure.getUriFor(Secure.USER_SETUP_COMPLETE),
Christine Franks39b03112018-07-03 14:46:07 -0700306 false /* notifyForDescendants */, mUserSetupObserver, mCurrentUser);
Justin Klaassen2696d992016-07-11 21:26:46 -0700307 } else if (mBootCompleted) {
308 setUp();
Justin Klaassen911e8892016-06-21 18:24:24 -0700309 }
310 }
311 }
312
Justin Klaassen2696d992016-07-11 21:26:46 -0700313 private static boolean isUserSetupCompleted(ContentResolver cr, int userHandle) {
314 return Secure.getIntForUser(cr, Secure.USER_SETUP_COMPLETE, 0, userHandle) == 1;
315 }
316
317 private void setUp() {
Justin Klaassenec8837a2016-08-23 12:04:42 -0700318 Slog.d(TAG, "setUp: currentUser=" + mCurrentUser);
319
Christine Franks57fdde82018-07-03 14:46:07 -0700320 // Listen for external changes to any of the settings.
321 if (mContentObserver == null) {
322 mContentObserver = new ContentObserver(new Handler(DisplayThread.get().getLooper())) {
323 @Override
324 public void onChange(boolean selfChange, Uri uri) {
325 super.onChange(selfChange, uri);
326
327 final String setting = uri == null ? null : uri.getLastPathSegment();
328 if (setting != null) {
329 switch (setting) {
330 case Secure.NIGHT_DISPLAY_ACTIVATED:
Christine Franks78a4dd42019-02-08 11:09:30 -0800331 final boolean activated = mNightDisplayTintController
332 .isActivatedSetting();
Christine Franks83cc5412018-07-03 14:46:07 -0700333 if (mNightDisplayTintController.isActivatedStateNotSet()
334 || mNightDisplayTintController.isActivated() != activated) {
Christine Franks78a4dd42019-02-08 11:09:30 -0800335 mNightDisplayTintController.setActivated(activated);
Christine Franks83cc5412018-07-03 14:46:07 -0700336 }
Christine Franks57fdde82018-07-03 14:46:07 -0700337 break;
338 case Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE:
Christine Franks78a4dd42019-02-08 11:09:30 -0800339 final int temperature = mNightDisplayTintController
340 .getColorTemperatureSetting();
Christine Franks83cc5412018-07-03 14:46:07 -0700341 if (mNightDisplayTintController.getColorTemperature()
342 != temperature) {
343 mNightDisplayTintController
344 .onColorTemperatureChanged(temperature);
345 }
Christine Franks57fdde82018-07-03 14:46:07 -0700346 break;
347 case Secure.NIGHT_DISPLAY_AUTO_MODE:
Christine Franks83cc5412018-07-03 14:46:07 -0700348 onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal());
Christine Franks57fdde82018-07-03 14:46:07 -0700349 break;
350 case Secure.NIGHT_DISPLAY_CUSTOM_START_TIME:
351 onNightDisplayCustomStartTimeChanged(
Christine Franks83cc5412018-07-03 14:46:07 -0700352 getNightDisplayCustomStartTimeInternal().getLocalTime());
Christine Franks57fdde82018-07-03 14:46:07 -0700353 break;
354 case Secure.NIGHT_DISPLAY_CUSTOM_END_TIME:
355 onNightDisplayCustomEndTimeChanged(
Christine Franks83cc5412018-07-03 14:46:07 -0700356 getNightDisplayCustomEndTimeInternal().getLocalTime());
Christine Franks57fdde82018-07-03 14:46:07 -0700357 break;
358 case System.DISPLAY_COLOR_MODE:
Christine Franks71e003e2019-01-24 14:40:20 -0800359 onDisplayColorModeChanged(getColorModeInternal());
Christine Franks57fdde82018-07-03 14:46:07 -0700360 break;
Christine Franks57fdde82018-07-03 14:46:07 -0700361 case Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED:
Christine Franks9114f462019-01-04 11:27:30 -0800362 onAccessibilityInversionChanged();
363 onAccessibilityActivated();
364 break;
365 case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:
366 onAccessibilityDaltonizerChanged();
367 onAccessibilityActivated();
368 break;
369 case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER:
370 onAccessibilityDaltonizerChanged();
Christine Franks57fdde82018-07-03 14:46:07 -0700371 break;
Christine Franks245ffd42018-11-16 13:45:14 -0800372 case Secure.DISPLAY_WHITE_BALANCE_ENABLED:
Daniel Solomon8b72c5b2018-11-25 11:07:13 -0800373 updateDisplayWhiteBalanceStatus();
Christine Franks245ffd42018-11-16 13:45:14 -0800374 break;
Christine Franks57fdde82018-07-03 14:46:07 -0700375 }
376 }
377 }
378 };
379 }
380 final ContentResolver cr = getContext().getContentResolver();
381 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_ACTIVATED),
382 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
383 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE),
384 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
385 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_AUTO_MODE),
386 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
387 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_START_TIME),
388 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
389 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_END_TIME),
390 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
391 cr.registerContentObserver(System.getUriFor(System.DISPLAY_COLOR_MODE),
392 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
393 cr.registerContentObserver(
394 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
395 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
396 cr.registerContentObserver(
397 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
398 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
Christine Franks9114f462019-01-04 11:27:30 -0800399 cr.registerContentObserver(
400 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
401 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
Christine Franks245ffd42018-11-16 13:45:14 -0800402 cr.registerContentObserver(Secure.getUriFor(Secure.DISPLAY_WHITE_BALANCE_ENABLED),
403 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
Justin Klaassen911e8892016-06-21 18:24:24 -0700404
Christine Franks11e63152019-03-14 11:16:06 -0700405 // Apply the accessibility settings first, since they override most other settings.
406 onAccessibilityInversionChanged();
407 onAccessibilityDaltonizerChanged();
408
Christine Frankscf388c22018-05-15 15:48:10 -0700409 // Set the color mode, if valid, and immediately apply the updated tint matrix based on the
410 // existing activated state. This ensures consistency of tint across the color mode change.
Christine Franks71e003e2019-01-24 14:40:20 -0800411 onDisplayColorModeChanged(getColorModeInternal());
Christine Frankscf388c22018-05-15 15:48:10 -0700412
Christine Franksa4ed3762019-01-24 15:37:04 -0800413 if (mNightDisplayTintController.isAvailable(getContext())) {
Christine Franks245ffd42018-11-16 13:45:14 -0800414 // Reset the activated state.
415 mNightDisplayTintController.setActivated(null);
Christine Frankscf388c22018-05-15 15:48:10 -0700416
Christine Franks245ffd42018-11-16 13:45:14 -0800417 // Prepare the night display color transformation matrix.
418 mNightDisplayTintController
419 .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
Christine Franks78a4dd42019-02-08 11:09:30 -0800420 mNightDisplayTintController
421 .setMatrix(mNightDisplayTintController.getColorTemperatureSetting());
Christine Franks8ad71492017-10-24 19:04:22 -0700422
Christine Franks245ffd42018-11-16 13:45:14 -0800423 // Initialize the current auto mode.
Christine Franks83cc5412018-07-03 14:46:07 -0700424 onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal());
Christine Franks6418d0b2017-02-13 09:48:00 -0800425
Christine Franks83cc5412018-07-03 14:46:07 -0700426 // Force the initialization of the current saved activation state.
Christine Franks245ffd42018-11-16 13:45:14 -0800427 if (mNightDisplayTintController.isActivatedStateNotSet()) {
Christine Franks78a4dd42019-02-08 11:09:30 -0800428 mNightDisplayTintController
429 .setActivated(mNightDisplayTintController.isActivatedSetting());
Christine Franks245ffd42018-11-16 13:45:14 -0800430 }
431 }
Justin Klaassen911e8892016-06-21 18:24:24 -0700432
Christine Franksa4ed3762019-01-24 15:37:04 -0800433 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
Christine Franks245ffd42018-11-16 13:45:14 -0800434 // Prepare the display white balance transform matrix.
Daniel Solomon8b72c5b2018-11-25 11:07:13 -0800435 mDisplayWhiteBalanceTintController.setUp(getContext(), true /* needsLinear */);
Christine Franks245ffd42018-11-16 13:45:14 -0800436
Daniel Solomon8b72c5b2018-11-25 11:07:13 -0800437 updateDisplayWhiteBalanceStatus();
Justin Klaassen911e8892016-06-21 18:24:24 -0700438 }
439 }
440
Justin Klaassen2696d992016-07-11 21:26:46 -0700441 private void tearDown() {
Justin Klaassenec8837a2016-08-23 12:04:42 -0700442 Slog.d(TAG, "tearDown: currentUser=" + mCurrentUser);
443
Christine Franks57fdde82018-07-03 14:46:07 -0700444 getContext().getContentResolver().unregisterContentObserver(mContentObserver);
445
Christine Franksa4ed3762019-01-24 15:37:04 -0800446 if (mNightDisplayTintController.isAvailable(getContext())) {
Christine Franks245ffd42018-11-16 13:45:14 -0800447 if (mNightDisplayAutoMode != null) {
448 mNightDisplayAutoMode.onStop();
449 mNightDisplayAutoMode = null;
450 }
451 mNightDisplayTintController.endAnimator();
Justin Klaassen911e8892016-06-21 18:24:24 -0700452 }
453
Christine Franksa4ed3762019-01-24 15:37:04 -0800454 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
Christine Franks245ffd42018-11-16 13:45:14 -0800455 mDisplayWhiteBalanceTintController.endAnimator();
Justin Klaassen639214e2016-07-14 21:00:06 -0700456 }
Christine Franks6d21d342019-02-07 15:09:03 -0800457
458 if (mGlobalSaturationTintController.isAvailable(getContext())) {
459 mGlobalSaturationTintController.setActivated(null);
460 }
Justin Klaassen911e8892016-06-21 18:24:24 -0700461 }
462
Christine Franks57fdde82018-07-03 14:46:07 -0700463 private void onNightDisplayAutoModeChanged(int autoMode) {
464 Slog.d(TAG, "onNightDisplayAutoModeChanged: autoMode=" + autoMode);
Justin Klaassenec8837a2016-08-23 12:04:42 -0700465
Christine Franks57fdde82018-07-03 14:46:07 -0700466 if (mNightDisplayAutoMode != null) {
467 mNightDisplayAutoMode.onStop();
468 mNightDisplayAutoMode = null;
Justin Klaassen911e8892016-06-21 18:24:24 -0700469 }
470
Christine Franks83cc5412018-07-03 14:46:07 -0700471 if (autoMode == AUTO_MODE_CUSTOM_TIME) {
Christine Franks57fdde82018-07-03 14:46:07 -0700472 mNightDisplayAutoMode = new CustomNightDisplayAutoMode();
Christine Franks83cc5412018-07-03 14:46:07 -0700473 } else if (autoMode == AUTO_MODE_TWILIGHT) {
Christine Franks57fdde82018-07-03 14:46:07 -0700474 mNightDisplayAutoMode = new TwilightNightDisplayAutoMode();
Justin Klaassen911e8892016-06-21 18:24:24 -0700475 }
476
Christine Franks57fdde82018-07-03 14:46:07 -0700477 if (mNightDisplayAutoMode != null) {
478 mNightDisplayAutoMode.onStart();
Justin Klaassen911e8892016-06-21 18:24:24 -0700479 }
480 }
481
Christine Franks57fdde82018-07-03 14:46:07 -0700482 private void onNightDisplayCustomStartTimeChanged(LocalTime startTime) {
483 Slog.d(TAG, "onNightDisplayCustomStartTimeChanged: startTime=" + startTime);
Justin Klaassenec8837a2016-08-23 12:04:42 -0700484
Christine Franks57fdde82018-07-03 14:46:07 -0700485 if (mNightDisplayAutoMode != null) {
486 mNightDisplayAutoMode.onCustomStartTimeChanged(startTime);
Justin Klaassen911e8892016-06-21 18:24:24 -0700487 }
488 }
489
Christine Franks57fdde82018-07-03 14:46:07 -0700490 private void onNightDisplayCustomEndTimeChanged(LocalTime endTime) {
491 Slog.d(TAG, "onNightDisplayCustomEndTimeChanged: endTime=" + endTime);
Justin Klaassenec8837a2016-08-23 12:04:42 -0700492
Christine Franks57fdde82018-07-03 14:46:07 -0700493 if (mNightDisplayAutoMode != null) {
494 mNightDisplayAutoMode.onCustomEndTimeChanged(endTime);
Justin Klaassen911e8892016-06-21 18:24:24 -0700495 }
496 }
497
Christine Franks57fdde82018-07-03 14:46:07 -0700498 private void onDisplayColorModeChanged(int mode) {
Christine Franks83cc5412018-07-03 14:46:07 -0700499 if (mode == NOT_SET) {
Christine Frankscf388c22018-05-15 15:48:10 -0700500 return;
501 }
502
Christine Franks245ffd42018-11-16 13:45:14 -0800503 mNightDisplayTintController.cancelAnimator();
504 mDisplayWhiteBalanceTintController.cancelAnimator();
505
Christine Franksa4ed3762019-01-24 15:37:04 -0800506 if (mNightDisplayTintController.isAvailable(getContext())) {
507 mNightDisplayTintController
508 .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
Christine Franks78a4dd42019-02-08 11:09:30 -0800509 mNightDisplayTintController
510 .setMatrix(mNightDisplayTintController.getColorTemperatureSetting());
Christine Franksa4ed3762019-01-24 15:37:04 -0800511 }
Christine Franks245ffd42018-11-16 13:45:14 -0800512
Daniel Solomon8b72c5b2018-11-25 11:07:13 -0800513 updateDisplayWhiteBalanceStatus();
Christine Franks8ad71492017-10-24 19:04:22 -0700514
Christine Franks218e6562017-11-27 10:20:14 -0800515 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
Christine Franks245ffd42018-11-16 13:45:14 -0800516 dtm.setColorMode(mode, mNightDisplayTintController.getMatrix());
Christine Franks8ad71492017-10-24 19:04:22 -0700517 }
518
Christine Franks9114f462019-01-04 11:27:30 -0800519 private void onAccessibilityActivated() {
Christine Franks71e003e2019-01-24 14:40:20 -0800520 onDisplayColorModeChanged(getColorModeInternal());
Daniel Solomon317a3572018-03-30 18:36:37 -0700521 }
522
Christine Franks9114f462019-01-04 11:27:30 -0800523 /**
524 * Apply the accessibility daltonizer transform based on the settings value.
525 */
526 private void onAccessibilityDaltonizerChanged() {
527 final boolean enabled = Secure.getIntForUser(getContext().getContentResolver(),
528 Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, mCurrentUser) != 0;
529 final int daltonizerMode = enabled ? Secure.getIntForUser(getContext().getContentResolver(),
530 Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
531 AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY, mCurrentUser)
532 : AccessibilityManager.DALTONIZER_DISABLED;
533
534 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
535 if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) {
536 // Monochromacy isn't supported by the native Daltonizer implementation; use grayscale.
537 dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE,
538 MATRIX_GRAYSCALE);
539 dtm.setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
540 } else {
541 dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE, null);
542 dtm.setDaltonizerMode(daltonizerMode);
543 }
544 }
545
546 /**
547 * Apply the accessibility inversion transform based on the settings value.
548 */
549 private void onAccessibilityInversionChanged() {
550 final boolean enabled = Secure.getIntForUser(getContext().getContentResolver(),
551 Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, mCurrentUser) != 0;
552 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
553 dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_INVERT_COLOR,
554 enabled ? MATRIX_INVERT_COLOR : null);
555 }
Christine Franks8ad71492017-10-24 19:04:22 -0700556
Christine Franks6418d0b2017-02-13 09:48:00 -0800557 /**
558 * Applies current color temperature matrix, or removes it if deactivated.
559 *
560 * @param immediate {@code true} skips transition animation
561 */
Christine Franks245ffd42018-11-16 13:45:14 -0800562 private void applyTint(TintController tintController, boolean immediate) {
563 tintController.cancelAnimator();
Christine Franks6418d0b2017-02-13 09:48:00 -0800564
Christine Franks6418d0b2017-02-13 09:48:00 -0800565 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
Christine Franks245ffd42018-11-16 13:45:14 -0800566 final float[] from = dtm.getColorMatrix(tintController.getLevel());
567 final float[] to = tintController.getMatrix();
Christine Franks6418d0b2017-02-13 09:48:00 -0800568
569 if (immediate) {
Christine Franks245ffd42018-11-16 13:45:14 -0800570 dtm.setColorMatrix(tintController.getLevel(), to);
Christine Franks6418d0b2017-02-13 09:48:00 -0800571 } else {
Christine Franks245ffd42018-11-16 13:45:14 -0800572 tintController.setAnimator(ValueAnimator.ofObject(COLOR_MATRIX_EVALUATOR,
573 from == null ? MATRIX_IDENTITY : from, to));
574 tintController.getAnimator().setDuration(TRANSITION_DURATION);
575 tintController.getAnimator().setInterpolator(AnimationUtils.loadInterpolator(
Christine Franks6418d0b2017-02-13 09:48:00 -0800576 getContext(), android.R.interpolator.fast_out_slow_in));
Christine Franks245ffd42018-11-16 13:45:14 -0800577 tintController.getAnimator().addUpdateListener((ValueAnimator animator) -> {
578 final float[] value = (float[]) animator.getAnimatedValue();
579 dtm.setColorMatrix(tintController.getLevel(), value);
Christine Franks6418d0b2017-02-13 09:48:00 -0800580 });
Christine Franks245ffd42018-11-16 13:45:14 -0800581 tintController.getAnimator().addListener(new AnimatorListenerAdapter() {
Christine Franks6418d0b2017-02-13 09:48:00 -0800582
583 private boolean mIsCancelled;
584
585 @Override
586 public void onAnimationCancel(Animator animator) {
587 mIsCancelled = true;
588 }
589
590 @Override
591 public void onAnimationEnd(Animator animator) {
592 if (!mIsCancelled) {
593 // Ensure final color matrix is set at the end of the animation. If the
594 // animation is cancelled then don't set the final color matrix so the new
595 // animator can pick up from where this one left off.
Christine Franks245ffd42018-11-16 13:45:14 -0800596 dtm.setColorMatrix(tintController.getLevel(), to);
Christine Franks6418d0b2017-02-13 09:48:00 -0800597 }
Christine Franks245ffd42018-11-16 13:45:14 -0800598 tintController.setAnimator(null);
Christine Franks6418d0b2017-02-13 09:48:00 -0800599 }
600 });
Christine Franks245ffd42018-11-16 13:45:14 -0800601 tintController.getAnimator().start();
Christine Franks6418d0b2017-02-13 09:48:00 -0800602 }
603 }
604
605 /**
Christine Franks39b03112018-07-03 14:46:07 -0700606 * Returns the first date time corresponding to the local time that occurs before the provided
607 * date time.
Christine Franks03213462017-08-25 13:57:26 -0700608 *
609 * @param compareTime the LocalDateTime to compare against
610 * @return the prior LocalDateTime corresponding to this local time
611 */
Christine Franks57fdde82018-07-03 14:46:07 -0700612 @VisibleForTesting
613 static LocalDateTime getDateTimeBefore(LocalTime localTime, LocalDateTime compareTime) {
Christine Franks03213462017-08-25 13:57:26 -0700614 final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
615 compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());
616
617 // Check if the local time has passed, if so return the same time yesterday.
618 return ldt.isAfter(compareTime) ? ldt.minusDays(1) : ldt;
619 }
620
621 /**
Christine Franks39b03112018-07-03 14:46:07 -0700622 * Returns the first date time corresponding to this local time that occurs after the provided
623 * date time.
Christine Franks03213462017-08-25 13:57:26 -0700624 *
625 * @param compareTime the LocalDateTime to compare against
626 * @return the next LocalDateTime corresponding to this local time
627 */
Christine Franks57fdde82018-07-03 14:46:07 -0700628 @VisibleForTesting
629 static LocalDateTime getDateTimeAfter(LocalTime localTime, LocalDateTime compareTime) {
Christine Franks03213462017-08-25 13:57:26 -0700630 final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
631 compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());
632
633 // Check if the local time has passed, if so return the same time tomorrow.
634 return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
635 }
636
Long Ling1d3f1892019-02-06 12:34:02 -0800637 @VisibleForTesting
638 void updateDisplayWhiteBalanceStatus() {
Daniel Solomon8b72c5b2018-11-25 11:07:13 -0800639 boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated();
Christine Franks0ada2772019-02-25 13:54:57 -0800640 mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled()
641 && !mNightDisplayTintController.isActivated()
642 && DisplayTransformManager.needsLinearColorMatrix());
Daniel Solomon8b72c5b2018-11-25 11:07:13 -0800643 boolean activated = mDisplayWhiteBalanceTintController.isActivated();
644
645 if (mDisplayWhiteBalanceListener != null && oldActivated != activated) {
646 mDisplayWhiteBalanceListener.onDisplayWhiteBalanceStatusChanged(activated);
Christine Franks245ffd42018-11-16 13:45:14 -0800647 }
Daniel Solomon86508f82019-01-18 19:01:02 -0800648
649 // If disabled, clear the tint. If enabled, do nothing more here and let the next
650 // temperature update set the correct tint.
651 if (!activated) {
Christine Franksc7fb9452019-02-04 08:45:33 -0800652 mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE);
Daniel Solomon86508f82019-01-18 19:01:02 -0800653 }
Christine Franks245ffd42018-11-16 13:45:14 -0800654 }
655
656 private boolean isDisplayWhiteBalanceSettingEnabled() {
657 return Secure.getIntForUser(getContext().getContentResolver(),
658 Secure.DISPLAY_WHITE_BALANCE_ENABLED, 0, mCurrentUser) == 1;
659 }
660
Christine Franks39b03112018-07-03 14:46:07 -0700661 private boolean isDeviceColorManagedInternal() {
662 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
663 return dtm.isDeviceColorManaged();
664 }
665
Christine Franks55194dc2019-01-15 13:47:06 -0800666 private int getTransformCapabilitiesInternal() {
667 int availabilityFlags = ColorDisplayManager.CAPABILITY_NONE;
668 if (SurfaceControl.getProtectedContentSupport()) {
669 availabilityFlags |= ColorDisplayManager.CAPABILITY_PROTECTED_CONTENT;
670 }
671 final Resources res = getContext().getResources();
672 if (res.getBoolean(R.bool.config_setColorTransformAccelerated)) {
673 availabilityFlags |= ColorDisplayManager.CAPABILITY_HARDWARE_ACCELERATION_GLOBAL;
674 }
675 if (res.getBoolean(R.bool.config_setColorTransformAcceleratedPerLayer)) {
676 availabilityFlags |= ColorDisplayManager.CAPABILITY_HARDWARE_ACCELERATION_PER_APP;
677 }
678 return availabilityFlags;
679 }
680
Christine Franks83cc5412018-07-03 14:46:07 -0700681 private boolean setNightDisplayAutoModeInternal(@AutoMode int autoMode) {
682 if (getNightDisplayAutoModeInternal() != autoMode) {
683 Secure.putStringForUser(getContext().getContentResolver(),
684 Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
685 null,
686 mCurrentUser);
687 }
688 return Secure.putIntForUser(getContext().getContentResolver(),
689 Secure.NIGHT_DISPLAY_AUTO_MODE, autoMode, mCurrentUser);
690 }
691
692 private int getNightDisplayAutoModeInternal() {
693 int autoMode = getNightDisplayAutoModeRawInternal();
694 if (autoMode == NOT_SET) {
695 autoMode = getContext().getResources().getInteger(
696 R.integer.config_defaultNightDisplayAutoMode);
697 }
698 if (autoMode != AUTO_MODE_DISABLED
699 && autoMode != AUTO_MODE_CUSTOM_TIME
700 && autoMode != AUTO_MODE_TWILIGHT) {
701 Slog.e(TAG, "Invalid autoMode: " + autoMode);
702 autoMode = AUTO_MODE_DISABLED;
703 }
704 return autoMode;
705 }
706
707 private int getNightDisplayAutoModeRawInternal() {
708 return Secure
709 .getIntForUser(getContext().getContentResolver(), Secure.NIGHT_DISPLAY_AUTO_MODE,
710 NOT_SET, mCurrentUser);
711 }
712
713 private Time getNightDisplayCustomStartTimeInternal() {
714 int startTimeValue = Secure.getIntForUser(getContext().getContentResolver(),
715 Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, NOT_SET, mCurrentUser);
716 if (startTimeValue == NOT_SET) {
717 startTimeValue = getContext().getResources().getInteger(
718 R.integer.config_defaultNightDisplayCustomStartTime);
719 }
720 return new Time(LocalTime.ofSecondOfDay(startTimeValue / 1000));
721 }
722
723 private boolean setNightDisplayCustomStartTimeInternal(Time startTime) {
724 return Secure.putIntForUser(getContext().getContentResolver(),
725 Secure.NIGHT_DISPLAY_CUSTOM_START_TIME,
726 startTime.getLocalTime().toSecondOfDay() * 1000,
727 mCurrentUser);
728 }
729
730 private Time getNightDisplayCustomEndTimeInternal() {
731 int endTimeValue = Secure.getIntForUser(getContext().getContentResolver(),
732 Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, NOT_SET, mCurrentUser);
733 if (endTimeValue == NOT_SET) {
734 endTimeValue = getContext().getResources().getInteger(
735 R.integer.config_defaultNightDisplayCustomEndTime);
736 }
737 return new Time(LocalTime.ofSecondOfDay(endTimeValue / 1000));
738 }
739
740 private boolean setNightDisplayCustomEndTimeInternal(Time endTime) {
741 return Secure.putIntForUser(getContext().getContentResolver(),
742 Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.getLocalTime().toSecondOfDay() * 1000,
743 mCurrentUser);
744 }
745
Christine Franks57fdde82018-07-03 14:46:07 -0700746 /**
747 * Returns the last time the night display transform activation state was changed, or {@link
748 * LocalDateTime#MIN} if night display has never been activated.
749 */
Christine Franks245ffd42018-11-16 13:45:14 -0800750 private LocalDateTime getNightDisplayLastActivatedTimeSetting() {
Christine Franks57fdde82018-07-03 14:46:07 -0700751 final ContentResolver cr = getContext().getContentResolver();
752 final String lastActivatedTime = Secure.getStringForUser(
753 cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, getContext().getUserId());
754 if (lastActivatedTime != null) {
755 try {
756 return LocalDateTime.parse(lastActivatedTime);
757 } catch (DateTimeParseException ignored) {
758 }
759 // Uses the old epoch time.
760 try {
761 return LocalDateTime.ofInstant(
762 Instant.ofEpochMilli(Long.parseLong(lastActivatedTime)),
763 ZoneId.systemDefault());
764 } catch (DateTimeException | NumberFormatException ignored) {
765 }
766 }
767 return LocalDateTime.MIN;
768 }
769
Christine Franksf3529b22019-01-03 13:20:17 -0800770 private boolean setAppSaturationLevelInternal(String packageName, int saturationLevel) {
771 return mAppSaturationController
772 .setSaturationLevel(packageName, mCurrentUser, saturationLevel);
773 }
774
Christine Franksd154fe52019-01-04 17:17:45 -0800775 private void setColorModeInternal(@ColorMode int colorMode) {
776 if (!isColorModeAvailable(colorMode)) {
777 throw new IllegalArgumentException("Invalid colorMode: " + colorMode);
778 }
779 System.putIntForUser(getContext().getContentResolver(), System.DISPLAY_COLOR_MODE,
780 colorMode,
781 mCurrentUser);
782 }
783
Christine Franks71e003e2019-01-24 14:40:20 -0800784 private @ColorMode int getColorModeInternal() {
Christine Franksd154fe52019-01-04 17:17:45 -0800785 final ContentResolver cr = getContext().getContentResolver();
786 if (Secure.getIntForUser(cr, Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
787 0, mCurrentUser) == 1
788 || Secure.getIntForUser(cr, Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
789 0, mCurrentUser) == 1) {
790 // There are restrictions on the available color modes combined with a11y transforms.
791 if (isColorModeAvailable(COLOR_MODE_SATURATED)) {
792 return COLOR_MODE_SATURATED;
793 } else if (isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
794 return COLOR_MODE_AUTOMATIC;
795 }
796 }
797
798 int colorMode = System.getIntForUser(cr, System.DISPLAY_COLOR_MODE, -1, mCurrentUser);
799 if (colorMode == -1) {
800 // There might be a system property controlling color mode that we need to respect; if
801 // not, this will set a suitable default.
802 colorMode = getCurrentColorModeFromSystemProperties();
803 }
804
805 // This happens when a color mode is no longer available (e.g., after system update or B&R)
806 // or the device does not support any color mode.
807 if (!isColorModeAvailable(colorMode)) {
808 if (colorMode == COLOR_MODE_BOOSTED && isColorModeAvailable(COLOR_MODE_NATURAL)) {
809 colorMode = COLOR_MODE_NATURAL;
810 } else if (colorMode == COLOR_MODE_SATURATED
811 && isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
812 colorMode = COLOR_MODE_AUTOMATIC;
813 } else if (colorMode == COLOR_MODE_AUTOMATIC
814 && isColorModeAvailable(COLOR_MODE_SATURATED)) {
815 colorMode = COLOR_MODE_SATURATED;
816 } else {
817 colorMode = -1;
818 }
819 }
820
821 return colorMode;
822 }
823
824 /**
825 * Get the current color mode from system properties, or return -1 if invalid.
826 *
Christine Franks0ada2772019-02-25 13:54:57 -0800827 * See {@link DisplayTransformManager}
Christine Franksd154fe52019-01-04 17:17:45 -0800828 */
Christine Franks78a4dd42019-02-08 11:09:30 -0800829 private @ColorMode int getCurrentColorModeFromSystemProperties() {
Christine Franksd154fe52019-01-04 17:17:45 -0800830 final int displayColorSetting = SystemProperties.getInt("persist.sys.sf.native_mode", 0);
831 if (displayColorSetting == 0) {
832 return "1.0".equals(SystemProperties.get("persist.sys.sf.color_saturation"))
833 ? COLOR_MODE_NATURAL : COLOR_MODE_BOOSTED;
834 } else if (displayColorSetting == 1) {
835 return COLOR_MODE_SATURATED;
836 } else if (displayColorSetting == 2) {
837 return COLOR_MODE_AUTOMATIC;
838 } else {
839 return -1;
840 }
841 }
842
843 private boolean isColorModeAvailable(@ColorMode int colorMode) {
844 final int[] availableColorModes = getContext().getResources().getIntArray(
845 R.array.config_availableColorModes);
846 if (availableColorModes != null) {
847 for (int mode : availableColorModes) {
848 if (mode == colorMode) {
849 return true;
850 }
851 }
852 }
853 return false;
854 }
855
Christine Franksf3529b22019-01-03 13:20:17 -0800856 private void dumpInternal(PrintWriter pw) {
857 pw.println("COLOR DISPLAY MANAGER dumpsys (color_display)");
Christine Franksa4ed3762019-01-24 15:37:04 -0800858
Christine Franks0ada2772019-02-25 13:54:57 -0800859 pw.println("Night display:");
Christine Franksa4ed3762019-01-24 15:37:04 -0800860 if (mNightDisplayTintController.isAvailable(getContext())) {
Christine Franksf3529b22019-01-03 13:20:17 -0800861 pw.println(" Activated: " + mNightDisplayTintController.isActivated());
Christine Franksa4ed3762019-01-24 15:37:04 -0800862 pw.println(" Color temp: " + mNightDisplayTintController.getColorTemperature());
Christine Franksf3529b22019-01-03 13:20:17 -0800863 } else {
864 pw.println(" Not available");
865 }
Christine Franksa4ed3762019-01-24 15:37:04 -0800866
867 pw.println("Global saturation:");
868 if (mGlobalSaturationTintController.isAvailable(getContext())) {
869 pw.println(" Activated: " + mGlobalSaturationTintController.isActivated());
870 } else {
871 pw.println(" Not available");
872 }
873
Christine Franksf3529b22019-01-03 13:20:17 -0800874 mAppSaturationController.dump(pw);
Christine Franksa4ed3762019-01-24 15:37:04 -0800875
876 pw.println("Display white balance:");
877 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
878 pw.println(" Activated: " + mDisplayWhiteBalanceTintController.isActivated());
Long Ling1d3f1892019-02-06 12:34:02 -0800879 mDisplayWhiteBalanceTintController.dump(pw);
Christine Franksa4ed3762019-01-24 15:37:04 -0800880 } else {
881 pw.println(" Not available");
882 }
883
884 pw.println("Color mode: " + getColorModeInternal());
Christine Franksf3529b22019-01-03 13:20:17 -0800885 }
886
Christine Franks57fdde82018-07-03 14:46:07 -0700887 private abstract class NightDisplayAutoMode {
888
889 public abstract void onActivated(boolean activated);
890
Justin Klaassen911e8892016-06-21 18:24:24 -0700891 public abstract void onStart();
Christine Frankse5bb03e2017-02-10 17:36:10 -0800892
Justin Klaassen911e8892016-06-21 18:24:24 -0700893 public abstract void onStop();
Christine Franks57fdde82018-07-03 14:46:07 -0700894
895 public void onCustomStartTimeChanged(LocalTime startTime) {
896 }
897
898 public void onCustomEndTimeChanged(LocalTime endTime) {
899 }
Justin Klaassen911e8892016-06-21 18:24:24 -0700900 }
901
Christine Franks57fdde82018-07-03 14:46:07 -0700902 private final class CustomNightDisplayAutoMode extends NightDisplayAutoMode implements
903 AlarmManager.OnAlarmListener {
Justin Klaassen911e8892016-06-21 18:24:24 -0700904
905 private final AlarmManager mAlarmManager;
906 private final BroadcastReceiver mTimeChangedReceiver;
907
Christine Franks03213462017-08-25 13:57:26 -0700908 private LocalTime mStartTime;
909 private LocalTime mEndTime;
Justin Klaassen911e8892016-06-21 18:24:24 -0700910
Christine Franks03213462017-08-25 13:57:26 -0700911 private LocalDateTime mLastActivatedTime;
Justin Klaassen911e8892016-06-21 18:24:24 -0700912
Christine Franks57fdde82018-07-03 14:46:07 -0700913 CustomNightDisplayAutoMode() {
Justin Klaassen911e8892016-06-21 18:24:24 -0700914 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
915 mTimeChangedReceiver = new BroadcastReceiver() {
916 @Override
917 public void onReceive(Context context, Intent intent) {
918 updateActivated();
919 }
920 };
921 }
922
923 private void updateActivated() {
Christine Franks03213462017-08-25 13:57:26 -0700924 final LocalDateTime now = LocalDateTime.now();
925 final LocalDateTime start = getDateTimeBefore(mStartTime, now);
926 final LocalDateTime end = getDateTimeAfter(mEndTime, start);
927 boolean activate = now.isBefore(end);
Justin Klaassen911e8892016-06-21 18:24:24 -0700928
Christine Frankse5bb03e2017-02-10 17:36:10 -0800929 if (mLastActivatedTime != null) {
Christine Frankse5bb03e2017-02-10 17:36:10 -0800930 // Maintain the existing activated state if within the current period.
Christine Franks0ada2772019-02-25 13:54:57 -0800931 if (mLastActivatedTime.isBefore(now)
932 && mLastActivatedTime.isAfter(start)
Christine Franks03213462017-08-25 13:57:26 -0700933 && (mLastActivatedTime.isAfter(end) || now.isBefore(end))) {
Christine Franks78a4dd42019-02-08 11:09:30 -0800934 activate = mNightDisplayTintController.isActivatedSetting();
Justin Klaassen911e8892016-06-21 18:24:24 -0700935 }
936 }
937
Christine Franks0ada2772019-02-25 13:54:57 -0800938 if (mNightDisplayTintController.isActivatedStateNotSet()
939 || (mNightDisplayTintController.isActivated() != activate)) {
Christine Franks83cc5412018-07-03 14:46:07 -0700940 mNightDisplayTintController.setActivated(activate);
Justin Klaassen911e8892016-06-21 18:24:24 -0700941 }
Christine Franks03213462017-08-25 13:57:26 -0700942
Christine Franks245ffd42018-11-16 13:45:14 -0800943 updateNextAlarm(mNightDisplayTintController.isActivated(), now);
Justin Klaassen911e8892016-06-21 18:24:24 -0700944 }
945
Christine Franks03213462017-08-25 13:57:26 -0700946 private void updateNextAlarm(@Nullable Boolean activated, @NonNull LocalDateTime now) {
Justin Klaassen4346f632016-08-08 15:01:47 -0700947 if (activated != null) {
Christine Franks03213462017-08-25 13:57:26 -0700948 final LocalDateTime next = activated ? getDateTimeAfter(mEndTime, now)
949 : getDateTimeAfter(mStartTime, now);
950 final long millis = next.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
951 mAlarmManager.setExact(AlarmManager.RTC, millis, TAG, this, null);
Justin Klaassen911e8892016-06-21 18:24:24 -0700952 }
953 }
954
955 @Override
956 public void onStart() {
957 final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_TIME_CHANGED);
958 intentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
959 getContext().registerReceiver(mTimeChangedReceiver, intentFilter);
960
Christine Franks83cc5412018-07-03 14:46:07 -0700961 mStartTime = getNightDisplayCustomStartTimeInternal().getLocalTime();
962 mEndTime = getNightDisplayCustomEndTimeInternal().getLocalTime();
Justin Klaassen911e8892016-06-21 18:24:24 -0700963
Christine Franks57fdde82018-07-03 14:46:07 -0700964 mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
Christine Frankse5bb03e2017-02-10 17:36:10 -0800965
Justin Klaassen911e8892016-06-21 18:24:24 -0700966 // Force an update to initialize state.
967 updateActivated();
968 }
969
970 @Override
971 public void onStop() {
972 getContext().unregisterReceiver(mTimeChangedReceiver);
973
974 mAlarmManager.cancel(this);
975 mLastActivatedTime = null;
976 }
977
978 @Override
979 public void onActivated(boolean activated) {
Christine Franks57fdde82018-07-03 14:46:07 -0700980 mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
Christine Franks03213462017-08-25 13:57:26 -0700981 updateNextAlarm(activated, LocalDateTime.now());
Justin Klaassen911e8892016-06-21 18:24:24 -0700982 }
983
984 @Override
Christine Franks03213462017-08-25 13:57:26 -0700985 public void onCustomStartTimeChanged(LocalTime startTime) {
Justin Klaassen911e8892016-06-21 18:24:24 -0700986 mStartTime = startTime;
987 mLastActivatedTime = null;
988 updateActivated();
989 }
990
991 @Override
Christine Franks03213462017-08-25 13:57:26 -0700992 public void onCustomEndTimeChanged(LocalTime endTime) {
Justin Klaassen911e8892016-06-21 18:24:24 -0700993 mEndTime = endTime;
994 mLastActivatedTime = null;
995 updateActivated();
996 }
997
998 @Override
999 public void onAlarm() {
Justin Klaassenec8837a2016-08-23 12:04:42 -07001000 Slog.d(TAG, "onAlarm");
Justin Klaassen911e8892016-06-21 18:24:24 -07001001 updateActivated();
1002 }
1003 }
1004
Christine Franks57fdde82018-07-03 14:46:07 -07001005 private final class TwilightNightDisplayAutoMode extends NightDisplayAutoMode implements
1006 TwilightListener {
Justin Klaassen911e8892016-06-21 18:24:24 -07001007
1008 private final TwilightManager mTwilightManager;
Christine Franks57fdde82018-07-03 14:46:07 -07001009 private LocalDateTime mLastActivatedTime;
Justin Klaassen911e8892016-06-21 18:24:24 -07001010
Christine Franks57fdde82018-07-03 14:46:07 -07001011 TwilightNightDisplayAutoMode() {
Justin Klaassen911e8892016-06-21 18:24:24 -07001012 mTwilightManager = getLocalService(TwilightManager.class);
Justin Klaassen911e8892016-06-21 18:24:24 -07001013 }
1014
Justin Klaassen908b86c2016-08-08 09:18:42 -07001015 private void updateActivated(TwilightState state) {
Justin Klaassen3da4c442017-05-05 15:19:33 -07001016 if (state == null) {
1017 // If there isn't a valid TwilightState then just keep the current activated
1018 // state.
1019 return;
1020 }
1021
1022 boolean activate = state.isNight();
Christine Franks57fdde82018-07-03 14:46:07 -07001023 if (mLastActivatedTime != null) {
Christine Franks03213462017-08-25 13:57:26 -07001024 final LocalDateTime now = LocalDateTime.now();
1025 final LocalDateTime sunrise = state.sunrise();
1026 final LocalDateTime sunset = state.sunset();
Christine Frankse5bb03e2017-02-10 17:36:10 -08001027 // Maintain the existing activated state if within the current period.
Christine Franks57fdde82018-07-03 14:46:07 -07001028 if (mLastActivatedTime.isBefore(now) && (mLastActivatedTime.isBefore(sunrise)
1029 ^ mLastActivatedTime.isBefore(sunset))) {
Christine Franks78a4dd42019-02-08 11:09:30 -08001030 activate = mNightDisplayTintController.isActivatedSetting();
Justin Klaassen911e8892016-06-21 18:24:24 -07001031 }
1032 }
Justin Klaassen908b86c2016-08-08 09:18:42 -07001033
Christine Franks245ffd42018-11-16 13:45:14 -08001034 if (mNightDisplayTintController.isActivatedStateNotSet() || (
1035 mNightDisplayTintController.isActivated() != activate)) {
Christine Franks83cc5412018-07-03 14:46:07 -07001036 mNightDisplayTintController.setActivated(activate);
Justin Klaassen908b86c2016-08-08 09:18:42 -07001037 }
Justin Klaassen911e8892016-06-21 18:24:24 -07001038 }
1039
1040 @Override
Christine Franks57fdde82018-07-03 14:46:07 -07001041 public void onActivated(boolean activated) {
1042 mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
1043 }
1044
1045 @Override
Justin Klaassen911e8892016-06-21 18:24:24 -07001046 public void onStart() {
1047 mTwilightManager.registerListener(this, mHandler);
Christine Franks57fdde82018-07-03 14:46:07 -07001048 mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
Justin Klaassen911e8892016-06-21 18:24:24 -07001049
1050 // Force an update to initialize state.
Justin Klaassen908b86c2016-08-08 09:18:42 -07001051 updateActivated(mTwilightManager.getLastTwilightState());
Justin Klaassen911e8892016-06-21 18:24:24 -07001052 }
1053
1054 @Override
1055 public void onStop() {
1056 mTwilightManager.unregisterListener(this);
Christine Franks57fdde82018-07-03 14:46:07 -07001057 mLastActivatedTime = null;
Justin Klaassen908b86c2016-08-08 09:18:42 -07001058 }
1059
1060 @Override
1061 public void onTwilightStateChanged(@Nullable TwilightState state) {
Justin Klaassenec8837a2016-08-23 12:04:42 -07001062 Slog.d(TAG, "onTwilightStateChanged: isNight="
1063 + (state == null ? null : state.isNight()));
Justin Klaassen908b86c2016-08-08 09:18:42 -07001064 updateActivated(state);
Justin Klaassen911e8892016-06-21 18:24:24 -07001065 }
1066 }
Justin Klaassen639214e2016-07-14 21:00:06 -07001067
1068 /**
1069 * Interpolates between two 4x4 color transform matrices (in column-major order).
1070 */
1071 private static class ColorMatrixEvaluator implements TypeEvaluator<float[]> {
1072
1073 /**
1074 * Result matrix returned by {@link #evaluate(float, float[], float[])}.
1075 */
1076 private final float[] mResultMatrix = new float[16];
1077
1078 @Override
1079 public float[] evaluate(float fraction, float[] startValue, float[] endValue) {
1080 for (int i = 0; i < mResultMatrix.length; i++) {
1081 mResultMatrix[i] = MathUtils.lerp(startValue[i], endValue[i], fraction);
1082 }
1083 return mResultMatrix;
1084 }
1085 }
Christine Franks39b03112018-07-03 14:46:07 -07001086
Christine Franks245ffd42018-11-16 13:45:14 -08001087 private abstract static class TintController {
1088
1089 private ValueAnimator mAnimator;
1090 private Boolean mIsActivated;
1091
1092 public ValueAnimator getAnimator() {
1093 return mAnimator;
1094 }
1095
1096 public void setAnimator(ValueAnimator animator) {
1097 mAnimator = animator;
1098 }
1099
1100 /**
1101 * Cancel the animator if it's still running.
1102 */
1103 public void cancelAnimator() {
1104 if (mAnimator != null) {
1105 mAnimator.cancel();
1106 }
1107 }
1108
1109 /**
1110 * End the animator if it's still running, jumping to the end state.
1111 */
1112 public void endAnimator() {
1113 if (mAnimator != null) {
1114 mAnimator.end();
1115 mAnimator = null;
1116 }
1117 }
1118
1119 public void setActivated(Boolean isActivated) {
1120 mIsActivated = isActivated;
1121 }
1122
1123 public boolean isActivated() {
1124 return mIsActivated != null && mIsActivated;
1125 }
1126
1127 public boolean isActivatedStateNotSet() {
1128 return mIsActivated == null;
1129 }
1130
1131 /**
Daniel Solomon8b72c5b2018-11-25 11:07:13 -08001132 * Dump debug information.
1133 */
1134 public void dump(PrintWriter pw) {
1135 }
1136
1137 /**
Christine Franks245ffd42018-11-16 13:45:14 -08001138 * Set up any constants needed for computing the matrix.
1139 */
1140 public abstract void setUp(Context context, boolean needsLinear);
1141
1142 /**
1143 * Sets the 4x4 matrix to apply.
1144 */
1145 public abstract void setMatrix(int value);
1146
1147 /**
1148 * Get the 4x4 matrix to apply.
1149 */
1150 public abstract float[] getMatrix();
1151
1152 /**
1153 * Get the color transform level to apply the matrix.
1154 */
1155 public abstract int getLevel();
Christine Franksa4ed3762019-01-24 15:37:04 -08001156
1157 /**
1158 * Returns whether or not this transform type is available on this device.
1159 */
1160 public abstract boolean isAvailable(Context context);
Christine Franks245ffd42018-11-16 13:45:14 -08001161 }
1162
Christine Franks83cc5412018-07-03 14:46:07 -07001163 private final class NightDisplayTintController extends TintController {
1164
Christine Franksa4ed3762019-01-24 15:37:04 -08001165 private final float[] mMatrix = new float[16];
Christine Franks83cc5412018-07-03 14:46:07 -07001166 private final float[] mColorTempCoefficients = new float[9];
Christine Franksa4ed3762019-01-24 15:37:04 -08001167
1168 private Boolean mIsAvailable;
Christine Franks83cc5412018-07-03 14:46:07 -07001169 private Integer mColorTemp;
1170
1171 /**
1172 * Set coefficients based on whether the color matrix is linear or not.
1173 */
1174 @Override
1175 public void setUp(Context context, boolean needsLinear) {
1176 final String[] coefficients = context.getResources().getStringArray(needsLinear
1177 ? R.array.config_nightDisplayColorTemperatureCoefficients
1178 : R.array.config_nightDisplayColorTemperatureCoefficientsNative);
1179 for (int i = 0; i < 9 && i < coefficients.length; i++) {
1180 mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]);
1181 }
1182 }
1183
1184 @Override
1185 public void setMatrix(int cct) {
1186 if (mMatrix.length != 16) {
1187 Slog.d(TAG, "The display transformation matrix must be 4x4");
1188 return;
1189 }
1190
1191 Matrix.setIdentityM(mMatrix, 0);
1192
1193 final float squareTemperature = cct * cct;
1194 final float red = squareTemperature * mColorTempCoefficients[0]
1195 + cct * mColorTempCoefficients[1] + mColorTempCoefficients[2];
1196 final float green = squareTemperature * mColorTempCoefficients[3]
1197 + cct * mColorTempCoefficients[4] + mColorTempCoefficients[5];
1198 final float blue = squareTemperature * mColorTempCoefficients[6]
1199 + cct * mColorTempCoefficients[7] + mColorTempCoefficients[8];
1200 mMatrix[0] = red;
1201 mMatrix[5] = green;
1202 mMatrix[10] = blue;
1203 }
1204
1205 @Override
1206 public float[] getMatrix() {
1207 return isActivated() ? mMatrix : MATRIX_IDENTITY;
1208 }
1209
1210 @Override
1211 public void setActivated(Boolean activated) {
1212 if (activated == null) {
1213 super.setActivated(null);
1214 return;
1215 }
1216
1217 boolean activationStateChanged = activated != isActivated();
1218
1219 if (!isActivatedStateNotSet() && activationStateChanged) {
1220 // This is a true state change, so set this as the last activation time.
1221 Secure.putStringForUser(getContext().getContentResolver(),
1222 Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
1223 LocalDateTime.now().toString(),
1224 mCurrentUser);
1225 }
1226
1227 if (isActivatedStateNotSet() || activationStateChanged) {
1228 super.setActivated(activated);
Christine Franks78a4dd42019-02-08 11:09:30 -08001229 if (isActivatedSetting() != activated) {
1230 Secure.putIntForUser(getContext().getContentResolver(),
1231 Secure.NIGHT_DISPLAY_ACTIVATED,
1232 activated ? 1 : 0, mCurrentUser);
1233 }
Christine Franks83cc5412018-07-03 14:46:07 -07001234 onActivated(activated);
1235 }
1236 }
1237
1238 @Override
1239 public int getLevel() {
1240 return LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
1241 }
1242
Christine Franksa4ed3762019-01-24 15:37:04 -08001243 @Override
1244 public boolean isAvailable(Context context) {
1245 if (mIsAvailable == null) {
1246 mIsAvailable = ColorDisplayManager.isNightDisplayAvailable(context);
1247 }
1248 return mIsAvailable;
1249 }
1250
Christine Franks78a4dd42019-02-08 11:09:30 -08001251 private void onActivated(boolean activated) {
Christine Franks83cc5412018-07-03 14:46:07 -07001252 Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display");
1253 if (mNightDisplayAutoMode != null) {
1254 mNightDisplayAutoMode.onActivated(activated);
1255 }
1256
Christine Franksa4ed3762019-01-24 15:37:04 -08001257 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
Christine Franks83cc5412018-07-03 14:46:07 -07001258 updateDisplayWhiteBalanceStatus();
1259 }
1260
1261 mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_ANIMATED);
1262 }
1263
1264 int getColorTemperature() {
1265 return mColorTemp != null ? clampNightDisplayColorTemperature(mColorTemp)
Christine Franks78a4dd42019-02-08 11:09:30 -08001266 : getColorTemperatureSetting();
Christine Franks83cc5412018-07-03 14:46:07 -07001267 }
1268
1269 boolean setColorTemperature(int temperature) {
1270 mColorTemp = temperature;
1271 final boolean success = Secure.putIntForUser(getContext().getContentResolver(),
1272 Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, temperature, mCurrentUser);
1273 onColorTemperatureChanged(temperature);
1274 return success;
1275 }
1276
1277 void onColorTemperatureChanged(int temperature) {
1278 setMatrix(temperature);
1279 mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE);
1280 }
Christine Franks78a4dd42019-02-08 11:09:30 -08001281
1282 boolean isActivatedSetting() {
Christine Franks44782612019-03-07 17:25:39 -08001283 if (mCurrentUser == UserHandle.USER_NULL) {
1284 return false;
1285 }
Christine Franks78a4dd42019-02-08 11:09:30 -08001286 return Secure.getIntForUser(getContext().getContentResolver(),
1287 Secure.NIGHT_DISPLAY_ACTIVATED, 0, mCurrentUser) == 1;
1288 }
1289
1290 int getColorTemperatureSetting() {
Christine Franks44782612019-03-07 17:25:39 -08001291 if (mCurrentUser == UserHandle.USER_NULL) {
1292 return NOT_SET;
1293 }
Christine Franks78a4dd42019-02-08 11:09:30 -08001294 return clampNightDisplayColorTemperature(Secure.getIntForUser(
1295 getContext().getContentResolver(), Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE,
1296 NOT_SET,
1297 mCurrentUser));
1298 }
1299
1300 private int clampNightDisplayColorTemperature(int colorTemperature) {
1301 if (colorTemperature == NOT_SET) {
1302 colorTemperature = getContext().getResources().getInteger(
1303 R.integer.config_nightDisplayColorTemperatureDefault);
1304 }
1305 final int minimumTemperature = ColorDisplayManager
1306 .getMinimumColorTemperature(getContext());
1307 final int maximumTemperature = ColorDisplayManager
1308 .getMaximumColorTemperature(getContext());
1309 if (colorTemperature < minimumTemperature) {
1310 colorTemperature = minimumTemperature;
1311 } else if (colorTemperature > maximumTemperature) {
1312 colorTemperature = maximumTemperature;
1313 }
1314
1315 return colorTemperature;
1316 }
Christine Franks83cc5412018-07-03 14:46:07 -07001317 }
1318
Long Ling1d3f1892019-02-06 12:34:02 -08001319 final class DisplayWhiteBalanceTintController extends TintController {
Christine Franks0ada2772019-02-25 13:54:57 -08001320
Long Ling1d3f1892019-02-06 12:34:02 -08001321 // Three chromaticity coordinates per color: X, Y, and Z
Christine Franks0ada2772019-02-25 13:54:57 -08001322 private static final int NUM_VALUES_PER_PRIMARY = 3;
Long Ling1d3f1892019-02-06 12:34:02 -08001323 // Four colors: red, green, blue, and white
Christine Franks0ada2772019-02-25 13:54:57 -08001324 private static final int NUM_DISPLAY_PRIMARIES_VALS = 4 * NUM_VALUES_PER_PRIMARY;
Long Ling1d3f1892019-02-06 12:34:02 -08001325
1326 private final Object mLock = new Object();
1327 @VisibleForTesting
1328 int mTemperatureMin;
1329 @VisibleForTesting
1330 int mTemperatureMax;
1331 private int mTemperatureDefault;
1332 private float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
1333 @VisibleForTesting
1334 ColorSpace.Rgb mDisplayColorSpaceRGB;
1335 private float[] mChromaticAdaptationMatrix;
1336 @VisibleForTesting
1337 int mCurrentColorTemperature;
1338 private float[] mCurrentColorTemperatureXYZ;
1339 private boolean mSetUp = false;
1340 private float[] mMatrixDisplayWhiteBalance = new float[16];
1341 private Boolean mIsAvailable;
1342
1343 @Override
1344 public void setUp(Context context, boolean needsLinear) {
1345 mSetUp = false;
1346 final Resources res = context.getResources();
1347
1348 ColorSpace.Rgb displayColorSpaceRGB = getDisplayColorSpaceFromSurfaceControl();
1349 if (displayColorSpaceRGB == null) {
1350 Slog.w(TAG, "Failed to get display color space from SurfaceControl, trying res");
1351 displayColorSpaceRGB = getDisplayColorSpaceFromResources(res);
1352 if (displayColorSpaceRGB == null) {
1353 Slog.e(TAG, "Failed to get display color space from resources");
1354 return;
1355 }
1356 }
1357
1358 final String[] nominalWhiteValues = res.getStringArray(
1359 R.array.config_displayWhiteBalanceDisplayNominalWhite);
1360 float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
1361 for (int i = 0; i < nominalWhiteValues.length; i++) {
1362 displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]);
1363 }
1364
1365 final int colorTemperatureMin = res.getInteger(
1366 R.integer.config_displayWhiteBalanceColorTemperatureMin);
1367 if (colorTemperatureMin <= 0) {
1368 Slog.e(TAG, "Display white balance minimum temperature must be greater than 0");
1369 return;
1370 }
1371
1372 final int colorTemperatureMax = res.getInteger(
1373 R.integer.config_displayWhiteBalanceColorTemperatureMax);
1374 if (colorTemperatureMax < colorTemperatureMin) {
1375 Slog.e(TAG, "Display white balance max temp must be greater or equal to min");
1376 return;
1377 }
1378
1379 final int colorTemperature = res.getInteger(
1380 R.integer.config_displayWhiteBalanceColorTemperatureDefault);
1381
1382 synchronized (mLock) {
1383 mDisplayColorSpaceRGB = displayColorSpaceRGB;
1384 mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ;
1385 mTemperatureMin = colorTemperatureMin;
1386 mTemperatureMax = colorTemperatureMax;
1387 mTemperatureDefault = colorTemperature;
1388 mSetUp = true;
1389 }
1390
1391 setMatrix(mTemperatureDefault);
1392 }
1393
1394 @Override
1395 public float[] getMatrix() {
1396 return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
1397 }
1398
1399 @Override
1400 public void setMatrix(int cct) {
1401 if (!mSetUp) {
1402 Slog.w(TAG, "Can't set display white balance temperature: uninitialized");
1403 return;
1404 }
1405
1406 if (cct < mTemperatureMin) {
1407 Slog.w(TAG, "Requested display color temperature is below allowed minimum");
1408 cct = mTemperatureMin;
1409 } else if (cct > mTemperatureMax) {
1410 Slog.w(TAG, "Requested display color temperature is above allowed maximum");
1411 cct = mTemperatureMax;
1412 }
1413
1414 Slog.d(TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct);
1415
1416 synchronized (mLock) {
1417 mCurrentColorTemperature = cct;
1418
1419 // Adapt the display's nominal white point to match the requested CCT value
1420 mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct);
1421
1422 mChromaticAdaptationMatrix =
1423 ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
1424 mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
1425
1426 // Convert the adaptation matrix to RGB space
1427 float[] result = ColorSpace.mul3x3(mChromaticAdaptationMatrix,
1428 mDisplayColorSpaceRGB.getTransform());
1429 result = ColorSpace.mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
1430
1431 // Normalize the transform matrix to peak white value in RGB space
1432 final float adaptedMaxR = result[0] + result[3] + result[6];
1433 final float adaptedMaxG = result[1] + result[4] + result[7];
1434 final float adaptedMaxB = result[2] + result[5] + result[8];
1435 final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
1436 for (int i = 0; i < result.length; i++) {
1437 result[i] /= denum;
1438 }
1439
1440 Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
1441 java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
1442 java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
1443 java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
1444 }
1445 }
1446
1447 @Override
1448 public int getLevel() {
1449 return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
1450 }
1451
1452 @Override
1453 public boolean isAvailable(Context context) {
1454 if (mIsAvailable == null) {
1455 mIsAvailable = ColorDisplayManager.isDisplayWhiteBalanceAvailable(context);
1456 }
1457 return mIsAvailable;
1458 }
1459
1460 /**
1461 * Format a given matrix into a string.
1462 *
1463 * @param matrix the matrix to format
1464 * @param cols number of columns in the matrix
1465 */
1466 private String matrixToString(float[] matrix, int cols) {
1467 if (matrix == null || cols <= 0) {
1468 Slog.e(TAG, "Invalid arguments when formatting matrix to string");
1469 return "";
1470 }
1471
1472 StringBuilder sb = new StringBuilder("");
1473 for (int i = 0; i < matrix.length; i++) {
1474 if (i % cols == 0) {
1475 sb.append("\n ");
1476 }
1477 sb.append(String.format("%9.6f ", matrix[i]));
1478 }
1479 return sb.toString();
1480 }
1481
1482 @Override
1483 public void dump(PrintWriter pw) {
1484 synchronized (mLock) {
1485 pw.println(" mSetUp = " + mSetUp);
1486 if (!mSetUp) {
1487 return;
1488 }
1489
1490 pw.println(" mTemperatureMin = " + mTemperatureMin);
1491 pw.println(" mTemperatureMax = " + mTemperatureMax);
1492 pw.println(" mTemperatureDefault = " + mTemperatureDefault);
1493 pw.println(" mCurrentColorTemperature = " + mCurrentColorTemperature);
Christine Franks0ada2772019-02-25 13:54:57 -08001494 pw.println(" mCurrentColorTemperatureXYZ = "
1495 + matrixToString(mCurrentColorTemperatureXYZ, 3));
1496 pw.println(" mDisplayColorSpaceRGB RGB-to-XYZ = "
1497 + matrixToString(mDisplayColorSpaceRGB.getTransform(), 3));
1498 pw.println(" mChromaticAdaptationMatrix = "
1499 + matrixToString(mChromaticAdaptationMatrix, 3));
1500 pw.println(" mDisplayColorSpaceRGB XYZ-to-RGB = "
1501 + matrixToString(mDisplayColorSpaceRGB.getInverseTransform(), 3));
1502 pw.println(" mMatrixDisplayWhiteBalance = "
1503 + matrixToString(mMatrixDisplayWhiteBalance, 4));
Long Ling1d3f1892019-02-06 12:34:02 -08001504 }
1505 }
1506
1507 private ColorSpace.Rgb makeRgbColorSpaceFromXYZ(float[] redGreenBlueXYZ, float[] whiteXYZ) {
1508 return new ColorSpace.Rgb(
Christine Franks0ada2772019-02-25 13:54:57 -08001509 "Display Color Space",
1510 redGreenBlueXYZ,
1511 whiteXYZ,
1512 2.2f // gamma, unused for display white balance
Long Ling1d3f1892019-02-06 12:34:02 -08001513 );
1514 }
1515
1516 private ColorSpace.Rgb getDisplayColorSpaceFromSurfaceControl() {
1517 final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
1518 if (displayToken == null) {
1519 return null;
1520 }
1521
1522 DisplayPrimaries primaries = SurfaceControl.getDisplayNativePrimaries(displayToken);
Christine Franks0ada2772019-02-25 13:54:57 -08001523 if (primaries == null || primaries.red == null || primaries.green == null
1524 || primaries.blue == null || primaries.white == null) {
Long Ling1d3f1892019-02-06 12:34:02 -08001525 return null;
1526 }
1527
1528 return makeRgbColorSpaceFromXYZ(
Christine Franks0ada2772019-02-25 13:54:57 -08001529 new float[]{
1530 primaries.red.X, primaries.red.Y, primaries.red.Z,
1531 primaries.green.X, primaries.green.Y, primaries.green.Z,
1532 primaries.blue.X, primaries.blue.Y, primaries.blue.Z,
Long Ling1d3f1892019-02-06 12:34:02 -08001533 },
Christine Franks0ada2772019-02-25 13:54:57 -08001534 new float[]{primaries.white.X, primaries.white.Y, primaries.white.Z}
1535 );
Long Ling1d3f1892019-02-06 12:34:02 -08001536 }
1537
1538 private ColorSpace.Rgb getDisplayColorSpaceFromResources(Resources res) {
1539 final String[] displayPrimariesValues = res.getStringArray(
1540 R.array.config_displayWhiteBalanceDisplayPrimaries);
1541 float[] displayRedGreenBlueXYZ =
1542 new float[NUM_DISPLAY_PRIMARIES_VALS - NUM_VALUES_PER_PRIMARY];
1543 float[] displayWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
1544
1545 for (int i = 0; i < displayRedGreenBlueXYZ.length; i++) {
1546 displayRedGreenBlueXYZ[i] = Float.parseFloat(displayPrimariesValues[i]);
1547 }
1548
1549 for (int i = 0; i < displayWhiteXYZ.length; i++) {
1550 displayWhiteXYZ[i] = Float.parseFloat(
1551 displayPrimariesValues[displayRedGreenBlueXYZ.length + i]);
1552 }
1553
1554 return makeRgbColorSpaceFromXYZ(displayRedGreenBlueXYZ, displayWhiteXYZ);
1555 }
Christine Franks0ada2772019-02-25 13:54:57 -08001556 }
Long Ling1d3f1892019-02-06 12:34:02 -08001557
Christine Franks245ffd42018-11-16 13:45:14 -08001558 /**
1559 * Local service that allows color transforms to be enabled from other system services.
1560 */
1561 public final class ColorDisplayServiceInternal {
1562
1563 /**
1564 * Set the current CCT value for the display white balance transform, and if the transform
1565 * is enabled, apply it.
1566 *
1567 * @param cct the color temperature in Kelvin.
1568 */
1569 public boolean setDisplayWhiteBalanceColorTemperature(int cct) {
1570 // Update the transform matrix even if it can't be applied.
Christine Franks245ffd42018-11-16 13:45:14 -08001571 mDisplayWhiteBalanceTintController.setMatrix(cct);
1572
1573 if (mDisplayWhiteBalanceTintController.isActivated()) {
Christine Franksc7fb9452019-02-04 08:45:33 -08001574 mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE);
Christine Franks245ffd42018-11-16 13:45:14 -08001575 return true;
1576 }
1577 return false;
1578 }
1579
1580 /**
1581 * Sets the listener and returns whether display white balance is currently enabled.
1582 */
1583 public boolean setDisplayWhiteBalanceListener(DisplayWhiteBalanceListener listener) {
1584 mDisplayWhiteBalanceListener = listener;
1585 return mDisplayWhiteBalanceTintController.isActivated();
1586 }
Daniel Solomon8b72c5b2018-11-25 11:07:13 -08001587
Christine Franksf3529b22019-01-03 13:20:17 -08001588 /**
1589 * Adds a {@link WeakReference<ColorTransformController>} for a newly started activity, and
1590 * invokes {@link ColorTransformController#applyAppSaturation(float[], float[])} if needed.
1591 */
Christine Franks55194dc2019-01-15 13:47:06 -08001592 public boolean attachColorTransformController(String packageName, @UserIdInt int userId,
Christine Franksf3529b22019-01-03 13:20:17 -08001593 WeakReference<ColorTransformController> controller) {
1594 return mAppSaturationController
Christine Franks55194dc2019-01-15 13:47:06 -08001595 .addColorTransformController(packageName, userId, controller);
Christine Franksf3529b22019-01-03 13:20:17 -08001596 }
Christine Franks245ffd42018-11-16 13:45:14 -08001597 }
1598
1599 /**
1600 * Listener for changes in display white balance status.
1601 */
1602 public interface DisplayWhiteBalanceListener {
1603
1604 /**
1605 * Notify that the display white balance status has changed, either due to preemption by
1606 * another transform or the feature being turned off.
1607 */
1608 void onDisplayWhiteBalanceStatusChanged(boolean enabled);
1609 }
1610
Christine Franks09c229e2018-12-14 10:37:40 -08001611 private final class TintHandler extends Handler {
1612
Christine Franks83cc5412018-07-03 14:46:07 -07001613 private TintHandler(Looper looper) {
Christine Franks09c229e2018-12-14 10:37:40 -08001614 super(looper, null, true /* async */);
1615 }
1616
1617 @Override
1618 public void handleMessage(Message msg) {
1619 switch (msg.what) {
1620 case MSG_APPLY_GLOBAL_SATURATION:
1621 mGlobalSaturationTintController.setMatrix(msg.arg1);
1622 applyTint(mGlobalSaturationTintController, false);
1623 break;
Christine Franks83cc5412018-07-03 14:46:07 -07001624 case MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE:
1625 applyTint(mNightDisplayTintController, true);
1626 break;
1627 case MSG_APPLY_NIGHT_DISPLAY_ANIMATED:
1628 applyTint(mNightDisplayTintController, false);
1629 break;
Christine Franksc7fb9452019-02-04 08:45:33 -08001630 case MSG_APPLY_DISPLAY_WHITE_BALANCE:
1631 applyTint(mDisplayWhiteBalanceTintController, false);
1632 break;
Christine Franks09c229e2018-12-14 10:37:40 -08001633 }
1634 }
1635 }
1636
Christine Franksf3529b22019-01-03 13:20:17 -08001637 /**
1638 * Interface for applying transforms to a given AppWindow.
1639 */
1640 public interface ColorTransformController {
1641
Christine Franksd154fe52019-01-04 17:17:45 -08001642 /**
1643 * Apply the given saturation (grayscale) matrix to the associated AppWindow.
1644 */
Christine Franksf3529b22019-01-03 13:20:17 -08001645 void applyAppSaturation(@Size(9) float[] matrix, @Size(3) float[] translation);
1646 }
1647
Christine Franks83cc5412018-07-03 14:46:07 -07001648 @VisibleForTesting
1649 final class BinderService extends IColorDisplayManager.Stub {
Christine Franks57fdde82018-07-03 14:46:07 -07001650
Christine Franks39b03112018-07-03 14:46:07 -07001651 @Override
Christine Franksd154fe52019-01-04 17:17:45 -08001652 public void setColorMode(int colorMode) {
1653 getContext().enforceCallingOrSelfPermission(
1654 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1655 "Permission required to set display color mode");
1656 final long token = Binder.clearCallingIdentity();
1657 try {
1658 setColorModeInternal(colorMode);
1659 } finally {
1660 Binder.restoreCallingIdentity(token);
1661 }
1662 }
1663
1664 @Override
1665 public int getColorMode() {
1666 final long token = Binder.clearCallingIdentity();
1667 try {
1668 return getColorModeInternal();
1669 } finally {
1670 Binder.restoreCallingIdentity(token);
1671 }
1672 }
1673
1674 @Override
Christine Franks39b03112018-07-03 14:46:07 -07001675 public boolean isDeviceColorManaged() {
1676 final long token = Binder.clearCallingIdentity();
1677 try {
1678 return isDeviceColorManagedInternal();
1679 } finally {
1680 Binder.restoreCallingIdentity(token);
1681 }
1682 }
Christine Franks09c229e2018-12-14 10:37:40 -08001683
1684 @Override
1685 public boolean setSaturationLevel(int level) {
1686 final boolean hasTransformsPermission = getContext()
1687 .checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
1688 == PackageManager.PERMISSION_GRANTED;
1689 final boolean hasLegacyPermission = getContext()
1690 .checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION)
1691 == PackageManager.PERMISSION_GRANTED;
1692 if (!hasTransformsPermission && !hasLegacyPermission) {
1693 throw new SecurityException("Permission required to set display saturation level");
1694 }
1695 final long token = Binder.clearCallingIdentity();
1696 try {
1697 final Message message = mHandler.obtainMessage(MSG_APPLY_GLOBAL_SATURATION);
1698 message.arg1 = level;
1699 mHandler.sendMessage(message);
1700 } finally {
1701 Binder.restoreCallingIdentity(token);
1702 }
1703 return true;
1704 }
Christine Franksf3529b22019-01-03 13:20:17 -08001705
1706 @Override
Christine Franks6d21d342019-02-07 15:09:03 -08001707 public boolean isSaturationActivated() {
1708 getContext().enforceCallingPermission(
1709 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1710 "Permission required to get display saturation level");
1711 final long token = Binder.clearCallingIdentity();
1712 try {
1713 return !mGlobalSaturationTintController.isActivatedStateNotSet()
1714 && mGlobalSaturationTintController.isActivated();
1715 } finally {
1716 Binder.restoreCallingIdentity(token);
1717 }
1718 }
1719
1720 @Override
Christine Franksf3529b22019-01-03 13:20:17 -08001721 public boolean setAppSaturationLevel(String packageName, int level) {
1722 getContext().enforceCallingPermission(
1723 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1724 "Permission required to set display saturation level");
1725 final long token = Binder.clearCallingIdentity();
1726 try {
1727 return setAppSaturationLevelInternal(packageName, level);
1728 } finally {
1729 Binder.restoreCallingIdentity(token);
1730 }
1731 }
1732
Christine Franks55194dc2019-01-15 13:47:06 -08001733 public int getTransformCapabilities() {
1734 getContext().enforceCallingPermission(
1735 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1736 "Permission required to query transform capabilities");
1737 final long token = Binder.clearCallingIdentity();
1738 try {
1739 return getTransformCapabilitiesInternal();
1740 } finally {
1741 Binder.restoreCallingIdentity(token);
1742 }
1743 }
1744
Christine Franksf3529b22019-01-03 13:20:17 -08001745 @Override
Christine Franks83cc5412018-07-03 14:46:07 -07001746 public boolean setNightDisplayActivated(boolean activated) {
1747 getContext().enforceCallingOrSelfPermission(
1748 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1749 "Permission required to set night display activated");
1750 final long token = Binder.clearCallingIdentity();
1751 try {
1752 mNightDisplayTintController.setActivated(activated);
1753 return true;
1754 } finally {
1755 Binder.restoreCallingIdentity(token);
1756 }
1757 }
1758
1759 @Override
1760 public boolean isNightDisplayActivated() {
1761 final long token = Binder.clearCallingIdentity();
1762 try {
1763 return mNightDisplayTintController.isActivated();
1764 } finally {
1765 Binder.restoreCallingIdentity(token);
1766 }
1767 }
1768
1769 @Override
1770 public boolean setNightDisplayColorTemperature(int temperature) {
1771 getContext().enforceCallingOrSelfPermission(
1772 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1773 "Permission required to set night display temperature");
1774 final long token = Binder.clearCallingIdentity();
1775 try {
1776 return mNightDisplayTintController.setColorTemperature(temperature);
1777 } finally {
1778 Binder.restoreCallingIdentity(token);
1779 }
1780 }
1781
1782 @Override
1783 public int getNightDisplayColorTemperature() {
1784 final long token = Binder.clearCallingIdentity();
1785 try {
1786 return mNightDisplayTintController.getColorTemperature();
1787 } finally {
1788 Binder.restoreCallingIdentity(token);
1789 }
1790 }
1791
1792 @Override
1793 public boolean setNightDisplayAutoMode(int autoMode) {
1794 getContext().enforceCallingOrSelfPermission(
1795 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1796 "Permission required to set night display auto mode");
1797 final long token = Binder.clearCallingIdentity();
1798 try {
1799 return setNightDisplayAutoModeInternal(autoMode);
1800 } finally {
1801 Binder.restoreCallingIdentity(token);
1802 }
1803 }
1804
1805 @Override
1806 public int getNightDisplayAutoMode() {
1807 getContext().enforceCallingOrSelfPermission(
1808 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1809 "Permission required to get night display auto mode");
1810 final long token = Binder.clearCallingIdentity();
1811 try {
1812 return getNightDisplayAutoModeInternal();
1813 } finally {
1814 Binder.restoreCallingIdentity(token);
1815 }
1816 }
1817
1818 @Override
1819 public int getNightDisplayAutoModeRaw() {
1820 final long token = Binder.clearCallingIdentity();
1821 try {
1822 return getNightDisplayAutoModeRawInternal();
1823 } finally {
1824 Binder.restoreCallingIdentity(token);
1825 }
1826 }
1827
1828 @Override
1829 public boolean setNightDisplayCustomStartTime(Time startTime) {
1830 getContext().enforceCallingOrSelfPermission(
1831 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1832 "Permission required to set night display custom start time");
1833 final long token = Binder.clearCallingIdentity();
1834 try {
1835 return setNightDisplayCustomStartTimeInternal(startTime);
1836 } finally {
1837 Binder.restoreCallingIdentity(token);
1838 }
1839 }
1840
1841 @Override
1842 public Time getNightDisplayCustomStartTime() {
1843 final long token = Binder.clearCallingIdentity();
1844 try {
1845 return getNightDisplayCustomStartTimeInternal();
1846 } finally {
1847 Binder.restoreCallingIdentity(token);
1848 }
1849 }
1850
1851 @Override
1852 public boolean setNightDisplayCustomEndTime(Time endTime) {
1853 getContext().enforceCallingOrSelfPermission(
1854 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1855 "Permission required to set night display custom end time");
1856 final long token = Binder.clearCallingIdentity();
1857 try {
1858 return setNightDisplayCustomEndTimeInternal(endTime);
1859 } finally {
1860 Binder.restoreCallingIdentity(token);
1861 }
1862 }
1863
1864 @Override
1865 public Time getNightDisplayCustomEndTime() {
1866 final long token = Binder.clearCallingIdentity();
1867 try {
1868 return getNightDisplayCustomEndTimeInternal();
1869 } finally {
1870 Binder.restoreCallingIdentity(token);
1871 }
1872 }
1873
1874 @Override
Christine Franksf3529b22019-01-03 13:20:17 -08001875 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Christine Franksd154fe52019-01-04 17:17:45 -08001876 if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
1877 return;
1878 }
Christine Franksf3529b22019-01-03 13:20:17 -08001879
1880 final long token = Binder.clearCallingIdentity();
1881 try {
1882 dumpInternal(pw);
1883 } finally {
1884 Binder.restoreCallingIdentity(token);
1885 }
1886 }
Christine Franks39b03112018-07-03 14:46:07 -07001887 }
Justin Klaassen911e8892016-06-21 18:24:24 -07001888}