Add accessibility display adjustments

BUG: 9057596
Change-Id: I5e7cc05159387cb00701e162d015e2f7ca6cbf4c
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6c6635d..7258e16 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3752,6 +3752,97 @@
                 "accessibility_captioning_font_scale";
 
         /**
+         * Setting that specifies whether the quick setting tile for display
+         * color inversion is enabled.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_DISPLAY_INVERSION_QUICK_SETTING_ENABLED =
+                "accessibility_display_inversion_quick_setting_enabled";
+
+        /**
+         * Setting that specifies whether display color inversion is enabled.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED =
+                "accessibility_display_inversion_enabled";
+
+        /**
+         * Integer property that specifies the type of color inversion to
+         * perform. Valid values are defined in AccessibilityManager.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_DISPLAY_INVERSION =
+                "accessibility_display_inversion";
+
+        /**
+         * Setting that specifies whether the quick setting tile for display
+         * color space adjustment is enabled.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_DISPLAY_DALTONIZER_QUICK_SETTING_ENABLED =
+                "accessibility_display_daltonizer_quick_setting_enabled";
+
+        /**
+         * Setting that specifies whether display color space adjustment is
+         * enabled.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED =
+                "accessibility_display_daltonizer_enabled";
+
+        /**
+         * Integer property that specifies the type of color space adjustment to
+         * perform. Valid values are defined in AccessibilityManager.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_DISPLAY_DALTONIZER =
+                "accessibility_display_daltonizer";
+
+        /**
+         * Setting that specifies whether the quick setting tile for display
+         * contrast enhancement is enabled.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_DISPLAY_CONTRAST_QUICK_SETTING_ENABLED =
+                "accessibility_display_contrast_quick_setting_enabled";
+
+        /**
+         * Setting that specifies whether display contrast enhancement is
+         * enabled.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED =
+                "accessibility_display_contrast_enabled";
+
+        /**
+         * Floating point property that specifies display contrast adjustment.
+         * Valid range is [0, ...] where 0 is gray, 1 is normal, and higher
+         * values indicate enhanced contrast.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_DISPLAY_CONTRAST =
+                "accessibility_display_contrast";
+
+        /**
+         * Floating point property that specifies display brightness adjustment.
+         * Valid range is [-1, 1] where -1 is black, 0 is default, and 1 is
+         * white.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_DISPLAY_BRIGHTNESS =
+                "accessibility_display_brightness";
+
+        /**
          * The timout for considering a press to be a long press in milliseconds.
          * @hide
          */
