blob: 85fb1e0f4bdf80aeb4d89e85561c74be849bec01 [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_NIGHT_DISPLAY;
Christine Franks39b03112018-07-03 14:46:07 -070028
Christine Franks09c229e2018-12-14 10:37:40 -080029import android.Manifest;
Justin Klaassen639214e2016-07-14 21:00:06 -070030import android.animation.Animator;
31import android.animation.AnimatorListenerAdapter;
32import android.animation.TypeEvaluator;
33import android.animation.ValueAnimator;
Justin Klaassen4346f632016-08-08 15:01:47 -070034import android.annotation.NonNull;
Justin Klaassen908b86c2016-08-08 09:18:42 -070035import android.annotation.Nullable;
Christine Franksf3529b22019-01-03 13:20:17 -080036import android.annotation.Size;
Christine Franks55194dc2019-01-15 13:47:06 -080037import android.annotation.UserIdInt;
Justin Klaassen911e8892016-06-21 18:24:24 -070038import android.app.AlarmManager;
39import android.content.BroadcastReceiver;
40import android.content.ContentResolver;
41import android.content.Context;
42import android.content.Intent;
43import android.content.IntentFilter;
Christine Franks09c229e2018-12-14 10:37:40 -080044import android.content.pm.PackageManager;
Daniel Solomon8b72c5b2018-11-25 11:07:13 -080045import android.content.res.Resources;
Justin Klaassen2696d992016-07-11 21:26:46 -070046import android.database.ContentObserver;
Christine Franksf3529b22019-01-03 13:20:17 -080047import android.hardware.display.ColorDisplayManager;
Christine Franks83cc5412018-07-03 14:46:07 -070048import android.hardware.display.ColorDisplayManager.AutoMode;
Christine Franksd154fe52019-01-04 17:17:45 -080049import android.hardware.display.ColorDisplayManager.ColorMode;
Christine Franks39b03112018-07-03 14:46:07 -070050import android.hardware.display.IColorDisplayManager;
Christine Franks83cc5412018-07-03 14:46:07 -070051import android.hardware.display.Time;
Justin Klaassen2696d992016-07-11 21:26:46 -070052import android.net.Uri;
Justin Klaassen639214e2016-07-14 21:00:06 -070053import android.opengl.Matrix;
Christine Franks39b03112018-07-03 14:46:07 -070054import android.os.Binder;
Justin Klaassen911e8892016-06-21 18:24:24 -070055import android.os.Handler;
56import android.os.Looper;
Christine Franks09c229e2018-12-14 10:37:40 -080057import android.os.Message;
Christine Franksd154fe52019-01-04 17:17:45 -080058import android.os.SystemProperties;
Justin Klaassen911e8892016-06-21 18:24:24 -070059import android.os.UserHandle;
60import android.provider.Settings.Secure;
Christine Franks57fdde82018-07-03 14:46:07 -070061import android.provider.Settings.System;
Justin Klaassen639214e2016-07-14 21:00:06 -070062import android.util.MathUtils;
Justin Klaassen911e8892016-06-21 18:24:24 -070063import android.util.Slog;
Christine Franks55194dc2019-01-15 13:47:06 -080064import android.view.SurfaceControl;
Christine Franks9114f462019-01-04 11:27:30 -080065import android.view.accessibility.AccessibilityManager;
Justin Klaassen639214e2016-07-14 21:00:06 -070066import android.view.animation.AnimationUtils;
Daniel Solomona4ab5672019-01-22 19:35:55 -080067
Christine Franks39b03112018-07-03 14:46:07 -070068import com.android.internal.R;
Christine Franks57fdde82018-07-03 14:46:07 -070069import com.android.internal.annotations.VisibleForTesting;
Christine Franksf3529b22019-01-03 13:20:17 -080070import com.android.internal.util.DumpUtils;
Christine Franks57fdde82018-07-03 14:46:07 -070071import com.android.server.DisplayThread;
Justin Klaassen911e8892016-06-21 18:24:24 -070072import com.android.server.SystemService;
73import com.android.server.twilight.TwilightListener;
74import com.android.server.twilight.TwilightManager;
75import com.android.server.twilight.TwilightState;
Christine Franksa4ed3762019-01-24 15:37:04 -080076
Christine Franksf3529b22019-01-03 13:20:17 -080077import java.io.FileDescriptor;
Daniel Solomon8b72c5b2018-11-25 11:07:13 -080078import java.io.PrintWriter;
Christine Franksf3529b22019-01-03 13:20:17 -080079import java.lang.ref.WeakReference;
Christine Franks57fdde82018-07-03 14:46:07 -070080import java.time.DateTimeException;
81import java.time.Instant;
Christine Franks03213462017-08-25 13:57:26 -070082import java.time.LocalDateTime;
83import java.time.LocalTime;
84import java.time.ZoneId;
Christine Franks57fdde82018-07-03 14:46:07 -070085import java.time.format.DateTimeParseException;
Christine Franks8ad71492017-10-24 19:04:22 -070086
Justin Klaassen911e8892016-06-21 18:24:24 -070087/**
Christine Franks39b03112018-07-03 14:46:07 -070088 * Controls the display's color transforms.
Justin Klaassen911e8892016-06-21 18:24:24 -070089 */
Christine Franks57fdde82018-07-03 14:46:07 -070090public final class ColorDisplayService extends SystemService {
Justin Klaassen911e8892016-06-21 18:24:24 -070091
Christine Franks7119e992019-03-14 17:28:21 -070092 static final String TAG = "ColorDisplayService";
Christine Franks7b83b4282017-01-18 14:55:00 -080093
94 /**
Justin Klaassen639214e2016-07-14 21:00:06 -070095 * The identity matrix, used if one of the given matrices is {@code null}.
96 */
Christine Franks6caba0f2019-03-07 17:48:25 -080097 static final float[] MATRIX_IDENTITY = new float[16];
Christine Franks57fdde82018-07-03 14:46:07 -070098
Justin Klaassen639214e2016-07-14 21:00:06 -070099 static {
100 Matrix.setIdentityM(MATRIX_IDENTITY, 0);
101 }
102
Christine Franks7119e992019-03-14 17:28:21 -0700103 /**
104 * The transition time, in milliseconds, for Night Display to turn on/off.
105 */
106 private static final long TRANSITION_DURATION = 3000L;
107
Christine Franks27912a32019-04-02 10:43:10 -0700108 private static final int MSG_USER_CHANGED = 0;
109 private static final int MSG_SET_UP = 1;
110 private static final int MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE = 2;
111 private static final int MSG_APPLY_NIGHT_DISPLAY_ANIMATED = 3;
112 private static final int MSG_APPLY_GLOBAL_SATURATION = 4;
113 private static final int MSG_APPLY_DISPLAY_WHITE_BALANCE = 5;
Christine Franks09c229e2018-12-14 10:37:40 -0800114
Justin Klaassen639214e2016-07-14 21:00:06 -0700115 /**
Christine Franks83cc5412018-07-03 14:46:07 -0700116 * Return value if a setting has not been set.
117 */
118 private static final int NOT_SET = -1;
119
120 /**
Justin Klaassen639214e2016-07-14 21:00:06 -0700121 * Evaluator used to animate color matrix transitions.
122 */
123 private static final ColorMatrixEvaluator COLOR_MATRIX_EVALUATOR = new ColorMatrixEvaluator();
124
Christine Franks83cc5412018-07-03 14:46:07 -0700125 private final NightDisplayTintController mNightDisplayTintController =
126 new NightDisplayTintController();
Christine Franks245ffd42018-11-16 13:45:14 -0800127
Long Ling1d3f1892019-02-06 12:34:02 -0800128 @VisibleForTesting
129 final DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController =
130 new DisplayWhiteBalanceTintController();
Christine Franks245ffd42018-11-16 13:45:14 -0800131
Christine Franks7119e992019-03-14 17:28:21 -0700132 private final TintController mGlobalSaturationTintController =
133 new GlobalSaturationTintController();
Christine Franks09c229e2018-12-14 10:37:40 -0800134
Christine Franks9114f462019-01-04 11:27:30 -0800135 /**
136 * Matrix and offset used for converting color to grayscale.
137 */
138 private static final float[] MATRIX_GRAYSCALE = new float[]{
139 .2126f, .2126f, .2126f, 0f,
140 .7152f, .7152f, .7152f, 0f,
141 .0722f, .0722f, .0722f, 0f,
142 0f, 0f, 0f, 1f
143 };
144
145 /**
146 * Matrix and offset used for luminance inversion. Represents a transform from RGB to YIQ color
147 * space, rotation around the Y axis by 180 degrees, transform back to RGB color space, and
148 * subtraction from 1. The last row represents a non-multiplied addition, see surfaceflinger's
149 * ProgramCache for full implementation details.
150 */
Christine Franksd154fe52019-01-04 17:17:45 -0800151 private static final float[] MATRIX_INVERT_COLOR = new float[]{
Christine Franks9114f462019-01-04 11:27:30 -0800152 0.402f, -0.598f, -0.599f, 0f,
153 -1.174f, -0.174f, -1.175f, 0f,
154 -0.228f, -0.228f, 0.772f, 0f,
155 1f, 1f, 1f, 1f
156 };
157
Justin Klaassen2696d992016-07-11 21:26:46 -0700158 private final Handler mHandler;
159
Christine Franksf3529b22019-01-03 13:20:17 -0800160 private final AppSaturationController mAppSaturationController = new AppSaturationController();
161
Justin Klaassen911e8892016-06-21 18:24:24 -0700162 private int mCurrentUser = UserHandle.USER_NULL;
Justin Klaassen2696d992016-07-11 21:26:46 -0700163 private ContentObserver mUserSetupObserver;
Justin Klaassen911e8892016-06-21 18:24:24 -0700164 private boolean mBootCompleted;
165
Christine Franks57fdde82018-07-03 14:46:07 -0700166 private ContentObserver mContentObserver;
Christine Franks57fdde82018-07-03 14:46:07 -0700167
Christine Franks245ffd42018-11-16 13:45:14 -0800168 private DisplayWhiteBalanceListener mDisplayWhiteBalanceListener;
169
Christine Franks57fdde82018-07-03 14:46:07 -0700170 private NightDisplayAutoMode mNightDisplayAutoMode;
Justin Klaassen911e8892016-06-21 18:24:24 -0700171
Christine Franks5397f032017-11-01 18:35:16 -0700172 public ColorDisplayService(Context context) {
Justin Klaassen911e8892016-06-21 18:24:24 -0700173 super(context);
Christine Franks83cc5412018-07-03 14:46:07 -0700174 mHandler = new TintHandler(DisplayThread.get().getLooper());
Justin Klaassen911e8892016-06-21 18:24:24 -0700175 }
176
177 @Override
178 public void onStart() {
Christine Franks39b03112018-07-03 14:46:07 -0700179 publishBinderService(Context.COLOR_DISPLAY_SERVICE, new BinderService());
Christine Franks245ffd42018-11-16 13:45:14 -0800180 publishLocalService(ColorDisplayServiceInternal.class, new ColorDisplayServiceInternal());
Christine Franks0ada2772019-02-25 13:54:57 -0800181 publishLocalService(DisplayTransformManager.class, new DisplayTransformManager());
Justin Klaassen911e8892016-06-21 18:24:24 -0700182 }
183
184 @Override
Justin Klaassen2696d992016-07-11 21:26:46 -0700185 public void onBootPhase(int phase) {
Christine Frankse5bb03e2017-02-10 17:36:10 -0800186 if (phase >= PHASE_BOOT_COMPLETED) {
Justin Klaassen2696d992016-07-11 21:26:46 -0700187 mBootCompleted = true;
188
189 // Register listeners now that boot is complete.
190 if (mCurrentUser != UserHandle.USER_NULL && mUserSetupObserver == null) {
Christine Franks27912a32019-04-02 10:43:10 -0700191 mHandler.sendEmptyMessage(MSG_SET_UP);
Justin Klaassen2696d992016-07-11 21:26:46 -0700192 }
193 }
194 }
195
196 @Override
Justin Klaassen911e8892016-06-21 18:24:24 -0700197 public void onStartUser(int userHandle) {
198 super.onStartUser(userHandle);
199
Justin Klaassen911e8892016-06-21 18:24:24 -0700200 if (mCurrentUser == UserHandle.USER_NULL) {
Christine Franks27912a32019-04-02 10:43:10 -0700201 final Message message = mHandler.obtainMessage(MSG_USER_CHANGED);
202 message.arg1 = userHandle;
203 mHandler.sendMessage(message);
Justin Klaassen911e8892016-06-21 18:24:24 -0700204 }
205 }
206
207 @Override
208 public void onSwitchUser(int userHandle) {
209 super.onSwitchUser(userHandle);
210
Christine Franks27912a32019-04-02 10:43:10 -0700211 final Message message = mHandler.obtainMessage(MSG_USER_CHANGED);
212 message.arg1 = userHandle;
213 mHandler.sendMessage(message);
Justin Klaassen911e8892016-06-21 18:24:24 -0700214 }
215
216 @Override
217 public void onStopUser(int userHandle) {
218 super.onStopUser(userHandle);
219
Justin Klaassen911e8892016-06-21 18:24:24 -0700220 if (mCurrentUser == userHandle) {
Christine Franks27912a32019-04-02 10:43:10 -0700221 final Message message = mHandler.obtainMessage(MSG_USER_CHANGED);
222 message.arg1 = UserHandle.USER_NULL;
223 mHandler.sendMessage(message);
Justin Klaassen911e8892016-06-21 18:24:24 -0700224 }
225 }
226
Justin Klaassen2696d992016-07-11 21:26:46 -0700227 private void onUserChanged(int userHandle) {
228 final ContentResolver cr = getContext().getContentResolver();
Justin Klaassen911e8892016-06-21 18:24:24 -0700229
Justin Klaassen2696d992016-07-11 21:26:46 -0700230 if (mCurrentUser != UserHandle.USER_NULL) {
231 if (mUserSetupObserver != null) {
232 cr.unregisterContentObserver(mUserSetupObserver);
233 mUserSetupObserver = null;
234 } else if (mBootCompleted) {
235 tearDown();
236 }
237 }
238
239 mCurrentUser = userHandle;
240
241 if (mCurrentUser != UserHandle.USER_NULL) {
242 if (!isUserSetupCompleted(cr, mCurrentUser)) {
243 mUserSetupObserver = new ContentObserver(mHandler) {
244 @Override
245 public void onChange(boolean selfChange, Uri uri) {
246 if (isUserSetupCompleted(cr, mCurrentUser)) {
247 cr.unregisterContentObserver(this);
248 mUserSetupObserver = null;
249
250 if (mBootCompleted) {
251 setUp();
252 }
253 }
254 }
255 };
256 cr.registerContentObserver(Secure.getUriFor(Secure.USER_SETUP_COMPLETE),
Christine Franks39b03112018-07-03 14:46:07 -0700257 false /* notifyForDescendants */, mUserSetupObserver, mCurrentUser);
Justin Klaassen2696d992016-07-11 21:26:46 -0700258 } else if (mBootCompleted) {
259 setUp();
Justin Klaassen911e8892016-06-21 18:24:24 -0700260 }
261 }
262 }
263
Justin Klaassen2696d992016-07-11 21:26:46 -0700264 private static boolean isUserSetupCompleted(ContentResolver cr, int userHandle) {
265 return Secure.getIntForUser(cr, Secure.USER_SETUP_COMPLETE, 0, userHandle) == 1;
266 }
267
268 private void setUp() {
Justin Klaassenec8837a2016-08-23 12:04:42 -0700269 Slog.d(TAG, "setUp: currentUser=" + mCurrentUser);
270
Christine Franks57fdde82018-07-03 14:46:07 -0700271 // Listen for external changes to any of the settings.
272 if (mContentObserver == null) {
Christine Franks27912a32019-04-02 10:43:10 -0700273 mContentObserver = new ContentObserver(mHandler) {
Christine Franks57fdde82018-07-03 14:46:07 -0700274 @Override
275 public void onChange(boolean selfChange, Uri uri) {
276 super.onChange(selfChange, uri);
277
278 final String setting = uri == null ? null : uri.getLastPathSegment();
279 if (setting != null) {
280 switch (setting) {
281 case Secure.NIGHT_DISPLAY_ACTIVATED:
Christine Franks78a4dd42019-02-08 11:09:30 -0800282 final boolean activated = mNightDisplayTintController
283 .isActivatedSetting();
Christine Franks83cc5412018-07-03 14:46:07 -0700284 if (mNightDisplayTintController.isActivatedStateNotSet()
285 || mNightDisplayTintController.isActivated() != activated) {
Christine Franks78a4dd42019-02-08 11:09:30 -0800286 mNightDisplayTintController.setActivated(activated);
Christine Franks83cc5412018-07-03 14:46:07 -0700287 }
Christine Franks57fdde82018-07-03 14:46:07 -0700288 break;
289 case Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE:
Christine Franks78a4dd42019-02-08 11:09:30 -0800290 final int temperature = mNightDisplayTintController
291 .getColorTemperatureSetting();
Christine Franks83cc5412018-07-03 14:46:07 -0700292 if (mNightDisplayTintController.getColorTemperature()
293 != temperature) {
294 mNightDisplayTintController
295 .onColorTemperatureChanged(temperature);
296 }
Christine Franks57fdde82018-07-03 14:46:07 -0700297 break;
298 case Secure.NIGHT_DISPLAY_AUTO_MODE:
Christine Franks83cc5412018-07-03 14:46:07 -0700299 onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal());
Christine Franks57fdde82018-07-03 14:46:07 -0700300 break;
301 case Secure.NIGHT_DISPLAY_CUSTOM_START_TIME:
302 onNightDisplayCustomStartTimeChanged(
Christine Franks83cc5412018-07-03 14:46:07 -0700303 getNightDisplayCustomStartTimeInternal().getLocalTime());
Christine Franks57fdde82018-07-03 14:46:07 -0700304 break;
305 case Secure.NIGHT_DISPLAY_CUSTOM_END_TIME:
306 onNightDisplayCustomEndTimeChanged(
Christine Franks83cc5412018-07-03 14:46:07 -0700307 getNightDisplayCustomEndTimeInternal().getLocalTime());
Christine Franks57fdde82018-07-03 14:46:07 -0700308 break;
309 case System.DISPLAY_COLOR_MODE:
Christine Franks71e003e2019-01-24 14:40:20 -0800310 onDisplayColorModeChanged(getColorModeInternal());
Christine Franks57fdde82018-07-03 14:46:07 -0700311 break;
Christine Franks57fdde82018-07-03 14:46:07 -0700312 case Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED:
Christine Franks9114f462019-01-04 11:27:30 -0800313 onAccessibilityInversionChanged();
314 onAccessibilityActivated();
315 break;
316 case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:
317 onAccessibilityDaltonizerChanged();
318 onAccessibilityActivated();
319 break;
320 case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER:
321 onAccessibilityDaltonizerChanged();
Christine Franks57fdde82018-07-03 14:46:07 -0700322 break;
Christine Franks245ffd42018-11-16 13:45:14 -0800323 case Secure.DISPLAY_WHITE_BALANCE_ENABLED:
Daniel Solomon8b72c5b2018-11-25 11:07:13 -0800324 updateDisplayWhiteBalanceStatus();
Christine Franks245ffd42018-11-16 13:45:14 -0800325 break;
Christine Franks57fdde82018-07-03 14:46:07 -0700326 }
327 }
328 }
329 };
330 }
331 final ContentResolver cr = getContext().getContentResolver();
332 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_ACTIVATED),
333 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
334 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE),
335 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
336 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_AUTO_MODE),
337 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
338 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_START_TIME),
339 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
340 cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_END_TIME),
341 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
342 cr.registerContentObserver(System.getUriFor(System.DISPLAY_COLOR_MODE),
343 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
344 cr.registerContentObserver(
345 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
346 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
347 cr.registerContentObserver(
348 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
349 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
Christine Franks9114f462019-01-04 11:27:30 -0800350 cr.registerContentObserver(
351 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
352 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
Christine Franks245ffd42018-11-16 13:45:14 -0800353 cr.registerContentObserver(Secure.getUriFor(Secure.DISPLAY_WHITE_BALANCE_ENABLED),
354 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
Justin Klaassen911e8892016-06-21 18:24:24 -0700355
Christine Franks11e63152019-03-14 11:16:06 -0700356 // Apply the accessibility settings first, since they override most other settings.
357 onAccessibilityInversionChanged();
358 onAccessibilityDaltonizerChanged();
359
Christine Frankscf388c22018-05-15 15:48:10 -0700360 // Set the color mode, if valid, and immediately apply the updated tint matrix based on the
361 // existing activated state. This ensures consistency of tint across the color mode change.
Christine Franks71e003e2019-01-24 14:40:20 -0800362 onDisplayColorModeChanged(getColorModeInternal());
Christine Frankscf388c22018-05-15 15:48:10 -0700363
Christine Franksa4ed3762019-01-24 15:37:04 -0800364 if (mNightDisplayTintController.isAvailable(getContext())) {
Christine Franks245ffd42018-11-16 13:45:14 -0800365 // Reset the activated state.
366 mNightDisplayTintController.setActivated(null);
Christine Frankscf388c22018-05-15 15:48:10 -0700367
Christine Franks245ffd42018-11-16 13:45:14 -0800368 // Prepare the night display color transformation matrix.
369 mNightDisplayTintController
370 .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
Christine Franks78a4dd42019-02-08 11:09:30 -0800371 mNightDisplayTintController
372 .setMatrix(mNightDisplayTintController.getColorTemperatureSetting());
Christine Franks8ad71492017-10-24 19:04:22 -0700373
Christine Franks245ffd42018-11-16 13:45:14 -0800374 // Initialize the current auto mode.
Christine Franks83cc5412018-07-03 14:46:07 -0700375 onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal());
Christine Franks6418d0b2017-02-13 09:48:00 -0800376
Christine Franks83cc5412018-07-03 14:46:07 -0700377 // Force the initialization of the current saved activation state.
Christine Franks245ffd42018-11-16 13:45:14 -0800378 if (mNightDisplayTintController.isActivatedStateNotSet()) {
Christine Franks78a4dd42019-02-08 11:09:30 -0800379 mNightDisplayTintController
380 .setActivated(mNightDisplayTintController.isActivatedSetting());
Christine Franks245ffd42018-11-16 13:45:14 -0800381 }
382 }
Justin Klaassen911e8892016-06-21 18:24:24 -0700383
Christine Franksa4ed3762019-01-24 15:37:04 -0800384 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
Christine Franks245ffd42018-11-16 13:45:14 -0800385 // Prepare the display white balance transform matrix.
Daniel Solomon8b72c5b2018-11-25 11:07:13 -0800386 mDisplayWhiteBalanceTintController.setUp(getContext(), true /* needsLinear */);
Christine Franks245ffd42018-11-16 13:45:14 -0800387
Daniel Solomon8b72c5b2018-11-25 11:07:13 -0800388 updateDisplayWhiteBalanceStatus();
Justin Klaassen911e8892016-06-21 18:24:24 -0700389 }
390 }
391
Justin Klaassen2696d992016-07-11 21:26:46 -0700392 private void tearDown() {
Justin Klaassenec8837a2016-08-23 12:04:42 -0700393 Slog.d(TAG, "tearDown: currentUser=" + mCurrentUser);
394
Christine Franks57fdde82018-07-03 14:46:07 -0700395 getContext().getContentResolver().unregisterContentObserver(mContentObserver);
396
Christine Franksa4ed3762019-01-24 15:37:04 -0800397 if (mNightDisplayTintController.isAvailable(getContext())) {
Christine Franks245ffd42018-11-16 13:45:14 -0800398 if (mNightDisplayAutoMode != null) {
399 mNightDisplayAutoMode.onStop();
400 mNightDisplayAutoMode = null;
401 }
402 mNightDisplayTintController.endAnimator();
Justin Klaassen911e8892016-06-21 18:24:24 -0700403 }
404
Christine Franksa4ed3762019-01-24 15:37:04 -0800405 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
Christine Franks245ffd42018-11-16 13:45:14 -0800406 mDisplayWhiteBalanceTintController.endAnimator();
Justin Klaassen639214e2016-07-14 21:00:06 -0700407 }
Christine Franks6d21d342019-02-07 15:09:03 -0800408
409 if (mGlobalSaturationTintController.isAvailable(getContext())) {
410 mGlobalSaturationTintController.setActivated(null);
411 }
Justin Klaassen911e8892016-06-21 18:24:24 -0700412 }
413
Christine Franks57fdde82018-07-03 14:46:07 -0700414 private void onNightDisplayAutoModeChanged(int autoMode) {
415 Slog.d(TAG, "onNightDisplayAutoModeChanged: autoMode=" + autoMode);
Justin Klaassenec8837a2016-08-23 12:04:42 -0700416
Christine Franks57fdde82018-07-03 14:46:07 -0700417 if (mNightDisplayAutoMode != null) {
418 mNightDisplayAutoMode.onStop();
419 mNightDisplayAutoMode = null;
Justin Klaassen911e8892016-06-21 18:24:24 -0700420 }
421
Christine Franks83cc5412018-07-03 14:46:07 -0700422 if (autoMode == AUTO_MODE_CUSTOM_TIME) {
Christine Franks57fdde82018-07-03 14:46:07 -0700423 mNightDisplayAutoMode = new CustomNightDisplayAutoMode();
Christine Franks83cc5412018-07-03 14:46:07 -0700424 } else if (autoMode == AUTO_MODE_TWILIGHT) {
Christine Franks57fdde82018-07-03 14:46:07 -0700425 mNightDisplayAutoMode = new TwilightNightDisplayAutoMode();
Justin Klaassen911e8892016-06-21 18:24:24 -0700426 }
427
Christine Franks57fdde82018-07-03 14:46:07 -0700428 if (mNightDisplayAutoMode != null) {
429 mNightDisplayAutoMode.onStart();
Justin Klaassen911e8892016-06-21 18:24:24 -0700430 }
431 }
432
Christine Franks57fdde82018-07-03 14:46:07 -0700433 private void onNightDisplayCustomStartTimeChanged(LocalTime startTime) {
434 Slog.d(TAG, "onNightDisplayCustomStartTimeChanged: startTime=" + startTime);
Justin Klaassenec8837a2016-08-23 12:04:42 -0700435
Christine Franks57fdde82018-07-03 14:46:07 -0700436 if (mNightDisplayAutoMode != null) {
437 mNightDisplayAutoMode.onCustomStartTimeChanged(startTime);
Justin Klaassen911e8892016-06-21 18:24:24 -0700438 }
439 }
440
Christine Franks57fdde82018-07-03 14:46:07 -0700441 private void onNightDisplayCustomEndTimeChanged(LocalTime endTime) {
442 Slog.d(TAG, "onNightDisplayCustomEndTimeChanged: endTime=" + endTime);
Justin Klaassenec8837a2016-08-23 12:04:42 -0700443
Christine Franks57fdde82018-07-03 14:46:07 -0700444 if (mNightDisplayAutoMode != null) {
445 mNightDisplayAutoMode.onCustomEndTimeChanged(endTime);
Justin Klaassen911e8892016-06-21 18:24:24 -0700446 }
447 }
448
Christine Franks57fdde82018-07-03 14:46:07 -0700449 private void onDisplayColorModeChanged(int mode) {
Christine Franks83cc5412018-07-03 14:46:07 -0700450 if (mode == NOT_SET) {
Christine Frankscf388c22018-05-15 15:48:10 -0700451 return;
452 }
453
Christine Franks245ffd42018-11-16 13:45:14 -0800454 mNightDisplayTintController.cancelAnimator();
455 mDisplayWhiteBalanceTintController.cancelAnimator();
456
Christine Franksa4ed3762019-01-24 15:37:04 -0800457 if (mNightDisplayTintController.isAvailable(getContext())) {
458 mNightDisplayTintController
459 .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
Christine Franks78a4dd42019-02-08 11:09:30 -0800460 mNightDisplayTintController
461 .setMatrix(mNightDisplayTintController.getColorTemperatureSetting());
Christine Franksa4ed3762019-01-24 15:37:04 -0800462 }
Christine Franks245ffd42018-11-16 13:45:14 -0800463
Christine Franks18ac4e22019-04-05 18:30:50 -0700464 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
465 updateDisplayWhiteBalanceStatus();
466 }
Christine Franks8ad71492017-10-24 19:04:22 -0700467
Christine Franks218e6562017-11-27 10:20:14 -0800468 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
Christine Franks245ffd42018-11-16 13:45:14 -0800469 dtm.setColorMode(mode, mNightDisplayTintController.getMatrix());
Christine Franks8ad71492017-10-24 19:04:22 -0700470 }
471
Christine Franks9114f462019-01-04 11:27:30 -0800472 private void onAccessibilityActivated() {
Christine Franks71e003e2019-01-24 14:40:20 -0800473 onDisplayColorModeChanged(getColorModeInternal());
Daniel Solomon317a3572018-03-30 18:36:37 -0700474 }
475
Daniel Solomonff24ba92019-04-11 19:29:31 -0700476 private boolean isAccessiblityDaltonizerEnabled() {
477 return Secure.getIntForUser(getContext().getContentResolver(),
478 Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, mCurrentUser) != 0;
479 }
480
481 private boolean isAccessiblityInversionEnabled() {
482 return Secure.getIntForUser(getContext().getContentResolver(),
483 Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, mCurrentUser) != 0;
484 }
485
486 private boolean isAccessibilityEnabled() {
487 return isAccessiblityDaltonizerEnabled() || isAccessiblityInversionEnabled();
488 }
489
Christine Franks9114f462019-01-04 11:27:30 -0800490 /**
491 * Apply the accessibility daltonizer transform based on the settings value.
492 */
493 private void onAccessibilityDaltonizerChanged() {
Christine Franks27912a32019-04-02 10:43:10 -0700494 if (mCurrentUser == UserHandle.USER_NULL) {
495 return;
496 }
Daniel Solomonff24ba92019-04-11 19:29:31 -0700497 final int daltonizerMode = isAccessiblityDaltonizerEnabled()
498 ? Secure.getIntForUser(getContext().getContentResolver(),
499 Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
500 AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY, mCurrentUser)
Christine Franks9114f462019-01-04 11:27:30 -0800501 : AccessibilityManager.DALTONIZER_DISABLED;
502
503 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
504 if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) {
505 // Monochromacy isn't supported by the native Daltonizer implementation; use grayscale.
506 dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE,
507 MATRIX_GRAYSCALE);
508 dtm.setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
509 } else {
510 dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE, null);
511 dtm.setDaltonizerMode(daltonizerMode);
512 }
513 }
514
515 /**
516 * Apply the accessibility inversion transform based on the settings value.
517 */
518 private void onAccessibilityInversionChanged() {
Christine Franks27912a32019-04-02 10:43:10 -0700519 if (mCurrentUser == UserHandle.USER_NULL) {
520 return;
521 }
Christine Franks9114f462019-01-04 11:27:30 -0800522 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
523 dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_INVERT_COLOR,
Daniel Solomonff24ba92019-04-11 19:29:31 -0700524 isAccessiblityInversionEnabled() ? MATRIX_INVERT_COLOR : null);
Christine Franks9114f462019-01-04 11:27:30 -0800525 }
Christine Franks8ad71492017-10-24 19:04:22 -0700526
Christine Franks6418d0b2017-02-13 09:48:00 -0800527 /**
528 * Applies current color temperature matrix, or removes it if deactivated.
529 *
530 * @param immediate {@code true} skips transition animation
531 */
Christine Franks245ffd42018-11-16 13:45:14 -0800532 private void applyTint(TintController tintController, boolean immediate) {
533 tintController.cancelAnimator();
Christine Franks6418d0b2017-02-13 09:48:00 -0800534
Christine Franks6418d0b2017-02-13 09:48:00 -0800535 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
Christine Franks245ffd42018-11-16 13:45:14 -0800536 final float[] from = dtm.getColorMatrix(tintController.getLevel());
537 final float[] to = tintController.getMatrix();
Christine Franks6418d0b2017-02-13 09:48:00 -0800538
539 if (immediate) {
Christine Franks245ffd42018-11-16 13:45:14 -0800540 dtm.setColorMatrix(tintController.getLevel(), to);
Christine Franks6418d0b2017-02-13 09:48:00 -0800541 } else {
Christine Franks245ffd42018-11-16 13:45:14 -0800542 tintController.setAnimator(ValueAnimator.ofObject(COLOR_MATRIX_EVALUATOR,
543 from == null ? MATRIX_IDENTITY : from, to));
544 tintController.getAnimator().setDuration(TRANSITION_DURATION);
545 tintController.getAnimator().setInterpolator(AnimationUtils.loadInterpolator(
Christine Franks6418d0b2017-02-13 09:48:00 -0800546 getContext(), android.R.interpolator.fast_out_slow_in));
Christine Franks245ffd42018-11-16 13:45:14 -0800547 tintController.getAnimator().addUpdateListener((ValueAnimator animator) -> {
548 final float[] value = (float[]) animator.getAnimatedValue();
549 dtm.setColorMatrix(tintController.getLevel(), value);
Christine Franks6418d0b2017-02-13 09:48:00 -0800550 });
Christine Franks245ffd42018-11-16 13:45:14 -0800551 tintController.getAnimator().addListener(new AnimatorListenerAdapter() {
Christine Franks6418d0b2017-02-13 09:48:00 -0800552
553 private boolean mIsCancelled;
554
555 @Override
556 public void onAnimationCancel(Animator animator) {
557 mIsCancelled = true;
558 }
559
560 @Override
561 public void onAnimationEnd(Animator animator) {
562 if (!mIsCancelled) {
563 // Ensure final color matrix is set at the end of the animation. If the
564 // animation is cancelled then don't set the final color matrix so the new
565 // animator can pick up from where this one left off.
Christine Franks245ffd42018-11-16 13:45:14 -0800566 dtm.setColorMatrix(tintController.getLevel(), to);
Christine Franks6418d0b2017-02-13 09:48:00 -0800567 }
Christine Franks245ffd42018-11-16 13:45:14 -0800568 tintController.setAnimator(null);
Christine Franks6418d0b2017-02-13 09:48:00 -0800569 }
570 });
Christine Franks245ffd42018-11-16 13:45:14 -0800571 tintController.getAnimator().start();
Christine Franks6418d0b2017-02-13 09:48:00 -0800572 }
573 }
574
575 /**
Christine Franks39b03112018-07-03 14:46:07 -0700576 * Returns the first date time corresponding to the local time that occurs before the provided
577 * date time.
Christine Franks03213462017-08-25 13:57:26 -0700578 *
579 * @param compareTime the LocalDateTime to compare against
580 * @return the prior LocalDateTime corresponding to this local time
581 */
Christine Franks57fdde82018-07-03 14:46:07 -0700582 @VisibleForTesting
583 static LocalDateTime getDateTimeBefore(LocalTime localTime, LocalDateTime compareTime) {
Christine Franks03213462017-08-25 13:57:26 -0700584 final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
585 compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());
586
587 // Check if the local time has passed, if so return the same time yesterday.
588 return ldt.isAfter(compareTime) ? ldt.minusDays(1) : ldt;
589 }
590
591 /**
Christine Franks39b03112018-07-03 14:46:07 -0700592 * Returns the first date time corresponding to this local time that occurs after the provided
593 * date time.
Christine Franks03213462017-08-25 13:57:26 -0700594 *
595 * @param compareTime the LocalDateTime to compare against
596 * @return the next LocalDateTime corresponding to this local time
597 */
Christine Franks57fdde82018-07-03 14:46:07 -0700598 @VisibleForTesting
599 static LocalDateTime getDateTimeAfter(LocalTime localTime, LocalDateTime compareTime) {
Christine Franks03213462017-08-25 13:57:26 -0700600 final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
601 compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());
602
603 // Check if the local time has passed, if so return the same time tomorrow.
604 return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
605 }
606
Long Ling1d3f1892019-02-06 12:34:02 -0800607 @VisibleForTesting
608 void updateDisplayWhiteBalanceStatus() {
Daniel Solomon8b72c5b2018-11-25 11:07:13 -0800609 boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated();
Christine Franks0ada2772019-02-25 13:54:57 -0800610 mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled()
611 && !mNightDisplayTintController.isActivated()
Daniel Solomonff24ba92019-04-11 19:29:31 -0700612 && !isAccessibilityEnabled()
Christine Franks0ada2772019-02-25 13:54:57 -0800613 && DisplayTransformManager.needsLinearColorMatrix());
Daniel Solomon8b72c5b2018-11-25 11:07:13 -0800614 boolean activated = mDisplayWhiteBalanceTintController.isActivated();
615
616 if (mDisplayWhiteBalanceListener != null && oldActivated != activated) {
617 mDisplayWhiteBalanceListener.onDisplayWhiteBalanceStatusChanged(activated);
Christine Franks245ffd42018-11-16 13:45:14 -0800618 }
Daniel Solomon86508f82019-01-18 19:01:02 -0800619
620 // If disabled, clear the tint. If enabled, do nothing more here and let the next
621 // temperature update set the correct tint.
622 if (!activated) {
Christine Franksc7fb9452019-02-04 08:45:33 -0800623 mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE);
Daniel Solomon86508f82019-01-18 19:01:02 -0800624 }
Christine Franks245ffd42018-11-16 13:45:14 -0800625 }
626
Christine Franks66783a82019-03-28 11:45:56 -0700627 private boolean setDisplayWhiteBalanceSettingEnabled(boolean enabled) {
628 if (mCurrentUser == UserHandle.USER_NULL) {
629 return false;
630 }
631 return Secure.putIntForUser(getContext().getContentResolver(),
632 Secure.DISPLAY_WHITE_BALANCE_ENABLED,
633 enabled ? 1 : 0, mCurrentUser);
634 }
635
Christine Franks245ffd42018-11-16 13:45:14 -0800636 private boolean isDisplayWhiteBalanceSettingEnabled() {
Christine Franks27912a32019-04-02 10:43:10 -0700637 if (mCurrentUser == UserHandle.USER_NULL) {
638 return false;
639 }
Christine Franks245ffd42018-11-16 13:45:14 -0800640 return Secure.getIntForUser(getContext().getContentResolver(),
Christine Franks18ac4e22019-04-05 18:30:50 -0700641 Secure.DISPLAY_WHITE_BALANCE_ENABLED,
642 getContext().getResources()
643 .getBoolean(R.bool.config_displayWhiteBalanceEnabledDefault) ? 1
644 : 0,
645 mCurrentUser) == 1;
Christine Franks245ffd42018-11-16 13:45:14 -0800646 }
647
Christine Franks39b03112018-07-03 14:46:07 -0700648 private boolean isDeviceColorManagedInternal() {
649 final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
650 return dtm.isDeviceColorManaged();
651 }
652
Christine Franks55194dc2019-01-15 13:47:06 -0800653 private int getTransformCapabilitiesInternal() {
654 int availabilityFlags = ColorDisplayManager.CAPABILITY_NONE;
655 if (SurfaceControl.getProtectedContentSupport()) {
656 availabilityFlags |= ColorDisplayManager.CAPABILITY_PROTECTED_CONTENT;
657 }
658 final Resources res = getContext().getResources();
659 if (res.getBoolean(R.bool.config_setColorTransformAccelerated)) {
660 availabilityFlags |= ColorDisplayManager.CAPABILITY_HARDWARE_ACCELERATION_GLOBAL;
661 }
662 if (res.getBoolean(R.bool.config_setColorTransformAcceleratedPerLayer)) {
663 availabilityFlags |= ColorDisplayManager.CAPABILITY_HARDWARE_ACCELERATION_PER_APP;
664 }
665 return availabilityFlags;
666 }
667
Christine Franks83cc5412018-07-03 14:46:07 -0700668 private boolean setNightDisplayAutoModeInternal(@AutoMode int autoMode) {
669 if (getNightDisplayAutoModeInternal() != autoMode) {
670 Secure.putStringForUser(getContext().getContentResolver(),
671 Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
672 null,
673 mCurrentUser);
674 }
675 return Secure.putIntForUser(getContext().getContentResolver(),
676 Secure.NIGHT_DISPLAY_AUTO_MODE, autoMode, mCurrentUser);
677 }
678
679 private int getNightDisplayAutoModeInternal() {
680 int autoMode = getNightDisplayAutoModeRawInternal();
681 if (autoMode == NOT_SET) {
682 autoMode = getContext().getResources().getInteger(
683 R.integer.config_defaultNightDisplayAutoMode);
684 }
685 if (autoMode != AUTO_MODE_DISABLED
686 && autoMode != AUTO_MODE_CUSTOM_TIME
687 && autoMode != AUTO_MODE_TWILIGHT) {
688 Slog.e(TAG, "Invalid autoMode: " + autoMode);
689 autoMode = AUTO_MODE_DISABLED;
690 }
691 return autoMode;
692 }
693
694 private int getNightDisplayAutoModeRawInternal() {
Christine Franks27912a32019-04-02 10:43:10 -0700695 if (mCurrentUser == UserHandle.USER_NULL) {
696 return NOT_SET;
697 }
Christine Franks83cc5412018-07-03 14:46:07 -0700698 return Secure
699 .getIntForUser(getContext().getContentResolver(), Secure.NIGHT_DISPLAY_AUTO_MODE,
700 NOT_SET, mCurrentUser);
701 }
702
703 private Time getNightDisplayCustomStartTimeInternal() {
704 int startTimeValue = Secure.getIntForUser(getContext().getContentResolver(),
705 Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, NOT_SET, mCurrentUser);
706 if (startTimeValue == NOT_SET) {
707 startTimeValue = getContext().getResources().getInteger(
708 R.integer.config_defaultNightDisplayCustomStartTime);
709 }
710 return new Time(LocalTime.ofSecondOfDay(startTimeValue / 1000));
711 }
712
713 private boolean setNightDisplayCustomStartTimeInternal(Time startTime) {
714 return Secure.putIntForUser(getContext().getContentResolver(),
715 Secure.NIGHT_DISPLAY_CUSTOM_START_TIME,
716 startTime.getLocalTime().toSecondOfDay() * 1000,
717 mCurrentUser);
718 }
719
720 private Time getNightDisplayCustomEndTimeInternal() {
721 int endTimeValue = Secure.getIntForUser(getContext().getContentResolver(),
722 Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, NOT_SET, mCurrentUser);
723 if (endTimeValue == NOT_SET) {
724 endTimeValue = getContext().getResources().getInteger(
725 R.integer.config_defaultNightDisplayCustomEndTime);
726 }
727 return new Time(LocalTime.ofSecondOfDay(endTimeValue / 1000));
728 }
729
730 private boolean setNightDisplayCustomEndTimeInternal(Time endTime) {
731 return Secure.putIntForUser(getContext().getContentResolver(),
732 Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.getLocalTime().toSecondOfDay() * 1000,
733 mCurrentUser);
734 }
735
Christine Franks57fdde82018-07-03 14:46:07 -0700736 /**
737 * Returns the last time the night display transform activation state was changed, or {@link
738 * LocalDateTime#MIN} if night display has never been activated.
739 */
Christine Franks245ffd42018-11-16 13:45:14 -0800740 private LocalDateTime getNightDisplayLastActivatedTimeSetting() {
Christine Franks57fdde82018-07-03 14:46:07 -0700741 final ContentResolver cr = getContext().getContentResolver();
742 final String lastActivatedTime = Secure.getStringForUser(
743 cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, getContext().getUserId());
744 if (lastActivatedTime != null) {
745 try {
746 return LocalDateTime.parse(lastActivatedTime);
747 } catch (DateTimeParseException ignored) {
748 }
749 // Uses the old epoch time.
750 try {
751 return LocalDateTime.ofInstant(
752 Instant.ofEpochMilli(Long.parseLong(lastActivatedTime)),
753 ZoneId.systemDefault());
754 } catch (DateTimeException | NumberFormatException ignored) {
755 }
756 }
757 return LocalDateTime.MIN;
758 }
759
Christine Franksf3529b22019-01-03 13:20:17 -0800760 private boolean setAppSaturationLevelInternal(String packageName, int saturationLevel) {
761 return mAppSaturationController
762 .setSaturationLevel(packageName, mCurrentUser, saturationLevel);
763 }
764
Christine Franksd154fe52019-01-04 17:17:45 -0800765 private void setColorModeInternal(@ColorMode int colorMode) {
766 if (!isColorModeAvailable(colorMode)) {
767 throw new IllegalArgumentException("Invalid colorMode: " + colorMode);
768 }
769 System.putIntForUser(getContext().getContentResolver(), System.DISPLAY_COLOR_MODE,
770 colorMode,
771 mCurrentUser);
772 }
773
Christine Franks71e003e2019-01-24 14:40:20 -0800774 private @ColorMode int getColorModeInternal() {
Christine Franksd154fe52019-01-04 17:17:45 -0800775 final ContentResolver cr = getContext().getContentResolver();
Daniel Solomonff24ba92019-04-11 19:29:31 -0700776 if (isAccessibilityEnabled()) {
Christine Franksd154fe52019-01-04 17:17:45 -0800777 // There are restrictions on the available color modes combined with a11y transforms.
778 if (isColorModeAvailable(COLOR_MODE_SATURATED)) {
779 return COLOR_MODE_SATURATED;
780 } else if (isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
781 return COLOR_MODE_AUTOMATIC;
782 }
783 }
784
785 int colorMode = System.getIntForUser(cr, System.DISPLAY_COLOR_MODE, -1, mCurrentUser);
786 if (colorMode == -1) {
787 // There might be a system property controlling color mode that we need to respect; if
788 // not, this will set a suitable default.
789 colorMode = getCurrentColorModeFromSystemProperties();
790 }
791
792 // This happens when a color mode is no longer available (e.g., after system update or B&R)
793 // or the device does not support any color mode.
794 if (!isColorModeAvailable(colorMode)) {
795 if (colorMode == COLOR_MODE_BOOSTED && isColorModeAvailable(COLOR_MODE_NATURAL)) {
796 colorMode = COLOR_MODE_NATURAL;
797 } else if (colorMode == COLOR_MODE_SATURATED
798 && isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
799 colorMode = COLOR_MODE_AUTOMATIC;
800 } else if (colorMode == COLOR_MODE_AUTOMATIC
801 && isColorModeAvailable(COLOR_MODE_SATURATED)) {
802 colorMode = COLOR_MODE_SATURATED;
803 } else {
804 colorMode = -1;
805 }
806 }
807
808 return colorMode;
809 }
810
811 /**
812 * Get the current color mode from system properties, or return -1 if invalid.
813 *
Christine Franks0ada2772019-02-25 13:54:57 -0800814 * See {@link DisplayTransformManager}
Christine Franksd154fe52019-01-04 17:17:45 -0800815 */
Christine Franks78a4dd42019-02-08 11:09:30 -0800816 private @ColorMode int getCurrentColorModeFromSystemProperties() {
Christine Franksd154fe52019-01-04 17:17:45 -0800817 final int displayColorSetting = SystemProperties.getInt("persist.sys.sf.native_mode", 0);
818 if (displayColorSetting == 0) {
819 return "1.0".equals(SystemProperties.get("persist.sys.sf.color_saturation"))
820 ? COLOR_MODE_NATURAL : COLOR_MODE_BOOSTED;
821 } else if (displayColorSetting == 1) {
822 return COLOR_MODE_SATURATED;
823 } else if (displayColorSetting == 2) {
824 return COLOR_MODE_AUTOMATIC;
825 } else {
826 return -1;
827 }
828 }
829
830 private boolean isColorModeAvailable(@ColorMode int colorMode) {
831 final int[] availableColorModes = getContext().getResources().getIntArray(
832 R.array.config_availableColorModes);
833 if (availableColorModes != null) {
834 for (int mode : availableColorModes) {
835 if (mode == colorMode) {
836 return true;
837 }
838 }
839 }
840 return false;
841 }
842
Christine Franksf3529b22019-01-03 13:20:17 -0800843 private void dumpInternal(PrintWriter pw) {
844 pw.println("COLOR DISPLAY MANAGER dumpsys (color_display)");
Christine Franksa4ed3762019-01-24 15:37:04 -0800845
Christine Franks0ada2772019-02-25 13:54:57 -0800846 pw.println("Night display:");
Christine Franksa4ed3762019-01-24 15:37:04 -0800847 if (mNightDisplayTintController.isAvailable(getContext())) {
Christine Franksf3529b22019-01-03 13:20:17 -0800848 pw.println(" Activated: " + mNightDisplayTintController.isActivated());
Christine Franksa4ed3762019-01-24 15:37:04 -0800849 pw.println(" Color temp: " + mNightDisplayTintController.getColorTemperature());
Christine Franksf3529b22019-01-03 13:20:17 -0800850 } else {
851 pw.println(" Not available");
852 }
Christine Franksa4ed3762019-01-24 15:37:04 -0800853
854 pw.println("Global saturation:");
855 if (mGlobalSaturationTintController.isAvailable(getContext())) {
856 pw.println(" Activated: " + mGlobalSaturationTintController.isActivated());
857 } else {
858 pw.println(" Not available");
859 }
860
Christine Franksf3529b22019-01-03 13:20:17 -0800861 mAppSaturationController.dump(pw);
Christine Franksa4ed3762019-01-24 15:37:04 -0800862
863 pw.println("Display white balance:");
864 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
865 pw.println(" Activated: " + mDisplayWhiteBalanceTintController.isActivated());
Long Ling1d3f1892019-02-06 12:34:02 -0800866 mDisplayWhiteBalanceTintController.dump(pw);
Christine Franksa4ed3762019-01-24 15:37:04 -0800867 } else {
868 pw.println(" Not available");
869 }
870
871 pw.println("Color mode: " + getColorModeInternal());
Christine Franksf3529b22019-01-03 13:20:17 -0800872 }
873
Christine Franks57fdde82018-07-03 14:46:07 -0700874 private abstract class NightDisplayAutoMode {
875
876 public abstract void onActivated(boolean activated);
877
Justin Klaassen911e8892016-06-21 18:24:24 -0700878 public abstract void onStart();
Christine Frankse5bb03e2017-02-10 17:36:10 -0800879
Justin Klaassen911e8892016-06-21 18:24:24 -0700880 public abstract void onStop();
Christine Franks57fdde82018-07-03 14:46:07 -0700881
882 public void onCustomStartTimeChanged(LocalTime startTime) {
883 }
884
885 public void onCustomEndTimeChanged(LocalTime endTime) {
886 }
Justin Klaassen911e8892016-06-21 18:24:24 -0700887 }
888
Christine Franks57fdde82018-07-03 14:46:07 -0700889 private final class CustomNightDisplayAutoMode extends NightDisplayAutoMode implements
890 AlarmManager.OnAlarmListener {
Justin Klaassen911e8892016-06-21 18:24:24 -0700891
892 private final AlarmManager mAlarmManager;
893 private final BroadcastReceiver mTimeChangedReceiver;
894
Christine Franks03213462017-08-25 13:57:26 -0700895 private LocalTime mStartTime;
896 private LocalTime mEndTime;
Justin Klaassen911e8892016-06-21 18:24:24 -0700897
Christine Franks03213462017-08-25 13:57:26 -0700898 private LocalDateTime mLastActivatedTime;
Justin Klaassen911e8892016-06-21 18:24:24 -0700899
Christine Franks57fdde82018-07-03 14:46:07 -0700900 CustomNightDisplayAutoMode() {
Justin Klaassen911e8892016-06-21 18:24:24 -0700901 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
902 mTimeChangedReceiver = new BroadcastReceiver() {
903 @Override
904 public void onReceive(Context context, Intent intent) {
905 updateActivated();
906 }
907 };
908 }
909
910 private void updateActivated() {
Christine Franks03213462017-08-25 13:57:26 -0700911 final LocalDateTime now = LocalDateTime.now();
912 final LocalDateTime start = getDateTimeBefore(mStartTime, now);
913 final LocalDateTime end = getDateTimeAfter(mEndTime, start);
914 boolean activate = now.isBefore(end);
Justin Klaassen911e8892016-06-21 18:24:24 -0700915
Christine Frankse5bb03e2017-02-10 17:36:10 -0800916 if (mLastActivatedTime != null) {
Christine Frankse5bb03e2017-02-10 17:36:10 -0800917 // Maintain the existing activated state if within the current period.
Christine Franks0ada2772019-02-25 13:54:57 -0800918 if (mLastActivatedTime.isBefore(now)
919 && mLastActivatedTime.isAfter(start)
Christine Franks03213462017-08-25 13:57:26 -0700920 && (mLastActivatedTime.isAfter(end) || now.isBefore(end))) {
Christine Franks78a4dd42019-02-08 11:09:30 -0800921 activate = mNightDisplayTintController.isActivatedSetting();
Justin Klaassen911e8892016-06-21 18:24:24 -0700922 }
923 }
924
Christine Franks0ada2772019-02-25 13:54:57 -0800925 if (mNightDisplayTintController.isActivatedStateNotSet()
926 || (mNightDisplayTintController.isActivated() != activate)) {
Christine Franks83cc5412018-07-03 14:46:07 -0700927 mNightDisplayTintController.setActivated(activate);
Justin Klaassen911e8892016-06-21 18:24:24 -0700928 }
Christine Franks03213462017-08-25 13:57:26 -0700929
Christine Franks245ffd42018-11-16 13:45:14 -0800930 updateNextAlarm(mNightDisplayTintController.isActivated(), now);
Justin Klaassen911e8892016-06-21 18:24:24 -0700931 }
932
Christine Franks03213462017-08-25 13:57:26 -0700933 private void updateNextAlarm(@Nullable Boolean activated, @NonNull LocalDateTime now) {
Justin Klaassen4346f632016-08-08 15:01:47 -0700934 if (activated != null) {
Christine Franks03213462017-08-25 13:57:26 -0700935 final LocalDateTime next = activated ? getDateTimeAfter(mEndTime, now)
936 : getDateTimeAfter(mStartTime, now);
937 final long millis = next.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
938 mAlarmManager.setExact(AlarmManager.RTC, millis, TAG, this, null);
Justin Klaassen911e8892016-06-21 18:24:24 -0700939 }
940 }
941
942 @Override
943 public void onStart() {
944 final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_TIME_CHANGED);
945 intentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
946 getContext().registerReceiver(mTimeChangedReceiver, intentFilter);
947
Christine Franks83cc5412018-07-03 14:46:07 -0700948 mStartTime = getNightDisplayCustomStartTimeInternal().getLocalTime();
949 mEndTime = getNightDisplayCustomEndTimeInternal().getLocalTime();
Justin Klaassen911e8892016-06-21 18:24:24 -0700950
Christine Franks57fdde82018-07-03 14:46:07 -0700951 mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
Christine Frankse5bb03e2017-02-10 17:36:10 -0800952
Justin Klaassen911e8892016-06-21 18:24:24 -0700953 // Force an update to initialize state.
954 updateActivated();
955 }
956
957 @Override
958 public void onStop() {
959 getContext().unregisterReceiver(mTimeChangedReceiver);
960
961 mAlarmManager.cancel(this);
962 mLastActivatedTime = null;
963 }
964
965 @Override
966 public void onActivated(boolean activated) {
Christine Franks57fdde82018-07-03 14:46:07 -0700967 mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
Christine Franks03213462017-08-25 13:57:26 -0700968 updateNextAlarm(activated, LocalDateTime.now());
Justin Klaassen911e8892016-06-21 18:24:24 -0700969 }
970
971 @Override
Christine Franks03213462017-08-25 13:57:26 -0700972 public void onCustomStartTimeChanged(LocalTime startTime) {
Justin Klaassen911e8892016-06-21 18:24:24 -0700973 mStartTime = startTime;
974 mLastActivatedTime = null;
975 updateActivated();
976 }
977
978 @Override
Christine Franks03213462017-08-25 13:57:26 -0700979 public void onCustomEndTimeChanged(LocalTime endTime) {
Justin Klaassen911e8892016-06-21 18:24:24 -0700980 mEndTime = endTime;
981 mLastActivatedTime = null;
982 updateActivated();
983 }
984
985 @Override
986 public void onAlarm() {
Justin Klaassenec8837a2016-08-23 12:04:42 -0700987 Slog.d(TAG, "onAlarm");
Justin Klaassen911e8892016-06-21 18:24:24 -0700988 updateActivated();
989 }
990 }
991
Christine Franks57fdde82018-07-03 14:46:07 -0700992 private final class TwilightNightDisplayAutoMode extends NightDisplayAutoMode implements
993 TwilightListener {
Justin Klaassen911e8892016-06-21 18:24:24 -0700994
995 private final TwilightManager mTwilightManager;
Christine Franks57fdde82018-07-03 14:46:07 -0700996 private LocalDateTime mLastActivatedTime;
Justin Klaassen911e8892016-06-21 18:24:24 -0700997
Christine Franks57fdde82018-07-03 14:46:07 -0700998 TwilightNightDisplayAutoMode() {
Justin Klaassen911e8892016-06-21 18:24:24 -0700999 mTwilightManager = getLocalService(TwilightManager.class);
Justin Klaassen911e8892016-06-21 18:24:24 -07001000 }
1001
Justin Klaassen908b86c2016-08-08 09:18:42 -07001002 private void updateActivated(TwilightState state) {
Justin Klaassen3da4c442017-05-05 15:19:33 -07001003 if (state == null) {
1004 // If there isn't a valid TwilightState then just keep the current activated
1005 // state.
1006 return;
1007 }
1008
1009 boolean activate = state.isNight();
Christine Franks57fdde82018-07-03 14:46:07 -07001010 if (mLastActivatedTime != null) {
Christine Franks03213462017-08-25 13:57:26 -07001011 final LocalDateTime now = LocalDateTime.now();
1012 final LocalDateTime sunrise = state.sunrise();
1013 final LocalDateTime sunset = state.sunset();
Christine Frankse5bb03e2017-02-10 17:36:10 -08001014 // Maintain the existing activated state if within the current period.
Christine Franks57fdde82018-07-03 14:46:07 -07001015 if (mLastActivatedTime.isBefore(now) && (mLastActivatedTime.isBefore(sunrise)
1016 ^ mLastActivatedTime.isBefore(sunset))) {
Christine Franks78a4dd42019-02-08 11:09:30 -08001017 activate = mNightDisplayTintController.isActivatedSetting();
Justin Klaassen911e8892016-06-21 18:24:24 -07001018 }
1019 }
Justin Klaassen908b86c2016-08-08 09:18:42 -07001020
Christine Franks245ffd42018-11-16 13:45:14 -08001021 if (mNightDisplayTintController.isActivatedStateNotSet() || (
1022 mNightDisplayTintController.isActivated() != activate)) {
Christine Franks83cc5412018-07-03 14:46:07 -07001023 mNightDisplayTintController.setActivated(activate);
Justin Klaassen908b86c2016-08-08 09:18:42 -07001024 }
Justin Klaassen911e8892016-06-21 18:24:24 -07001025 }
1026
1027 @Override
Christine Franks57fdde82018-07-03 14:46:07 -07001028 public void onActivated(boolean activated) {
1029 mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
1030 }
1031
1032 @Override
Justin Klaassen911e8892016-06-21 18:24:24 -07001033 public void onStart() {
1034 mTwilightManager.registerListener(this, mHandler);
Christine Franks57fdde82018-07-03 14:46:07 -07001035 mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
Justin Klaassen911e8892016-06-21 18:24:24 -07001036
1037 // Force an update to initialize state.
Justin Klaassen908b86c2016-08-08 09:18:42 -07001038 updateActivated(mTwilightManager.getLastTwilightState());
Justin Klaassen911e8892016-06-21 18:24:24 -07001039 }
1040
1041 @Override
1042 public void onStop() {
1043 mTwilightManager.unregisterListener(this);
Christine Franks57fdde82018-07-03 14:46:07 -07001044 mLastActivatedTime = null;
Justin Klaassen908b86c2016-08-08 09:18:42 -07001045 }
1046
1047 @Override
1048 public void onTwilightStateChanged(@Nullable TwilightState state) {
Justin Klaassenec8837a2016-08-23 12:04:42 -07001049 Slog.d(TAG, "onTwilightStateChanged: isNight="
1050 + (state == null ? null : state.isNight()));
Justin Klaassen908b86c2016-08-08 09:18:42 -07001051 updateActivated(state);
Justin Klaassen911e8892016-06-21 18:24:24 -07001052 }
1053 }
Justin Klaassen639214e2016-07-14 21:00:06 -07001054
1055 /**
1056 * Interpolates between two 4x4 color transform matrices (in column-major order).
1057 */
1058 private static class ColorMatrixEvaluator implements TypeEvaluator<float[]> {
1059
1060 /**
1061 * Result matrix returned by {@link #evaluate(float, float[], float[])}.
1062 */
1063 private final float[] mResultMatrix = new float[16];
1064
1065 @Override
1066 public float[] evaluate(float fraction, float[] startValue, float[] endValue) {
1067 for (int i = 0; i < mResultMatrix.length; i++) {
1068 mResultMatrix[i] = MathUtils.lerp(startValue[i], endValue[i], fraction);
1069 }
1070 return mResultMatrix;
1071 }
1072 }
Christine Franks39b03112018-07-03 14:46:07 -07001073
Christine Franks83cc5412018-07-03 14:46:07 -07001074 private final class NightDisplayTintController extends TintController {
1075
Christine Franksa4ed3762019-01-24 15:37:04 -08001076 private final float[] mMatrix = new float[16];
Christine Franks83cc5412018-07-03 14:46:07 -07001077 private final float[] mColorTempCoefficients = new float[9];
Christine Franksa4ed3762019-01-24 15:37:04 -08001078
1079 private Boolean mIsAvailable;
Christine Franks83cc5412018-07-03 14:46:07 -07001080 private Integer mColorTemp;
1081
1082 /**
1083 * Set coefficients based on whether the color matrix is linear or not.
1084 */
1085 @Override
1086 public void setUp(Context context, boolean needsLinear) {
1087 final String[] coefficients = context.getResources().getStringArray(needsLinear
1088 ? R.array.config_nightDisplayColorTemperatureCoefficients
1089 : R.array.config_nightDisplayColorTemperatureCoefficientsNative);
1090 for (int i = 0; i < 9 && i < coefficients.length; i++) {
1091 mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]);
1092 }
1093 }
1094
1095 @Override
1096 public void setMatrix(int cct) {
1097 if (mMatrix.length != 16) {
1098 Slog.d(TAG, "The display transformation matrix must be 4x4");
1099 return;
1100 }
1101
1102 Matrix.setIdentityM(mMatrix, 0);
1103
1104 final float squareTemperature = cct * cct;
1105 final float red = squareTemperature * mColorTempCoefficients[0]
1106 + cct * mColorTempCoefficients[1] + mColorTempCoefficients[2];
1107 final float green = squareTemperature * mColorTempCoefficients[3]
1108 + cct * mColorTempCoefficients[4] + mColorTempCoefficients[5];
1109 final float blue = squareTemperature * mColorTempCoefficients[6]
1110 + cct * mColorTempCoefficients[7] + mColorTempCoefficients[8];
1111 mMatrix[0] = red;
1112 mMatrix[5] = green;
1113 mMatrix[10] = blue;
1114 }
1115
1116 @Override
1117 public float[] getMatrix() {
1118 return isActivated() ? mMatrix : MATRIX_IDENTITY;
1119 }
1120
1121 @Override
1122 public void setActivated(Boolean activated) {
1123 if (activated == null) {
1124 super.setActivated(null);
1125 return;
1126 }
1127
1128 boolean activationStateChanged = activated != isActivated();
1129
1130 if (!isActivatedStateNotSet() && activationStateChanged) {
1131 // This is a true state change, so set this as the last activation time.
1132 Secure.putStringForUser(getContext().getContentResolver(),
1133 Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
1134 LocalDateTime.now().toString(),
1135 mCurrentUser);
1136 }
1137
1138 if (isActivatedStateNotSet() || activationStateChanged) {
1139 super.setActivated(activated);
Christine Franks78a4dd42019-02-08 11:09:30 -08001140 if (isActivatedSetting() != activated) {
1141 Secure.putIntForUser(getContext().getContentResolver(),
1142 Secure.NIGHT_DISPLAY_ACTIVATED,
1143 activated ? 1 : 0, mCurrentUser);
1144 }
Christine Franks83cc5412018-07-03 14:46:07 -07001145 onActivated(activated);
1146 }
1147 }
1148
1149 @Override
1150 public int getLevel() {
1151 return LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
1152 }
1153
Christine Franksa4ed3762019-01-24 15:37:04 -08001154 @Override
1155 public boolean isAvailable(Context context) {
1156 if (mIsAvailable == null) {
1157 mIsAvailable = ColorDisplayManager.isNightDisplayAvailable(context);
1158 }
1159 return mIsAvailable;
1160 }
1161
Christine Franks78a4dd42019-02-08 11:09:30 -08001162 private void onActivated(boolean activated) {
Christine Franks83cc5412018-07-03 14:46:07 -07001163 Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display");
1164 if (mNightDisplayAutoMode != null) {
1165 mNightDisplayAutoMode.onActivated(activated);
1166 }
1167
Christine Franksa4ed3762019-01-24 15:37:04 -08001168 if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
Christine Franks83cc5412018-07-03 14:46:07 -07001169 updateDisplayWhiteBalanceStatus();
1170 }
1171
1172 mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_ANIMATED);
1173 }
1174
1175 int getColorTemperature() {
1176 return mColorTemp != null ? clampNightDisplayColorTemperature(mColorTemp)
Christine Franks78a4dd42019-02-08 11:09:30 -08001177 : getColorTemperatureSetting();
Christine Franks83cc5412018-07-03 14:46:07 -07001178 }
1179
1180 boolean setColorTemperature(int temperature) {
1181 mColorTemp = temperature;
1182 final boolean success = Secure.putIntForUser(getContext().getContentResolver(),
1183 Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, temperature, mCurrentUser);
1184 onColorTemperatureChanged(temperature);
1185 return success;
1186 }
1187
1188 void onColorTemperatureChanged(int temperature) {
1189 setMatrix(temperature);
1190 mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE);
1191 }
Christine Franks78a4dd42019-02-08 11:09:30 -08001192
1193 boolean isActivatedSetting() {
Christine Franks44782612019-03-07 17:25:39 -08001194 if (mCurrentUser == UserHandle.USER_NULL) {
1195 return false;
1196 }
Christine Franks78a4dd42019-02-08 11:09:30 -08001197 return Secure.getIntForUser(getContext().getContentResolver(),
1198 Secure.NIGHT_DISPLAY_ACTIVATED, 0, mCurrentUser) == 1;
1199 }
1200
1201 int getColorTemperatureSetting() {
Christine Franks44782612019-03-07 17:25:39 -08001202 if (mCurrentUser == UserHandle.USER_NULL) {
1203 return NOT_SET;
1204 }
Christine Franks78a4dd42019-02-08 11:09:30 -08001205 return clampNightDisplayColorTemperature(Secure.getIntForUser(
1206 getContext().getContentResolver(), Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE,
1207 NOT_SET,
1208 mCurrentUser));
1209 }
1210
1211 private int clampNightDisplayColorTemperature(int colorTemperature) {
1212 if (colorTemperature == NOT_SET) {
1213 colorTemperature = getContext().getResources().getInteger(
1214 R.integer.config_nightDisplayColorTemperatureDefault);
1215 }
1216 final int minimumTemperature = ColorDisplayManager
1217 .getMinimumColorTemperature(getContext());
1218 final int maximumTemperature = ColorDisplayManager
1219 .getMaximumColorTemperature(getContext());
1220 if (colorTemperature < minimumTemperature) {
1221 colorTemperature = minimumTemperature;
1222 } else if (colorTemperature > maximumTemperature) {
1223 colorTemperature = maximumTemperature;
1224 }
1225
1226 return colorTemperature;
1227 }
Christine Franks83cc5412018-07-03 14:46:07 -07001228 }
1229
Christine Franks245ffd42018-11-16 13:45:14 -08001230 /**
1231 * Local service that allows color transforms to be enabled from other system services.
1232 */
1233 public final class ColorDisplayServiceInternal {
1234
1235 /**
1236 * Set the current CCT value for the display white balance transform, and if the transform
1237 * is enabled, apply it.
1238 *
1239 * @param cct the color temperature in Kelvin.
1240 */
1241 public boolean setDisplayWhiteBalanceColorTemperature(int cct) {
1242 // Update the transform matrix even if it can't be applied.
Christine Franks245ffd42018-11-16 13:45:14 -08001243 mDisplayWhiteBalanceTintController.setMatrix(cct);
1244
1245 if (mDisplayWhiteBalanceTintController.isActivated()) {
Christine Franksc7fb9452019-02-04 08:45:33 -08001246 mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE);
Christine Franks245ffd42018-11-16 13:45:14 -08001247 return true;
1248 }
1249 return false;
1250 }
1251
1252 /**
Daniel Solomon37816412019-04-10 15:17:41 -07001253 * Reset the CCT value for the display white balance transform to its default value.
1254 */
1255 public boolean resetDisplayWhiteBalanceColorTemperature() {
1256 return setDisplayWhiteBalanceColorTemperature(getContext().getResources()
1257 .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault));
1258 }
1259
1260 /**
Christine Franks245ffd42018-11-16 13:45:14 -08001261 * Sets the listener and returns whether display white balance is currently enabled.
1262 */
1263 public boolean setDisplayWhiteBalanceListener(DisplayWhiteBalanceListener listener) {
1264 mDisplayWhiteBalanceListener = listener;
1265 return mDisplayWhiteBalanceTintController.isActivated();
1266 }
Daniel Solomon8b72c5b2018-11-25 11:07:13 -08001267
Christine Franksf3529b22019-01-03 13:20:17 -08001268 /**
Christine Franks66783a82019-03-28 11:45:56 -07001269 * Returns whether Display white balance is currently enabled.
1270 */
1271 public boolean isDisplayWhiteBalanceEnabled() {
1272 return isDisplayWhiteBalanceSettingEnabled();
1273 }
1274
1275 /**
Christine Franksf3529b22019-01-03 13:20:17 -08001276 * Adds a {@link WeakReference<ColorTransformController>} for a newly started activity, and
1277 * invokes {@link ColorTransformController#applyAppSaturation(float[], float[])} if needed.
1278 */
Christine Franks55194dc2019-01-15 13:47:06 -08001279 public boolean attachColorTransformController(String packageName, @UserIdInt int userId,
Christine Franksf3529b22019-01-03 13:20:17 -08001280 WeakReference<ColorTransformController> controller) {
1281 return mAppSaturationController
Christine Franks55194dc2019-01-15 13:47:06 -08001282 .addColorTransformController(packageName, userId, controller);
Christine Franksf3529b22019-01-03 13:20:17 -08001283 }
Christine Franks245ffd42018-11-16 13:45:14 -08001284 }
1285
1286 /**
1287 * Listener for changes in display white balance status.
1288 */
1289 public interface DisplayWhiteBalanceListener {
1290
1291 /**
1292 * Notify that the display white balance status has changed, either due to preemption by
1293 * another transform or the feature being turned off.
1294 */
Christine Franks66783a82019-03-28 11:45:56 -07001295 void onDisplayWhiteBalanceStatusChanged(boolean activated);
Christine Franks245ffd42018-11-16 13:45:14 -08001296 }
1297
Christine Franks09c229e2018-12-14 10:37:40 -08001298 private final class TintHandler extends Handler {
1299
Christine Franks83cc5412018-07-03 14:46:07 -07001300 private TintHandler(Looper looper) {
Christine Franks09c229e2018-12-14 10:37:40 -08001301 super(looper, null, true /* async */);
1302 }
1303
1304 @Override
1305 public void handleMessage(Message msg) {
1306 switch (msg.what) {
Christine Franks27912a32019-04-02 10:43:10 -07001307 case MSG_USER_CHANGED:
1308 onUserChanged(msg.arg1);
1309 break;
1310 case MSG_SET_UP:
1311 setUp();
1312 break;
Christine Franks09c229e2018-12-14 10:37:40 -08001313 case MSG_APPLY_GLOBAL_SATURATION:
1314 mGlobalSaturationTintController.setMatrix(msg.arg1);
1315 applyTint(mGlobalSaturationTintController, false);
1316 break;
Christine Franks83cc5412018-07-03 14:46:07 -07001317 case MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE:
1318 applyTint(mNightDisplayTintController, true);
1319 break;
1320 case MSG_APPLY_NIGHT_DISPLAY_ANIMATED:
1321 applyTint(mNightDisplayTintController, false);
1322 break;
Christine Franksc7fb9452019-02-04 08:45:33 -08001323 case MSG_APPLY_DISPLAY_WHITE_BALANCE:
1324 applyTint(mDisplayWhiteBalanceTintController, false);
1325 break;
Christine Franks09c229e2018-12-14 10:37:40 -08001326 }
1327 }
1328 }
1329
Christine Franksf3529b22019-01-03 13:20:17 -08001330 /**
1331 * Interface for applying transforms to a given AppWindow.
1332 */
1333 public interface ColorTransformController {
1334
Christine Franksd154fe52019-01-04 17:17:45 -08001335 /**
1336 * Apply the given saturation (grayscale) matrix to the associated AppWindow.
1337 */
Christine Franksf3529b22019-01-03 13:20:17 -08001338 void applyAppSaturation(@Size(9) float[] matrix, @Size(3) float[] translation);
1339 }
1340
Christine Franks83cc5412018-07-03 14:46:07 -07001341 @VisibleForTesting
1342 final class BinderService extends IColorDisplayManager.Stub {
Christine Franks57fdde82018-07-03 14:46:07 -07001343
Christine Franks39b03112018-07-03 14:46:07 -07001344 @Override
Christine Franksd154fe52019-01-04 17:17:45 -08001345 public void setColorMode(int colorMode) {
1346 getContext().enforceCallingOrSelfPermission(
1347 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1348 "Permission required to set display color mode");
1349 final long token = Binder.clearCallingIdentity();
1350 try {
1351 setColorModeInternal(colorMode);
1352 } finally {
1353 Binder.restoreCallingIdentity(token);
1354 }
1355 }
1356
1357 @Override
1358 public int getColorMode() {
1359 final long token = Binder.clearCallingIdentity();
1360 try {
1361 return getColorModeInternal();
1362 } finally {
1363 Binder.restoreCallingIdentity(token);
1364 }
1365 }
1366
1367 @Override
Christine Franks39b03112018-07-03 14:46:07 -07001368 public boolean isDeviceColorManaged() {
1369 final long token = Binder.clearCallingIdentity();
1370 try {
1371 return isDeviceColorManagedInternal();
1372 } finally {
1373 Binder.restoreCallingIdentity(token);
1374 }
1375 }
Christine Franks09c229e2018-12-14 10:37:40 -08001376
1377 @Override
1378 public boolean setSaturationLevel(int level) {
1379 final boolean hasTransformsPermission = getContext()
1380 .checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
1381 == PackageManager.PERMISSION_GRANTED;
1382 final boolean hasLegacyPermission = getContext()
1383 .checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION)
1384 == PackageManager.PERMISSION_GRANTED;
1385 if (!hasTransformsPermission && !hasLegacyPermission) {
1386 throw new SecurityException("Permission required to set display saturation level");
1387 }
1388 final long token = Binder.clearCallingIdentity();
1389 try {
1390 final Message message = mHandler.obtainMessage(MSG_APPLY_GLOBAL_SATURATION);
1391 message.arg1 = level;
1392 mHandler.sendMessage(message);
1393 } finally {
1394 Binder.restoreCallingIdentity(token);
1395 }
1396 return true;
1397 }
Christine Franksf3529b22019-01-03 13:20:17 -08001398
1399 @Override
Christine Franks6d21d342019-02-07 15:09:03 -08001400 public boolean isSaturationActivated() {
1401 getContext().enforceCallingPermission(
1402 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1403 "Permission required to get display saturation level");
1404 final long token = Binder.clearCallingIdentity();
1405 try {
1406 return !mGlobalSaturationTintController.isActivatedStateNotSet()
1407 && mGlobalSaturationTintController.isActivated();
1408 } finally {
1409 Binder.restoreCallingIdentity(token);
1410 }
1411 }
1412
1413 @Override
Christine Franksf3529b22019-01-03 13:20:17 -08001414 public boolean setAppSaturationLevel(String packageName, int level) {
1415 getContext().enforceCallingPermission(
1416 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1417 "Permission required to set display saturation level");
1418 final long token = Binder.clearCallingIdentity();
1419 try {
1420 return setAppSaturationLevelInternal(packageName, level);
1421 } finally {
1422 Binder.restoreCallingIdentity(token);
1423 }
1424 }
1425
Christine Franks55194dc2019-01-15 13:47:06 -08001426 public int getTransformCapabilities() {
1427 getContext().enforceCallingPermission(
1428 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1429 "Permission required to query transform capabilities");
1430 final long token = Binder.clearCallingIdentity();
1431 try {
1432 return getTransformCapabilitiesInternal();
1433 } finally {
1434 Binder.restoreCallingIdentity(token);
1435 }
1436 }
1437
Christine Franksf3529b22019-01-03 13:20:17 -08001438 @Override
Christine Franks83cc5412018-07-03 14:46:07 -07001439 public boolean setNightDisplayActivated(boolean activated) {
1440 getContext().enforceCallingOrSelfPermission(
1441 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1442 "Permission required to set night display activated");
1443 final long token = Binder.clearCallingIdentity();
1444 try {
1445 mNightDisplayTintController.setActivated(activated);
1446 return true;
1447 } finally {
1448 Binder.restoreCallingIdentity(token);
1449 }
1450 }
1451
1452 @Override
1453 public boolean isNightDisplayActivated() {
1454 final long token = Binder.clearCallingIdentity();
1455 try {
1456 return mNightDisplayTintController.isActivated();
1457 } finally {
1458 Binder.restoreCallingIdentity(token);
1459 }
1460 }
1461
1462 @Override
1463 public boolean setNightDisplayColorTemperature(int temperature) {
1464 getContext().enforceCallingOrSelfPermission(
1465 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1466 "Permission required to set night display temperature");
1467 final long token = Binder.clearCallingIdentity();
1468 try {
1469 return mNightDisplayTintController.setColorTemperature(temperature);
1470 } finally {
1471 Binder.restoreCallingIdentity(token);
1472 }
1473 }
1474
1475 @Override
1476 public int getNightDisplayColorTemperature() {
1477 final long token = Binder.clearCallingIdentity();
1478 try {
1479 return mNightDisplayTintController.getColorTemperature();
1480 } finally {
1481 Binder.restoreCallingIdentity(token);
1482 }
1483 }
1484
1485 @Override
1486 public boolean setNightDisplayAutoMode(int autoMode) {
1487 getContext().enforceCallingOrSelfPermission(
1488 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1489 "Permission required to set night display auto mode");
1490 final long token = Binder.clearCallingIdentity();
1491 try {
1492 return setNightDisplayAutoModeInternal(autoMode);
1493 } finally {
1494 Binder.restoreCallingIdentity(token);
1495 }
1496 }
1497
1498 @Override
1499 public int getNightDisplayAutoMode() {
1500 getContext().enforceCallingOrSelfPermission(
1501 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1502 "Permission required to get night display auto mode");
1503 final long token = Binder.clearCallingIdentity();
1504 try {
1505 return getNightDisplayAutoModeInternal();
1506 } finally {
1507 Binder.restoreCallingIdentity(token);
1508 }
1509 }
1510
1511 @Override
1512 public int getNightDisplayAutoModeRaw() {
1513 final long token = Binder.clearCallingIdentity();
1514 try {
1515 return getNightDisplayAutoModeRawInternal();
1516 } finally {
1517 Binder.restoreCallingIdentity(token);
1518 }
1519 }
1520
1521 @Override
1522 public boolean setNightDisplayCustomStartTime(Time startTime) {
1523 getContext().enforceCallingOrSelfPermission(
1524 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1525 "Permission required to set night display custom start time");
1526 final long token = Binder.clearCallingIdentity();
1527 try {
1528 return setNightDisplayCustomStartTimeInternal(startTime);
1529 } finally {
1530 Binder.restoreCallingIdentity(token);
1531 }
1532 }
1533
1534 @Override
1535 public Time getNightDisplayCustomStartTime() {
1536 final long token = Binder.clearCallingIdentity();
1537 try {
1538 return getNightDisplayCustomStartTimeInternal();
1539 } finally {
1540 Binder.restoreCallingIdentity(token);
1541 }
1542 }
1543
1544 @Override
1545 public boolean setNightDisplayCustomEndTime(Time endTime) {
1546 getContext().enforceCallingOrSelfPermission(
1547 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1548 "Permission required to set night display custom end time");
1549 final long token = Binder.clearCallingIdentity();
1550 try {
1551 return setNightDisplayCustomEndTimeInternal(endTime);
1552 } finally {
1553 Binder.restoreCallingIdentity(token);
1554 }
1555 }
1556
1557 @Override
1558 public Time getNightDisplayCustomEndTime() {
1559 final long token = Binder.clearCallingIdentity();
1560 try {
1561 return getNightDisplayCustomEndTimeInternal();
1562 } finally {
1563 Binder.restoreCallingIdentity(token);
1564 }
1565 }
1566
1567 @Override
Christine Franks66783a82019-03-28 11:45:56 -07001568 public boolean setDisplayWhiteBalanceEnabled(boolean enabled) {
1569 getContext().enforceCallingOrSelfPermission(
1570 Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1571 "Permission required to set night display activated");
1572 final long token = Binder.clearCallingIdentity();
1573 try {
1574 return setDisplayWhiteBalanceSettingEnabled(enabled);
1575 } finally {
1576 Binder.restoreCallingIdentity(token);
1577 }
1578 }
1579
1580 @Override
1581 public boolean isDisplayWhiteBalanceEnabled() {
1582 final long token = Binder.clearCallingIdentity();
1583 try {
1584 return isDisplayWhiteBalanceSettingEnabled();
1585 } finally {
1586 Binder.restoreCallingIdentity(token);
1587 }
1588 }
1589
1590 @Override
Christine Franksf3529b22019-01-03 13:20:17 -08001591 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Christine Franksd154fe52019-01-04 17:17:45 -08001592 if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
1593 return;
1594 }
Christine Franksf3529b22019-01-03 13:20:17 -08001595
1596 final long token = Binder.clearCallingIdentity();
1597 try {
1598 dumpInternal(pw);
1599 } finally {
1600 Binder.restoreCallingIdentity(token);
1601 }
1602 }
Christine Franks39b03112018-07-03 14:46:07 -07001603 }
Justin Klaassen911e8892016-06-21 18:24:24 -07001604}