Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 44a95593 authored by Christine Franks's avatar Christine Franks
Browse files

Add tint controller for bright color reduction

Bug: 168065315
Test: atest FrameworksServicesTests:ColorDisplayServiceTest and
atest FrameworksServicesTests:ReduceBrightColorsTintControllerTest

Change-Id: I777cafa01e33b06778cf6bc07c91211f9a7e6570
parent b37c18a5
Loading
Loading
Loading
Loading
+86 −16
Original line number Diff line number Diff line
@@ -77,7 +77,6 @@ import com.android.internal.util.DumpUtils;
import com.android.server.DisplayThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemService.TargetUser;
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
@@ -119,6 +118,7 @@ public final class ColorDisplayService extends SystemService {
    private static final int MSG_APPLY_NIGHT_DISPLAY_ANIMATED = 3;
    private static final int MSG_APPLY_GLOBAL_SATURATION = 4;
    private static final int MSG_APPLY_DISPLAY_WHITE_BALANCE = 5;
    private static final int MSG_APPLY_REDUCE_BRIGHT_COLORS = 6;

    /**
     * Return value if a setting has not been set.
@@ -129,17 +129,6 @@ public final class ColorDisplayService extends SystemService {
     * Evaluator used to animate color matrix transitions.
     */
    private static final ColorMatrixEvaluator COLOR_MATRIX_EVALUATOR = new ColorMatrixEvaluator();

    private final NightDisplayTintController mNightDisplayTintController =
            new NightDisplayTintController();

    @VisibleForTesting
    final DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController =
            new DisplayWhiteBalanceTintController();

    private final TintController mGlobalSaturationTintController =
            new GlobalSaturationTintController();

    /**
     * Matrix and offset used for converting color to grayscale.
     */
@@ -163,6 +152,16 @@ public final class ColorDisplayService extends SystemService {
            1f, 1f, 1f, 1f
    };

    @VisibleForTesting
    final DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController =
            new DisplayWhiteBalanceTintController();
    private final NightDisplayTintController mNightDisplayTintController =
            new NightDisplayTintController();
    private final TintController mGlobalSaturationTintController =
            new GlobalSaturationTintController();
    private final ReduceBrightColorsTintController mReduceBrightColorsTintController =
            new ReduceBrightColorsTintController();

    private final Handler mHandler;

    private final AppSaturationController mAppSaturationController = new AppSaturationController();
@@ -354,6 +353,14 @@ public final class ColorDisplayService extends SystemService {
                            case Secure.DISPLAY_WHITE_BALANCE_ENABLED:
                                updateDisplayWhiteBalanceStatus();
                                break;
                            case Secure.REDUCE_BRIGHT_COLORS_ACTIVATED:
                                onReduceBrightColorsActivationChanged();
                                mHandler.sendEmptyMessage(MSG_APPLY_REDUCE_BRIGHT_COLORS);
                                break;
                            case Secure.REDUCE_BRIGHT_COLORS_LEVEL:
                                onReduceBrightColorsStrengthLevelChanged();
                                mHandler.sendEmptyMessage(MSG_APPLY_REDUCE_BRIGHT_COLORS);
                                break;
                        }
                    }
                }
