Move Night Display methods to ColorDisplayManager

Bug: 111215474
Test: atest FrameworksServicesTest:ColorDisplayServiceTest
Change-Id: Idb16af8dfa1c65bb638b2537e4a162b624069430
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index 3a58160..58c88b3 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -16,6 +16,10 @@
 
 package com.android.server.display;
 
+import static android.hardware.display.ColorDisplayManager.AUTO_MODE_CUSTOM_TIME;
+import static android.hardware.display.ColorDisplayManager.AUTO_MODE_DISABLED;
+import static android.hardware.display.ColorDisplayManager.AUTO_MODE_TWILIGHT;
+
 import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
 import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
 import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_SATURATION;
@@ -40,7 +44,9 @@
 import android.database.ContentObserver;
 import android.graphics.ColorSpace;
 import android.hardware.display.ColorDisplayManager;
+import android.hardware.display.ColorDisplayManager.AutoMode;
 import android.hardware.display.IColorDisplayManager;
+import android.hardware.display.Time;
 import android.net.Uri;
 import android.opengl.Matrix;
 import android.os.Binder;
@@ -103,59 +109,17 @@
     private static final int MSG_APPLY_GLOBAL_SATURATION = 2;
 
     /**
+     * Return value if a setting has not been set.
+     */
+    private static final int NOT_SET = -1;
+
+    /**
      * Evaluator used to animate color matrix transitions.
      */
     private static final ColorMatrixEvaluator COLOR_MATRIX_EVALUATOR = new ColorMatrixEvaluator();
 
-    private final TintController mNightDisplayTintController = new TintController() {
-
-        private float[] mMatrixNightDisplay = new float[16];
-        private final float[] mColorTempCoefficients = new float[9];
-
-        /**
-         * Set coefficients based on whether the color matrix is linear or not.
-         */
-        @Override
-        public void setUp(Context context, boolean needsLinear) {
-            final String[] coefficients = context.getResources().getStringArray(needsLinear
-                    ? R.array.config_nightDisplayColorTemperatureCoefficients
-                    : R.array.config_nightDisplayColorTemperatureCoefficientsNative);
-            for (int i = 0; i < 9 && i < coefficients.length; i++) {
-                mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]);
-            }
-        }
-
-        @Override
-        public void setMatrix(int cct) {
-            if (mMatrixNightDisplay.length != 16) {
-                Slog.d(TAG, "The display transformation matrix must be 4x4");
-                return;
-            }
-
-            Matrix.setIdentityM(mMatrixNightDisplay, 0);
-
-            final float squareTemperature = cct * cct;
-            final float red = squareTemperature * mColorTempCoefficients[0]
-                    + cct * mColorTempCoefficients[1] + mColorTempCoefficients[2];
-            final float green = squareTemperature * mColorTempCoefficients[3]
-                    + cct * mColorTempCoefficients[4] + mColorTempCoefficients[5];
-            final float blue = squareTemperature * mColorTempCoefficients[6]
-                    + cct * mColorTempCoefficients[7] + mColorTempCoefficients[8];
-            mMatrixNightDisplay[0] = red;
-            mMatrixNightDisplay[5] = green;
-            mMatrixNightDisplay[10] = blue;
-        }
-
-        @Override
-        public float[] getMatrix() {
-            return isActivated() ? mMatrixNightDisplay : MATRIX_IDENTITY;
-        }
-
-        @Override
-        public int getLevel() {
-            return LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
-        }
-    };
+    private final NightDisplayTintController mNightDisplayTintController =
+            new NightDisplayTintController();
 
     private final TintController mDisplayWhiteBalanceTintController = new TintController() {
         // Three chromaticity coordinates per color: X, Y, and Z
@@ -386,7 +350,7 @@
                 float saturation = saturationLevel * 0.1f;
                 float desaturation = 1.0f - saturation;
                 float[] luminance = {0.231f * desaturation, 0.715f * desaturation,
-                    0.072f * desaturation};
+                        0.072f * desaturation};
                 mMatrixGlobalSaturation[0] = luminance[0] + saturation;
                 mMatrixGlobalSaturation[1] = luminance[0];
                 mMatrixGlobalSaturation[2] = luminance[0];
@@ -445,7 +409,7 @@
 
     public ColorDisplayService(Context context) {
         super(context);
-        mHandler = new TintHandler(Looper.getMainLooper());
+        mHandler = new TintHandler(DisplayThread.get().getLooper());
     }
 
     @Override
