Minimize use of header in adjusting notification colors.

Also adds support for 'inverted' icons.

Test: atest SystemUITests
Test: manual testing of numerous notification configurations
Change-Id: I6fd9aeec9f5971495d514add2bbb30b50db7d3c1
This commit is contained in:
Jeff DeCew
2020-10-21 09:44:49 -04:00
parent 73e65d4291
commit 858ad2ac33
6 changed files with 134 additions and 54 deletions

View File

@@ -82,7 +82,6 @@ import android.util.Pair;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.Gravity;
import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewGroup;
import android.view.contentcapture.ContentCaptureContext;
@@ -5862,24 +5861,16 @@ public class Notification implements Parcelable
}
/**
* Apply any necessariy colors to the small icon
* Apply any necessary colors to the small icon
*/
private void processSmallIconColor(Icon smallIcon, RemoteViews contentView,
StandardTemplateParams p) {
boolean colorable = !isLegacy() || getColorUtil().isGrayscaleIcon(mContext, smallIcon);
int color;
if (isColorized(p)) {
color = getPrimaryTextColor(p);
} else {
color = resolveContrastColor(p);
}
if (colorable) {
contentView.setDrawableTint(R.id.icon, false, color,
PorterDuff.Mode.SRC_ATOP);
}
int color = isColorized(p) ? getPrimaryTextColor(p) : resolveContrastColor(p);
contentView.setInt(R.id.icon, "setBackgroundColor",
resolveBackgroundColor(p));
contentView.setInt(R.id.icon, "setOriginalIconColor",
colorable ? color : NotificationHeaderView.NO_COLOR);
colorable ? color : COLOR_INVALID);
}
/**
@@ -5892,8 +5883,8 @@ public class Notification implements Parcelable
if (largeIcon != null && isLegacy()
&& getColorUtil().isGrayscaleIcon(mContext, largeIcon)) {
// resolve color will fall back to the default when legacy
contentView.setDrawableTint(R.id.icon, false, resolveContrastColor(p),
PorterDuff.Mode.SRC_ATOP);
int color = resolveContrastColor(p);
contentView.setInt(R.id.icon, "setOriginalIconColor", color);
}
}

View File

@@ -17,7 +17,6 @@
package android.view;
import android.annotation.Nullable;
import android.app.Notification;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Resources;
@@ -42,7 +41,6 @@ import java.util.ArrayList;
*/
@RemoteViews.RemoteView
public class NotificationHeaderView extends ViewGroup {
public static final int NO_COLOR = Notification.COLOR_INVALID;
private final int mChildMinWidth;
private final int mContentEndMargin;
private final int mGravity;
@@ -294,14 +292,6 @@ public class NotificationHeaderView extends ViewGroup {
updateTouchListener();
}
public int getOriginalIconColor() {
return mIcon.getOriginalIconColor();
}
public int getOriginalNotificationColor() {
return mExpandButton.getOriginalNotificationColor();
}
public void setShowWorkBadgeAtEnd(boolean showWorkBadgeAtEnd) {
if (showWorkBadgeAtEnd != mShowWorkBadgeAtEnd) {
setClipToPadding(!showWorkBadgeAtEnd);

View File

@@ -16,12 +16,15 @@
package com.android.internal.widget;
import static com.android.internal.widget.ColoredIconHelper.applyGrayTint;
import android.annotation.DrawableRes;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
@@ -48,6 +51,7 @@ public class CachingIconView extends ImageView {
private Consumer<Integer> mOnVisibilityChangedListener;
private Consumer<Boolean> mOnForceHiddenChangedListener;
private int mIconColor;
private int mBackgroundColor;
private boolean mWillBeForceHidden;
@UnsupportedAppUsage
@@ -230,9 +234,55 @@ public class CachingIconView extends ImageView {
return mForceHidden;
}
/**
* Provides the notification's background color to the icon. This is only used when the icon
* is "inverted". This should be called before calling {@link #setOriginalIconColor(int)}.
*/
@RemotableViewMethod
public void setBackgroundColor(int color) {
mBackgroundColor = color;
}
/**
* Sets the icon color. If COLOR_INVALID is set, the icon's color filter will
* not be altered. If there is a background drawable, this method uses the value from
* {@link #setBackgroundColor(int)} which must have been already called.
*/
@RemotableViewMethod
public void setOriginalIconColor(int color) {
mIconColor = color;
Drawable background = getBackground();
Drawable icon = getDrawable();
boolean hasColor = color != ColoredIconHelper.COLOR_INVALID;
if (background == null) {
// This is the pre-S style -- colored icon with no background.
if (hasColor) {
icon.mutate().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
}
} else {
// When there is a background drawable, color it with the foreground color and
// colorize the icon itself with the background color, creating an inverted effect.
if (hasColor) {
background.mutate().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
icon.mutate().setColorFilter(mBackgroundColor, PorterDuff.Mode.SRC_ATOP);
} else {
background.mutate().setColorFilter(mBackgroundColor, PorterDuff.Mode.SRC_ATOP);
}
}
}
/**
* Set the icon's color filter: to gray if true, otherwise colored.
* If this icon has no original color, this has no effect.
*/
public void setGrayedOut(boolean grayedOut) {
// If there is a background drawable, then it has the foreground color and the image
// drawable has the background color, creating an inverted efffect.
Drawable drawable = getBackground();
if (drawable == null) {
drawable = getDrawable();
}
applyGrayTint(mContext, drawable, grayedOut, mIconColor);
}
public int getOriginalIconColor() {

View File

@@ -0,0 +1,57 @@
/*
* 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.internal.widget;
import android.annotation.ColorInt;
import android.app.Notification;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import com.android.internal.util.ContrastColorUtil;
/** Helpers for colored icons */
final class ColoredIconHelper {
@ColorInt
static final int COLOR_INVALID = Notification.COLOR_INVALID;
private ColoredIconHelper() {
}
/**
* Apply a gray tint or the original color to a drawable, accounting for the night mode in
* selecting the gray.
*/
static void applyGrayTint(Context ctx, Drawable drawable, boolean apply, int originalColor) {
if (originalColor == COLOR_INVALID) {
return;
}
if (apply) {
// lets gray it out
Configuration config = ctx.getResources().getConfiguration();
boolean inNightMode = (config.uiMode & Configuration.UI_MODE_NIGHT_MASK)
== Configuration.UI_MODE_NIGHT_YES;
int grey = ContrastColorUtil.resolveColor(ctx, Notification.COLOR_DEFAULT, inNightMode);
drawable.mutate().setColorFilter(grey, PorterDuff.Mode.SRC_ATOP);
} else {
// lets reset it
drawable.mutate().setColorFilter(originalColor, PorterDuff.Mode.SRC_ATOP);
}
}
}

View File

@@ -16,6 +16,8 @@
package com.android.internal.widget;
import static com.android.internal.widget.ColoredIconHelper.applyGrayTint;
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Rect;
@@ -70,6 +72,14 @@ public class NotificationExpandButton extends ImageView {
return mOriginalNotificationColor;
}
/**
* Set the button's color filter: to gray if true, otherwise colored.
* If this button has no original color, this has no effect.
*/
public void setGrayedOut(boolean shouldApply) {
applyGrayTint(mContext, getDrawable(), shouldApply, mOriginalNotificationColor);
}
private void extendRectToMinTouchSize(Rect rect) {
int touchTargetSize = (int) (getResources().getDisplayMetrics().density * 48);
rect.left = rect.centerX() - touchTargetSize / 2;

View File

@@ -17,18 +17,16 @@
package com.android.systemui.statusbar;
import android.app.Notification;
import android.content.res.Configuration;
import android.graphics.PorterDuff;
import android.graphics.drawable.Icon;
import android.text.TextUtils;
import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.util.ContrastColorUtil;
import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.ConversationLayout;
import com.android.internal.widget.NotificationExpandButton;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationContentView;
@@ -67,30 +65,14 @@ public class NotificationHeaderUtil {
private final static ResultApplicator mGreyApplicator = new ResultApplicator() {
@Override
public void apply(View parent, View view, boolean apply, boolean reset) {
NotificationHeaderView header = (NotificationHeaderView) view;
ImageView icon = view.findViewById(com.android.internal.R.id.icon);
ImageView expand = view.findViewById(com.android.internal.R.id.expand_button);
applyToChild(icon, apply, header.getOriginalIconColor());
applyToChild(expand, apply, header.getOriginalNotificationColor());
}
private void applyToChild(View view, boolean shouldApply, int originalColor) {
if (originalColor != NotificationHeaderView.NO_COLOR) {
ImageView imageView = (ImageView) view;
imageView.getDrawable().mutate();
if (shouldApply) {
// lets gray it out
Configuration config = view.getContext().getResources().getConfiguration();
boolean inNightMode = (config.uiMode & Configuration.UI_MODE_NIGHT_MASK)
== Configuration.UI_MODE_NIGHT_YES;
int grey = ContrastColorUtil.resolveColor(view.getContext(),
Notification.COLOR_DEFAULT, inNightMode);
imageView.getDrawable().setColorFilter(grey, PorterDuff.Mode.SRC_ATOP);
} else {
// lets reset it
imageView.getDrawable().setColorFilter(originalColor,
PorterDuff.Mode.SRC_ATOP);
}
CachingIconView icon = view.findViewById(com.android.internal.R.id.icon);
if (icon != null) {
icon.setGrayedOut(apply);
}
NotificationExpandButton expand =
view.findViewById(com.android.internal.R.id.expand_button);
if (expand != null) {
expand.setGrayedOut(apply);
}
}
};