diff --git a/core/java/android/util/MatrixUtils.java b/core/java/android/util/MatrixUtils.java
new file mode 100644
index 0000000..c443d6c
--- /dev/null
+++ b/core/java/android/util/MatrixUtils.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import java.util.Arrays;
+
+/**
+ * A class that contains utility methods related to matrices.
+ *
+ * @hide
+ */
+public class MatrixUtils {
+    private MatrixUtils() {
+        // This class is non-instantiable.
+    }
+
+    /**
+     * Sets a matrix to the identity matrix.
+     *
+     * @param out output matrix of size n*m
+     * @param n number of rows in the output matrix
+     * @param m number of columns in the output matrix
+     */
+    public static void setIdentityM(float[] out, int n, int m) {
+        final int size = n * m;
+        if (out.length != size) {
+            throw new IllegalArgumentException("Invalid dimensions for output matrix");
+        }
+
+        Arrays.fill(out, 0, size, 0);
+        for (int i = Math.min(m,n) - 1; i >= 0; i--) {
+            out[i * (m + 1)] = 1;
+        }
+    }
+
+    /**
+     * Add two matrices. May be used in-place by specifying the same value for
+     * the out matrix and one of the input matrices.
+     *
+     * @param ab output matrix of size n*m
+     * @param a left-hand matrix of size n*m
+     * @param n number of rows in the left-hand matrix
+     * @param m number of columns in the left-hand matrix
+     * @param b right-hand matrix of size n*m
+     */
+    public static void addMM(float[] ab, float[] a, int n, int m, float[] b) {
+        final int size = n * m;
+        if (a.length != size) {
+            throw new IllegalArgumentException("Invalid dimensions for matrix a");
+        } else if (b.length != size) {
+            throw new IllegalArgumentException("Invalid dimensions for matrix b");
+        } else if (ab.length != size) {
+            throw new IllegalArgumentException("Invalid dimensions for matrix ab");
+        }
+
+        for (int i = 0; i < size; i++) {
+            ab[i] = a[i] + b[i];
+        }
+    }
+
+    /**
+     * Multiply two matrices.
+     *
+     * @param ab output matrix of size n*p
+     * @param a left-hand matrix of size n*m
+     * @param n number of rows in the left-hand matrix
+     * @param m number of columns in the left-hand matrix
+     * @param b right-hand matrix of size m*p
+     * @param p number of columns in the right-hand matrix
+     */
+    public static void multiplyMM(float[] ab, float[] a, int n, int m, float[] b, int p) {
+        if (a.length != n * m) {
+            throw new IllegalArgumentException("Invalid dimensions for matrix a");
+        } else if (b.length != m * p) {
+            throw new IllegalArgumentException("Invalid dimensions for matrix b");
+        } else if (ab.length != n * p) {
+            throw new IllegalArgumentException("Invalid dimensions for matrix ab");
+        }
+
+        for (int i = 0; i < n; i++) {
+            for (int j = 0; j < p; j++) {
+                float sum = 0;
+                for (int k = 0; k < m; k++) {
+                    sum += a[i * m + k] * b[k * p + j];
+                }
+                ab[i * p + j] = sum;
+            }
+        }
+    }
+
+    /**
+     * Multiply a matrix by a scalar value. May be used in-place by specifying
+     * the same value for the input and output matrices.
+     *
+     * @param out output matrix
+     * @param in input matrix
+     * @param scalar scalar value
+     */
+    public static void multiplyMS(float[] out, float[] in, float scalar) {
+        final int n = out.length;
+        for (int i = 0; i < n; i++) {
+            out[i] = in[i] * scalar;
+        }
+    }
+}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 04ce7e2..020b92c 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -75,6 +75,42 @@
     /** @hide */
     public static final int STATE_FLAG_TOUCH_EXPLORATION_ENABLED = 0x00000002;
 
+    /** @hide */
+    public static final int INVERSION_DISABLED = -1;
+
+    /** @hide */
+    public static final int INVERSION_STANDARD = 0;
+
+    /** @hide */
+    public static final int INVERSION_HUE_ONLY = 1;
+
+    /** @hide */
+    public static final int INVERSION_VALUE_ONLY = 2;
+
+    /** @hide */
+    public static final int DALTONIZER_DISABLED = -1;
+
+    /** @hide */
+    public static final int DALTONIZER_SIMULATE_MONOCHROMACY = 0;
+
+    /** @hide */
+    public static final int DALTONIZER_SIMULATE_PROTANOMALY = 1;
+
+    /** @hide */
+    public static final int DALTONIZER_SIMULATE_DEUTERANOMALY = 2;
+
+    /** @hide */
+    public static final int DALTONIZER_SIMULATE_TRITANOMALY = 3;
+
+    /** @hide */
+    public static final int DALTONIZER_CORRECT_PROTANOMALY = 11;
+
+    /** @hide */
+    public static final int DALTONIZER_CORRECT_DEUTERANOMALY = 12;
+
+    /** @hide */
+    public static final int DALTONIZER_CORRECT_TRITANOMALY = 13;
+
     static final Object sInstanceSync = new Object();
 
     private static AccessibilityManager sInstance;
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 83e69d6f..9203be7 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -51,6 +51,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Parcel;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -61,6 +62,7 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.text.TextUtils.SimpleStringSplitter;
+import android.util.MatrixUtils;
 import android.util.Pools.Pool;
 import android.util.Pools.SimplePool;
 import android.util.Slog;
@@ -139,6 +141,56 @@
 
     private static final int MAX_POOL_SIZE = 10;
 
