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

Commit c317933a authored by Selim Cinek's avatar Selim Cinek
Browse files

Fixed fading and dozemode for custom notifications

The custom notifications were fading really ugly when they
had a dark background like media notifications, because
it was fading from dark to dark.
Now this background is shared for both custom views which also
reduces overdraw for them.

In addition does the doze mode now work much nicer because we're
only fading them to greyscale instead of inverting.
This also fixed an issue where legacy custom notifications with
a dark background were colorful during doze.

Bug: 19437552
Change-Id: I87798da9ac11b9abfe4470b6ca53b555da3aa629
parent e81b82ba
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@
    <item type="id" name="transformation_start_y_tag"/>
    <item type="id" name="transformation_start_scale_x_tag"/>
    <item type="id" name="transformation_start_scale_y_tag"/>
    <item type="id" name="custom_background_color"/>

    <!-- Whether the icon is from a notification for which targetSdk < L -->
    <item type="id" name="icon_is_pre_L"/>
+63 −7
Original line number Diff line number Diff line
@@ -36,7 +36,9 @@ import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackStateAnimator;

/**
 * Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
@@ -121,6 +123,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
    private float mAnimationTranslationY;
    private boolean mDrawingAppearAnimation;
    private ValueAnimator mAppearAnimator;
    private ValueAnimator mBackgroundColorAnimator;
    private float mAppearAnimationFraction = -1.0f;
    private float mAppearAnimationTranslation;
    private boolean mShowingLegacyBackground;
@@ -157,6 +160,9 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
    };
    private float mShadowAlpha = 1.0f;
    private FakeShadowView mFakeShadow;
    private int mCurrentBackgroundTint;
    private int mTargetTint;
    private int mStartTint;

    public ActivatableNotificationView(Context context, AttributeSet attrs) {
        super(context, attrs);
@@ -457,21 +463,63 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
     * Sets the tint color of the background
     */
    public void setTintColor(int color) {
        setTintColor(color, false);
    }

    /**
     * Sets the tint color of the background
     */
    public void setTintColor(int color, boolean animated) {
        mBgTint = color;
        updateBackgroundTint();
        updateBackgroundTint(animated);
    }

    protected void updateBackgroundTint() {
        int color = getBgColor();
        updateBackgroundTint(false /* animated */);
    }

    private void updateBackgroundTint(boolean animated) {
        if (mBackgroundColorAnimator != null) {
            mBackgroundColorAnimator.cancel();
        }
        int rippleColor = getRippleColor();
        mBackgroundDimmed.setRippleColor(rippleColor);
        mBackgroundNormal.setRippleColor(rippleColor);
        int color = calculateBgColor();
        if (!animated) {
            setBackgroundTintColor(color);
        } else if (color != mCurrentBackgroundTint) {
            mStartTint = mCurrentBackgroundTint;
            mTargetTint = color;
            mBackgroundColorAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
            mBackgroundColorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int newColor = NotificationUtils.interpolateColors(mStartTint, mTargetTint,
                            animation.getAnimatedFraction());
                    setBackgroundTintColor(newColor);
                }
            });
            mBackgroundColorAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
            mBackgroundColorAnimator.setInterpolator(Interpolators.LINEAR);
            mBackgroundColorAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mBackgroundColorAnimator = null;
                }
            });
            mBackgroundColorAnimator.start();
        }
    }

    private void setBackgroundTintColor(int color) {
        mCurrentBackgroundTint = color;
        if (color == mNormalColor) {
            // We don't need to tint a normal notification
            color = 0;
        }
        mBackgroundDimmed.setTint(color);
        mBackgroundNormal.setTint(color);
        mBackgroundDimmed.setRippleColor(rippleColor);
        mBackgroundNormal.setRippleColor(rippleColor);
    }

    /**
@@ -773,8 +821,12 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView

    protected abstract View getContentView();

    public int getBgColor() {
        if (mBgTint != 0) {
    public int calculateBgColor() {
        return calculateBgColor(true /* withTint */);
    }

    private int calculateBgColor(boolean withTint) {
        if (withTint && mBgTint != 0) {
            return mBgTint;
        } else if (mShowingLegacyBackground) {
            return mLegacyColor;
@@ -839,7 +891,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
    }

    public boolean hasSameBgColor(ActivatableNotificationView otherView) {
        return getBgColor() == otherView.getBgColor();
        return calculateBgColor() == otherView.calculateBgColor();
    }

    @Override
@@ -863,6 +915,10 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
                outlineTranslation);
    }

    public int getBackgroundColorWithoutTint() {
        return calculateBgColor(false /* withTint */);
    }

    public interface OnActivatedListener {
        void onActivated(ActivatableNotificationView view);
        void onActivationReset(ActivatableNotificationView view);
+9 −1
Original line number Diff line number Diff line
@@ -568,6 +568,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
        mPublicLayout.reInflateViews();
    }

    public void setContentBackground(int customBackgroundColor, boolean animate,
            NotificationContentView notificationContentView) {
        if (getShowingLayout() == notificationContentView) {
            setTintColor(customBackgroundColor, animate);
        }
    }

    public interface ExpansionLogger {
        public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
    }
