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

Commit 35943915 authored by Evan Laird's avatar Evan Laird
Browse files

[Sb] Add background and foreground support to icon tints

This CL adds the possibility to tint a status bar icon with both a
background and foreground color. It does this by making the following
changes:

1. Add support for tint and foregroundColor in TintedIconManager
2. Define contrasting colors for DarkIconDispatcher, and add a new
   callback that exposes them
3. Support a new interface method (with a default impl) on
   StatusIconDisplayable that can accept the foreground tint

As of now, there are no clients of this new tint color. Follow-up CLs
will implement usage on ModernStatusBarMobileView.

Test: compile
Test: visually inspect that icons are the same color
Test: check dumpsys for information from DarkIconDispatcher
Bug: 270385675
Change-Id: I3280ba7839d7b351ea97e0cb42e2450c0b4b935b
parent 502ec035
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -371,7 +371,8 @@ private fun StatusIcons(
            val iconContainer = StatusIconContainer(context, null)
            val iconManager = createTintedIconManager(iconContainer, StatusBarLocation.QS)
            iconManager.setTint(
                Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary)
                Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary),
                Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimaryInverse),
            )
            statusBarIconController.addIconGroup(iconManager)

+50 −1
Original line number Diff line number Diff line
@@ -71,7 +71,11 @@ public interface DarkIconDispatcher {
      */
    void applyDark(DarkReceiver object);

    /** The default tint (applicable for dark backgrounds) is white */
    int DEFAULT_ICON_TINT = Color.WHITE;
    /** To support an icon which wants to create contrast, the default tint is black-on-white. */
    int DEFAULT_INVERSE_ICON_TINT = Color.BLACK;

    Rect sTmpRect = new Rect();
    int[] sTmpInt2 = new int[2];

@@ -87,6 +91,18 @@ public interface DarkIconDispatcher {
        }
    }

    /**
     * @return the tint to apply to a foreground, given that the background is tinted
     *         per {@link #getTint}
     */
    static int getInverseTint(Collection<Rect> tintAreas, View view, int inverseColor) {
        if (isInAreas(tintAreas, view)) {
            return inverseColor;
        } else {
            return DEFAULT_INVERSE_ICON_TINT;
        }
    }

    /**
     * @return true if more than half of the view area are in any of the given
     *         areas, false otherwise
@@ -129,7 +145,40 @@ public interface DarkIconDispatcher {
     */
    @ProvidesInterface(version = DarkReceiver.VERSION)
    interface DarkReceiver {
        int VERSION = 2;
        int VERSION = 3;

        /**
         * @param areas list of regions on screen where the tint applies
         * @param darkIntensity float representing the level of tint. In the range [0,1]
         * @param tint the tint applicable as a foreground contrast to the dark regions. This value
         *             is interpolated between a default light and dark tone, and is therefore
         *             usable as-is, as long as the view is in one of the areas defined in
         *             {@code areas}.
         *
         * @see DarkIconDispatcher#isInArea(Rect, View) for utilizing {@code areas}
         *
         * Note: only one of {@link #onDarkChanged(ArrayList, float, int)} or
         * {@link #onDarkChangedWithContrast(ArrayList, int, int)} need to be implemented, as both
         * will be called in the same circumstances.
         */
        void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint);

        /**
         * New version of onDarkChanged, which describes a tint plus an optional contrastTint
         * that can be used if the tint is applied to the background of an icon.
         *
         * We use the 2 here to avoid the case where an existing override of onDarkChanged
         * might pass in parameters as bare numbers (e.g. 0 instead of 0f) which might get
         * mistakenly cast to (int) and therefore trigger this method.
         *
         * @param areas list of areas where dark tint applies
         * @param tint int describing the tint color to use
         * @param contrastTint if desired, a contrasting color that can be used for a foreground
         *
         * Note: only one of {@link #onDarkChanged(ArrayList, float, int)} or
         * {@link #onDarkChangedWithContrast(ArrayList, int, int)} need to be implemented, as both
         * will be called in the same circumstances.
         */
        default void onDarkChangedWithContrast(ArrayList<Rect> areas, int tint, int contrastTint) {}
    }
}
+3 −2
Original line number Diff line number Diff line
@@ -38,7 +38,6 @@ import androidx.core.view.doOnLayout
import com.android.app.animation.Interpolators
import com.android.settingslib.Utils
import com.android.systemui.Dumpable
import com.android.systemui.res.R
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.battery.BatteryMeterView
import com.android.systemui.battery.BatteryMeterViewController
@@ -49,6 +48,7 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.ChipVisibilityListener
import com.android.systemui.qs.HeaderPrivacyIconsController
import com.android.systemui.res.R
import com.android.systemui.shade.ShadeHeaderController.Companion.HEADER_TRANSITION_ID
import com.android.systemui.shade.ShadeHeaderController.Companion.LARGE_SCREEN_HEADER_CONSTRAINT
import com.android.systemui.shade.ShadeHeaderController.Companion.LARGE_SCREEN_HEADER_TRANSITION_ID
@@ -304,7 +304,8 @@ constructor(

        iconManager = tintedIconManagerFactory.create(iconContainer, StatusBarLocation.QS)
        iconManager.setTint(
            Utils.getColorAttrDefaultColor(header.context, android.R.attr.textColorPrimary)
            Utils.getColorAttrDefaultColor(header.context, android.R.attr.textColorPrimary),
            Utils.getColorAttrDefaultColor(header.context, android.R.attr.textColorPrimaryInverse),
        )

        carrierIconSlots =
+15 −0
Original line number Diff line number Diff line
@@ -21,6 +21,21 @@ import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
public interface StatusIconDisplayable extends DarkReceiver {
    String getSlot();
    void setStaticDrawableColor(int color);

    /**
     * For a layer drawable, or one that has a background, {@code tintColor} should be used as the
     * background tint for the container, while {@code contrastColor} can be used as the foreground
     * drawable's tint so that it is visible on the background. Essentially, tintColor should apply
     * to the portion of the icon that borders the underlying window content (status bar's
     * background), and the contrastColor only need be used to distinguish from the tintColor.
     *
     * Defaults to calling {@link #setStaticDrawableColor(int)} with only the tint color, so modern
     * callers can just call this method and still get the default behavior.
     */
    default void setStaticDrawableColor(int tintColor, int contrastColor) {
        setStaticDrawableColor(tintColor);
    }

    void setDecorColor(int color);

    /** Sets the visible state that this displayable should be. */
+25 −1
Original line number Diff line number Diff line
@@ -47,6 +47,11 @@ public class DarkIconDispatcherImpl implements SysuiDarkIconDispatcher,
    private final ArrayMap<Object, DarkReceiver> mReceivers = new ArrayMap<>();

    private int mIconTint = DEFAULT_ICON_TINT;
    private int mContrastTint = DEFAULT_INVERSE_ICON_TINT;

    private int mDarkModeContrastColor = DEFAULT_ICON_TINT;
    private int mLightModeContrastColor = DEFAULT_INVERSE_ICON_TINT;

    private float mDarkIntensity;
    private int mDarkModeIconColorSingleTone;
    private int mLightModeIconColorSingleTone;
@@ -83,6 +88,7 @@ public class DarkIconDispatcherImpl implements SysuiDarkIconDispatcher,
    public void addDarkReceiver(DarkReceiver receiver) {
        mReceivers.put(receiver, receiver);
        receiver.onDarkChanged(mTintAreas, mDarkIntensity, mIconTint);
        receiver.onDarkChangedWithContrast(mTintAreas, mIconTint, mContrastTint);
    }

    public void addDarkReceiver(ImageView imageView) {
@@ -90,6 +96,7 @@ public class DarkIconDispatcherImpl implements SysuiDarkIconDispatcher,
                ColorStateList.valueOf(getTint(mTintAreas, imageView, mIconTint)));
        mReceivers.put(imageView, receiver);
        receiver.onDarkChanged(mTintAreas, mDarkIntensity, mIconTint);
        receiver.onDarkChangedWithContrast(mTintAreas, mIconTint, mContrastTint);
    }

    public void removeDarkReceiver(DarkReceiver object) {
@@ -102,6 +109,7 @@ public class DarkIconDispatcherImpl implements SysuiDarkIconDispatcher,

    public void applyDark(DarkReceiver object) {
        mReceivers.get(object).onDarkChanged(mTintAreas, mDarkIntensity, mIconTint);
        mReceivers.get(object).onDarkChangedWithContrast(mTintAreas, mIconTint, mContrastTint);
    }

    /**
@@ -125,8 +133,13 @@ public class DarkIconDispatcherImpl implements SysuiDarkIconDispatcher,
    @Override
    public void applyDarkIntensity(float darkIntensity) {
        mDarkIntensity = darkIntensity;
        mIconTint = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
        ArgbEvaluator evaluator = ArgbEvaluator.getInstance();

        mIconTint = (int) evaluator.evaluate(darkIntensity,
                mLightModeIconColorSingleTone, mDarkModeIconColorSingleTone);
        mContrastTint = (int) evaluator
                .evaluate(darkIntensity, mLightModeContrastColor, mDarkModeContrastColor);

        applyIconTint();
    }

@@ -139,6 +152,7 @@ public class DarkIconDispatcherImpl implements SysuiDarkIconDispatcher,
        mDarkChangeFlow.setValue(new DarkChange(mTintAreas, mDarkIntensity, mIconTint));
        for (int i = 0; i < mReceivers.size(); i++) {
            mReceivers.valueAt(i).onDarkChanged(mTintAreas, mDarkIntensity, mIconTint);
            mReceivers.valueAt(i).onDarkChangedWithContrast(mTintAreas, mIconTint, mContrastTint);
        }
    }

@@ -146,6 +160,16 @@ public class DarkIconDispatcherImpl implements SysuiDarkIconDispatcher,
    public void dump(PrintWriter pw, String[] args) {
        pw.println("DarkIconDispatcher: ");
        pw.println("  mIconTint: 0x" + Integer.toHexString(mIconTint));
        pw.println("  mContrastTint: 0x" + Integer.toHexString(mContrastTint));

        pw.println("  mDarkModeIconColorSingleTone: 0x"
                + Integer.toHexString(mDarkModeIconColorSingleTone));
        pw.println("  mLightModeIconColorSingleTone: 0x"
                + Integer.toHexString(mLightModeIconColorSingleTone));

        pw.println("  mDarkModeContrastColor: 0x" + Integer.toHexString(mDarkModeContrastColor));
        pw.println("  mLightModeContrastColor: 0x" + Integer.toHexString(mLightModeContrastColor));

        pw.println("  mDarkIntensity: " + mDarkIntensity + "f");
        pw.println("  mTintAreas: " + mTintAreas);
    }
Loading