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

Commit a47ea5ec authored by Julia Tuttle's avatar Julia Tuttle
Browse files

Restore the notification background's hovered/pressed tints

As far as I know, NotificationBackgroundView always has the "custom
background" set to R.drawable.notification_material_bg, which is a
layer-list with two layers:

The bottom layer is the real notification background color, which (at
the moment) defaults to materialColorSurfaceContainerHigh, and should be
replaced with the tint color if the notification is colorized.

The top layer is a selector that blends in a state-dependent amount of
the notification foreground color, which (at the moment) defaults to
materialColorOnSurface, and should be replaced with the calculated
foreground color if the notification is colorized. This is what gives
the notification background's default, hovered, and pressed states a
distinct appearance.

Right now, neither of those things are happening. At first, we were
tinting the entire LayerDrawable with the tint color, but *only when not
hovered or pressed*, so the notification would de-colorize when hovered
or pressed.

I "fixed" that in ag/25397894 by tinting it in all three states, but
then the default, hovered, and pressed states became indistinguishable.

This change specifically updates only the *bottom* layer with a
colorized notification's background color, so the default, hovered, and
pressed states are all colorized *and* distinguishable.

This change does *not* update the *top* layer with a colorized
notification's *foreground* color, which would result in more
distinguishable states for some color situations, but would also require
much more plumbing of colors.

Bug: 277285099
Bug: 310318993
Test: manual: observe default/hovered/pressed states of colorized notif
Flag: NA
Change-Id: Ie2d256fa73155647742293f8fc5db33a2053db8b
parent 66461b5b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
        android:color="?android:attr/colorControlHighlight">
    <item>
    <item android:id="@+id/notification_background_color_layer">
        <shape>
            <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" />
        </shape>
+38 −13
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import androidx.annotation.NonNull;
@@ -42,9 +43,11 @@ import java.util.Arrays;
 * A view that can be used for both the dimmed and normal background of an notification.
 */
public class NotificationBackgroundView extends View implements Dumpable {
    private static final String TAG = "NotificationBackgroundView";

    private final boolean mDontModifyCorners;
    private Drawable mBackground;
    private Drawable mBackgroundDrawableToTint;
    private int mClipTopAmount;
    private int mClipBottomAmount;
    private int mTintColor;
@@ -131,6 +134,7 @@ public class NotificationBackgroundView extends View implements Dumpable {
            unscheduleDrawable(mBackground);
        }
        mBackground = background;
        mBackgroundDrawableToTint = findBackgroundDrawableToTint(mBackground);
        mRippleColor = null;
        mBackground.mutate();
        if (mBackground != null) {
@@ -144,25 +148,46 @@ public class NotificationBackgroundView extends View implements Dumpable {
        invalidate();
    }

    // setCustomBackground should be called from ActivatableNotificationView.initBackground
    // with R.drawable.notification_material_bg, which is a layer-list with a lower layer
    // for the background color (annotated with an ID so we can find it) and an upper layer
    // to blend in the stateful @color/notification_overlay_color.
    //
    // If the notification is tinted, we want to set a tint list on *just that lower layer* that
    // will replace the default materialColorSurfaceContainerHigh *without* wiping out the stateful
    // tints in the upper layer that make the hovered and pressed states visible.
    //
    // This function fishes that lower layer out, or makes a fuss in logcat if it can't find it.
    private @Nullable Drawable findBackgroundDrawableToTint(@Nullable Drawable background) {
        if (background == null) {
            return null;
        }

        if (!(background instanceof LayerDrawable)) {
            Log.wtf(TAG, "background is not a LayerDrawable: " + background);
            return background;
        }

        final Drawable backgroundColorLayer = ((LayerDrawable) background).findDrawableByLayerId(
                R.id.notification_background_color_layer);

        if (backgroundColorLayer == null) {
            Log.wtf(TAG, "background is missing background color layer: " + background);
            return background;
        }

        return backgroundColorLayer;
    }

    public void setCustomBackground(int drawableResId) {
        final Drawable d = mContext.getDrawable(drawableResId);
        setCustomBackground(d);
    }

    public void setTint(int tintColor) {
        if (tintColor != 0) {
            ColorStateList stateList = new ColorStateList(new int[][]{
                    new int[]{com.android.internal.R.attr.state_pressed},
                    new int[]{com.android.internal.R.attr.state_hovered},
                    new int[]{}},

                    new int[]{tintColor, tintColor, tintColor}
            );
            mBackground.setTintMode(PorterDuff.Mode.SRC_ATOP);
            mBackground.setTintList(stateList);
        } else {
            mBackground.setTintList(null);
        }
        mBackgroundDrawableToTint.setTint(tintColor);
        mBackgroundDrawableToTint.setTintMode(PorterDuff.Mode.SRC_ATOP);

        mTintColor = tintColor;
        invalidate();
    }