Add feature flag, and support for new secure settings in framework

The secure setting is only updated and guarded with feature flag.
Reason for single update rather than 2 separate API to update level vs
mode : In Daltonizer.cpp either of the change requires re-calculation of
all matrices (current implementation). We can optimize further later
once we have basic functionality implemented and working.

Test: Locally tested
Bug: 322829049
Flag: com.android.server.accessibility.enable_color_correction_saturation

Change-Id: Ic919c7f01ce4723ecf933b7bdc25a530e372f5ae
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index 82579d8..2b18b7d 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -183,3 +183,10 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "enable_color_correction_saturation"
+    namespace: "accessibility"
+    description: "Feature allows users to change color correction saturation for daltonizer."
+    bug: "322829049"
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 0bb93a9..3883604 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -78,6 +78,7 @@
 import com.android.server.DisplayThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.accessibility.Flags;
 import com.android.server.display.feature.DisplayManagerFlags;
 import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
@@ -356,6 +357,11 @@
                             case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER:
                                 onAccessibilityDaltonizerChanged();
                                 break;
+                            case Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL:
+                                if (Flags.enableColorCorrectionSaturation()) {
+                                    onAccessibilityDaltonizerChanged();
+                                }
+                                break;
                             case Secure.DISPLAY_WHITE_BALANCE_ENABLED:
                                 updateDisplayWhiteBalanceStatus();
                                 break;
@@ -398,6 +404,11 @@
                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
         cr.registerContentObserver(Secure.getUriFor(Secure.REDUCE_BRIGHT_COLORS_LEVEL),
                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
+        if (Flags.enableColorCorrectionSaturation()) {
+            cr.registerContentObserver(
+                    Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL),
+                    false /* notifyForDescendants */, mContentObserver, mCurrentUser);
+        }
 
         // Apply the accessibility settings first, since they override most other settings.
         onAccessibilityInversionChanged();
@@ -597,21 +608,31 @@
         if (mCurrentUser == UserHandle.USER_NULL) {
             return;
         }
+        var contentResolver = getContext().getContentResolver();
         final int daltonizerMode = isAccessiblityDaltonizerEnabled()
-                ? Secure.getIntForUser(getContext().getContentResolver(),
-                    Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
-                    AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY, mCurrentUser)
+                ? Secure.getIntForUser(contentResolver,
+                Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
+                AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY, mCurrentUser)
                 : AccessibilityManager.DALTONIZER_DISABLED;
 
+        int saturation = NOT_SET;
+        if (Flags.enableColorCorrectionSaturation()) {
+            saturation = Secure.getIntForUser(
+                    contentResolver,
+                    Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL,
+                    NOT_SET,
+                    mCurrentUser);
+        }
+
         final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
         if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) {
             // Monochromacy isn't supported by the native Daltonizer implementation; use grayscale.
             dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE,
                     MATRIX_GRAYSCALE);
-            dtm.setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
+            dtm.setDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED, saturation);
         } else {
             dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_GRAYSCALE, null);
-            dtm.setDaltonizerMode(daltonizerMode);
+            dtm.setDaltonizerMode(daltonizerMode, saturation);
         }
     }
 
diff --git a/services/core/java/com/android/server/display/color/DisplayTransformManager.java b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
index 0dba9e1..a76c427 100644
--- a/services/core/java/com/android/server/display/color/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
@@ -16,6 +16,7 @@
 
 package com.android.server.display.color;
 
+import android.annotation.IntRange;
 import android.app.ActivityTaskManager;
 import android.hardware.display.ColorDisplayManager;
 import android.opengl.Matrix;
@@ -111,9 +112,15 @@
     /**
      * Lock used for synchronize access to {@link #mDaltonizerMode}.
      */
-    private final Object mDaltonizerModeLock = new Object();
+    @VisibleForTesting
+    final Object mDaltonizerModeLock = new Object();
+    @VisibleForTesting
     @GuardedBy("mDaltonizerModeLock")
-    private int mDaltonizerMode = -1;
+    int mDaltonizerMode = -1;
+
+    @VisibleForTesting
+    @GuardedBy("mDaltonizerModeLock")
+    int mDaltonizerLevel = -1;
 
     private static final IBinder sFlinger = ServiceManager.getService(SURFACE_FLINGER);
 
@@ -168,12 +175,15 @@
      * various types of color blindness.
      *
      * @param mode the new Daltonization mode, or -1 to disable
+     * @param level the level of saturation for color correction [-1,10] inclusive. -1 for when
+     *              it is not set.
      */
-    public void setDaltonizerMode(int mode) {
+    public void setDaltonizerMode(int mode, @IntRange(from = -1, to = 10) int level) {
         synchronized (mDaltonizerModeLock) {
-            if (mDaltonizerMode != mode) {
+            if (mDaltonizerMode != mode || mDaltonizerLevel != level) {
                 mDaltonizerMode = mode;
-                applyDaltonizerMode(mode);
+                mDaltonizerLevel = level;
+                applyDaltonizerMode(mode, level);
             }
         }
     }
@@ -223,10 +233,11 @@
     /**
      * Propagates the provided Daltonization mode to the SurfaceFlinger.
      */
-    private static void applyDaltonizerMode(int mode) {
+    private static void applyDaltonizerMode(int mode, int level) {
         final Parcel data = Parcel.obtain();
         data.writeInterfaceToken("android.ui.ISurfaceComposer");
         data.writeInt(mode);
+        data.writeInt(level);
         try {
             sFlinger.transact(SURFACE_FLINGER_TRANSACTION_DALTONIZER, data, null, 0);
         } catch (RemoteException ex) {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/color/DisplayTransformManagerTest.java b/services/tests/displayservicetests/src/com/android/server/display/color/DisplayTransformManagerTest.java
index a785300..27f87aa 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/color/DisplayTransformManagerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/color/DisplayTransformManagerTest.java
@@ -161,4 +161,20 @@
                 .isEqualTo(Integer.toString(testPropertyValue));
     }
 
+    @Test
+    public void daltonizer_defaultValues() {
+        synchronized (mDtm.mDaltonizerModeLock) {
+            assertThat(mDtm.mDaltonizerMode).isEqualTo(-1);
+            assertThat(mDtm.mDaltonizerLevel).isEqualTo(-1);
+        }
+    }
+
+    @Test
+    public void setDaltonizerMode_newValues_valuesUpdated() {
+        mDtm.setDaltonizerMode(0, 0);
+        synchronized (mDtm.mDaltonizerModeLock) {
+            assertThat(mDtm.mDaltonizerMode).isEqualTo(0);
+            assertThat(mDtm.mDaltonizerLevel).isEqualTo(0);
+        }
+    }
 }