@@ -548,23 +512,30 @@
                     if (setting != null) {
                         switch (setting) {
                             case Secure.NIGHT_DISPLAY_ACTIVATED:
-                                onNightDisplayActivated(mNightDisplayController.isActivated());
+                                final boolean activated = isNightDisplayActivatedSetting();
+                                if (mNightDisplayTintController.isActivatedStateNotSet()
+                                        || mNightDisplayTintController.isActivated() != activated) {
+                                    mNightDisplayTintController.onActivated(activated);
+                                }
                                 break;
                             case Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE:
-                                onNightDisplayColorTemperatureChanged(
-                                        mNightDisplayController.getColorTemperature());
+                                final int temperature = getNightDisplayColorTemperatureSetting();
+                                if (mNightDisplayTintController.getColorTemperature()
+                                        != temperature) {
+                                    mNightDisplayTintController
+                                            .onColorTemperatureChanged(temperature);
+                                }
                                 break;
                             case Secure.NIGHT_DISPLAY_AUTO_MODE:
-                                onNightDisplayAutoModeChanged(
-                                        mNightDisplayController.getAutoMode());
+                                onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal());
                                 break;
                             case Secure.NIGHT_DISPLAY_CUSTOM_START_TIME:
                                 onNightDisplayCustomStartTimeChanged(
-                                        mNightDisplayController.getCustomStartTime());
+                                        getNightDisplayCustomStartTimeInternal().getLocalTime());
                                 break;
                             case Secure.NIGHT_DISPLAY_CUSTOM_END_TIME:
                                 onNightDisplayCustomEndTimeChanged(
-                                        mNightDisplayController.getCustomEndTime());
+                                        getNightDisplayCustomEndTimeInternal().getLocalTime());
                                 break;
                             case System.DISPLAY_COLOR_MODE:
                                 onDisplayColorModeChanged(mNightDisplayController.getColorMode());
@@ -624,14 +595,14 @@
             // Prepare the night display color transformation matrix.
             mNightDisplayTintController
                     .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
-            mNightDisplayTintController.setMatrix(mNightDisplayController.getColorTemperature());
+            mNightDisplayTintController.setMatrix(getNightDisplayColorTemperatureSetting());
 
             // Initialize the current auto mode.
-            onNightDisplayAutoModeChanged(mNightDisplayController.getAutoMode());
+            onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal());
 
-            // Force the initialization current activated state.
+            // Force the initialization of the current saved activation state.
             if (mNightDisplayTintController.isActivatedStateNotSet()) {
-                onNightDisplayActivated(mNightDisplayController.isActivated());
+                mNightDisplayTintController.onActivated(isNightDisplayActivatedSetting());
             }
         }
 
@@ -665,23 +636,6 @@
         }
     }
 
-    private void onNightDisplayActivated(boolean activated) {
-        if (mNightDisplayTintController.isActivatedStateNotSet()
-                || mNightDisplayTintController.isActivated() != activated) {
-            Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display");
-
-            mNightDisplayTintController.setActivated(activated);
-
-            if (mNightDisplayAutoMode != null) {
-                mNightDisplayAutoMode.onActivated(activated);
-            }
-
-            updateDisplayWhiteBalanceStatus();
-
-            applyTint(mNightDisplayTintController, false);
-        }
-    }
-
     private void onNightDisplayAutoModeChanged(int autoMode) {
         Slog.d(TAG, "onNightDisplayAutoModeChanged: autoMode=" + autoMode);
 
@@ -690,9 +644,9 @@
             mNightDisplayAutoMode = null;
         }
 
-        if (autoMode == ColorDisplayController.AUTO_MODE_CUSTOM) {
+        if (autoMode == AUTO_MODE_CUSTOM_TIME) {
             mNightDisplayAutoMode = new CustomNightDisplayAutoMode();
-        } else if (autoMode == ColorDisplayController.AUTO_MODE_TWILIGHT) {
+        } else if (autoMode == AUTO_MODE_TWILIGHT) {
             mNightDisplayAutoMode = new TwilightNightDisplayAutoMode();
         }
 
@@ -717,13 +671,8 @@
         }
     }
 
