Added a new API to colorize notifications

Ongoing notifications can now be colorized.
This will use the color provided as the background
and invert most text colors

Test: runtest -x cts/tests/app/src/android/app/cts/NotificationTest.java
Bug: 34469375
Change-Id: I818e8db96c868d8bcde8f28c253efd581eeccaa2
This commit is contained in:
Selim Cinek
2017-01-19 17:36:00 -08:00
parent 5be6f33996
commit 7b9605b79c
12 changed files with 284 additions and 60 deletions

View File

@@ -5050,6 +5050,7 @@ package android.app {
field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
field public static final java.lang.String EXTRA_COLORIZED = "android.colorized";
field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
field public static final java.lang.String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
field public static final java.lang.String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
@@ -5215,6 +5216,7 @@ package android.app {
method public android.app.Notification.Builder setChannel(java.lang.String);
method public android.app.Notification.Builder setChronometerCountDown(boolean);
method public android.app.Notification.Builder setColor(int);
method public android.app.Notification.Builder setColorized(boolean);
method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
method public deprecated android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);

View File

@@ -5210,6 +5210,7 @@ package android.app {
field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
field public static final java.lang.String EXTRA_COLORIZED = "android.colorized";
field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
field public static final java.lang.String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
field public static final java.lang.String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
@@ -5377,6 +5378,7 @@ package android.app {
method public android.app.Notification.Builder setChannel(java.lang.String);
method public android.app.Notification.Builder setChronometerCountDown(boolean);
method public android.app.Notification.Builder setColor(int);
method public android.app.Notification.Builder setColorized(boolean);
method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
method public deprecated android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);

View File

@@ -5060,6 +5060,7 @@ package android.app {
field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
field public static final java.lang.String EXTRA_COLORIZED = "android.colorized";
field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
field public static final java.lang.String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
field public static final java.lang.String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
@@ -5225,6 +5226,7 @@ package android.app {
method public android.app.Notification.Builder setChannel(java.lang.String);
method public android.app.Notification.Builder setChronometerCountDown(boolean);
method public android.app.Notification.Builder setColor(int);
method public android.app.Notification.Builder setColorized(boolean);
method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
method public deprecated android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);

View File

@@ -71,7 +71,6 @@ import android.widget.RemoteViews;
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.NotificationColorUtil;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -981,6 +980,12 @@ public class Notification implements Parcelable
*/
public static final String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
/**
* {@link #extras} key: whether the notification should be colorized as
* supplied to {@link Builder#setColorized(boolean)}}.
*/
public static final String EXTRA_COLORIZED = "android.colorized";
/**
* {@link #extras} key: the user that built the notification.
*
@@ -2438,6 +2443,8 @@ public class Notification implements Parcelable
private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
private ArrayList<String> mPersonList = new ArrayList<String>();
private NotificationColorUtil mColorUtil;
private boolean mIsLegacy;
private boolean mIsLegacyInitialized;
private boolean mColorUtilInited = false;
/**
@@ -2456,6 +2463,10 @@ public class Notification implements Parcelable
* so make sure to call {@link StandardTemplateParams#reset()} before using it.
*/
StandardTemplateParams mParams = new StandardTemplateParams();
private int mTextColorsAreForBackground = COLOR_INVALID;
private int mPrimaryTextColor = COLOR_INVALID;
private int mSecondaryTextColor = COLOR_INVALID;
private int mActionBarColor = COLOR_INVALID;
/**
* Constructs a new Builder with the defaults:
@@ -2540,7 +2551,7 @@ public class Notification implements Parcelable
private NotificationColorUtil getColorUtil() {
if (!mColorUtilInited) {
mColorUtilInited = true;
if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
if (isLegacy() || isColorized()) {
mColorUtil = NotificationColorUtil.getInstance(mContext);
}
}
@@ -3024,6 +3035,22 @@ public class Notification implements Parcelable
return this;
}
/**
* Set whether this notification should be colorized. When set, the color set with
* {@link #setColor(int)} will be used as the background color of this notification.
* <p>
* The coloring will only be applied if the notification is ongoing.
* This should only be used for high priority ongoing tasks like navigation, an ongoing
* call, or other similarly high-priority events for the user.
*
* @see Builder#setOngoing(boolean)
* @see Builder#setColor(int)
*/
public Builder setColorized(boolean colorize) {
mN.extras.putBoolean(EXTRA_COLORIZED, colorize);
return this;
}
/**
* Set this flag if you would only like the sound, vibrate
* and ticker to be played if the notification is not already showing.
@@ -3389,6 +3416,10 @@ public class Notification implements Parcelable
if (profileBadge != null) {
contentView.setImageViewBitmap(R.id.profile_badge, profileBadge);
contentView.setViewVisibility(R.id.profile_badge, View.VISIBLE);
if (isColorized()) {
contentView.setDrawableParameters(R.id.profile_badge, false, -1,
getPrimaryTextColor(), PorterDuff.Mode.SRC_ATOP, -1);
}
}
}
@@ -3446,13 +3477,14 @@ public class Notification implements Parcelable
resetStandardTemplate(contentView);
final Bundle ex = mN.extras;
updateBackgroundColor(contentView);
bindNotificationHeader(contentView, p.ambient);
bindLargeIcon(contentView);
boolean showProgress = handleProgressBar(p.hasProgress, contentView, ex);
if (p.title != null) {
contentView.setViewVisibility(R.id.title, View.VISIBLE);
contentView.setTextViewText(R.id.title, p.title);
setTextViewColorPrimary(contentView, R.id.title);
contentView.setViewLayoutWidth(R.id.title, showProgress
? ViewGroup.LayoutParams.WRAP_CONTENT
: ViewGroup.LayoutParams.MATCH_PARENT);
@@ -3461,6 +3493,7 @@ public class Notification implements Parcelable
int textId = showProgress ? com.android.internal.R.id.text_line_1
: com.android.internal.R.id.text;
contentView.setTextViewText(textId, p.text);
setTextViewColorSecondary(contentView, textId);
contentView.setViewVisibility(textId, View.VISIBLE);
}
@@ -3469,6 +3502,52 @@ public class Notification implements Parcelable
return contentView;
}
private void setTextViewColorPrimary(RemoteViews contentView, int id) {
ensureColors();
contentView.setTextColor(id, mPrimaryTextColor);
}
private int getPrimaryTextColor() {
ensureColors();
return mPrimaryTextColor;
}
private int getActionBarColor() {
ensureColors();
return mActionBarColor;
}
private void setTextViewColorSecondary(RemoteViews contentView, int id) {
ensureColors();
contentView.setTextColor(id, mSecondaryTextColor);
}
private void ensureColors() {
int backgroundColor = getBackgroundColor();
if (mPrimaryTextColor == COLOR_INVALID
|| mSecondaryTextColor == COLOR_INVALID
|| mActionBarColor == COLOR_INVALID
|| mTextColorsAreForBackground != backgroundColor) {
mTextColorsAreForBackground = backgroundColor;
mPrimaryTextColor = NotificationColorUtil.resolvePrimaryColor(
mContext, backgroundColor);
mSecondaryTextColor = NotificationColorUtil.resolveSecondaryColor(
mContext, backgroundColor);
mActionBarColor = NotificationColorUtil.resolveActionBarColor(backgroundColor);
}
}
private void updateBackgroundColor(RemoteViews contentView) {
if (isColorized()) {
contentView.setInt(R.id.status_bar_latest_event_content, "setBackgroundColor",
getBackgroundColor());
} else {
// Clear it!
contentView.setInt(R.id.status_bar_latest_event_content, "setBackgroundResource",
0);
}
}
/**
* @param remoteView the remote view to update the minheight in
* @param hasMinHeight does it have a mimHeight
@@ -3535,15 +3614,17 @@ public class Notification implements Parcelable
}
private void bindExpandButton(RemoteViews contentView) {
contentView.setDrawableParameters(R.id.expand_button, false, -1, resolveContrastColor(),
int color = isColorized() ? getPrimaryTextColor() : resolveContrastColor();
contentView.setDrawableParameters(R.id.expand_button, false, -1, color,
PorterDuff.Mode.SRC_ATOP, -1);
contentView.setInt(R.id.notification_header, "setOriginalNotificationColor",
resolveContrastColor());
color);
}
private void bindHeaderChronometerAndTime(RemoteViews contentView) {
if (showsTimeOrChronometer()) {
contentView.setViewVisibility(R.id.time_divider, View.VISIBLE);
setTextViewColorSecondary(contentView, R.id.time_divider);
if (mN.extras.getBoolean(EXTRA_SHOW_CHRONOMETER)) {
contentView.setViewVisibility(R.id.chronometer, View.VISIBLE);
contentView.setLong(R.id.chronometer, "setBase",
@@ -3551,9 +3632,11 @@ public class Notification implements Parcelable
contentView.setBoolean(R.id.chronometer, "setStarted", true);
boolean countsDown = mN.extras.getBoolean(EXTRA_CHRONOMETER_COUNT_DOWN);
contentView.setChronometerCountDown(R.id.chronometer, countsDown);
setTextViewColorSecondary(contentView, R.id.chronometer);
} else {
contentView.setViewVisibility(R.id.time, View.VISIBLE);
contentView.setLong(R.id.time, "setTime", mN.when);
setTextViewColorSecondary(contentView, R.id.time);
}
} else {
// We still want a time to be set but gone, such that we can show and hide it
@@ -3576,8 +3659,10 @@ public class Notification implements Parcelable
if (headerText != null) {
// TODO: Remove the span entirely to only have the string with propper formating.
contentView.setTextViewText(R.id.header_text, processLegacyText(headerText));
setTextViewColorSecondary(contentView, R.id.header_text);
contentView.setViewVisibility(R.id.header_text, View.VISIBLE);
contentView.setViewVisibility(R.id.header_text_divider, View.VISIBLE);
setTextViewColorSecondary(contentView, R.id.header_text_divider);
}
}
@@ -3616,8 +3701,12 @@ public class Notification implements Parcelable
}
private void bindHeaderAppName(RemoteViews contentView, boolean ambient) {
contentView.setTextViewText(R.id.app_name_text, loadHeaderAppName());
contentView.setTextColor(R.id.app_name_text,
ambient ? resolveAmbientColor() : resolveContrastColor());
if (isColorized()) {
setTextViewColorPrimary(contentView, R.id.app_name_text);
} else {
contentView.setTextColor(R.id.app_name_text,
ambient ? resolveAmbientColor() : resolveContrastColor());
}
}
private void bindSmallIcon(RemoteViews contentView, boolean ambient) {
@@ -3675,6 +3764,11 @@ public class Notification implements Parcelable
big.setViewVisibility(R.id.actions, View.VISIBLE);
if (p.ambient) {
big.setInt(R.id.actions, "setBackgroundColor", Color.TRANSPARENT);
} else if (isColorized()) {
big.setInt(R.id.actions, "setBackgroundColor", getActionBarColor());
} else {
big.setInt(R.id.actions, "setBackgroundColor", mContext.getColor(
R.color.notification_action_list));
}
big.setViewLayoutMarginBottomDimen(R.id.notification_action_list_margin_target,
R.dimen.notification_action_list_height);
@@ -3696,15 +3790,18 @@ public class Notification implements Parcelable
&& replyText.length > 0 && !TextUtils.isEmpty(replyText[0])) {
big.setViewVisibility(R.id.notification_material_reply_container, View.VISIBLE);
big.setTextViewText(R.id.notification_material_reply_text_1, replyText[0]);
setTextViewColorSecondary(big, R.id.notification_material_reply_text_1);
if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1])) {
big.setViewVisibility(R.id.notification_material_reply_text_2, View.VISIBLE);
big.setTextViewText(R.id.notification_material_reply_text_2, replyText[1]);
setTextViewColorSecondary(big, R.id.notification_material_reply_text_2);
if (replyText.length > 2 && !TextUtils.isEmpty(replyText[2])) {
big.setViewVisibility(
R.id.notification_material_reply_text_3, View.VISIBLE);
big.setTextViewText(R.id.notification_material_reply_text_3, replyText[2]);
setTextViewColorSecondary(big, R.id.notification_material_reply_text_3);
}
}
}
@@ -3930,6 +4027,7 @@ public class Notification implements Parcelable
if (action.mRemoteInputs != null) {
button.setRemoteInputs(R.id.action0, action.mRemoteInputs);
}
// TODO: handle emphasized mode / actions right
if (emphazisedMode) {
// change the background bgColor
int bgColor = mContext.getColor(oddAction ? R.color.notification_action_list
@@ -3945,16 +4043,19 @@ public class Notification implements Parcelable
title = ensureColorSpanContrast(title, bgColor, outResultColor);
}
button.setTextViewText(R.id.action0, title);
setTextViewColorPrimary(button, R.id.action0);
if (outResultColor != null && outResultColor[0] != null) {
// We need to set the text color as well since changing a text to uppercase
// clears its spans.
button.setTextColor(R.id.action0, outResultColor[0]);
} else if (mN.color != COLOR_DEFAULT) {
} else if (mN.color != COLOR_DEFAULT && !isColorized()) {
button.setTextColor(R.id.action0,resolveContrastColor());
}
} else {
button.setTextViewText(R.id.action0, processLegacyText(action.title));
if (mN.color != COLOR_DEFAULT) {
if (isColorized()) {
setTextViewColorPrimary(button, R.id.action0);
} else if (mN.color != COLOR_DEFAULT) {
button.setTextColor(R.id.action0,
ambient ? resolveAmbientColor() : resolveContrastColor());
}
@@ -4073,11 +4174,16 @@ public class Notification implements Parcelable
* doesn't create material notifications by itself) app.
*/
private boolean isLegacy() {
return getColorUtil() != null;
if (!mIsLegacyInitialized) {
mIsLegacy = mContext.getApplicationInfo().targetSdkVersion
< Build.VERSION_CODES.LOLLIPOP;
mIsLegacyInitialized = true;
}
return mIsLegacy;
}
private CharSequence processLegacyText(CharSequence charSequence) {
if (isLegacy()) {
if (isLegacy() || isColorized()) {
return getColorUtil().invertCharSequenceColors(charSequence);
} else {
return charSequence;
@@ -4339,6 +4445,37 @@ public class Notification implements Parcelable
private int getActionTombstoneLayoutResource() {
return R.layout.notification_material_action_tombstone;
}
private int getBackgroundColor() {
if (isColorized()) {
return mN.color;
} else {
return COLOR_DEFAULT;
}
}
private boolean isColorized() {
return mN.isColorized();
}
}
/**
* @return whether this notification is ongoing and can't be dismissed by the user.
*/
private boolean isOngoing() {
final int ongoingFlags = Notification.FLAG_FOREGROUND_SERVICE
| Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
return (flags & ongoingFlags) != 0;
}
/**
* @return true if this notification is colorized. This also factors in wheather the
* notification is ongoing.
*
* @hide
*/
public boolean isColorized() {
return extras.getBoolean(EXTRA_COLORIZED) && isOngoing();
}
private boolean hasLargeIcon() {
@@ -4672,6 +4809,7 @@ public class Notification implements Parcelable
RemoteViews contentView = getStandardView(mBuilder.getBigPictureLayoutResource());
if (mSummaryTextSet) {
contentView.setTextViewText(R.id.text, mBuilder.processLegacyText(mSummaryText));
mBuilder.setTextViewColorSecondary(contentView, R.id.text);
contentView.setViewVisibility(R.id.text, View.VISIBLE);
}
mBuilder.setContentMinHeight(contentView, mBuilder.mN.hasLargeIcon());
@@ -4827,6 +4965,7 @@ public class Notification implements Parcelable
static void applyBigTextContentView(Builder builder,
RemoteViews contentView, CharSequence bigTextText) {
contentView.setTextViewText(R.id.big_text, bigTextText);
builder.setTextViewColorSecondary(contentView, R.id.big_text);
contentView.setViewVisibility(R.id.big_text,
TextUtils.isEmpty(bigTextText) ? View.GONE : View.VISIBLE);
contentView.setInt(R.id.big_text, "setMaxLines", calculateMaxLines(builder));
@@ -5070,7 +5209,7 @@ public class Notification implements Parcelable
: (m == null) ? null : m.mSender;
CharSequence text = (m == null)
? null
: mConversationTitle != null ? makeMessageLine(m) : m.mText;
: mConversationTitle != null ? makeMessageLine(m, mBuilder) : m.mText;
return mBuilder.applyStandardTemplateWithActions(mBuilder.getBaseLayoutResource(),
mBuilder.mParams.reset().hasProgress(false).title(title).text(text));
@@ -5108,7 +5247,7 @@ public class Notification implements Parcelable
CharSequence text;
if (hasTitle) {
bigTitle = title;
text = makeMessageLine(mMessages.get(0));
text = makeMessageLine(mMessages.get(0), mBuilder);
} else {
bigTitle = mMessages.get(0).mSender;
text = mMessages.get(0).mText;
@@ -5146,7 +5285,7 @@ public class Notification implements Parcelable
Message m = mHistoricMessages.get(firstHistoricMessage + i);
int rowId = rowIds[i];
contentView.setTextViewText(rowId, makeMessageLine(m));
contentView.setTextViewText(rowId, makeMessageLine(m, mBuilder));
if (contractedMessage == m) {
contractedChildId = rowId;
@@ -5161,7 +5300,8 @@ public class Notification implements Parcelable
int rowId = rowIds[i];
contentView.setViewVisibility(rowId, View.VISIBLE);
contentView.setTextViewText(rowId, makeMessageLine(m));
contentView.setTextViewText(rowId, makeMessageLine(m, mBuilder));
mBuilder.setTextViewColorSecondary(contentView, rowId);
if (contractedMessage == m) {
contractedChildId = rowId;
@@ -5183,17 +5323,22 @@ public class Notification implements Parcelable
return contentView;
}
private CharSequence makeMessageLine(Message m) {
private CharSequence makeMessageLine(Message m, Builder builder) {
BidiFormatter bidi = BidiFormatter.getInstance();
SpannableStringBuilder sb = new SpannableStringBuilder();
boolean colorize = builder.isColorized();
if (TextUtils.isEmpty(m.mSender)) {
CharSequence replyName = mUserDisplayName == null ? "" : mUserDisplayName;
sb.append(bidi.unicodeWrap(replyName),
makeFontColorSpan(mBuilder.resolveContrastColor()),
makeFontColorSpan(colorize
? builder.getPrimaryTextColor()
: mBuilder.resolveContrastColor()),
0 /* flags */);
} else {
sb.append(bidi.unicodeWrap(m.mSender),
makeFontColorSpan(Color.BLACK),
makeFontColorSpan(colorize
? builder.getPrimaryTextColor()
: Color.BLACK),
0 /* flags */);
}
CharSequence text = m.mText == null ? "" : m.mText;
@@ -5212,7 +5357,7 @@ public class Notification implements Parcelable
: (m == null) ? null : m.mSender;
CharSequence text = (m == null)
? null
: mConversationTitle != null ? makeMessageLine(m) : m.mText;
: mConversationTitle != null ? makeMessageLine(m, mBuilder) : m.mText;
return mBuilder.applyStandardTemplateWithActions(mBuilder.getBigBaseLayoutResource(),
mBuilder.mParams.reset().hasProgress(false).title(title).text(text));
@@ -5503,6 +5648,7 @@ public class Notification implements Parcelable
if (!TextUtils.isEmpty(str)) {
contentView.setViewVisibility(rowIds[i], View.VISIBLE);
contentView.setTextViewText(rowIds[i], mBuilder.processLegacyText(str));
mBuilder.setTextViewColorSecondary(contentView, rowIds[i]);
contentView.setViewPadding(rowIds[i], 0, topPadding, 0, 0);
handleInboxImageMargin(contentView, rowIds[i], first);
if (first) {

View File

@@ -33,6 +33,8 @@ import android.graphics.drawable.Icon;
import android.graphics.drawable.VectorDrawable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.CharacterStyle;
import android.text.style.ForegroundColorSpan;
import android.text.style.TextAppearanceSpan;
import android.util.Log;
import android.util.Pair;
@@ -184,8 +186,24 @@ public class NotificationColorUtil {
SpannableStringBuilder builder = new SpannableStringBuilder(ss.toString());
for (Object span : spans) {
Object resultSpan = span;
if (span instanceof TextAppearanceSpan) {
resultSpan = processTextAppearanceSpan((TextAppearanceSpan) span);
if (resultSpan instanceof CharacterStyle) {
resultSpan = ((CharacterStyle) span).getUnderlying();
}
if (resultSpan instanceof TextAppearanceSpan) {
TextAppearanceSpan processedSpan = processTextAppearanceSpan(
(TextAppearanceSpan) span);
if (processedSpan != resultSpan) {
resultSpan = processedSpan;
} else {
// we need to still take the orgininal for wrapped spans
resultSpan = span;
}
} else if (resultSpan instanceof ForegroundColorSpan) {
ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan;
int foregroundColor = originalSpan.getForegroundColor();
resultSpan = new ForegroundColorSpan(processColor(foregroundColor));
} else {
resultSpan = span;
}
builder.setSpan(resultSpan, ss.getSpanStart(span), ss.getSpanEnd(span),
ss.getSpanFlags(span));
@@ -416,6 +434,48 @@ public class NotificationColorUtil {
return color;
}
public static int resolvePrimaryColor(Context context, int backgroundColor) {
boolean useDark = shouldUseDark(backgroundColor);
if (useDark) {
return context.getColor(
com.android.internal.R.color.notification_primary_text_color_light);
} else {
return context.getColor(
com.android.internal.R.color.notification_primary_text_color_dark);
}
}
public static int resolveSecondaryColor(Context context, int backgroundColor) {
boolean useDark = shouldUseDark(backgroundColor);
if (useDark) {
return context.getColor(
com.android.internal.R.color.notification_secondary_text_color_light);
} else {
return context.getColor(
com.android.internal.R.color.notification_secondary_text_color_dark);
}
}
public static int resolveActionBarColor(int backgroundColor) {
boolean useDark = shouldUseDark(backgroundColor);
final double[] result = ColorUtilsFromCompat.getTempDouble3Array();
ColorUtilsFromCompat.colorToLAB(backgroundColor, result);
if (useDark && result[0] < 97 || !useDark && result[0] < 4) {
result[0] = Math.min(100, result[0] + 7);
} else {
result[0] = Math.max(0, result[0] - 7);
}
return ColorUtilsFromCompat.LABToColor(result[0], result[1], result[2]);
}
private static boolean shouldUseDark(int backgroundColor) {
boolean useDark = backgroundColor == Notification.COLOR_DEFAULT;
if (!useDark) {
useDark = ColorUtilsFromCompat.calculateLuminance(backgroundColor) > 0.5;
}
return useDark;
}
/**
* Framework copy of functions needed from android.support.v4.graphics.ColorUtils.
*/

View File

@@ -89,7 +89,7 @@
<color name="perms_dangerous_perm_color">#33b5e5</color>
<color name="shadow">#cc222222</color>
<color name="perms_costs_money">#fff4511e</color>
<!-- For search-related UIs -->
<color name="search_url_text_normal">#7fa87f</color>
<color name="search_url_text_selected">@android:color/black</color>
@@ -132,6 +132,10 @@
<drawable name="notification_template_icon_low_bg">#0cffffff</drawable>
<drawable name="notification_template_divider">#29000000</drawable>
<drawable name="notification_template_divider_media">#29ffffff</drawable>
<color name="notification_primary_text_color_light">@color/primary_text_default_material_light</color>
<color name="notification_primary_text_color_dark">@color/primary_text_default_material_dark</color>
<color name="notification_secondary_text_color_light">@color/secondary_text_material_light</color>
<color name="notification_secondary_text_color_dark">@color/secondary_text_material_dark</color>
<color name="notification_material_background_color">#ffffffff</color>

View File

@@ -451,14 +451,14 @@ please see styles_device_defaults.xml.
</style>
<style name="TextAppearance.Material.Notification">
<item name="textColor">@color/secondary_text_material_light</item>
<item name="textColor">@color/notification_secondary_text_color_light</item>
<item name="textSize">@dimen/notification_text_size</item>
</style>
<style name="TextAppearance.Material.Notification.Reply" />
<style name="TextAppearance.Material.Notification.Title">
<item name="textColor">@color/primary_text_default_material_light</item>
<item name="textColor">@color/notification_primary_text_color_light</item>
<item name="textSize">@dimen/notification_title_text_size</item>
</style>
@@ -467,7 +467,7 @@ please see styles_device_defaults.xml.
</style>
<style name="TextAppearance.Material.Notification.Info">
<item name="textColor">@color/secondary_text_default_material_light</item>
<item name="textColor">@color/notification_secondary_text_color_light</item>
<item name="textSize">@dimen/notification_subtext_size</item>
</style>

View File

@@ -2791,6 +2791,11 @@
<java-symbol type="string" name="notification_header_divider_symbol_with_spaces" />
<java-symbol type="string" name="config_defaultCellBroadcastReceiverComponent" />
<java-symbol type="color" name="notification_primary_text_color_light" />
<java-symbol type="color" name="notification_primary_text_color_dark" />
<java-symbol type="color" name="notification_secondary_text_color_light" />
<java-symbol type="color" name="notification_secondary_text_color_dark" />
<java-symbol type="string" name="app_category_game" />
<java-symbol type="string" name="app_category_audio" />
<java-symbol type="string" name="app_category_video" />

View File

@@ -58,7 +58,6 @@
<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"/>

View File

@@ -40,9 +40,6 @@ 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, ExpandableNotificationRow row) {
@@ -105,32 +102,6 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper {
mView.setAlpha(visible ? 1.0f : 0.0f);
}
@Override
public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
super.notifyContentUpdated(notification, isLowPriority);
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() {
// Parent notifications should always use the normal background color
return mRow.isSummaryWithChildren() ? 0 : mBackgroundColor;
}
@Override
public void setShowingLegacyBackground(boolean showing) {
super.setShowingLegacyBackground(showing);

View File

@@ -19,12 +19,17 @@ package com.android.systemui.statusbar.notification;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.service.notification.StatusBarNotification;
import android.support.v4.graphics.ColorUtils;
import android.view.NotificationHeaderView;
import android.view.View;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.TransformableView;
@@ -40,6 +45,8 @@ public abstract class NotificationViewWrapper implements TransformableView {
protected final View mView;
protected final ExpandableNotificationRow mRow;
protected boolean mDark;
private int mBackgroundColor = 0;
protected boolean mShouldInvertDark;
protected boolean mDarkInitialized = false;
public static NotificationViewWrapper wrap(Context ctx, View v, ExpandableNotificationRow row) {
@@ -85,7 +92,19 @@ public abstract class NotificationViewWrapper implements TransformableView {
*/
public void notifyContentUpdated(StatusBarNotification notification, boolean isLowPriority) {
mDarkInitialized = false;
};
Drawable background = mView.getBackground();
mBackgroundColor = 0;
if (background instanceof ColorDrawable) {
mBackgroundColor = ((ColorDrawable) background).getColor();
mView.setBackground(null);
}
mShouldInvertDark = mBackgroundColor == 0 || isColorLight(mBackgroundColor);
}
private boolean isColorLight(int backgroundColor) {
return Color.alpha(backgroundColor) == 0
|| ColorUtils.calculateLuminance(backgroundColor) > 0.5;
}
protected void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
@@ -156,7 +175,8 @@ public abstract class NotificationViewWrapper implements TransformableView {
}
public int getCustomBackgroundColor() {
return 0;
// Parent notifications should always use the normal background color
return mRow.isSummaryWithChildren() ? 0 : mBackgroundColor;
}
public void setShowingLegacyBackground(boolean showing) {

View File

@@ -30,7 +30,6 @@ import android.provider.Settings;
import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Slog;
import java.util.Comparator;
import java.util.Objects;
@@ -57,7 +56,15 @@ public class NotificationComparator
@Override
public int compare(NotificationRecord left, NotificationRecord right) {
// First up: sufficiently important ongoing notifications of certain categories
// first all colorized notifications
boolean leftImportantColorized = isImportantColorized(left);
boolean rightImportantColorized = isImportantColorized(right);
if (leftImportantColorized != rightImportantColorized) {
return -1 * Boolean.compare(leftImportantColorized, rightImportantColorized);
}
// sufficiently important ongoing notifications of certain categories
boolean leftImportantOngoing = isImportantOngoing(left);
boolean rightImportantOngoing = isImportantOngoing(right);
@@ -106,6 +113,13 @@ public class NotificationComparator
return -1 * Long.compare(left.getRankingTimeMs(), right.getRankingTimeMs());
}
private boolean isImportantColorized(NotificationRecord record) {
if (record.getImportance() < NotificationManager.IMPORTANCE_LOW) {
return false;
}
return record.getNotification().isColorized();
}
private boolean isImportantOngoing(NotificationRecord record) {
if (!isOngoing(record)) {
return false;
@@ -148,7 +162,6 @@ public class NotificationComparator
return (record.getNotification().flags & ongoingFlags) != 0;
}
private Class<? extends Notification.Style> getNotificationStyle(NotificationRecord record) {
String templateClass =
record.getNotification().extras.getString(Notification.EXTRA_TEMPLATE);