@@ -1107,7 +1114,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
        } else {
            animateShowingPublic(delay, duration);
        }

        NotificationContentView showingLayout = getShowingLayout();
        showingLayout.updateBackgroundColor(animated);
        mPrivateLayout.updateExpandButtons(isExpandable());
        updateClearability();
        mShowingPublicInitialized = true;
+54 −5
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import com.android.systemui.R;
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
import com.android.systemui.statusbar.notification.NotificationCustomViewWrapper;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.NotificationViewWrapper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.RemoteInputView;
@@ -48,7 +49,7 @@ public class NotificationContentView extends FrameLayout {
    private static final int VISIBLE_TYPE_EXPANDED = 1;
    private static final int VISIBLE_TYPE_HEADSUP = 2;
    private static final int VISIBLE_TYPE_SINGLELINE = 3;
    private static final int UNDEFINED = -1;
    public static final int UNDEFINED = -1;

    private final Rect mClipBounds = new Rect();
    private final int mMinContractedHeight;
@@ -367,6 +368,7 @@ public class NotificationContentView extends FrameLayout {
            getViewForVisibleType(visibleType).setVisibility(View.VISIBLE);
            hiddenView.transformTo(shownView, 0.0f);
            mVisibleType = visibleType;
            updateBackgroundColor(true /* animate */);
        }
        if (mTransformationStartVisibleType != UNDEFINED
                && mVisibleType != mTransformationStartVisibleType) {
@@ -376,11 +378,29 @@ public class NotificationContentView extends FrameLayout {
            float transformationAmount = calculateTransformationAmount();
            shownView.transformFrom(hiddenView, transformationAmount);
            hiddenView.transformTo(shownView, transformationAmount);
            updateBackgroundTransformation(transformationAmount);
        } else {
            updateViewVisibilities(visibleType);
            updateBackgroundColor(false);
        }
    }

    private void updateBackgroundTransformation(float transformationAmount) {
        int endColor = getBackgroundColor(mVisibleType);
        int startColor = getBackgroundColor(mTransformationStartVisibleType);
        if (endColor != startColor) {
            if (startColor == 0) {
                startColor = mContainingNotification.getBackgroundColorWithoutTint();
            }
            if (endColor == 0) {
                endColor = mContainingNotification.getBackgroundColorWithoutTint();
            }
            endColor = NotificationUtils.interpolateColors(startColor, endColor,
                    transformationAmount);
        }
        mContainingNotification.setContentBackground(endColor, false, this);
    }

    private float calculateTransformationAmount() {
        int startHeight = getViewForVisibleType(mTransformationStartVisibleType).getHeight();
        int endHeight = getViewForVisibleType(mVisibleType).getHeight();
@@ -457,7 +477,22 @@ public class NotificationContentView extends FrameLayout {
                updateViewVisibilities(visibleType);
            }
            mVisibleType = visibleType;
            updateBackgroundColor(animate);
        }
    }

    public void updateBackgroundColor(boolean animate) {
        int customBackgroundColor = getBackgroundColor(mVisibleType);
        mContainingNotification.setContentBackground(customBackgroundColor, animate, this);
    }

    private int getBackgroundColor(int visibleType) {
        NotificationViewWrapper currentVisibleWrapper = getVisibleWrapper(visibleType);
        int customBackgroundColor = 0;
        if (currentVisibleWrapper != null) {
            customBackgroundColor = currentVisibleWrapper.getCustomBackgroundColor();
        }
        return customBackgroundColor;
    }

    private void updateViewVisibilities(int visibleType) {
@@ -530,8 +565,8 @@ public class NotificationContentView extends FrameLayout {
        }
    }

    private NotificationViewWrapper getCurrentVisibleWrapper() {
        switch (mVisibleType) {
    private NotificationViewWrapper getVisibleWrapper(int visibleType) {
        switch (visibleType) {
            case VISIBLE_TYPE_EXPANDED:
                return mExpandedWrapper;
            case VISIBLE_TYPE_HEADSUP:
@@ -606,7 +641,6 @@ public class NotificationContentView extends FrameLayout {
            return;
        }
        mDark = dark;
        dark = dark && !mShowingLegacyBackground;
        if (mVisibleType == VISIBLE_TYPE_CONTRACTED || !dark) {
            mContractedWrapper.setDark(dark, fade, delay);
        }
@@ -637,6 +671,19 @@ public class NotificationContentView extends FrameLayout {

    public void setShowingLegacyBackground(boolean showing) {
        mShowingLegacyBackground = showing;
        updateShowingLegacyBackground();
    }

    private void updateShowingLegacyBackground() {
        if (mContractedChild != null) {
            mContractedWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
        }
        if (mExpandedChild != null) {
            mExpandedWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
        }
        if (mHeadsUpChild != null) {
            mHeadsUpWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
        }
    }

    public void setIsChildInGroup(boolean isChildInGroup) {
@@ -658,6 +705,7 @@ public class NotificationContentView extends FrameLayout {
        if (mHeadsUpChild != null) {
            mHeadsUpWrapper.notifyContentUpdated(entry.notification);
        }
        updateShowingLegacyBackground();
        selectLayout(false /* animate */, true /* force */);
        setDark(mDark, false /* animate */, 0 /* delay */);
    }
@@ -779,7 +827,7 @@ public class NotificationContentView extends FrameLayout {
    }

    public NotificationHeaderView getVisibleNotificationHeader() {
        NotificationViewWrapper wrapper = getCurrentVisibleWrapper();
        NotificationViewWrapper wrapper = getVisibleWrapper(mVisibleType);
        return wrapper == null ? null : wrapper.getNotificationHeader();
    }

@@ -807,6 +855,7 @@ public class NotificationContentView extends FrameLayout {
            mTransformationStartVisibleType = UNDEFINED;
            mVisibleType = calculateVisibleType();
            updateViewVisibilities(mVisibleType);
            updateBackgroundColor(false);
        }
    }
}
+86 −3
Original line number Diff line number Diff line
@@ -16,8 +16,19 @@

package com.android.systemui.statusbar.notification;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.graphics.Color;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.service.notification.StatusBarNotification;
import android.support.v4.graphics.ColorUtils;
import android.view.View;

import com.android.systemui.R;
import com.android.systemui.ViewInvertHelper;
import com.android.systemui.statusbar.phone.NotificationPanelView;

@@ -27,6 +38,11 @@ import com.android.systemui.statusbar.phone.NotificationPanelView;
public class NotificationCustomViewWrapper extends NotificationViewWrapper {

    private final ViewInvertHelper mInvertHelper;
    private final Paint mGreyPaint = new Paint();
    private int mBackgroundColor = 0;
    private static final int CUSTOM_BACKGROUND_TAG = R.id.custom_background_color;
    private boolean mShouldInvertDark;
    private boolean mShowingLegacyBackground;

    protected NotificationCustomViewWrapper(View view) {
        super(view);
@@ -39,11 +55,47 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper {
            return;
        }
        super.setDark(dark, fade, delay);
        if (!mShowingLegacyBackground && mShouldInvertDark) {
            if (fade) {
                mInvertHelper.fade(dark, delay);
            } else {
                mInvertHelper.update(dark);
            }
        } else {
            mView.setLayerType(dark ? View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE, null);
            if (fade) {
                fadeGrayscale(dark, delay);
            } else {
                updateGrayscale(dark);
            }
        }
    }

    protected void fadeGrayscale(final boolean dark, long delay) {
        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                updateGrayscaleMatrix((float) animation.getAnimatedValue());
                mGreyPaint.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
                mView.setLayerPaint(mGreyPaint);
            }
        }, dark, delay, new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                if (!dark) {
                    mView.setLayerType(View.LAYER_TYPE_NONE, null);
                }
            }
        });
    }

    protected void updateGrayscale(boolean dark) {
        if (dark) {
            updateGrayscaleMatrix(1f);
            mGreyPaint.setColorFilter(
                    new ColorMatrixColorFilter(mGrayscaleColorMatrix));
            mView.setLayerPaint(mGreyPaint);
        }
    }

    @Override
