diff options
6 files changed, 191 insertions, 9 deletions
| diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a27df3a70259..62f4bf5833d3 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3096,6 +3096,12 @@ public final class Settings {          private static final Validator DIM_SCREEN_VALIDATOR = sBooleanValidator;          /** +         * The display color mode. +         * @hide +         */ +        public static final String DISPLAY_COLOR_MODE = "display_color_mode"; + +        /**           * The amount of time in milliseconds before the device goes to sleep or begins           * to dream after a period of inactivity.  This value is also known as the           * user activity timeout period since the screen isn't necessarily turned off diff --git a/core/java/com/android/internal/app/NightDisplayController.java b/core/java/com/android/internal/app/NightDisplayController.java index 7a1383c7a01c..b2053c004e2f 100644 --- a/core/java/com/android/internal/app/NightDisplayController.java +++ b/core/java/com/android/internal/app/NightDisplayController.java @@ -26,6 +26,7 @@ import android.net.Uri;  import android.os.Handler;  import android.os.Looper;  import android.provider.Settings.Secure; +import android.provider.Settings.System;  import android.util.Slog;  import com.android.internal.R; @@ -76,6 +77,29 @@ public final class NightDisplayController {       */      public static final int AUTO_MODE_TWILIGHT = 2; +    @Retention(RetentionPolicy.SOURCE) +    @IntDef({ COLOR_MODE_NATURAL, COLOR_MODE_BOOSTED, COLOR_MODE_SATURATED }) +    public @interface ColorMode {} + +    /** +     * Color mode with natural colors. +     * +     * @see #setColorMode(int) +     */ +    public static final int COLOR_MODE_NATURAL = 0; +    /** +     * Color mode with boosted colors. +     * +     * @see #setColorMode(int) +     */ +    public static final int COLOR_MODE_BOOSTED = 1; +    /** +     * Color mode with saturated colors. +     * +     * @see #setColorMode(int) +     */ +    public static final int COLOR_MODE_SATURATED = 2; +      private final Context mContext;      private final int mUserId; @@ -306,6 +330,31 @@ public final class NightDisplayController {      }      /** +     * Get the current color mode. +     */ +    public int getColorMode() { +        final int colorMode = System.getIntForUser(mContext.getContentResolver(), +            System.DISPLAY_COLOR_MODE, COLOR_MODE_BOOSTED, mUserId); +        if (colorMode < COLOR_MODE_NATURAL || colorMode > COLOR_MODE_SATURATED) { +            return COLOR_MODE_BOOSTED; +        } +        return colorMode; +    } + +    /** +     * Set the current color mode. +     * +     * @param colorMode the color mode +     */ +    public void setColorMode(@ColorMode int colorMode) { +        if (colorMode < COLOR_MODE_NATURAL || colorMode > COLOR_MODE_SATURATED) { +            throw new IllegalArgumentException("Invalid colorMode: " + colorMode); +        } +        System.putIntForUser(mContext.getContentResolver(), System.DISPLAY_COLOR_MODE, colorMode, +                mUserId); +    } + +    /**       * Returns the minimum allowed color temperature (in Kelvin) to tint the display when activated.       */      public int getMinimumColorTemperature() { @@ -351,6 +400,9 @@ public final class NightDisplayController {                  case Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE:                      mCallback.onColorTemperatureChanged(getColorTemperature());                      break; +                case System.DISPLAY_COLOR_MODE: +                    mCallback.onDisplayColorModeChanged(getColorMode()); +                    break;              }          }      } @@ -379,6 +431,8 @@ public final class NightDisplayController {                          false /* notifyForDescendants */, mContentObserver, mUserId);                  cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE),                          false /* notifyForDescendants */, mContentObserver, mUserId); +                cr.registerContentObserver(System.getUriFor(System.DISPLAY_COLOR_MODE), +                        false /* notifyForDecendants */, mContentObserver, mUserId);              }          }      } @@ -425,5 +479,12 @@ public final class NightDisplayController {           * @param colorTemperature the color temperature to tint the screen           */          default void onColorTemperatureChanged(int colorTemperature) {} + +        /** +         * Callback invoked when the color mode changes. +         * +         * @param displayColorMode the color mode +         */ +        default void onDisplayColorModeChanged(int displayColorMode) {}      }  } diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 49d251aaaac5..c2814d72ebe0 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -901,6 +901,18 @@      <!-- Maximum color temperature, in Kelvin, supported by Night display. -->      <integer name="config_nightDisplayColorTemperatureMax">4082</integer> +    <string-array name="config_nightDisplayColorTemperatureCoefficientsNative"> +        <!-- R a-coefficient --> <item>0.0</item> +        <!-- R b-coefficient --> <item>0.0</item> +        <!-- R y-intercept --> <item>1.0</item> +        <!-- G a-coefficient --> <item>-0.00000000962353339</item> +        <!-- G b-coefficient --> <item>0.000153045476</item> +        <!-- G y-intercept --> <item>0.390782778</item> +        <!-- B a-coefficient --> <item>-0.0000000189359041</item> +        <!-- B b-coefficient --> <item>0.000302412211</item> +        <!-- B y-intercept --> <item>-0.198650895</item> +    </string-array> +      <string-array name="config_nightDisplayColorTemperatureCoefficients">          <!-- R a-coefficient --> <item>0.0</item>          <!-- R b-coefficient --> <item>0.0</item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 467d61e24d7c..f301644f8f89 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2842,6 +2842,7 @@    <java-symbol type="integer" name="config_nightDisplayColorTemperatureMin" />    <java-symbol type="integer" name="config_nightDisplayColorTemperatureMax" />    <java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficients" /> +  <java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficientsNative" />    <!-- Default first user restrictions -->    <java-symbol type="array" name="config_defaultFirstUserRestrictions" /> diff --git a/services/core/java/com/android/server/display/DisplayTransformManager.java b/services/core/java/com/android/server/display/DisplayTransformManager.java index dbbb318db63b..bef6898a4ecf 100644 --- a/services/core/java/com/android/server/display/DisplayTransformManager.java +++ b/services/core/java/com/android/server/display/DisplayTransformManager.java @@ -16,15 +16,20 @@  package com.android.server.display; +import android.app.ActivityManager; +import android.app.IActivityManager;  import android.opengl.Matrix;  import android.os.IBinder;  import android.os.Parcel;  import android.os.RemoteException;  import android.os.ServiceManager; +import android.os.SystemProperties; +import android.util.Log;  import android.util.Slog;  import android.util.SparseArray;  import com.android.internal.annotations.GuardedBy; +import com.android.internal.app.NightDisplayController;  import java.util.Arrays;  /** @@ -34,6 +39,8 @@ public class DisplayTransformManager {      private static final String TAG = "DisplayTransformManager"; +    private static final String SURFACE_FLINGER = "SurfaceFlinger"; +      /**       * Color transform level used by Night display to tint the display red.       */ @@ -50,6 +57,15 @@ public class DisplayTransformManager {      private static final int SURFACE_FLINGER_TRANSACTION_COLOR_MATRIX = 1015;      private static final int SURFACE_FLINGER_TRANSACTION_DALTONIZER = 1014; +    private static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation"; +    private static final String PERSISTENT_PROPERTY_NATIVE_MODE = "persist.sys.sf.native_mode"; + +    private static final int SURFACE_FLINGER_TRANSACTION_SATURATION = 1022; +    private static final int SURFACE_FLINGER_TRANSACTION_NATIVE_MODE = 1023; + +    private static final float COLOR_SATURATION_NATURAL = 1.0f; +    private static final float COLOR_SATURATION_BOOSTED = 1.1f; +      /**       * Map of level -> color transformation matrix.       */ @@ -161,7 +177,7 @@ public class DisplayTransformManager {       * Propagates the provided color transformation matrix to the SurfaceFlinger.       */      private static void applyColorMatrix(float[] m) { -        final IBinder flinger = ServiceManager.getService("SurfaceFlinger"); +        final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER);          if (flinger != null) {              final Parcel data = Parcel.obtain();              data.writeInterfaceToken("android.ui.ISurfaceComposer"); @@ -187,7 +203,7 @@ public class DisplayTransformManager {       * Propagates the provided Daltonization mode to the SurfaceFlinger.       */      private static void applyDaltonizerMode(int mode) { -        final IBinder flinger = ServiceManager.getService("SurfaceFlinger"); +        final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER);          if (flinger != null) {              final Parcel data = Parcel.obtain();              data.writeInterfaceToken("android.ui.ISurfaceComposer"); @@ -201,4 +217,73 @@ public class DisplayTransformManager {              }          }      } + +    public static boolean isNativeModeEnabled() { +        return SystemProperties.getBoolean(PERSISTENT_PROPERTY_NATIVE_MODE, false); +    } + +    public boolean setColorMode(int colorMode) { +        if (colorMode == NightDisplayController.COLOR_MODE_NATURAL) { +            applySaturation(COLOR_SATURATION_NATURAL); +            setNativeMode(false); +        } else if (colorMode == NightDisplayController.COLOR_MODE_BOOSTED) { +            applySaturation(COLOR_SATURATION_BOOSTED); +            setNativeMode(false); +        } else if (colorMode == NightDisplayController.COLOR_MODE_SATURATED) { +            applySaturation(COLOR_SATURATION_NATURAL); +            setNativeMode(true); +        } + +        updateConfiguration(); + +        return true; +    } + +    /** +     * Propagates the provided saturation to the SurfaceFlinger. +     */ +    private void applySaturation(float saturation) { +        SystemProperties.set(PERSISTENT_PROPERTY_SATURATION, Float.toString(saturation)); +        final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER); +        if (flinger != null) { +            final Parcel data = Parcel.obtain(); +            data.writeInterfaceToken("android.ui.ISurfaceComposer"); +            data.writeFloat(saturation); +            try { +                flinger.transact(SURFACE_FLINGER_TRANSACTION_SATURATION, data, null, 0); +            } catch (RemoteException ex) { +                Log.e(TAG, "Failed to set saturation", ex); +            } finally { +                data.recycle(); +            } +        } +    } + +    /** +     * Toggles native mode on/off in SurfaceFlinger. +     */ +    private void setNativeMode(boolean enabled) { +        SystemProperties.set(PERSISTENT_PROPERTY_NATIVE_MODE, enabled ? "1" : "0"); +        final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER); +        if (flinger != null) { +            final Parcel data = Parcel.obtain(); +            data.writeInterfaceToken("android.ui.ISurfaceComposer"); +            data.writeInt(enabled ? 1 : 0); +            try { +                flinger.transact(SURFACE_FLINGER_TRANSACTION_NATIVE_MODE, data, null, 0); +            } catch (RemoteException ex) { +                Log.e(TAG, "Failed to set native mode", ex); +            } finally { +                data.recycle(); +            } +        } +    } + +    private void updateConfiguration() { +        try { +            ActivityManager.getService().updateConfiguration(null); +        } catch (RemoteException e) { +            Log.e(TAG, "Could not update configuration", e); +        } +    }  } diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java index 9cf136720881..a7c3ff9e0104 100644 --- a/services/core/java/com/android/server/display/NightDisplayService.java +++ b/services/core/java/com/android/server/display/NightDisplayService.java @@ -52,7 +52,8 @@ import java.time.LocalDateTime;  import java.time.LocalTime;  import java.time.ZoneId;  import java.util.concurrent.atomic.AtomicBoolean; -import java.util.TimeZone; + +import com.android.internal.R;  import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY; @@ -126,12 +127,6 @@ public final class NightDisplayService extends SystemService      public NightDisplayService(Context context) {          super(context);          mHandler = new Handler(Looper.getMainLooper()); - -        final String[] coefficients = context.getResources().getStringArray( -                com.android.internal.R.array.config_nightDisplayColorTemperatureCoefficients); -        for (int i = 0; i < 9 && i < coefficients.length; i++) { -            mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]); -        }      }      @Override @@ -236,6 +231,8 @@ public final class NightDisplayService extends SystemService          mController = new NightDisplayController(getContext(), mCurrentUser);          mController.setListener(this); +        setCoefficientMatrix(getContext()); +          // Prepare color transformation matrix.          setMatrix(mController.getColorTemperature(), mMatrixNight); @@ -331,6 +328,26 @@ public final class NightDisplayService extends SystemService          applyTint(true);      } +    @Override +    public void onDisplayColorModeChanged(int colorMode) { +        final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class); +        dtm.setColorMode(colorMode); + +        setCoefficientMatrix(getContext()); +        setMatrix(mController.getColorTemperature(), mMatrixNight); +        applyTint(true); +    } + +    private void setCoefficientMatrix(Context context) { +        final boolean isNative = DisplayTransformManager.isNativeModeEnabled(); +        final String[] coefficients = context.getResources().getStringArray(isNative +                ? R.array.config_nightDisplayColorTemperatureCoefficientsNative +                : R.array.config_nightDisplayColorTemperatureCoefficients); +        for (int i = 0; i < 9 && i < coefficients.length; i++) { +            mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]); +        } +    } +      /**       * Applies current color temperature matrix, or removes it if deactivated.       * |