+    /** Matrix used for converting color to grayscale. */
+    private static final float[] GRAYSCALE_MATRIX = new float[] {
+        .2126f, .2126f, .2126f,
+        .7152f, .7152f, .7152f,
+        .0722f, .0722f, .0722f
+    };
+
+    /** Matrix used for standard display inversion. */
+    private static final float[] INVERSION_MATRIX_STANDARD = new float[] {
+        -1,  0,  0,
+         0, -1,  0,
+         0,  0, -1
+    };
+
+    /** Offset used for standard display inversion. */
+    private static final float INVERSION_OFFSET_STANDARD = 1;
+
+    /** Matrix and offset used for hue-only display inversion. */
+    private static final float[] INVERSION_MATRIX_HUE_ONLY = new float[] {
+          0, .5f, .5f,
+        .5f,   0, .5f,
+        .5f, .5f,   0
+    };
+
+    /** Offset used for hue-only display inversion. */
+    private static final float INVERSION_OFFSET_HUE_ONLY = 0;
+
+    /** Matrix and offset used for value-only display inversion. */
+    private static final float[] INVERSION_MATRIX_VALUE_ONLY = new float[] {
+           0, -.5f, -.5f,
+        -.5f,    0, -.5f,
+        -.5f, -.5f,    0
+    };
+
+    /** Offset used for value-only display inversion. */
+    private static final float INVERSION_OFFSET_VALUE_ONLY = 1;
+
+    /** Default contrast for display contrast enhancement. */
+    private static final float DEFAULT_DISPLAY_CONTRAST = 2;
+
+    /** Default brightness for display contrast enhancement. */
+    private static final float DEFAULT_DISPLAY_BRIGHTNESS = 0;
+
+    /** Default inversion mode for display color inversion. */
+    private static final int DEFAULT_DISPLAY_INVERSION = AccessibilityManager.INVERSION_STANDARD;
+
+    /** Default inversion mode for display color correction. */
+    private static final int DEFAULT_DISPLAY_DALTONIZER =
+            AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY;
+
     private static int sIdCounter = 0;
 
     private static int sNextWindowId;
@@ -1297,6 +1349,7 @@
         updateFilterKeyEventsLocked(userState);
         updateTouchExplorationLocked(userState);
         updateEnhancedWebAccessibilityLocked(userState);
+        updateDisplayColorAdjustmentSettingsLocked(userState);
         scheduleUpdateInputFilter(userState);
         scheduleUpdateClientsIfNeededLocked(userState);
     }
@@ -1355,6 +1408,7 @@
         somthingChanged |= readTouchExplorationEnabledSettingLocked(userState);
         somthingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
         somthingChanged |= readDisplayMagnificationEnabledSettingLocked(userState);
+        somthingChanged |= readDisplayColorAdjustmentSettingsLocked(userState);
         return somthingChanged;
     }
 
@@ -1403,6 +1457,136 @@
          return false;
     }
 