@@ -51,4 +103,35 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper {
        super.setVisible(visible);
        mView.setAlpha(visible ? 1.0f : 0.0f);
    }

    @Override
    public void notifyContentUpdated(StatusBarNotification notification) {
        super.notifyContentUpdated(notification);
        Drawable background = mView.getBackground();
        mBackgroundColor = 0;
        if (background instanceof ColorDrawable) {
            mBackgroundColor = ((ColorDrawable) background).getColor();
            mView.setBackground(null);
            mView.setTag(CUSTOM_BACKGROUND_TAG, mBackgroundColor);
        } else if (mView.getTag(CUSTOM_BACKGROUND_TAG) != null) {
            mBackgroundColor = (int) mView.getTag(CUSTOM_BACKGROUND_TAG);
        }
        mShouldInvertDark = mBackgroundColor == 0 || isColorLight(mBackgroundColor);
    }

    private boolean isColorLight(int backgroundColor) {
        return Color.alpha(backgroundColor) == 0
                || ColorUtils.calculateLuminance(backgroundColor) > 0.5;
    }

    @Override
    public int getCustomBackgroundColor() {
        return mBackgroundColor;
    }

    @Override
    public void setShowingLegacyBackground(boolean showing) {
        super.setShowingLegacyBackground(showing);
        mShowingLegacyBackground = showing;
    }
}
Loading