-    private void onNightDisplayColorTemperatureChanged(int colorTemperature) {
-        mNightDisplayTintController.setMatrix(colorTemperature);
-        applyTint(mNightDisplayTintController, true);
-    }
-
     private void onDisplayColorModeChanged(int mode) {
-        if (mode == -1) {
+        if (mode == NOT_SET) {
             return;
         }
 
@@ -732,7 +681,7 @@
 
         mNightDisplayTintController
                 .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
-        mNightDisplayTintController.setMatrix(mNightDisplayController.getColorTemperature());
+        mNightDisplayTintController.setMatrix(getNightDisplayColorTemperatureSetting());
 
         updateDisplayWhiteBalanceStatus();
 
@@ -901,6 +850,71 @@
         return availabilityFlags;
     }
 
+    private boolean setNightDisplayAutoModeInternal(@AutoMode int autoMode) {
+        if (getNightDisplayAutoModeInternal() != autoMode) {
+            Secure.putStringForUser(getContext().getContentResolver(),
+                    Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+                    null,
+                    mCurrentUser);
+        }
+        return Secure.putIntForUser(getContext().getContentResolver(),
+                Secure.NIGHT_DISPLAY_AUTO_MODE, autoMode, mCurrentUser);
+    }
+
+    private int getNightDisplayAutoModeInternal() {
+        int autoMode = getNightDisplayAutoModeRawInternal();
+        if (autoMode == NOT_SET) {
+            autoMode = getContext().getResources().getInteger(
+                    R.integer.config_defaultNightDisplayAutoMode);
+        }
+        if (autoMode != AUTO_MODE_DISABLED
+                && autoMode != AUTO_MODE_CUSTOM_TIME
+                && autoMode != AUTO_MODE_TWILIGHT) {
+            Slog.e(TAG, "Invalid autoMode: " + autoMode);
+            autoMode = AUTO_MODE_DISABLED;
+        }
+        return autoMode;
+    }
+
+    private int getNightDisplayAutoModeRawInternal() {
+        return Secure
+                .getIntForUser(getContext().getContentResolver(), Secure.NIGHT_DISPLAY_AUTO_MODE,
+                        NOT_SET, mCurrentUser);
+    }
+
+    private Time getNightDisplayCustomStartTimeInternal() {
+        int startTimeValue = Secure.getIntForUser(getContext().getContentResolver(),
+                Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, NOT_SET, mCurrentUser);
+        if (startTimeValue == NOT_SET) {
+            startTimeValue = getContext().getResources().getInteger(
+                    R.integer.config_defaultNightDisplayCustomStartTime);
+        }
+        return new Time(LocalTime.ofSecondOfDay(startTimeValue / 1000));
+    }
+
+    private boolean setNightDisplayCustomStartTimeInternal(Time startTime) {
+        return Secure.putIntForUser(getContext().getContentResolver(),
+                Secure.NIGHT_DISPLAY_CUSTOM_START_TIME,
+                startTime.getLocalTime().toSecondOfDay() * 1000,
+                mCurrentUser);
+    }
+
+    private Time getNightDisplayCustomEndTimeInternal() {
+        int endTimeValue = Secure.getIntForUser(getContext().getContentResolver(),
+                Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, NOT_SET, mCurrentUser);
+        if (endTimeValue == NOT_SET) {
+            endTimeValue = getContext().getResources().getInteger(
+                    R.integer.config_defaultNightDisplayCustomEndTime);
+        }
+        return new Time(LocalTime.ofSecondOfDay(endTimeValue / 1000));
+    }
+
+    private boolean setNightDisplayCustomEndTimeInternal(Time endTime) {
+        return Secure.putIntForUser(getContext().getContentResolver(),
+                Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.getLocalTime().toSecondOfDay() * 1000,
+                mCurrentUser);
+    }
+
     /**
      * Returns the last time the night display transform activation state was changed, or {@link
      * LocalDateTime#MIN} if night display has never been activated.
@@ -941,6 +955,33 @@
         mAppSaturationController.dump(pw);
     }
 
+    private boolean isNightDisplayActivatedSetting() {
+        return Secure.getIntForUser(getContext().getContentResolver(),
+                Secure.NIGHT_DISPLAY_ACTIVATED, 0, mCurrentUser) == 1;
+    }
+
+    private int getNightDisplayColorTemperatureSetting() {
+        return clampNightDisplayColorTemperature(Secure.getIntForUser(
+                getContext().getContentResolver(), Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, NOT_SET,
+                mCurrentUser));
+    }
+
+    private int clampNightDisplayColorTemperature(int colorTemperature) {
+        if (colorTemperature == NOT_SET) {
+            colorTemperature = getContext().getResources().getInteger(
+                    R.integer.config_nightDisplayColorTemperatureDefault);
+        }
+        final int minimumTemperature = ColorDisplayManager.getMinimumColorTemperature(getContext());
+        final int maximumTemperature = ColorDisplayManager.getMaximumColorTemperature(getContext());
+        if (colorTemperature < minimumTemperature) {
+            colorTemperature = minimumTemperature;
+        } else if (colorTemperature > maximumTemperature) {
+            colorTemperature = maximumTemperature;
+        }
+
+        return colorTemperature;
+    }
+
     private abstract class NightDisplayAutoMode {
 
         public abstract void onActivated(boolean activated);
@@ -987,13 +1028,13 @@
                 // Maintain the existing activated state if within the current period.
                 if (mLastActivatedTime.isBefore(now) && mLastActivatedTime.isAfter(start)
                         && (mLastActivatedTime.isAfter(end) || now.isBefore(end))) {
-                    activate = mNightDisplayController.isActivated();
+                    activate = isNightDisplayActivatedSetting();
                 }
             }
 
             if (mNightDisplayTintController.isActivatedStateNotSet() || (
                     mNightDisplayTintController.isActivated() != activate)) {
-                mNightDisplayController.setActivated(activate);
+                mNightDisplayTintController.setActivated(activate);
             }
 
             updateNextAlarm(mNightDisplayTintController.isActivated(), now);
@@ -1014,8 +1055,8 @@
             intentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
             getContext().registerReceiver(mTimeChangedReceiver, intentFilter);
 
-            mStartTime = mNightDisplayController.getCustomStartTime();
-            mEndTime = mNightDisplayController.getCustomEndTime();
+            mStartTime = getNightDisplayCustomStartTimeInternal().getLocalTime();
+            mEndTime = getNightDisplayCustomEndTimeInternal().getLocalTime();
 
             mLastActivatedTime = getNightDisplayLastActivatedTimeSetting();
 
@@ -1083,13 +1124,13 @@
                 // Maintain the existing activated state if within the current period.
                 if (mLastActivatedTime.isBefore(now) && (mLastActivatedTime.isBefore(sunrise)
                         ^ mLastActivatedTime.isBefore(sunset))) {
-                    activate = mNightDisplayController.isActivated();
+                    activate = isNightDisplayActivatedSetting();
                 }
             }
 
             if (mNightDisplayTintController.isActivatedStateNotSet() || (
                     mNightDisplayTintController.isActivated() != activate)) {
-                mNightDisplayController.setActivated(activate);
+                mNightDisplayTintController.setActivated(activate);
             }
         }
 
@@ -1211,6 +1252,114 @@
         public abstract int getLevel();
     }
 
+    private final class NightDisplayTintController extends TintController {
+
+        private float[] mMatrix = new float[16];
+        private final float[] mColorTempCoefficients = new float[9];
+        private Integer mColorTemp;
+
+        /**
+         * Set coefficients based on whether the color matrix is linear or not.
+         */
+        @Override
+        public void setUp(Context context, boolean needsLinear) {
+            final String[] coefficients = context.getResources().getStringArray(needsLinear
+                    ? R.array.config_nightDisplayColorTemperatureCoefficients
+                    : R.array.config_nightDisplayColorTemperatureCoefficientsNative);
+            for (int i = 0; i < 9 && i < coefficients.length; i++) {
+                mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]);
+            }
+        }
+
+        @Override
+        public void setMatrix(int cct) {
+            if (mMatrix.length != 16) {
+                Slog.d(TAG, "The display transformation matrix must be 4x4");
+                return;
+            }
+
+            Matrix.setIdentityM(mMatrix, 0);
+
+            final float squareTemperature = cct * cct;
+            final float red = squareTemperature * mColorTempCoefficients[0]
+                    + cct * mColorTempCoefficients[1] + mColorTempCoefficients[2];
+            final float green = squareTemperature * mColorTempCoefficients[3]
+                    + cct * mColorTempCoefficients[4] + mColorTempCoefficients[5];
+            final float blue = squareTemperature * mColorTempCoefficients[6]
+                    + cct * mColorTempCoefficients[7] + mColorTempCoefficients[8];
+            mMatrix[0] = red;
+            mMatrix[5] = green;
+            mMatrix[10] = blue;
+        }
+
+        @Override
+        public float[] getMatrix() {
+            return isActivated() ? mMatrix : MATRIX_IDENTITY;
+        }
+
+        @Override
+        public void setActivated(Boolean activated) {
+            if (activated == null) {
+                super.setActivated(null);
+                return;
+            }
+
+            boolean activationStateChanged = activated != isActivated();
+
+            if (!isActivatedStateNotSet() && activationStateChanged) {
+                // This is a true state change, so set this as the last activation time.
+                Secure.putStringForUser(getContext().getContentResolver(),
+                        Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+                        LocalDateTime.now().toString(),
+                        mCurrentUser);
+            }
+
+            if (isActivatedStateNotSet() || activationStateChanged) {
+                super.setActivated(activated);
+                Secure.putIntForUser(getContext().getContentResolver(),
+                        Secure.NIGHT_DISPLAY_ACTIVATED,
+                        activated ? 1 : 0, mCurrentUser);
+                onActivated(activated);
+            }
+        }
+
+        @Override
+        public int getLevel() {
+            return LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
+        }
+
+        void onActivated(boolean activated) {
+            Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display");
+            if (mNightDisplayAutoMode != null) {
+                mNightDisplayAutoMode.onActivated(activated);
+            }
+
+            if (ColorDisplayManager.isDisplayWhiteBalanceAvailable(getContext())) {
+                updateDisplayWhiteBalanceStatus();
+            }
+
+            mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_ANIMATED);
+        }
+
+        int getColorTemperature() {
+            return mColorTemp != null ? clampNightDisplayColorTemperature(mColorTemp)
+                    : getNightDisplayColorTemperatureSetting();
+        }
+
+        boolean setColorTemperature(int temperature) {
+            mColorTemp = temperature;
+            final boolean success = Secure.putIntForUser(getContext().getContentResolver(),
+                    Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, temperature, mCurrentUser);
+            onColorTemperatureChanged(temperature);
+            return success;
+        }
+
+        void onColorTemperatureChanged(int temperature) {
+            setMatrix(temperature);
+            mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE);
+        }
+    }
+
     /**
      * Local service that allows color transforms to be enabled from other system services.
      */
