• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.display.color;
18 
19 import static android.hardware.display.ColorDisplayManager.AUTO_MODE_CUSTOM_TIME;
20 import static android.hardware.display.ColorDisplayManager.AUTO_MODE_DISABLED;
21 import static android.hardware.display.ColorDisplayManager.AUTO_MODE_TWILIGHT;
22 import static android.hardware.display.ColorDisplayManager.COLOR_MODE_AUTOMATIC;
23 import static android.hardware.display.ColorDisplayManager.COLOR_MODE_BOOSTED;
24 import static android.hardware.display.ColorDisplayManager.COLOR_MODE_NATURAL;
25 import static android.hardware.display.ColorDisplayManager.COLOR_MODE_SATURATED;
26 import static android.hardware.display.ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MAX;
27 import static android.hardware.display.ColorDisplayManager.VENDOR_COLOR_MODE_RANGE_MIN;
28 
29 import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
30 
31 import android.Manifest;
32 import android.animation.Animator;
33 import android.animation.AnimatorListenerAdapter;
34 import android.animation.TypeEvaluator;
35 import android.animation.ValueAnimator;
36 import android.annotation.NonNull;
37 import android.annotation.Nullable;
38 import android.annotation.Size;
39 import android.annotation.UserIdInt;
40 import android.app.AlarmManager;
41 import android.content.BroadcastReceiver;
42 import android.content.ContentResolver;
43 import android.content.Context;
44 import android.content.Intent;
45 import android.content.IntentFilter;
46 import android.content.pm.PackageManager;
47 import android.content.pm.PackageManagerInternal;
48 import android.content.res.Resources;
49 import android.database.ContentObserver;
50 import android.hardware.display.ColorDisplayManager;
51 import android.hardware.display.ColorDisplayManager.AutoMode;
52 import android.hardware.display.ColorDisplayManager.ColorMode;
53 import android.hardware.display.IColorDisplayManager;
54 import android.hardware.display.Time;
55 import android.net.Uri;
56 import android.opengl.Matrix;
57 import android.os.Binder;
58 import android.os.Handler;
59 import android.os.Looper;
60 import android.os.Message;
61 import android.os.SystemProperties;
62 import android.os.UserHandle;
63 import android.provider.Settings.Secure;
64 import android.provider.Settings.System;
65 import android.util.MathUtils;
66 import android.util.Slog;
67 import android.util.SparseIntArray;
68 import android.view.Display;
69 import android.view.SurfaceControl;
70 import android.view.accessibility.AccessibilityManager;
71 import android.view.animation.AnimationUtils;
72 
73 import com.android.internal.R;
74 import com.android.internal.annotations.VisibleForTesting;
75 import com.android.internal.util.DumpUtils;
76 import com.android.server.DisplayThread;
77 import com.android.server.LocalServices;
78 import com.android.server.SystemService;
79 import com.android.server.twilight.TwilightListener;
80 import com.android.server.twilight.TwilightManager;
81 import com.android.server.twilight.TwilightState;
82 
83 import java.io.FileDescriptor;
84 import java.io.PrintWriter;
85 import java.lang.ref.WeakReference;
86 import java.time.DateTimeException;
87 import java.time.Instant;
88 import java.time.LocalDateTime;
89 import java.time.LocalTime;
90 import java.time.ZoneId;
91 import java.time.format.DateTimeParseException;
92 
93 /**
94  * Controls the display's color transforms.
95  */
96 public final class ColorDisplayService extends SystemService {
97 
98     static final String TAG = "ColorDisplayService";
99 
100     /**
101      * The identity matrix, used if one of the given matrices is {@code null}.
102      */
103     static final float[] MATRIX_IDENTITY = new float[16];
104 
105     static {
Matrix.setIdentityM(MATRIX_IDENTITY, 0)106         Matrix.setIdentityM(MATRIX_IDENTITY, 0);
107     }
108 
109     /**
110      * The transition time, in milliseconds, for Night Display to turn on/off.
111      */
112     private static final long TRANSITION_DURATION = 3000L;
113 
114     private static final int MSG_USER_CHANGED = 0;
115     private static final int MSG_SET_UP = 1;
116     private static final int MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE = 2;
117     private static final int MSG_APPLY_NIGHT_DISPLAY_ANIMATED = 3;
118     private static final int MSG_APPLY_GLOBAL_SATURATION = 4;
119     private static final int MSG_APPLY_DISPLAY_WHITE_BALANCE = 5;
120 
121     /**
122      * Return value if a setting has not been set.
123      */
124     private static final int NOT_SET = -1;
125 
126     /**
127      * Evaluator used to animate color matrix transitions.
128      */
129     private static final ColorMatrixEvaluator COLOR_MATRIX_EVALUATOR = new ColorMatrixEvaluator();
130 
131     private final NightDisplayTintController mNightDisplayTintController =
132             new NightDisplayTintController();
133 
134     @VisibleForTesting
135     final DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController =
136             new DisplayWhiteBalanceTintController();
137 
138     private final TintController mGlobalSaturationTintController =
139             new GlobalSaturationTintController();
140 
141     /**
142      * Matrix and offset used for converting color to grayscale.
143      */
144     private static final float[] MATRIX_GRAYSCALE = new float[]{
145             .2126f, .2126f, .2126f, 0f,
146             .7152f, .7152f, .7152f, 0f,
147             .0722f, .0722f, .0722f, 0f,
148             0f, 0f, 0f, 1f
149     };
150 
151     /**
152      * Matrix and offset used for luminance inversion. Represents a transform from RGB to YIQ color
153      * space, rotation around the Y axis by 180 degrees, transform back to RGB color space, and
154      * subtraction from 1. The last row represents a non-multiplied addition, see surfaceflinger's
155      * ProgramCache for full implementation details.
156      */
157     private static final float[] MATRIX_INVERT_COLOR = new float[]{
158             0.402f, -0.598f, -0.599f, 0f,
159             -1.174f, -0.174f, -1.175f, 0f,
160             -0.228f, -0.228f, 0.772f, 0f,
161             1f, 1f, 1f, 1f
162     };
163 
164     private final Handler mHandler;
165 
166     private final AppSaturationController mAppSaturationController = new AppSaturationController();
167 
168     private int mCurrentUser = UserHandle.USER_NULL;
169     private ContentObserver mUserSetupObserver;
170     private boolean mBootCompleted;
171 
172     private ContentObserver mContentObserver;
173 
174     private DisplayWhiteBalanceListener mDisplayWhiteBalanceListener;
175 
176     private NightDisplayAutoMode mNightDisplayAutoMode;
177 
178     /**
179      * Map of color modes -> display composition colorspace
180      */
181     private SparseIntArray mColorModeCompositionColorSpaces = null;
182 
ColorDisplayService(Context context)183     public ColorDisplayService(Context context) {
184         super(context);
185         mHandler = new TintHandler(DisplayThread.get().getLooper());
186     }
187 
188     @Override
onStart()189     public void onStart() {
190         publishBinderService(Context.COLOR_DISPLAY_SERVICE, new BinderService());
191         publishLocalService(ColorDisplayServiceInternal.class, new ColorDisplayServiceInternal());
192         publishLocalService(DisplayTransformManager.class, new DisplayTransformManager());
193     }
194 
195     @Override
onBootPhase(int phase)196     public void onBootPhase(int phase) {
197         if (phase >= PHASE_BOOT_COMPLETED) {
198             mBootCompleted = true;
199 
200             // Register listeners now that boot is complete.
201             if (mCurrentUser != UserHandle.USER_NULL && mUserSetupObserver == null) {
202                 mHandler.sendEmptyMessage(MSG_SET_UP);
203             }
204         }
205     }
206 
207     @Override
onStartUser(int userHandle)208     public void onStartUser(int userHandle) {
209         super.onStartUser(userHandle);
210 
211         if (mCurrentUser == UserHandle.USER_NULL) {
212             final Message message = mHandler.obtainMessage(MSG_USER_CHANGED);
213             message.arg1 = userHandle;
214             mHandler.sendMessage(message);
215         }
216     }
217 
218     @Override
onSwitchUser(int userHandle)219     public void onSwitchUser(int userHandle) {
220         super.onSwitchUser(userHandle);
221 
222         final Message message = mHandler.obtainMessage(MSG_USER_CHANGED);
223         message.arg1 = userHandle;
224         mHandler.sendMessage(message);
225     }
226 
227     @Override
onStopUser(int userHandle)228     public void onStopUser(int userHandle) {
229         super.onStopUser(userHandle);
230 
231         if (mCurrentUser == userHandle) {
232             final Message message = mHandler.obtainMessage(MSG_USER_CHANGED);
233             message.arg1 = UserHandle.USER_NULL;
234             mHandler.sendMessage(message);
235         }
236     }
237 
onUserChanged(int userHandle)238     @VisibleForTesting void onUserChanged(int userHandle) {
239         final ContentResolver cr = getContext().getContentResolver();
240 
241         if (mCurrentUser != UserHandle.USER_NULL) {
242             if (mUserSetupObserver != null) {
243                 cr.unregisterContentObserver(mUserSetupObserver);
244                 mUserSetupObserver = null;
245             } else if (mBootCompleted) {
246                 tearDown();
247             }
248         }
249 
250         mCurrentUser = userHandle;
251 
252         if (mCurrentUser != UserHandle.USER_NULL) {
253             if (!isUserSetupCompleted(cr, mCurrentUser)) {
254                 mUserSetupObserver = new ContentObserver(mHandler) {
255                     @Override
256                     public void onChange(boolean selfChange, Uri uri) {
257                         if (isUserSetupCompleted(cr, mCurrentUser)) {
258                             cr.unregisterContentObserver(this);
259                             mUserSetupObserver = null;
260 
261                             if (mBootCompleted) {
262                                 setUp();
263                             }
264                         }
265                     }
266                 };
267                 cr.registerContentObserver(Secure.getUriFor(Secure.USER_SETUP_COMPLETE),
268                         false /* notifyForDescendants */, mUserSetupObserver, mCurrentUser);
269             } else if (mBootCompleted) {
270                 setUp();
271             }
272         }
273     }
274 
isUserSetupCompleted(ContentResolver cr, int userHandle)275     private static boolean isUserSetupCompleted(ContentResolver cr, int userHandle) {
276         return Secure.getIntForUser(cr, Secure.USER_SETUP_COMPLETE, 0, userHandle) == 1;
277     }
278 
setUpDisplayCompositionColorSpaces(Resources res)279     private void setUpDisplayCompositionColorSpaces(Resources res) {
280         mColorModeCompositionColorSpaces = null;
281 
282         final int[] colorModes = res.getIntArray(R.array.config_displayCompositionColorModes);
283         if (colorModes == null) {
284             return;
285         }
286 
287         final int[] compSpaces = res.getIntArray(R.array.config_displayCompositionColorSpaces);
288         if (compSpaces == null) {
289             return;
290         }
291 
292         if (colorModes.length != compSpaces.length) {
293             Slog.e(TAG, "Number of composition color spaces doesn't match specified color modes");
294             return;
295         }
296 
297         mColorModeCompositionColorSpaces = new SparseIntArray(colorModes.length);
298         for (int i = 0; i < colorModes.length; i++) {
299             mColorModeCompositionColorSpaces.put(colorModes[i], compSpaces[i]);
300         }
301     }
302 
setUp()303     private void setUp() {
304         Slog.d(TAG, "setUp: currentUser=" + mCurrentUser);
305 
306         // Listen for external changes to any of the settings.
307         if (mContentObserver == null) {
308             mContentObserver = new ContentObserver(mHandler) {
309                 @Override
310                 public void onChange(boolean selfChange, Uri uri) {
311                     super.onChange(selfChange, uri);
312 
313                     final String setting = uri == null ? null : uri.getLastPathSegment();
314                     if (setting != null) {
315                         switch (setting) {
316                             case Secure.NIGHT_DISPLAY_ACTIVATED:
317                                 final boolean activated = mNightDisplayTintController
318                                         .isActivatedSetting();
319                                 if (mNightDisplayTintController.isActivatedStateNotSet()
320                                         || mNightDisplayTintController.isActivated() != activated) {
321                                     mNightDisplayTintController.setActivated(activated);
322                                 }
323                                 break;
324                             case Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE:
325                                 final int temperature = mNightDisplayTintController
326                                         .getColorTemperatureSetting();
327                                 if (mNightDisplayTintController.getColorTemperature()
328                                         != temperature) {
329                                     mNightDisplayTintController
330                                             .onColorTemperatureChanged(temperature);
331                                 }
332                                 break;
333                             case Secure.NIGHT_DISPLAY_AUTO_MODE:
334                                 onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal());
335                                 break;
336                             case Secure.NIGHT_DISPLAY_CUSTOM_START_TIME:
337                                 onNightDisplayCustomStartTimeChanged(
338                                         getNightDisplayCustomStartTimeInternal().getLocalTime());
339                                 break;
340                             case Secure.NIGHT_DISPLAY_CUSTOM_END_TIME:
341                                 onNightDisplayCustomEndTimeChanged(
342                                         getNightDisplayCustomEndTimeInternal().getLocalTime());
343                                 break;
344                             case System.DISPLAY_COLOR_MODE:
345                                 onDisplayColorModeChanged(getColorModeInternal());
346                                 break;
347                             case Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED:
348                                 onAccessibilityInversionChanged();
349                                 onAccessibilityActivated();
350                                 break;
351                             case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:
352                                 onAccessibilityDaltonizerChanged();
353                                 onAccessibilityActivated();
354                                 break;
355                             case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER:
356                                 onAccessibilityDaltonizerChanged();
357                                 break;
358                             case Secure.DISPLAY_WHITE_BALANCE_ENABLED:
359                                 updateDisplayWhiteBalanceStatus();
360                                 break;
361                         }
362                     }
363                 }
364             };
365         }
366         final ContentResolver cr = getContext().getContentResolver();
367         cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_ACTIVATED),
368                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
369         cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE),
370                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
371         cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_AUTO_MODE),
372                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
373         cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_START_TIME),
374                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
375         cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_END_TIME),
376                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
377         cr.registerContentObserver(System.getUriFor(System.DISPLAY_COLOR_MODE),
378                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
379         cr.registerContentObserver(
380                 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
381                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
382         cr.registerContentObserver(
383                 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
384                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
385         cr.registerContentObserver(
386                 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
387                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
388         cr.registerContentObserver(Secure.getUriFor(Secure.DISPLAY_WHITE_BALANCE_ENABLED),
389                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
390 
391         // Apply the accessibility settings first, since they override most other settings.
392         onAccessibilityInversionChanged();
393         onAccessibilityDaltonizerChanged();
394 
395         setUpDisplayCompositionColorSpaces(getContext().getResources());
396 
397         // Set the color mode, if valid, and immediately apply the updated tint matrix based on the
398         // existing activated state. This ensures consistency of tint across the color mode change.
399         onDisplayColorModeChanged(getColorModeInternal());
400 
401         if (mNightDisplayTintController.isAvailable(getContext())) {
402             // Reset the activated state.
403             mNightDisplayTintController.setActivated(null);
404 
405             // Prepare the night display color transformation matrix.
406             mNightDisplayTintController
407                     .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
408             mNightDisplayTintController
409                     .setMatrix(mNightDisplayTintController.getColorTemperatureSetting());
410 
411             // Initialize the current auto mode.
412             onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal());
413 
414             // Force the initialization of the current saved activation state.
415             if (mNightDisplayTintController.isActivatedStateNotSet()) {
416                 mNightDisplayTintController
417                         .setActivated(mNightDisplayTintController.isActivatedSetting());
418             }
419         }
420 
421         if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
422             // Prepare the display white balance transform matrix.
423             mDisplayWhiteBalanceTintController.setUp(getContext(), true /* needsLinear */);
424 
425             updateDisplayWhiteBalanceStatus();
426         }
427     }
428 
tearDown()429     private void tearDown() {
430         Slog.d(TAG, "tearDown: currentUser=" + mCurrentUser);
431 
432         if (mContentObserver != null) {
433             getContext().getContentResolver().unregisterContentObserver(mContentObserver);
434         }
435 
436         if (mNightDisplayTintController.isAvailable(getContext())) {
437             if (mNightDisplayAutoMode != null) {
438                 mNightDisplayAutoMode.onStop();
439                 mNightDisplayAutoMode = null;
440             }
441             mNightDisplayTintController.endAnimator();
442         }
443 
444         if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
445             mDisplayWhiteBalanceTintController.endAnimator();
446         }
447 
448         if (mGlobalSaturationTintController.isAvailable(getContext())) {
449             mGlobalSaturationTintController.setActivated(null);
450         }
451     }
452 
onNightDisplayAutoModeChanged(int autoMode)453     private void onNightDisplayAutoModeChanged(int autoMode) {
454         Slog.d(TAG, "onNightDisplayAutoModeChanged: autoMode=" + autoMode);
455 
456         if (mNightDisplayAutoMode != null) {
457             mNightDisplayAutoMode.onStop();
458             mNightDisplayAutoMode = null;
459         }
460 
461         if (autoMode == AUTO_MODE_CUSTOM_TIME) {
462             mNightDisplayAutoMode = new CustomNightDisplayAutoMode();
463         } else if (autoMode == AUTO_MODE_TWILIGHT) {
464             mNightDisplayAutoMode = new TwilightNightDisplayAutoMode();
465         }
466 
467         if (mNightDisplayAutoMode != null) {
468             mNightDisplayAutoMode.onStart();
469         }
470     }
471 
onNightDisplayCustomStartTimeChanged(LocalTime startTime)472     private void onNightDisplayCustomStartTimeChanged(LocalTime startTime) {
473         Slog.d(TAG, "onNightDisplayCustomStartTimeChanged: startTime=" + startTime);
474 
475         if (mNightDisplayAutoMode != null) {
476             mNightDisplayAutoMode.onCustomStartTimeChanged(startTime);
477         }
478     }
479 
onNightDisplayCustomEndTimeChanged(LocalTime endTime)480     private void onNightDisplayCustomEndTimeChanged(LocalTime endTime) {
481         Slog.d(TAG, "onNightDisplayCustomEndTimeChanged: endTime=" + endTime);
482 
483         if (mNightDisplayAutoMode != null) {
484             mNightDisplayAutoMode.onCustomEndTimeChanged(endTime);
485         }
486     }
487 
getCompositionColorSpace(int mode)488     private int getCompositionColorSpace(int mode) {
489         if (mColorModeCompositionColorSpaces == null) {
490             return Display.COLOR_MODE_INVALID;
491         }
492 
493         return mColorModeCompositionColorSpaces.get(mode, Display.COLOR_MODE_INVALID);
494     }
495 
onDisplayColorModeChanged(int mode)496     private void onDisplayColorModeChanged(int mode) {
497         if (mode == NOT_SET) {
498             return;
499         }
500 
501         mNightDisplayTintController.cancelAnimator();
502         mDisplayWhiteBalanceTintController.cancelAnimator();
503 
504         if (mNightDisplayTintController.isAvailable(getContext())) {
505             mNightDisplayTintController
506                     .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
507             mNightDisplayTintController
508                     .setMatrix(mNightDisplayTintController.getColorTemperatureSetting());
509         }
510 
511         // dtm.setColorMode() needs to be called before
512         // updateDisplayWhiteBalanceStatus(), this is because the latter calls
513         // DisplayTransformManager.needsLinearColorMatrix(), therefore it is dependent
514         // on the state of DisplayTransformManager.
515         final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
516         dtm.setColorMode(mode, mNightDisplayTintController.getMatrix(),
517                 getCompositionColorSpace(mode));
518 
519         if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
520             updateDisplayWhiteBalanceStatus();
521         }
522     }
523 
onAccessibilityActivated()524     private void onAccessibilityActivated() {
525         onDisplayColorModeChanged(getColorModeInternal());
526     }
527 
isAccessiblityDaltonizerEnabled()528     private boolean isAccessiblityDaltonizerEnabled() {
529         return Secure.getIntForUser(getContext().getContentResolver(),
530             Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, mCurrentUser) != 0;
531     }
532 
isAccessiblityInversionEnabled()533     private boolean isAccessiblityInversionEnabled() {
534         return Secure.getIntForUser(getContext().getContentResolver(),
535             Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, mCurrentUser) != 0;
536     }
537 
isAccessibilityEnabled()538     private boolean isAccessibilityEnabled() {
539         return isAccessiblityDaltonizerEnabled() || isAccessiblityInversionEnabled();
540     }
541 
542     /**
543      * Apply the accessibility daltonizer transform based on the settings value.
544      */
onAccessibilityDaltonizerChanged()545     private void onAccessibilityDaltonizerChanged() {
546         if (mCurrentUser == UserHandle.USER_NULL) {
547             return;
548         }
549         final int daltonizerMode = isAccessiblityDaltonizerEnabled()
550                 ? Secure.getIntForUser(getContext().getContentResolver(),
551                     Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
552                     AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY, mCurrentUser)
553                 : AccessibilityManager.DALTONIZER_DISABLED;
554 
555         final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
556         if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) {
557             // Monochromacy isn't supported by the native Daltonizer implementation; use grayscale.
558             dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE,
559                     MATRIX_GRAYSCALE);
560             dtm.setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
561         } else {
562             dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE, null);
563             dtm.setDaltonizerMode(daltonizerMode);
564         }
565     }
566 
567     /**
568      * Apply the accessibility inversion transform based on the settings value.
569      */
onAccessibilityInversionChanged()570     private void onAccessibilityInversionChanged() {
571         if (mCurrentUser == UserHandle.USER_NULL) {
572             return;
573         }
574         final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
575         dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_INVERT_COLOR,
576                 isAccessiblityInversionEnabled() ? MATRIX_INVERT_COLOR : null);
577     }
578 
579     /**
580      * Applies current color temperature matrix, or removes it if deactivated.
581      *
582      * @param immediate {@code true} skips transition animation
583      */
applyTint(TintController tintController, boolean immediate)584     private void applyTint(TintController tintController, boolean immediate) {
585         tintController.cancelAnimator();
586 
587         final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
588         final float[] from = dtm.getColorMatrix(tintController.getLevel());
589         final float[] to = tintController.getMatrix();
590 
591         if (immediate) {
592             dtm.setColorMatrix(tintController.getLevel(), to);
593         } else {
594             TintValueAnimator valueAnimator = TintValueAnimator.ofMatrix(COLOR_MATRIX_EVALUATOR,
595                     from == null ? MATRIX_IDENTITY : from, to);
596             tintController.setAnimator(valueAnimator);
597             valueAnimator.setDuration(TRANSITION_DURATION);
598             valueAnimator.setInterpolator(AnimationUtils.loadInterpolator(
599                     getContext(), android.R.interpolator.fast_out_slow_in));
600             valueAnimator.addUpdateListener((ValueAnimator animator) -> {
601                 final float[] value = (float[]) animator.getAnimatedValue();
602                 dtm.setColorMatrix(tintController.getLevel(), value);
603                 ((TintValueAnimator) animator).updateMinMaxComponents();
604             });
605             valueAnimator.addListener(new AnimatorListenerAdapter() {
606 
607                 private boolean mIsCancelled;
608 
609                 @Override
610                 public void onAnimationCancel(Animator animator) {
611                     mIsCancelled = true;
612                 }
613 
614                 @Override
615                 public void onAnimationEnd(Animator animator) {
616                     TintValueAnimator t = (TintValueAnimator) animator;
617                     Slog.d(TAG, tintController.getClass().getSimpleName()
618                             + " Animation cancelled: " + mIsCancelled
619                             + " to matrix: " + TintController.matrixToString(to, 16)
620                             + " min matrix coefficients: "
621                             + TintController.matrixToString(t.getMin(), 16)
622                             + " max matrix coefficients: "
623                             + TintController.matrixToString(t.getMax(), 16));
624                     if (!mIsCancelled) {
625                         // Ensure final color matrix is set at the end of the animation. If the
626                         // animation is cancelled then don't set the final color matrix so the new
627                         // animator can pick up from where this one left off.
628                         dtm.setColorMatrix(tintController.getLevel(), to);
629                     }
630                     tintController.setAnimator(null);
631                 }
632             });
633             valueAnimator.start();
634         }
635     }
636 
637     /**
638      * Returns the first date time corresponding to the local time that occurs before the provided
639      * date time.
640      *
641      * @param compareTime the LocalDateTime to compare against
642      * @return the prior LocalDateTime corresponding to this local time
643      */
644     @VisibleForTesting
getDateTimeBefore(LocalTime localTime, LocalDateTime compareTime)645     static LocalDateTime getDateTimeBefore(LocalTime localTime, LocalDateTime compareTime) {
646         final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
647                 compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());
648 
649         // Check if the local time has passed, if so return the same time yesterday.
650         return ldt.isAfter(compareTime) ? ldt.minusDays(1) : ldt;
651     }
652 
653     /**
654      * Returns the first date time corresponding to this local time that occurs after the provided
655      * date time.
656      *
657      * @param compareTime the LocalDateTime to compare against
658      * @return the next LocalDateTime corresponding to this local time
659      */
660     @VisibleForTesting
getDateTimeAfter(LocalTime localTime, LocalDateTime compareTime)661     static LocalDateTime getDateTimeAfter(LocalTime localTime, LocalDateTime compareTime) {
662         final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
663                 compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());
664 
665         // Check if the local time has passed, if so return the same time tomorrow.
666         return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
667     }
668 
669     @VisibleForTesting
updateDisplayWhiteBalanceStatus()670     void updateDisplayWhiteBalanceStatus() {
671         boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated();
672         mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled()
673                 && !mNightDisplayTintController.isActivated()
674                 && !isAccessibilityEnabled()
675                 && DisplayTransformManager.needsLinearColorMatrix());
676         boolean activated = mDisplayWhiteBalanceTintController.isActivated();
677 
678         if (mDisplayWhiteBalanceListener != null && oldActivated != activated) {
679             mDisplayWhiteBalanceListener.onDisplayWhiteBalanceStatusChanged(activated);
680         }
681 
682         // If disabled, clear the tint. If enabled, do nothing more here and let the next
683         // temperature update set the correct tint.
684         if (!activated) {
685             mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE);
686         }
687     }
688 
setDisplayWhiteBalanceSettingEnabled(boolean enabled)689     private boolean setDisplayWhiteBalanceSettingEnabled(boolean enabled) {
690         if (mCurrentUser == UserHandle.USER_NULL) {
691             return false;
692         }
693         return Secure.putIntForUser(getContext().getContentResolver(),
694                 Secure.DISPLAY_WHITE_BALANCE_ENABLED,
695                 enabled ? 1 : 0, mCurrentUser);
696     }
697 
isDisplayWhiteBalanceSettingEnabled()698     private boolean isDisplayWhiteBalanceSettingEnabled() {
699         if (mCurrentUser == UserHandle.USER_NULL) {
700             return false;
701         }
702         return Secure.getIntForUser(getContext().getContentResolver(),
703                 Secure.DISPLAY_WHITE_BALANCE_ENABLED,
704                 getContext().getResources()
705                         .getBoolean(R.bool.config_displayWhiteBalanceEnabledDefault) ? 1
706                         : 0,
707                 mCurrentUser) == 1;
708     }
709 
isDeviceColorManagedInternal()710     private boolean isDeviceColorManagedInternal() {
711         final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
712         return dtm.isDeviceColorManaged();
713     }
714 
getTransformCapabilitiesInternal()715     private int getTransformCapabilitiesInternal() {
716         int availabilityFlags = ColorDisplayManager.CAPABILITY_NONE;
717         if (SurfaceControl.getProtectedContentSupport()) {
718             availabilityFlags |= ColorDisplayManager.CAPABILITY_PROTECTED_CONTENT;
719         }
720         final Resources res = getContext().getResources();
721         if (res.getBoolean(R.bool.config_setColorTransformAccelerated)) {
722             availabilityFlags |= ColorDisplayManager.CAPABILITY_HARDWARE_ACCELERATION_GLOBAL;
723         }
724         if (res.getBoolean(R.bool.config_setColorTransformAcceleratedPerLayer)) {
725             availabilityFlags |= ColorDisplayManager.CAPABILITY_HARDWARE_ACCELERATION_PER_APP;
726         }
727         return availabilityFlags;
728     }
729 
setNightDisplayAutoModeInternal(@utoMode int autoMode)730     private boolean setNightDisplayAutoModeInternal(@AutoMode int autoMode) {
731         if (getNightDisplayAutoModeInternal() != autoMode) {
732             Secure.putStringForUser(getContext().getContentResolver(),
733                     Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
734                     null,
735                     mCurrentUser);
736         }
737         return Secure.putIntForUser(getContext().getContentResolver(),
738                 Secure.NIGHT_DISPLAY_AUTO_MODE, autoMode, mCurrentUser);
739     }
740 
getNightDisplayAutoModeInternal()741     private int getNightDisplayAutoModeInternal() {
742         int autoMode = getNightDisplayAutoModeRawInternal();
743         if (autoMode == NOT_SET) {
744             autoMode = getContext().getResources().getInteger(
745                     R.integer.config_defaultNightDisplayAutoMode);
746         }
747         if (autoMode != AUTO_MODE_DISABLED
748                 && autoMode != AUTO_MODE_CUSTOM_TIME
749                 && autoMode != AUTO_MODE_TWILIGHT) {
750             Slog.e(TAG, "Invalid autoMode: " + autoMode);
751             autoMode = AUTO_MODE_DISABLED;
752         }
753         return autoMode;
754     }
755 
getNightDisplayAutoModeRawInternal()756     private int getNightDisplayAutoModeRawInternal() {
757         if (mCurrentUser == UserHandle.USER_NULL) {
758             return NOT_SET;
759         }
760         return Secure
761                 .getIntForUser(getContext().getContentResolver(), Secure.NIGHT_DISPLAY_AUTO_MODE,
762                         NOT_SET, mCurrentUser);
763     }
764 
getNightDisplayCustomStartTimeInternal()765     private Time getNightDisplayCustomStartTimeInternal() {
766         int startTimeValue = Secure.getIntForUser(getContext().getContentResolver(),
767                 Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, NOT_SET, mCurrentUser);
768         if (startTimeValue == NOT_SET) {
769             startTimeValue = getContext().getResources().getInteger(
770                     R.integer.config_defaultNightDisplayCustomStartTime);
771         }
772         return new Time(LocalTime.ofSecondOfDay(startTimeValue / 1000));
773     }
774 
setNightDisplayCustomStartTimeInternal(Time startTime)775     private boolean setNightDisplayCustomStartTimeInternal(Time startTime) {
776         return Secure.putIntForUser(getContext().getContentResolver(),
777                 Secure.NIGHT_DISPLAY_CUSTOM_START_TIME,
778                 startTime.getLocalTime().toSecondOfDay() * 1000,
779                 mCurrentUser);
780     }
781 
getNightDisplayCustomEndTimeInternal()782     private Time getNightDisplayCustomEndTimeInternal() {
783         int endTimeValue = Secure.getIntForUser(getContext().getContentResolver(),
784                 Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, NOT_SET, mCurrentUser);
785         if (endTimeValue == NOT_SET) {
786             endTimeValue = getContext().getResources().getInteger(
787                     R.integer.config_defaultNightDisplayCustomEndTime);
788         }
789         return new Time(LocalTime.ofSecondOfDay(endTimeValue / 1000));
790     }
791 
setNightDisplayCustomEndTimeInternal(Time endTime)792     private boolean setNightDisplayCustomEndTimeInternal(Time endTime) {
793         return Secure.putIntForUser(getContext().getContentResolver(),
794                 Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.getLocalTime().toSecondOfDay() * 1000,
795                 mCurrentUser);
796     }
797 
798     /**
799      * Returns the last time the night display transform activation state was changed, or {@link
800      * LocalDateTime#MIN} if night display has never been activated.
801      */
getNightDisplayLastActivatedTimeSetting()802     private LocalDateTime getNightDisplayLastActivatedTimeSetting() {
803         final ContentResolver cr = getContext().getContentResolver();
804         final String lastActivatedTime = Secure.getStringForUser(
805                 cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, getContext().getUserId());
806         if (lastActivatedTime != null) {
807             try {
808                 return LocalDateTime.parse(lastActivatedTime);
809             } catch (DateTimeParseException ignored) {
810             }
811             // Uses the old epoch time.
812             try {
813                 return LocalDateTime.ofInstant(
814                         Instant.ofEpochMilli(Long.parseLong(lastActivatedTime)),
815                         ZoneId.systemDefault());
816             } catch (DateTimeException | NumberFormatException ignored) {
817             }
818         }
819         return LocalDateTime.MIN;
820     }
821 
setAppSaturationLevelInternal(String callingPackageName, String affectedPackageName, int saturationLevel)822     private boolean setAppSaturationLevelInternal(String callingPackageName,
823             String affectedPackageName, int saturationLevel) {
824         return mAppSaturationController
825                 .setSaturationLevel(callingPackageName, affectedPackageName, mCurrentUser,
826                         saturationLevel);
827     }
828 
setColorModeInternal(@olorMode int colorMode)829     private void setColorModeInternal(@ColorMode int colorMode) {
830         if (!isColorModeAvailable(colorMode)) {
831             throw new IllegalArgumentException("Invalid colorMode: " + colorMode);
832         }
833         System.putIntForUser(getContext().getContentResolver(), System.DISPLAY_COLOR_MODE,
834                 colorMode,
835                 mCurrentUser);
836     }
837 
getColorModeInternal()838     private @ColorMode int getColorModeInternal() {
839         final ContentResolver cr = getContext().getContentResolver();
840         if (isAccessibilityEnabled()) {
841             // There are restrictions on the available color modes combined with a11y transforms.
842             final int a11yColorMode = getContext().getResources().getInteger(
843                     R.integer.config_accessibilityColorMode);
844             if (a11yColorMode >= 0) {
845                 return a11yColorMode;
846             }
847         }
848 
849         int colorMode = System.getIntForUser(cr, System.DISPLAY_COLOR_MODE, -1, mCurrentUser);
850         if (colorMode == -1) {
851             // There might be a system property controlling color mode that we need to respect; if
852             // not, this will set a suitable default.
853             colorMode = getCurrentColorModeFromSystemProperties();
854         }
855 
856         // This happens when a color mode is no longer available (e.g., after system update or B&R)
857         // or the device does not support any color mode.
858         if (!isColorModeAvailable(colorMode)) {
859             if (colorMode == COLOR_MODE_BOOSTED && isColorModeAvailable(COLOR_MODE_NATURAL)) {
860                 colorMode = COLOR_MODE_NATURAL;
861             } else if (colorMode == COLOR_MODE_SATURATED
862                     && isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
863                 colorMode = COLOR_MODE_AUTOMATIC;
864             } else if (colorMode == COLOR_MODE_AUTOMATIC
865                     && isColorModeAvailable(COLOR_MODE_SATURATED)) {
866                 colorMode = COLOR_MODE_SATURATED;
867             } else {
868                 colorMode = -1;
869             }
870         }
871 
872         return colorMode;
873     }
874 
875     /**
876      * Get the current color mode from system properties, or return -1 if invalid.
877      *
878      * See {@link DisplayTransformManager}
879      */
getCurrentColorModeFromSystemProperties()880     private @ColorMode int getCurrentColorModeFromSystemProperties() {
881         final int displayColorSetting = SystemProperties.getInt("persist.sys.sf.native_mode", 0);
882         if (displayColorSetting == 0) {
883             return "1.0".equals(SystemProperties.get("persist.sys.sf.color_saturation"))
884                     ? COLOR_MODE_NATURAL : COLOR_MODE_BOOSTED;
885         } else if (displayColorSetting == 1) {
886             return COLOR_MODE_SATURATED;
887         } else if (displayColorSetting == 2) {
888             return COLOR_MODE_AUTOMATIC;
889         } else if (displayColorSetting >= VENDOR_COLOR_MODE_RANGE_MIN
890                 && displayColorSetting <= VENDOR_COLOR_MODE_RANGE_MAX) {
891             return displayColorSetting;
892         } else {
893             return -1;
894         }
895     }
896 
isColorModeAvailable(@olorMode int colorMode)897     private boolean isColorModeAvailable(@ColorMode int colorMode) {
898         final int[] availableColorModes = getContext().getResources().getIntArray(
899                 R.array.config_availableColorModes);
900         if (availableColorModes != null) {
901             for (int mode : availableColorModes) {
902                 if (mode == colorMode) {
903                     return true;
904                 }
905             }
906         }
907         return false;
908     }
909 
dumpInternal(PrintWriter pw)910     private void dumpInternal(PrintWriter pw) {
911         pw.println("COLOR DISPLAY MANAGER dumpsys (color_display)");
912 
913         pw.println("Night display:");
914         if (mNightDisplayTintController.isAvailable(getContext())) {
915             pw.println("    Activated: " + mNightDisplayTintController.isActivated());
916             pw.println("    Color temp: " + mNightDisplayTintController.getColorTemperature());
917         } else {
918             pw.println("    Not available");
919         }
920 
921         pw.println("Global saturation:");
922         if (mGlobalSaturationTintController.isAvailable(getContext())) {
923             pw.println("    Activated: " + mGlobalSaturationTintController.isActivated());
924         } else {
925             pw.println("    Not available");
926         }
927 
928         mAppSaturationController.dump(pw);
929 
930         pw.println("Display white balance:");
931         if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
932             pw.println("    Activated: " + mDisplayWhiteBalanceTintController.isActivated());
933             mDisplayWhiteBalanceTintController.dump(pw);
934         } else {
935             pw.println("    Not available");
936         }
937 
938         pw.println("Color mode: " + getColorModeInternal());
939     }
940 
941     private abstract class NightDisplayAutoMode {
942 
onActivated(boolean activated)943         public abstract void onActivated(boolean activated);
944 
onStart()945         public abstract void onStart();
946 
onStop()947         public abstract void onStop();
948 
onCustomStartTimeChanged(LocalTime startTime)949         public void onCustomStartTimeChanged(LocalTime startTime) {
950         }
951 
onCustomEndTimeChanged(LocalTime endTime)952         public void onCustomEndTimeChanged(LocalTime endTime) {
953         }
954     }
955 
956     private final class CustomNightDisplayAutoMode extends NightDisplayAutoMode implements
957             AlarmManager.OnAlarmListener {
958 
959         private final AlarmManager mAlarmManager;
960         private final BroadcastReceiver mTimeChangedReceiver;
961 
962         private LocalTime mStartTime;
963         private LocalTime mEndTime;
964 
965         private LocalDateTime mLastActivatedTime;
966 
CustomNightDisplayAutoMode()967         CustomNightDisplayAutoMode() {
968             mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
969             mTimeChangedReceiver = new BroadcastReceiver() {
970                 @Override
971                 public void onReceive(Context context, Intent intent) {
972                     updateActivated();
973                 }
974             };
975         }
976 
updateActivated()977         private void updateActivated() {
978             final LocalDateTime now = LocalDateTime.now();
979             final LocalDateTime start = getDateTimeBefore(mStartTime, now);
980             final LocalDateTime end = getDateTimeAfter(mEndTime, start);
981             boolean activate = now.isBefore(end);
982 
983             if (mLastActivatedTime != null) {
984                 // Maintain the existing activated state if within the current period.
985                 if (mLastActivatedTime.isBefore(now)
986                         && mLastActivatedTime.isAfter(start)
987                         && (mLastActivatedTime.isAfter(end) || now.isBefore(end))) {
988                     activate = mNightDisplayTintController.isActivatedSetting();
989                 }
990             }
991 
992             if (mNightDisplayTintController.isActivatedStateNotSet()
993                     || (mNightDisplayTintController.isActivated() != activate)) {
994                 mNightDisplayTintController.setActivated(activate, activate ? start : end);
995             }
996 
997             updateNextAlarm(mNightDisplayTintController.isActivated(), now);
998         }
999 
updateNextAlarm(@ullable Boolean activated, @NonNull LocalDateTime now)1000         private void updateNextAlarm(@Nullable Boolean activated, @NonNull LocalDateTime now) {
1001             if (activated != null) {
1002                 final LocalDateTime next = activated ? getDateTimeAfter(mEndTime, now)
1003                         : getDateTimeAfter(mStartTime, now);
1004                 final long millis = next.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
1005                 mAlarmManager.setExact(AlarmManager.RTC, millis, TAG, this, null);
1006             }
1007         }
1008 
1009         @Override
onStart()1010         public void onStart() {
1011             final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_TIME_CHANGED);
1012             intentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
1013             getContext().registerReceiver(mTimeChangedReceiver, intentFilter);
1014 
1015             mStartTime = getNightDisplayCustomStartTimeInternal().getLocalTime();
1016             mEndTime = getNightDisplayCustomEndTimeInternal().getLocalTime();
1017 
1018             mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
1019 
1020             // Force an update to initialize state.
1021             updateActivated();
1022         }
1023 
1024         @Override
onStop()1025         public void onStop() {
1026             getContext().unregisterReceiver(mTimeChangedReceiver);
1027 
1028             mAlarmManager.cancel(this);
1029             mLastActivatedTime = null;
1030         }
1031 
1032         @Override
onActivated(boolean activated)1033         public void onActivated(boolean activated) {
1034             mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
1035             updateNextAlarm(activated, LocalDateTime.now());
1036         }
1037 
1038         @Override
onCustomStartTimeChanged(LocalTime startTime)1039         public void onCustomStartTimeChanged(LocalTime startTime) {
1040             mStartTime = startTime;
1041             mLastActivatedTime = null;
1042             updateActivated();
1043         }
1044 
1045         @Override
onCustomEndTimeChanged(LocalTime endTime)1046         public void onCustomEndTimeChanged(LocalTime endTime) {
1047             mEndTime = endTime;
1048             mLastActivatedTime = null;
1049             updateActivated();
1050         }
1051 
1052         @Override
onAlarm()1053         public void onAlarm() {
1054             Slog.d(TAG, "onAlarm");
1055             updateActivated();
1056         }
1057     }
1058 
1059     private final class TwilightNightDisplayAutoMode extends NightDisplayAutoMode implements
1060             TwilightListener {
1061 
1062         private final TwilightManager mTwilightManager;
1063         private LocalDateTime mLastActivatedTime;
1064 
TwilightNightDisplayAutoMode()1065         TwilightNightDisplayAutoMode() {
1066             mTwilightManager = getLocalService(TwilightManager.class);
1067         }
1068 
updateActivated(TwilightState state)1069         private void updateActivated(TwilightState state) {
1070             if (state == null) {
1071                 // If there isn't a valid TwilightState then just keep the current activated
1072                 // state.
1073                 return;
1074             }
1075 
1076             boolean activate = state.isNight();
1077             if (mLastActivatedTime != null) {
1078                 final LocalDateTime now = LocalDateTime.now();
1079                 final LocalDateTime sunrise = state.sunrise();
1080                 final LocalDateTime sunset = state.sunset();
1081                 // Maintain the existing activated state if within the current period.
1082                 if (mLastActivatedTime.isBefore(now) && (mLastActivatedTime.isBefore(sunrise)
1083                         ^ mLastActivatedTime.isBefore(sunset))) {
1084                     activate = mNightDisplayTintController.isActivatedSetting();
1085                 }
1086             }
1087 
1088             if (mNightDisplayTintController.isActivatedStateNotSet() || (
1089                     mNightDisplayTintController.isActivated() != activate)) {
1090                 mNightDisplayTintController.setActivated(activate);
1091             }
1092         }
1093 
1094         @Override
onActivated(boolean activated)1095         public void onActivated(boolean activated) {
1096             mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
1097         }
1098 
1099         @Override
onStart()1100         public void onStart() {
1101             mTwilightManager.registerListener(this, mHandler);
1102             mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
1103 
1104             // Force an update to initialize state.
1105             updateActivated(mTwilightManager.getLastTwilightState());
1106         }
1107 
1108         @Override
onStop()1109         public void onStop() {
1110             mTwilightManager.unregisterListener(this);
1111             mLastActivatedTime = null;
1112         }
1113 
1114         @Override
onTwilightStateChanged(@ullable TwilightState state)1115         public void onTwilightStateChanged(@Nullable TwilightState state) {
1116             Slog.d(TAG, "onTwilightStateChanged: isNight="
1117                     + (state == null ? null : state.isNight()));
1118             updateActivated(state);
1119         }
1120     }
1121 
1122     /**
1123      * Only animates matrices and saves min and max coefficients for logging.
1124      */
1125     static class TintValueAnimator extends ValueAnimator {
1126         private float[] min;
1127         private float[] max;
1128 
ofMatrix(ColorMatrixEvaluator evaluator, Object... values)1129         public static TintValueAnimator ofMatrix(ColorMatrixEvaluator evaluator,
1130                 Object... values) {
1131             TintValueAnimator anim = new TintValueAnimator();
1132             anim.setObjectValues(values);
1133             anim.setEvaluator(evaluator);
1134             if (values == null || values.length == 0) {
1135                 return null;
1136             }
1137             float[] m = (float[]) values[0];
1138             anim.min = new float[m.length];
1139             anim.max = new float[m.length];
1140             for (int i = 0; i < m.length; ++i) {
1141                 anim.min[i] = Float.MAX_VALUE;
1142                 anim.max[i] = Float.MIN_VALUE;
1143             }
1144             return anim;
1145         }
1146 
updateMinMaxComponents()1147         public void updateMinMaxComponents() {
1148             float[] value = (float[]) getAnimatedValue();
1149             if (value == null) {
1150                 return;
1151             }
1152             for (int i = 0; i < value.length; ++i) {
1153                 min[i] = Math.min(min[i], value[i]);
1154                 max[i] = Math.max(max[i], value[i]);
1155             }
1156         }
1157 
getMin()1158         public float[] getMin() {
1159             return min;
1160         }
1161 
getMax()1162         public float[] getMax() {
1163             return max;
1164         }
1165     }
1166 
1167     /**
1168      * Interpolates between two 4x4 color transform matrices (in column-major order).
1169      */
1170     private static class ColorMatrixEvaluator implements TypeEvaluator<float[]> {
1171 
1172         /**
1173          * Result matrix returned by {@link #evaluate(float, float[], float[])}.
1174          */
1175         private final float[] mResultMatrix = new float[16];
1176 
1177         @Override
evaluate(float fraction, float[] startValue, float[] endValue)1178         public float[] evaluate(float fraction, float[] startValue, float[] endValue) {
1179             for (int i = 0; i < mResultMatrix.length; i++) {
1180                 mResultMatrix[i] = MathUtils.lerp(startValue[i], endValue[i], fraction);
1181             }
1182             return mResultMatrix;
1183         }
1184     }
1185 
1186     private final class NightDisplayTintController extends TintController {
1187 
1188         private final float[] mMatrix = new float[16];
1189         private final float[] mColorTempCoefficients = new float[9];
1190 
1191         private Boolean mIsAvailable;
1192         private Integer mColorTemp;
1193 
1194         /**
1195          * Set coefficients based on whether the color matrix is linear or not.
1196          */
1197         @Override
setUp(Context context, boolean needsLinear)1198         public void setUp(Context context, boolean needsLinear) {
1199             final String[] coefficients = context.getResources().getStringArray(needsLinear
1200                     ? R.array.config_nightDisplayColorTemperatureCoefficients
1201                     : R.array.config_nightDisplayColorTemperatureCoefficientsNative);
1202             for (int i = 0; i < 9 && i < coefficients.length; i++) {
1203                 mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]);
1204             }
1205         }
1206 
1207         @Override
setMatrix(int cct)1208         public void setMatrix(int cct) {
1209             if (mMatrix.length != 16) {
1210                 Slog.d(TAG, "The display transformation matrix must be 4x4");
1211                 return;
1212             }
1213 
1214             Matrix.setIdentityM(mMatrix, 0);
1215 
1216             final float squareTemperature = cct * cct;
1217             final float red = squareTemperature * mColorTempCoefficients[0]
1218                     + cct * mColorTempCoefficients[1] + mColorTempCoefficients[2];
1219             final float green = squareTemperature * mColorTempCoefficients[3]
1220                     + cct * mColorTempCoefficients[4] + mColorTempCoefficients[5];
1221             final float blue = squareTemperature * mColorTempCoefficients[6]
1222                     + cct * mColorTempCoefficients[7] + mColorTempCoefficients[8];
1223             mMatrix[0] = red;
1224             mMatrix[5] = green;
1225             mMatrix[10] = blue;
1226         }
1227 
1228         @Override
getMatrix()1229         public float[] getMatrix() {
1230             return isActivated() ? mMatrix : MATRIX_IDENTITY;
1231         }
1232 
1233         @Override
setActivated(Boolean activated)1234         public void setActivated(Boolean activated) {
1235             setActivated(activated, LocalDateTime.now());
1236         }
1237 
1238         /**
1239          * Use directly when it is important that the last activation time be exact (for example, an
1240          * automatic change). Otherwise use {@link #setActivated(Boolean)}.
1241          */
setActivated(Boolean activated, @NonNull LocalDateTime lastActivationTime)1242         public void setActivated(Boolean activated, @NonNull LocalDateTime lastActivationTime) {
1243             if (activated == null) {
1244                 super.setActivated(null);
1245                 return;
1246             }
1247 
1248             boolean activationStateChanged = activated != isActivated();
1249 
1250             if (!isActivatedStateNotSet() && activationStateChanged) {
1251                 // This is a true state change, so set this as the last activation time.
1252                 Secure.putStringForUser(getContext().getContentResolver(),
1253                         Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
1254                         lastActivationTime.toString(),
1255                         mCurrentUser);
1256             }
1257 
1258             if (isActivatedStateNotSet() || activationStateChanged) {
1259                 super.setActivated(activated);
1260                 if (isActivatedSetting() != activated) {
1261                     Secure.putIntForUser(getContext().getContentResolver(),
1262                             Secure.NIGHT_DISPLAY_ACTIVATED,
1263                             activated ? 1 : 0, mCurrentUser);
1264                 }
1265                 onActivated(activated);
1266             }
1267         }
1268 
1269         @Override
getLevel()1270         public int getLevel() {
1271             return LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
1272         }
1273 
1274         @Override
isAvailable(Context context)1275         public boolean isAvailable(Context context) {
1276             if (mIsAvailable == null) {
1277                 mIsAvailable = ColorDisplayManager.isNightDisplayAvailable(context);
1278             }
1279             return mIsAvailable;
1280         }
1281 
onActivated(boolean activated)1282         private void onActivated(boolean activated) {
1283             Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display");
1284             if (mNightDisplayAutoMode != null) {
1285                 mNightDisplayAutoMode.onActivated(activated);
1286             }
1287 
1288             if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
1289                 updateDisplayWhiteBalanceStatus();
1290             }
1291 
1292             mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_ANIMATED);
1293         }
1294 
getColorTemperature()1295         int getColorTemperature() {
1296             return mColorTemp != null ? clampNightDisplayColorTemperature(mColorTemp)
1297                     : getColorTemperatureSetting();
1298         }
1299 
setColorTemperature(int temperature)1300         boolean setColorTemperature(int temperature) {
1301             mColorTemp = temperature;
1302             final boolean success = Secure.putIntForUser(getContext().getContentResolver(),
1303                     Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, temperature, mCurrentUser);
1304             onColorTemperatureChanged(temperature);
1305             return success;
1306         }
1307 
onColorTemperatureChanged(int temperature)1308         void onColorTemperatureChanged(int temperature) {
1309             setMatrix(temperature);
1310             mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE);
1311         }
1312 
isActivatedSetting()1313         boolean isActivatedSetting() {
1314             if (mCurrentUser == UserHandle.USER_NULL) {
1315                 return false;
1316             }
1317             return Secure.getIntForUser(getContext().getContentResolver(),
1318                     Secure.NIGHT_DISPLAY_ACTIVATED, 0, mCurrentUser) == 1;
1319         }
1320 
getColorTemperatureSetting()1321         int getColorTemperatureSetting() {
1322             if (mCurrentUser == UserHandle.USER_NULL) {
1323                 return NOT_SET;
1324             }
1325             return clampNightDisplayColorTemperature(Secure.getIntForUser(
1326                     getContext().getContentResolver(), Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE,
1327                     NOT_SET,
1328                     mCurrentUser));
1329         }
1330 
clampNightDisplayColorTemperature(int colorTemperature)1331         private int clampNightDisplayColorTemperature(int colorTemperature) {
1332             if (colorTemperature == NOT_SET) {
1333                 colorTemperature = getContext().getResources().getInteger(
1334                         R.integer.config_nightDisplayColorTemperatureDefault);
1335             }
1336             final int minimumTemperature = ColorDisplayManager
1337                     .getMinimumColorTemperature(getContext());
1338             final int maximumTemperature = ColorDisplayManager
1339                     .getMaximumColorTemperature(getContext());
1340             if (colorTemperature < minimumTemperature) {
1341                 colorTemperature = minimumTemperature;
1342             } else if (colorTemperature > maximumTemperature) {
1343                 colorTemperature = maximumTemperature;
1344             }
1345 
1346             return colorTemperature;
1347         }
1348     }
1349 
1350     /**
1351      * Local service that allows color transforms to be enabled from other system services.
1352      */
1353     public final class ColorDisplayServiceInternal {
1354 
1355         /**
1356          * Set the current CCT value for the display white balance transform, and if the transform
1357          * is enabled, apply it.
1358          *
1359          * @param cct the color temperature in Kelvin.
1360          */
setDisplayWhiteBalanceColorTemperature(int cct)1361         public boolean setDisplayWhiteBalanceColorTemperature(int cct) {
1362             // Update the transform matrix even if it can't be applied.
1363             mDisplayWhiteBalanceTintController.setMatrix(cct);
1364 
1365             if (mDisplayWhiteBalanceTintController.isActivated()) {
1366                 mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE);
1367                 return true;
1368             }
1369             return false;
1370         }
1371 
1372         /**
1373          * Reset the CCT value for the display white balance transform to its default value.
1374          */
resetDisplayWhiteBalanceColorTemperature()1375         public boolean resetDisplayWhiteBalanceColorTemperature() {
1376             int temperatureDefault = getContext().getResources()
1377                     .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault);
1378             Slog.d(TAG, "resetDisplayWhiteBalanceColorTemperature: " + temperatureDefault);
1379             return setDisplayWhiteBalanceColorTemperature(temperatureDefault);
1380         }
1381 
1382         /**
1383          * Sets the listener and returns whether display white balance is currently enabled.
1384          */
setDisplayWhiteBalanceListener(DisplayWhiteBalanceListener listener)1385         public boolean setDisplayWhiteBalanceListener(DisplayWhiteBalanceListener listener) {
1386             mDisplayWhiteBalanceListener = listener;
1387             return mDisplayWhiteBalanceTintController.isActivated();
1388         }
1389 
1390         /**
1391          * Returns whether Display white balance is currently enabled.
1392          */
isDisplayWhiteBalanceEnabled()1393         public boolean isDisplayWhiteBalanceEnabled() {
1394             return isDisplayWhiteBalanceSettingEnabled();
1395         }
1396 
1397         /**
1398          * Adds a {@link WeakReference<ColorTransformController>} for a newly started activity, and
1399          * invokes {@link ColorTransformController#applyAppSaturation(float[], float[])} if needed.
1400          */
attachColorTransformController(String packageName, @UserIdInt int userId, WeakReference<ColorTransformController> controller)1401         public boolean attachColorTransformController(String packageName, @UserIdInt int userId,
1402                 WeakReference<ColorTransformController> controller) {
1403             return mAppSaturationController
1404                     .addColorTransformController(packageName, userId, controller);
1405         }
1406     }
1407 
1408     /**
1409      * Listener for changes in display white balance status.
1410      */
1411     public interface DisplayWhiteBalanceListener {
1412 
1413         /**
1414          * Notify that the display white balance status has changed, either due to preemption by
1415          * another transform or the feature being turned off.
1416          */
onDisplayWhiteBalanceStatusChanged(boolean activated)1417         void onDisplayWhiteBalanceStatusChanged(boolean activated);
1418     }
1419 
1420     private final class TintHandler extends Handler {
1421 
TintHandler(Looper looper)1422         private TintHandler(Looper looper) {
1423             super(looper, null, true /* async */);
1424         }
1425 
1426         @Override
handleMessage(Message msg)1427         public void handleMessage(Message msg) {
1428             switch (msg.what) {
1429                 case MSG_USER_CHANGED:
1430                     onUserChanged(msg.arg1);
1431                     break;
1432                 case MSG_SET_UP:
1433                     setUp();
1434                     break;
1435                 case MSG_APPLY_GLOBAL_SATURATION:
1436                     mGlobalSaturationTintController.setMatrix(msg.arg1);
1437                     applyTint(mGlobalSaturationTintController, false);
1438                     break;
1439                 case MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE:
1440                     applyTint(mNightDisplayTintController, true);
1441                     break;
1442                 case MSG_APPLY_NIGHT_DISPLAY_ANIMATED:
1443                     applyTint(mNightDisplayTintController, false);
1444                     break;
1445                 case MSG_APPLY_DISPLAY_WHITE_BALANCE:
1446                     applyTint(mDisplayWhiteBalanceTintController, false);
1447                     break;
1448             }
1449         }
1450     }
1451 
1452     /**
1453      * Interface for applying transforms to a given AppWindow.
1454      */
1455     public interface ColorTransformController {
1456 
1457         /**
1458          * Apply the given saturation (grayscale) matrix to the associated AppWindow.
1459          */
applyAppSaturation(@ize9) float[] matrix, @Size(3) float[] translation)1460         void applyAppSaturation(@Size(9) float[] matrix, @Size(3) float[] translation);
1461     }
1462 
1463     @VisibleForTesting
1464     final class BinderService extends IColorDisplayManager.Stub {
1465 
1466         @Override
setColorMode(int colorMode)1467         public void setColorMode(int colorMode) {
1468             getContext().enforceCallingOrSelfPermission(
1469                     Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1470                     "Permission required to set display color mode");
1471             final long token = Binder.clearCallingIdentity();
1472             try {
1473                 setColorModeInternal(colorMode);
1474             } finally {
1475                 Binder.restoreCallingIdentity(token);
1476             }
1477         }
1478 
1479         @Override
getColorMode()1480         public int getColorMode() {
1481             final long token = Binder.clearCallingIdentity();
1482             try {
1483                 return getColorModeInternal();
1484             } finally {
1485                 Binder.restoreCallingIdentity(token);
1486             }
1487         }
1488 
1489         @Override
isDeviceColorManaged()1490         public boolean isDeviceColorManaged() {
1491             final long token = Binder.clearCallingIdentity();
1492             try {
1493                 return isDeviceColorManagedInternal();
1494             } finally {
1495                 Binder.restoreCallingIdentity(token);
1496             }
1497         }
1498 
1499         @Override
setSaturationLevel(int level)1500         public boolean setSaturationLevel(int level) {
1501             final boolean hasTransformsPermission = getContext()
1502                     .checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
1503                     == PackageManager.PERMISSION_GRANTED;
1504             final boolean hasLegacyPermission = getContext()
1505                     .checkCallingPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION)
1506                     == PackageManager.PERMISSION_GRANTED;
1507             if (!hasTransformsPermission && !hasLegacyPermission) {
1508                 throw new SecurityException("Permission required to set display saturation level");
1509             }
1510             final long token = Binder.clearCallingIdentity();
1511             try {
1512                 final Message message = mHandler.obtainMessage(MSG_APPLY_GLOBAL_SATURATION);
1513                 message.arg1 = level;
1514                 mHandler.sendMessage(message);
1515             } finally {
1516                 Binder.restoreCallingIdentity(token);
1517             }
1518             return true;
1519         }
1520 
1521         @Override
isSaturationActivated()1522         public boolean isSaturationActivated() {
1523             getContext().enforceCallingPermission(
1524                     Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1525                     "Permission required to get display saturation level");
1526             final long token = Binder.clearCallingIdentity();
1527             try {
1528                 return !mGlobalSaturationTintController.isActivatedStateNotSet()
1529                         && mGlobalSaturationTintController.isActivated();
1530             } finally {
1531                 Binder.restoreCallingIdentity(token);
1532             }
1533         }
1534 
1535         @Override
setAppSaturationLevel(String packageName, int level)1536         public boolean setAppSaturationLevel(String packageName, int level) {
1537             getContext().enforceCallingPermission(
1538                     Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1539                     "Permission required to set display saturation level");
1540             final String callingPackageName = LocalServices.getService(PackageManagerInternal.class)
1541                     .getNameForUid(Binder.getCallingUid());
1542             final long token = Binder.clearCallingIdentity();
1543             try {
1544                 return setAppSaturationLevelInternal(callingPackageName, packageName, level);
1545             } finally {
1546                 Binder.restoreCallingIdentity(token);
1547             }
1548         }
1549 
getTransformCapabilities()1550         public int getTransformCapabilities() {
1551             getContext().enforceCallingPermission(
1552                     Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1553                     "Permission required to query transform capabilities");
1554             final long token = Binder.clearCallingIdentity();
1555             try {
1556                 return getTransformCapabilitiesInternal();
1557             } finally {
1558                 Binder.restoreCallingIdentity(token);
1559             }
1560         }
1561 
1562         @Override
setNightDisplayActivated(boolean activated)1563         public boolean setNightDisplayActivated(boolean activated) {
1564             getContext().enforceCallingOrSelfPermission(
1565                     Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1566                     "Permission required to set night display activated");
1567             final long token = Binder.clearCallingIdentity();
1568             try {
1569                 mNightDisplayTintController.setActivated(activated);
1570                 return true;
1571             } finally {
1572                 Binder.restoreCallingIdentity(token);
1573             }
1574         }
1575 
1576         @Override
isNightDisplayActivated()1577         public boolean isNightDisplayActivated() {
1578             final long token = Binder.clearCallingIdentity();
1579             try {
1580                 return mNightDisplayTintController.isActivated();
1581             } finally {
1582                 Binder.restoreCallingIdentity(token);
1583             }
1584         }
1585 
1586         @Override
setNightDisplayColorTemperature(int temperature)1587         public boolean setNightDisplayColorTemperature(int temperature) {
1588             getContext().enforceCallingOrSelfPermission(
1589                     Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1590                     "Permission required to set night display temperature");
1591             final long token = Binder.clearCallingIdentity();
1592             try {
1593                 return mNightDisplayTintController.setColorTemperature(temperature);
1594             } finally {
1595                 Binder.restoreCallingIdentity(token);
1596             }
1597         }
1598 
1599         @Override
getNightDisplayColorTemperature()1600         public int getNightDisplayColorTemperature() {
1601             final long token = Binder.clearCallingIdentity();
1602             try {
1603                 return mNightDisplayTintController.getColorTemperature();
1604             } finally {
1605                 Binder.restoreCallingIdentity(token);
1606             }
1607         }
1608 
1609         @Override
setNightDisplayAutoMode(int autoMode)1610         public boolean setNightDisplayAutoMode(int autoMode) {
1611             getContext().enforceCallingOrSelfPermission(
1612                     Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1613                     "Permission required to set night display auto mode");
1614             final long token = Binder.clearCallingIdentity();
1615             try {
1616                 return setNightDisplayAutoModeInternal(autoMode);
1617             } finally {
1618                 Binder.restoreCallingIdentity(token);
1619             }
1620         }
1621 
1622         @Override
getNightDisplayAutoMode()1623         public int getNightDisplayAutoMode() {
1624             getContext().enforceCallingOrSelfPermission(
1625                     Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1626                     "Permission required to get night display auto mode");
1627             final long token = Binder.clearCallingIdentity();
1628             try {
1629                 return getNightDisplayAutoModeInternal();
1630             } finally {
1631                 Binder.restoreCallingIdentity(token);
1632             }
1633         }
1634 
1635         @Override
getNightDisplayAutoModeRaw()1636         public int getNightDisplayAutoModeRaw() {
1637             final long token = Binder.clearCallingIdentity();
1638             try {
1639                 return getNightDisplayAutoModeRawInternal();
1640             } finally {
1641                 Binder.restoreCallingIdentity(token);
1642             }
1643         }
1644 
1645         @Override
setNightDisplayCustomStartTime(Time startTime)1646         public boolean setNightDisplayCustomStartTime(Time startTime) {
1647             getContext().enforceCallingOrSelfPermission(
1648                     Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1649                     "Permission required to set night display custom start time");
1650             final long token = Binder.clearCallingIdentity();
1651             try {
1652                 return setNightDisplayCustomStartTimeInternal(startTime);
1653             } finally {
1654                 Binder.restoreCallingIdentity(token);
1655             }
1656         }
1657 
1658         @Override
getNightDisplayCustomStartTime()1659         public Time getNightDisplayCustomStartTime() {
1660             final long token = Binder.clearCallingIdentity();
1661             try {
1662                 return getNightDisplayCustomStartTimeInternal();
1663             } finally {
1664                 Binder.restoreCallingIdentity(token);
1665             }
1666         }
1667 
1668         @Override
setNightDisplayCustomEndTime(Time endTime)1669         public boolean setNightDisplayCustomEndTime(Time endTime) {
1670             getContext().enforceCallingOrSelfPermission(
1671                     Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1672                     "Permission required to set night display custom end time");
1673             final long token = Binder.clearCallingIdentity();
1674             try {
1675                 return setNightDisplayCustomEndTimeInternal(endTime);
1676             } finally {
1677                 Binder.restoreCallingIdentity(token);
1678             }
1679         }
1680 
1681         @Override
getNightDisplayCustomEndTime()1682         public Time getNightDisplayCustomEndTime() {
1683             final long token = Binder.clearCallingIdentity();
1684             try {
1685                 return getNightDisplayCustomEndTimeInternal();
1686             } finally {
1687                 Binder.restoreCallingIdentity(token);
1688             }
1689         }
1690 
1691         @Override
setDisplayWhiteBalanceEnabled(boolean enabled)1692         public boolean setDisplayWhiteBalanceEnabled(boolean enabled) {
1693             getContext().enforceCallingOrSelfPermission(
1694                     Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
1695                     "Permission required to set night display activated");
1696             final long token = Binder.clearCallingIdentity();
1697             try {
1698                 return setDisplayWhiteBalanceSettingEnabled(enabled);
1699             } finally {
1700                 Binder.restoreCallingIdentity(token);
1701             }
1702         }
1703 
1704         @Override
isDisplayWhiteBalanceEnabled()1705         public boolean isDisplayWhiteBalanceEnabled() {
1706             final long token = Binder.clearCallingIdentity();
1707             try {
1708                 return isDisplayWhiteBalanceSettingEnabled();
1709             } finally {
1710                 Binder.restoreCallingIdentity(token);
1711             }
1712         }
1713 
1714         @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1715         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1716             if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
1717                 return;
1718             }
1719 
1720             final long token = Binder.clearCallingIdentity();
1721             try {
1722                 dumpInternal(pw);
1723             } finally {
1724                 Binder.restoreCallingIdentity(token);
1725             }
1726         }
1727     }
1728 }
1729