Notification color fixes

* Change Notification.isColorized() to return false if the given color is COLOR_DEFAULT.  This removes an odd, inconsistent, and likely unused state.
* Remove config_tintNotificationsWithTheme which we're not going to be using to reduce the color palette complexity.
* Change ensureColors() to use the theme's primary/secondary text colors.
* Numerous simplifications in logic that fall out from these changes.

Bug: 181048615
Test: atest NotificationComparatorTest NotificationTest AppOpsCoordinatorTest NotificationGutsManagerTest NotificationManagerServiceTest NotificationBuilderTest
Change-Id: Ie49cc9f3f9ea01685ae026587e2d1cdb96391eb2
This commit is contained in:
Jeff DeCew 2021-03-29 12:50:32 -04:00
parent fbcde0f713
commit d11b3561c9
10 changed files with 81 additions and 88 deletions

View File

@ -3701,7 +3701,6 @@ public class Notification implements Parcelable
private boolean mRebuildStyledRemoteViews;
private boolean mTintActionButtons;
private boolean mTintWithThemeAccent;
private boolean mInNightMode;
/**
@ -3737,7 +3736,6 @@ public class Notification implements Parcelable
mContext = context;
Resources res = mContext.getResources();
mTintActionButtons = res.getBoolean(R.bool.config_tintNotificationActionButtons);
mTintWithThemeAccent = res.getBoolean(R.bool.config_tintNotificationsWithTheme);
if (res.getBoolean(R.bool.config_enableNightMode)) {
Configuration currentConfig = res.getConfiguration();
@ -5132,15 +5130,21 @@ public class Notification implements Parcelable
|| mSecondaryTextColor == COLOR_INVALID
|| mTextColorsAreForBackground != backgroundColor) {
mTextColorsAreForBackground = backgroundColor;
mPrimaryTextColor = ContrastColorUtil.resolvePrimaryColor(mContext,
int defaultPrimaryTextColor = ContrastColorUtil.resolvePrimaryColor(mContext,
backgroundColor, mInNightMode);
mSecondaryTextColor = ContrastColorUtil.resolveSecondaryColor(mContext,
int defaultSecondaryTextColor = ContrastColorUtil.resolveSecondaryColor(mContext,
backgroundColor, mInNightMode);
if (backgroundColor != COLOR_DEFAULT && isColorized(p)) {
boolean colorized = backgroundColor != COLOR_DEFAULT;
if (colorized) {
mPrimaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
mPrimaryTextColor, backgroundColor, 4.5);
defaultPrimaryTextColor, backgroundColor, 4.5);
mSecondaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
mSecondaryTextColor, backgroundColor, 4.5);
defaultSecondaryTextColor, backgroundColor, 4.5);
} else {
mPrimaryTextColor = obtainThemeColor(R.attr.textColorPrimary,
defaultPrimaryTextColor);
mSecondaryTextColor = obtainThemeColor(R.attr.textColorSecondary,
defaultSecondaryTextColor);
}
}
}
@ -5167,11 +5171,9 @@ public class Notification implements Parcelable
contentView.setProgressBar(R.id.progress, max, progress, ind);
contentView.setProgressBackgroundTintList(R.id.progress,
mContext.getColorStateList(R.color.notification_progress_background_color));
if (mTintWithThemeAccent || getRawColor(p) != COLOR_DEFAULT) {
ColorStateList progressTint = ColorStateList.valueOf(getAccentColor(p));
contentView.setProgressTintList(R.id.progress, progressTint);
contentView.setProgressIndeterminateTintList(R.id.progress, progressTint);
}
ColorStateList progressTint = ColorStateList.valueOf(getAccentColor(p));
contentView.setProgressTintList(R.id.progress, progressTint);
contentView.setProgressIndeterminateTintList(R.id.progress, progressTint);
return true;
} else {
contentView.setViewVisibility(R.id.progress, View.GONE);
@ -6002,8 +6004,7 @@ public class Notification implements Parcelable
background = outResultColor[0].getDefaultColor();
textColor = ContrastColorUtil.resolvePrimaryColor(mContext,
background, mInNightMode);
} else if (mTintActionButtons && !mInNightMode
&& getRawColor(p) != COLOR_DEFAULT && !isColorized(p)) {
} else if (mTintActionButtons && !mInNightMode && !isColorized(p)) {
textColor = getAccentColor(p);
} else {
textColor = getPrimaryTextColor(p);
@ -6181,7 +6182,7 @@ public class Notification implements Parcelable
* is the primary text color, otherwise it's the contrast-adjusted app-provided color.
*/
private @ColorInt int getSmallIconColor(StandardTemplateParams p) {
return isColorized(p) ? getPrimaryTextColor(p) : getContrastColor(p);
return getContrastColor(p);
}
/**
@ -6193,11 +6194,9 @@ public class Notification implements Parcelable
if (isColorized(p)) {
return getPrimaryTextColor(p);
}
if (mTintWithThemeAccent) {
int color = obtainThemeColor(R.attr.colorAccent, COLOR_INVALID);
if (color != COLOR_INVALID) {
return color;
}
int color = obtainThemeColor(R.attr.colorAccent, COLOR_INVALID);
if (color != COLOR_INVALID) {
return color;
}
return getContrastColor(p);
}
@ -6207,7 +6206,7 @@ public class Notification implements Parcelable
* color when colorized, or when not using theme color tints.
*/
private @ColorInt int getProtectionColor(StandardTemplateParams p) {
if (mTintWithThemeAccent && !isColorized(p)) {
if (!isColorized(p)) {
int color = obtainThemeColor(R.attr.colorBackgroundFloating, COLOR_INVALID);
if (color != COLOR_INVALID) {
return color;
@ -6226,12 +6225,10 @@ public class Notification implements Parcelable
if (isColorized(p)) {
return getPrimaryTextColor(p);
}
if (mTintWithThemeAccent) {
int color = obtainThemeColor(com.android.internal.R.attr.colorAccentTertiary,
COLOR_INVALID);
if (color != COLOR_INVALID) {
return color;
}
int color = obtainThemeColor(com.android.internal.R.attr.colorAccentTertiary,
COLOR_INVALID);
if (color != COLOR_INVALID) {
return color;
}
return getContrastColor(p);
}
@ -6261,6 +6258,9 @@ public class Notification implements Parcelable
* Gets the contrast-adjusted version of the color provided by the app.
*/
private @ColorInt int getContrastColor(StandardTemplateParams p) {
if (isColorized(p)) {
return getPrimaryTextColor(p);
}
int rawColor = getRawColor(p);
if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
return mCachedContrastColor;
@ -6271,9 +6271,10 @@ public class Notification implements Parcelable
int background = getDefaultBackgroundColor();
if (rawColor == COLOR_DEFAULT) {
ensureColors(p);
color = ContrastColorUtil.resolveDefaultColor(mContext, background, mInNightMode);
if (mTintWithThemeAccent) {
color = obtainThemeColor(R.attr.colorAccent, color);
color = obtainThemeColor(R.attr.colorAccent, COLOR_INVALID);
if (color == COLOR_INVALID) {
color = ContrastColorUtil.resolveDefaultColor(mContext, background,
mInNightMode);
}
} else {
color = ContrastColorUtil.resolveContrastColor(mContext, rawColor,
@ -6294,11 +6295,6 @@ public class Notification implements Parcelable
* @param p the template params to inflate this with
*/
private @ColorInt int getRawColor(StandardTemplateParams p) {
// When notifications are theme-tinted, the raw color is only used for the icon, so go
// ahead and keep that color instead of changing the color for minimized notifs.
if (p.mReduceHighlights && !mTintWithThemeAccent) {
return COLOR_DEFAULT;
}
return mN.color;
}
@ -6405,6 +6401,7 @@ public class Notification implements Parcelable
+ " notification: " + mN.mShortcutId
+ " vs bubble: " + mN.mBubbleMetadata.getShortcutId());
}
validateColorizedHasColor();
// first, add any extras from the calling code
if (mUserExtras != null) {
@ -6458,6 +6455,21 @@ public class Notification implements Parcelable
return mN;
}
// This code is executed on behalf of other apps' notifications, sometimes even by 3p apps,
// a use case that is not supported by the Compat Framework library.
@SuppressWarnings("AndroidFrameworkCompatChange")
private void validateColorizedHasColor() {
if (mN.color == COLOR_DEFAULT && mN.extras.getBoolean(EXTRA_COLORIZED)) {
if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.S) {
throw new IllegalArgumentException(
"Colorized notifications must set a color (other than COLOR_DEFAULT).");
} else {
Log.w(TAG, "Colorized notifications must set a color (other than "
+ "COLOR_DEFAULT). This is required for apps targeting S.");
}
}
}
/**
* Returns the color for the given Theme.DeviceDefault.DayNight attribute, or
* defValue if that could not be completed
@ -6470,13 +6482,9 @@ public class Notification implements Parcelable
}
theme = new ContextThemeWrapper(mContext, R.style.Theme_DeviceDefault_DayNight)
.getTheme();
TypedArray ta = theme.obtainStyledAttributes(new int[]{attrRes});
if (ta == null) {
return defaultColor;
try (TypedArray ta = theme.obtainStyledAttributes(new int[]{attrRes})) {
return ta.getColor(0, defaultColor);
}
int background = ta.getColor(0, defaultColor);
ta.recycle();
return background;
}
/**
@ -6590,11 +6598,7 @@ public class Notification implements Parcelable
* which must be resolved by the caller before being used.
*/
private @ColorInt int getUnresolvedBackgroundColor(StandardTemplateParams p) {
if (isColorized(p)) {
return getRawColor(p);
} else {
return COLOR_DEFAULT;
}
return isColorized(p) ? getRawColor(p) : COLOR_DEFAULT;
}
/**
@ -6768,7 +6772,7 @@ public class Notification implements Parcelable
* @hide
*/
public boolean isColorized() {
return extras.getBoolean(EXTRA_COLORIZED)
return color != COLOR_DEFAULT && extras.getBoolean(EXTRA_COLORIZED)
&& (hasColorizedPermission() || isForegroundService());
}

View File

@ -3943,10 +3943,6 @@
color supplied by the Notification.Builder if present. -->
<bool name="config_tintNotificationActionButtons">true</bool>
<!-- Flag indicating that tinted items (actions, expander, etc) are to be tinted using the
theme color, rather than the notification color. -->
<bool name="config_tintNotificationsWithTheme">true</bool>
<!-- Show area update info settings in CellBroadcastReceiver and information in SIM status in Settings app -->
<bool name="config_showAreaUpdateInfoSettings">false</bool>

View File

@ -1890,7 +1890,6 @@
<java-symbol type="bool" name="config_notificationHeaderClickableForExpand" />
<java-symbol type="bool" name="config_enableNightMode" />
<java-symbol type="bool" name="config_tintNotificationActionButtons" />
<java-symbol type="bool" name="config_tintNotificationsWithTheme" />
<java-symbol type="bool" name="config_dozeAfterScreenOffByDefault" />
<java-symbol type="bool" name="config_enableActivityRecognitionHardwareOverlay" />
<java-symbol type="bool" name="config_enableFusedLocationOverlay" />

View File

@ -28,6 +28,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.LocusId;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.Icon;
import android.media.session.MediaSession;
import android.os.Build;
@ -60,7 +61,7 @@ public class NotificationTest {
public void testColorizedByPermission() {
Notification n = new Notification.Builder(mContext, "test")
.setFlag(Notification.FLAG_CAN_COLORIZE, true)
.setColorized(true)
.setColorized(true).setColor(Color.WHITE)
.build();
assertTrue(n.isColorized());
@ -71,7 +72,7 @@ public class NotificationTest {
n = new Notification.Builder(mContext, "test")
.setFlag(Notification.FLAG_CAN_COLORIZE, false)
.setColorized(true)
.setColorized(true).setColor(Color.WHITE)
.build();
assertFalse(n.isColorized());
}
@ -80,7 +81,7 @@ public class NotificationTest {
public void testColorizedByForeground() {
Notification n = new Notification.Builder(mContext, "test")
.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
.setColorized(true)
.setColorized(true).setColor(Color.WHITE)
.build();
assertTrue(n.isColorized());
@ -91,7 +92,7 @@ public class NotificationTest {
n = new Notification.Builder(mContext, "test")
.setFlag(Notification.FLAG_FOREGROUND_SERVICE, false)
.setColorized(true)
.setColorized(true).setColor(Color.WHITE)
.build();
assertFalse(n.isColorized());
}

View File

@ -105,7 +105,6 @@ public class NotificationChildrenContainer extends ViewGroup {
private ViewGroup mCurrentHeader;
private boolean mIsConversation;
private boolean mTintWithThemeAccent;
private boolean mShowGroupCountInExpander;
private boolean mShowDividersWhenExpanded;
private boolean mHideDividersDuringExpand;
@ -149,8 +148,6 @@ public class NotificationChildrenContainer extends ViewGroup {
com.android.internal.R.dimen.notification_content_margin);
mEnableShadowOnChildNotifications =
res.getBoolean(R.bool.config_enableShadowOnChildNotifications);
mTintWithThemeAccent =
res.getBoolean(com.android.internal.R.bool.config_tintNotificationsWithTheme);
mShowGroupCountInExpander =
res.getBoolean(R.bool.config_showNotificationGroupCountInExpander);
mShowDividersWhenExpanded =
@ -1223,14 +1220,11 @@ public class NotificationChildrenContainer extends ViewGroup {
return;
}
int color = mContainingNotification.getNotificationColor();
if (mTintWithThemeAccent) {
// We're using the theme accent, color with the accent color instead of the notif color
Resources.Theme theme = new ContextThemeWrapper(mContext,
com.android.internal.R.style.Theme_DeviceDefault_DayNight).getTheme();
TypedArray ta = theme.obtainStyledAttributes(
new int[]{com.android.internal.R.attr.colorAccent});
Resources.Theme theme = new ContextThemeWrapper(mContext,
com.android.internal.R.style.Theme_DeviceDefault_DayNight).getTheme();
try (TypedArray ta = theme.obtainStyledAttributes(
new int[]{com.android.internal.R.attr.colorAccent})) {
color = ta.getColor(0, color);
ta.recycle();
}
mHybridGroupManager.setOverflowNumberColor(mOverflowNumber, color);
}

View File

@ -28,8 +28,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
import android.os.Bundle;
import android.graphics.Color;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
@ -120,7 +119,8 @@ public class AppOpsCoordinatorTest extends SysuiTestCase {
mEntryBuilder
.setFlag(mContext, FLAG_FOREGROUND_SERVICE, true)
.setImportance(IMPORTANCE_DEFAULT)
.modifyNotification(mContext).setColorized(true);
.modifyNotification(mContext)
.setColorized(true).setColor(Color.WHITE);
// THEN the entry is in the fgs section
assertTrue(mFgsSection.isInSection(mEntryBuilder.build()));
@ -132,7 +132,8 @@ public class AppOpsCoordinatorTest extends SysuiTestCase {
mEntryBuilder
.setFlag(mContext, FLAG_FOREGROUND_SERVICE, true)
.setImportance(IMPORTANCE_MIN)
.modifyNotification(mContext).setColorized(true);
.modifyNotification(mContext)
.setColorized(true).setColor(Color.WHITE);
// THEN the entry is NOT in the fgs section
assertFalse(mFgsSection.isInSection(mEntryBuilder.build()));

View File

@ -51,6 +51,7 @@ import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutManager;
import android.graphics.Color;
import android.os.Binder;
import android.os.Handler;
import android.provider.Settings;
@ -486,7 +487,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
Notification.Builder nb = new Notification.Builder(mContext,
mTestNotificationChannel.getId())
.setContentTitle("foo")
.setColorized(true)
.setColorized(true).setColor(Color.RED)
.setFlag(Notification.FLAG_CAN_COLORIZE, true)
.setSmallIcon(android.R.drawable.sym_def_app_icon);

View File

@ -31,6 +31,7 @@ import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Build;
import android.os.UserHandle;
import android.provider.Settings;
@ -193,7 +194,7 @@ public class NotificationComparatorTest extends UiServiceTestCase {
Notification n11 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_MESSAGE)
.setColorized(true)
.setColorized(true).setColor(Color.WHITE)
.build();
mRecordCheaterColorized = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "cheater", uid2, uid2, n11, new UserHandle(userId),
@ -202,7 +203,7 @@ public class NotificationComparatorTest extends UiServiceTestCase {
Notification n12 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_MESSAGE)
.setColorized(true)
.setColorized(true).setColor(Color.WHITE)
.setStyle(new Notification.MediaStyle())
.build();
mNoMediaSessionMedia = new NotificationRecord(mContext, new StatusBarNotification(
@ -212,7 +213,7 @@ public class NotificationComparatorTest extends UiServiceTestCase {
Notification n13 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
.setColorized(true /* colorized */)
.setColorized(true).setColor(Color.WHITE)
.build();
mRecordColorized = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "colorized", uid2, uid2, n13,
@ -221,7 +222,7 @@ public class NotificationComparatorTest extends UiServiceTestCase {
Notification n14 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_CALL)
.setColorized(true)
.setColorized(true).setColor(Color.WHITE)
.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
.build();
mRecordColorizedCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,

View File

@ -3284,7 +3284,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
Notification.Builder nb = new Notification.Builder(mContext,
mTestNotificationChannel.getId())
.setContentTitle("foo")
.setColorized(true)
.setColorized(true).setColor(Color.WHITE)
.setFlag(Notification.FLAG_CAN_COLORIZE, true)
.setSmallIcon(android.R.drawable.sym_def_app_icon);
StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,

View File

@ -25,27 +25,22 @@ import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Icon;
import android.media.AudioAttributes;
import android.os.Bundle;
import android.os.Vibrator;
import android.os.Handler;
import android.os.UserHandle;
import android.util.Log;
import android.net.Uri;
import android.os.SystemClock;
import android.widget.RemoteViews;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
// private NM API
import android.app.INotificationManager;
import android.os.SystemClock;
import android.os.Vibrator;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;
public class NotificationTestList extends TestActivity
@ -185,6 +180,7 @@ public class NotificationTestList extends TestActivity
.setContentTitle("default priority group 1")
.setGroup("group1")
.setOngoing(true)
.setColor(Color.WHITE)
.setColorized(true)
.build();
mNM.notify(6002, n);