@@ -1270,7 +1419,7 @@
 
     private final class TintHandler extends Handler {
 
-        TintHandler(Looper looper) {
+        private TintHandler(Looper looper) {
             super(looper, null, true /* async */);
         }
 
@@ -1281,6 +1430,12 @@
                     mGlobalSaturationTintController.setMatrix(msg.arg1);
                     applyTint(mGlobalSaturationTintController, false);
                     break;
+                case MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE:
+                    applyTint(mNightDisplayTintController, true);
+                    break;
+                case MSG_APPLY_NIGHT_DISPLAY_ANIMATED:
+                    applyTint(mNightDisplayTintController, false);
+                    break;
             }
         }
     }
@@ -1294,7 +1449,8 @@
         void applyAppSaturation(@Size(9) float[] matrix, @Size(3) float[] translation);
     }
 
-    private final class BinderService extends IColorDisplayManager.Stub {
+    @VisibleForTesting
+    final class BinderService extends IColorDisplayManager.Stub {
 
         @Override
         public boolean isDeviceColorManaged() {
@@ -1354,6 +1510,135 @@
         }
 
         @Override
+        public boolean setNightDisplayActivated(boolean activated) {
+            getContext().enforceCallingOrSelfPermission(
+                    Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+                    "Permission required to set night display activated");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mNightDisplayTintController.setActivated(activated);
+                return true;
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public boolean isNightDisplayActivated() {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return mNightDisplayTintController.isActivated();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public boolean setNightDisplayColorTemperature(int temperature) {
+            getContext().enforceCallingOrSelfPermission(
+                    Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+                    "Permission required to set night display temperature");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return mNightDisplayTintController.setColorTemperature(temperature);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public int getNightDisplayColorTemperature() {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return mNightDisplayTintController.getColorTemperature();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public boolean setNightDisplayAutoMode(int autoMode) {
+            getContext().enforceCallingOrSelfPermission(
+                    Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+                    "Permission required to set night display auto mode");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return setNightDisplayAutoModeInternal(autoMode);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public int getNightDisplayAutoMode() {
+            getContext().enforceCallingOrSelfPermission(
+                    Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+                    "Permission required to get night display auto mode");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getNightDisplayAutoModeInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public int getNightDisplayAutoModeRaw() {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getNightDisplayAutoModeRawInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public boolean setNightDisplayCustomStartTime(Time startTime) {
+            getContext().enforceCallingOrSelfPermission(
+                    Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+                    "Permission required to set night display custom start time");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return setNightDisplayCustomStartTimeInternal(startTime);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public Time getNightDisplayCustomStartTime() {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getNightDisplayCustomStartTimeInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public boolean setNightDisplayCustomEndTime(Time endTime) {
+            getContext().enforceCallingOrSelfPermission(
+                    Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+                    "Permission required to set night display custom end time");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return setNightDisplayCustomEndTimeInternal(endTime);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public Time getNightDisplayCustomEndTime() {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getNightDisplayCustomEndTimeInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;