@@ -372,17 +379,19 @@ public final class ColorDisplayService extends SystemService {
                false /* notifyForDescendants */, mContentObserver, mCurrentUser);
        cr.registerContentObserver(System.getUriFor(System.DISPLAY_COLOR_MODE),
                false /* notifyForDescendants */, mContentObserver, mCurrentUser);
        cr.registerContentObserver(
                Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
        cr.registerContentObserver(Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
                false /* notifyForDescendants */, mContentObserver, mCurrentUser);
        cr.registerContentObserver(
                Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
                false /* notifyForDescendants */, mContentObserver, mCurrentUser);
        cr.registerContentObserver(
                Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
        cr.registerContentObserver(Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
                false /* notifyForDescendants */, mContentObserver, mCurrentUser);
        cr.registerContentObserver(Secure.getUriFor(Secure.DISPLAY_WHITE_BALANCE_ENABLED),
                false /* notifyForDescendants */, mContentObserver, mCurrentUser);
        cr.registerContentObserver(Secure.getUriFor(Secure.REDUCE_BRIGHT_COLORS_ACTIVATED),
                false /* notifyForDescendants */, mContentObserver, mCurrentUser);
        cr.registerContentObserver(Secure.getUriFor(Secure.REDUCE_BRIGHT_COLORS_LEVEL),
                false /* notifyForDescendants */, mContentObserver, mCurrentUser);

        // Apply the accessibility settings first, since they override most other settings.
        onAccessibilityInversionChanged();
@@ -420,6 +429,17 @@ public final class ColorDisplayService extends SystemService {

            updateDisplayWhiteBalanceStatus();
        }

        if (mReduceBrightColorsTintController.isAvailable(getContext())) {
            mReduceBrightColorsTintController
                    .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
            onReduceBrightColorsStrengthLevelChanged();
            final boolean reset = resetReduceBrightColors();
            if (!reset) {
                onReduceBrightColorsActivationChanged();
                mHandler.sendEmptyMessage(MSG_APPLY_REDUCE_BRIGHT_COLORS);
            }
        }
    }

    private void tearDown() {
@@ -444,6 +464,27 @@ public final class ColorDisplayService extends SystemService {
        if (mGlobalSaturationTintController.isAvailable(getContext())) {
            mGlobalSaturationTintController.setActivated(null);
        }

        if (mReduceBrightColorsTintController.isAvailable(getContext())) {
            mReduceBrightColorsTintController.setActivated(null);
        }
    }

    private boolean resetReduceBrightColors() {
        if (mCurrentUser == UserHandle.USER_NULL) {
            return false;
        }

        final boolean isSettingActivated = Secure.getIntForUser(getContext().getContentResolver(),
                Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 0, mCurrentUser) == 1;
        final boolean shouldResetOnReboot = Secure.getIntForUser(getContext().getContentResolver(),
                Secure.REDUCE_BRIGHT_COLORS_PERSIST_ACROSS_REBOOTS, 0, mCurrentUser) == 0;
        if (isSettingActivated && mReduceBrightColorsTintController.isActivatedStateNotSet()
                && shouldResetOnReboot) {
            return Secure.putIntForUser(getContext().getContentResolver(),
                    Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 0, mCurrentUser);
        }
        return false;
    }

    private void onNightDisplayAutoModeChanged(int autoMode) {
@@ -572,6 +613,24 @@ public final class ColorDisplayService extends SystemService {
                isAccessiblityInversionEnabled() ? MATRIX_INVERT_COLOR : null);
    }

    private void onReduceBrightColorsActivationChanged() {
        if (mCurrentUser == UserHandle.USER_NULL) {
            return;
        }
        mReduceBrightColorsTintController.setActivated(
                Secure.getIntForUser(getContext().getContentResolver(),
                        Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 0, mCurrentUser) == 1);
    }

    private void onReduceBrightColorsStrengthLevelChanged() {
        if (mCurrentUser == UserHandle.USER_NULL) {
            return;
        }
        mReduceBrightColorsTintController.setMatrix(
                Secure.getIntForUser(getContext().getContentResolver(),
                        Secure.REDUCE_BRIGHT_COLORS_LEVEL, 0, mCurrentUser));
    }

    /**
     * Applies current color temperature matrix, or removes it if deactivated.
     *
@@ -937,6 +996,14 @@ public final class ColorDisplayService extends SystemService {
            pw.println("    Not available");
        }

        pw.println("Reduce bright colors:");
        if (mReduceBrightColorsTintController.isAvailable(getContext())) {
            pw.println("    Activated: " + mReduceBrightColorsTintController.isActivated());
            mReduceBrightColorsTintController.dump(pw);
        } else {
            pw.println("    Not available");
        }

        pw.println("Color mode: " + getColorModeInternal());
    }

@@ -1438,6 +1505,9 @@ public final class ColorDisplayService extends SystemService {
                    mGlobalSaturationTintController.setMatrix(msg.arg1);
                    applyTint(mGlobalSaturationTintController, false);
                    break;
                case MSG_APPLY_REDUCE_BRIGHT_COLORS:
                    applyTint(mReduceBrightColorsTintController, true);
                    break;
                case MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE:
                    applyTint(mNightDisplayTintController, true);
                    break;
+5 −1
Original line number Diff line number Diff line
@@ -58,6 +58,10 @@ public class DisplayTransformManager {
     * Color transform level used by A11y services to make the display monochromatic.
     */
    public static final int LEVEL_COLOR_MATRIX_GRAYSCALE = 200;
    /**
     * Color transform level used by A11y services to reduce bright colors.
     */
    public static final int LEVEL_COLOR_MATRIX_REDUCE_BRIGHT_COLORS = 250;
    /**
     * Color transform level used by A11y services to invert the display colors.
     */
@@ -97,7 +101,7 @@ public class DisplayTransformManager {
     * Map of level -> color transformation matrix.
     */
    @GuardedBy("mColorMatrix")
    private final SparseArray<float[]> mColorMatrix = new SparseArray<>(5);
    private final SparseArray<float[]> mColorMatrix = new SparseArray<>(6);
    /**
     * Temporary matrix used internally by {@link #computeColorMatrixLocked()}.
     */
+113 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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 com.android.server.display.color;

import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_REDUCE_BRIGHT_COLORS;

import android.content.Context;
import android.hardware.display.ColorDisplayManager;
import android.opengl.Matrix;
import android.util.Slog;

import com.android.internal.R;

import java.io.PrintWriter;
import java.util.Arrays;

/**
 * Control the color transform for bright color reduction.
 */
public class ReduceBrightColorsTintController extends TintController {

    private final float[] mMatrix = new float[16];
    private final float[] mCoefficients = new float[9];

    private int mStrength;

    @Override
    public void setUp(Context context, boolean needsLinear) {
        final String[] coefficients = context.getResources().getStringArray(
                needsLinear ? R.array.config_reduceBrightColorsCoefficients
                        : R.array.config_reduceBrightColorsCoefficientsNative);
        for (int i = 0; i < 9 && i < coefficients.length; i++) {
            mCoefficients[i] = Float.parseFloat(coefficients[i]);
        }
    }

    @Override
    public float[] getMatrix() {
        return isActivated() ? Arrays.copyOf(mMatrix, mMatrix.length)
                : ColorDisplayService.MATRIX_IDENTITY;
    }

    @Override
    public void setMatrix(int strengthLevel) {
        // Clamp to valid range.
        if (strengthLevel < 0) {
            strengthLevel = 0;
        } else if (strengthLevel > 100) {
            strengthLevel = 100;
        }
        Slog.d(ColorDisplayService.TAG, "Setting bright color reduction level: " + strengthLevel);
        mStrength = strengthLevel;

        Matrix.setIdentityM(mMatrix, 0);

        final float percentageStrength = strengthLevel / 100f;
        final float squaredPercentageStrength = percentageStrength * percentageStrength;
        final float red =
                squaredPercentageStrength * mCoefficients[0] + percentageStrength * mCoefficients[1]
                        + mCoefficients[2];
        final float green =
                squaredPercentageStrength * mCoefficients[3] + percentageStrength * mCoefficients[4]
                        + mCoefficients[5];
        final float blue =
                squaredPercentageStrength * mCoefficients[6] + percentageStrength * mCoefficients[7]
                        + mCoefficients[8];
        mMatrix[0] = clamp(red);
        mMatrix[5] = clamp(green);
        mMatrix[10] = clamp(blue);
    }

    private float clamp(float value) {
        if (value > 1f) {
            return 1f;
        } else if (value < 0f) {
            return 0f;
        }
        return value;
    }

    @Override
    public void dump(PrintWriter pw) {
        pw.println("    mStrength = " + mStrength);
    }

    @Override
    public int getLevel() {
        return LEVEL_COLOR_MATRIX_REDUCE_BRIGHT_COLORS;
    }

    @Override
    public boolean isAvailable(Context context) {
        return ColorDisplayManager.isColorTransformAccelerated(context);
    }

    public int getStrength() {
        return mStrength;
    }
}