+    private boolean readDisplayColorAdjustmentSettingsLocked(UserState userState) {
+        final ContentResolver cr = mContext.getContentResolver();
+        final int userId = userState.mUserId;
+
+        boolean hasColorTransform = Settings.Secure.getIntForUser(
+                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) == 1;
+
+        if (!hasColorTransform) {
+            hasColorTransform |= Settings.Secure.getIntForUser(
+                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED, 0, userId) == 1;
+        }
+
+        if (!hasColorTransform) {
+            hasColorTransform |= Settings.Secure.getIntForUser(
+                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) == 1;
+        }
+
+        if (userState.mHasDisplayColorAdjustment != hasColorTransform) {
+            userState.mHasDisplayColorAdjustment = hasColorTransform;
+            return true;
+        }
+
+        // If adjustment is enabled, always assume there was a transform change.
+        return hasColorTransform;
+    }
+
+    private void updateDisplayColorAdjustmentSettingsLocked(UserState userState) {
+        final ContentResolver cr = mContext.getContentResolver();
+        final int userId = userState.mUserId;
+        final float[] offsetVector = new float[3];
+        float[] colorOffset = new float[3];
+        float[] outputOffset = new float[3];
+        float[] colorMatrix = new float[9];
+        float[] outputMatrix = new float[9];
+        boolean hasColorTransform = false;
+
+        MatrixUtils.setIdentityM(colorMatrix, 3, 3);
+
+        final boolean inversionEnabled = Settings.Secure.getIntForUser(
+                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) == 1;
+        if (inversionEnabled) {
+            final int inversionMode = Settings.Secure.getIntForUser(cr,
+                    Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION, DEFAULT_DISPLAY_INVERSION,
+                    userId);
+            final float[] inversionMatrix;
+            final float inversionOffset;
+            switch (inversionMode) {
+                case AccessibilityManager.INVERSION_HUE_ONLY:
+                    inversionMatrix = INVERSION_MATRIX_HUE_ONLY;
+                    inversionOffset = INVERSION_OFFSET_HUE_ONLY;
+                    break;
+                case AccessibilityManager.INVERSION_VALUE_ONLY:
+                    inversionMatrix = INVERSION_MATRIX_VALUE_ONLY;
+                    inversionOffset = INVERSION_OFFSET_VALUE_ONLY;
+                    break;
+                default:
+                    inversionMatrix = INVERSION_MATRIX_STANDARD;
+                    inversionOffset = INVERSION_OFFSET_STANDARD;
+            }
+
+            Arrays.fill(offsetVector, inversionOffset);
+
+            MatrixUtils.multiplyMM(outputMatrix, colorMatrix, 3, 3, inversionMatrix, 3);
+            MatrixUtils.multiplyMM(outputOffset, colorOffset, 1, 3, inversionMatrix, 3);
+            MatrixUtils.addMM(colorOffset, outputOffset, 1, 3, offsetVector);
+
+            final float[] temp = colorMatrix;
+            colorMatrix = outputMatrix;
+            outputMatrix = temp;
+
+            hasColorTransform = true;
+        }
+
+        final boolean contrastEnabled = Settings.Secure.getIntForUser(
+                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED, 0, userId) == 1;
+        if (contrastEnabled) {
+            final float contrast = Settings.Secure.getFloatForUser(cr,
+                    Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST, DEFAULT_DISPLAY_CONTRAST,
+                    userId);
+            final float brightness = Settings.Secure.getFloatForUser(cr,
+                    Settings.Secure.ACCESSIBILITY_DISPLAY_BRIGHTNESS, DEFAULT_DISPLAY_BRIGHTNESS,
+                    userId);
+            final float offset = brightness * contrast - 0.5f * contrast + 0.5f;
+            Arrays.fill(offsetVector, offset);
+
+            MatrixUtils.multiplyMS(outputMatrix, colorMatrix, contrast);
+            MatrixUtils.multiplyMS(outputOffset, colorOffset, contrast);
+            MatrixUtils.addMM(colorOffset, outputOffset, 1, 3, offsetVector);
+
+            final float[] temp = colorMatrix;
+            colorMatrix = outputMatrix;
+            outputMatrix = temp;
+
+            hasColorTransform = true;
+        }
+
+        final boolean daltonizerEnabled = Settings.Secure.getIntForUser(
+                cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0;
+        if (daltonizerEnabled) {
+            final int daltonizerMode = Settings.Secure.getIntForUser(cr,
+                    Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, DEFAULT_DISPLAY_DALTONIZER,
+                    userId);
+            // Monochromacy isn't supported by the native Daltonizer.
+            if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) {
+                MatrixUtils.multiplyMM(outputMatrix, colorMatrix, 3, 3, GRAYSCALE_MATRIX, 3);
+                MatrixUtils.multiplyMM(outputOffset, colorOffset, 1, 3, GRAYSCALE_MATRIX, 3);
+
+                final float[] temp = colorMatrix;
+                colorMatrix = outputMatrix;
+                outputMatrix = temp;
+
+                final float[] tempVec = colorOffset;
+                colorOffset = outputOffset;
+                outputOffset = temp;
+
+                nativeSetDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
+            } else {
+                nativeSetDaltonizerMode(daltonizerMode);
+            }
+        } else {
+            nativeSetDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
+        }
+
+        if (hasColorTransform) {
+            nativeSetColorTransform(colorMatrix, colorOffset);
+        } else {
+            nativeSetColorTransform(null, null);
+        }
+    }
+
     private void updateTouchExplorationLocked(UserState userState) {
         boolean enabled = false;
         final int serviceCount = userState.mBoundServices.size();
@@ -1524,6 +1708,59 @@
         }
     }
 
+    /**
+     * Sets the surface flinger's Daltonization mode. This adjusts the color
+     * space to correct for or simulate various types of color blindness.
+     *
+     * @param mode new Daltonization mode
+     */
+    private static void nativeSetDaltonizerMode(int mode) {
+        try {
+            final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
+            if (flinger != null) {
+                final Parcel data = Parcel.obtain();
+                data.writeInterfaceToken("android.ui.ISurfaceComposer");
+                data.writeInt(mode);
+                flinger.transact(1014, data, null, 0);
+                data.recycle();
+            }
+        } catch (RemoteException ex) {
+            Slog.e(LOG_TAG, "Failed to set Daltonizer mode", ex);
+        }
+    }
+
+    /**
+     * Sets the surface flinger's color transformation matrix and offset. If
+     * either value is null, color transformations are disabled.
+     *
+     * @param matrix new color transformation matrix, or null to disable
+     * @param offset new color transformation offset, or null to disable
+     */
+    private static void nativeSetColorTransform(float[] matrix, float[] offset) {
+        try {
+            final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
+            if (flinger != null) {
+                final Parcel data = Parcel.obtain();
+                data.writeInterfaceToken("android.ui.ISurfaceComposer");
+                if (matrix != null && offset != null) {
+                    data.writeInt(1);
+                    for (int i = 0; i < 9; i++) {
+                        data.writeFloat(matrix[i]);
+                    }
+                    for (int i = 0; i < 3; i++) {
+                        data.writeFloat(offset[i]);
+                    }
+                } else {
+                    data.writeInt(0);
+                }
+                flinger.transact(1015, data, null, 0);
+                data.recycle();
+            }
+        } catch (RemoteException ex) {
+            Slog.e(LOG_TAG, "Failed to set color transform", ex);
+        }
+    }
+
     private class AccessibilityConnectionWrapper implements DeathRecipient {
         private final int mWindowId;
         private final int mUserId;
@@ -2947,6 +3184,7 @@
         public boolean mIsEnhancedWebAccessibilityEnabled;
         public boolean mIsDisplayMagnificationEnabled;
         public boolean mIsFilterKeyEventsEnabled;
+        public boolean mHasDisplayColorAdjustment;
 
         private Service mUiAutomationService;
         private IAccessibilityServiceClient mUiAutomationServiceClient;
@@ -3038,6 +3276,23 @@
         private final Uri mEnhancedWebAccessibilityUri = Settings.Secure
                 .getUriFor(Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION);
 
+        private final Uri mDisplayContrastEnabledUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED);
+        private final Uri mDisplayContrastUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST);
+        private final Uri mDisplayBrightnessUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_DISPLAY_BRIGHTNESS);
+
+        private final Uri mDisplayInversionEnabledUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
+        private final Uri mDisplayInversionUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION);
+
+        private final Uri mDisplayDaltonizerEnabledUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED);
+        private final Uri mDisplayDaltonizerUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER);
+
         public AccessibilityContentObserver(Handler handler) {
             super(handler);
         }
@@ -3056,6 +3311,20 @@
                     false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(mEnhancedWebAccessibilityUri,
                     false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(
+                    mDisplayContrastEnabledUri, false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(
+                    mDisplayContrastUri, false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(
+                    mDisplayBrightnessUri, false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(
+                    mDisplayInversionEnabledUri, false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(
+                    mDisplayInversionUri, false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(
+                    mDisplayDaltonizerEnabledUri, false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(
+                    mDisplayDaltonizerUri, false, this, UserHandle.USER_ALL);
         }
 
         @Override
@@ -3120,6 +3389,22 @@
                         }
                     }
                 }
+            } else if (mDisplayContrastEnabledUri.equals(uri)
+                    || mDisplayInversionEnabledUri.equals(uri)
+                    || mDisplayDaltonizerEnabledUri.equals(uri)
+                    || mDisplayContrastUri.equals(uri)
+                    || mDisplayBrightnessUri.equals(uri)
+                    || mDisplayInversionUri.equals(uri)
+                    || mDisplayDaltonizerUri.equals(uri)) {
+                synchronized (mLock) {
+                    // We will update when the automation service dies.
+                    UserState userState = getCurrentUserStateLocked();
+                    if (userState.mUiAutomationService == null) {
+                        if (readDisplayColorAdjustmentSettingsLocked(userState)) {
+                            updateDisplayColorAdjustmentSettingsLocked(userState);
+                        }
+                    }
+                }
             }
         }
     }