Loading core/java/android/app/Notification.java +34 −7 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ShortcutInfo; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; Loading Loading @@ -2752,6 +2754,9 @@ public class Notification implements Parcelable private ArrayList<Action> mOriginalActions; private boolean mRebuildStyledRemoteViews; private boolean mTintActionButtons; private boolean mInNightMode; /** * Constructs a new Builder with the defaults: * Loading Loading @@ -2783,6 +2788,14 @@ public class Notification implements Parcelable */ public Builder(Context context, Notification toAdopt) { mContext = context; Resources res = mContext.getResources(); mTintActionButtons = res.getBoolean(R.bool.config_tintNotificationActionButtons); if (res.getBoolean(R.bool.config_enableNightMode)) { Configuration currentConfig = res.getConfiguration(); mInNightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; } if (toAdopt == null) { mN = new Notification(); Loading Loading @@ -4631,14 +4644,14 @@ public class Notification implements Parcelable // 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 && !isColorized()) { } else if (mN.color != COLOR_DEFAULT && !isColorized() && mTintActionButtons) { button.setTextColor(R.id.action0,resolveContrastColor()); } } else { button.setTextViewText(R.id.action0, processLegacyText(action.title)); if (isColorized() && !ambient) { setTextViewColorPrimary(button, R.id.action0); } else if (mN.color != COLOR_DEFAULT) { } else if (mN.color != COLOR_DEFAULT && mTintActionButtons) { button.setTextColor(R.id.action0, ambient ? resolveAmbientColor() : resolveContrastColor()); } Loading Loading @@ -4717,7 +4730,7 @@ public class Notification implements Parcelable int[] newColors = new int[colors.length]; for (int i = 0; i < newColors.length; i++) { newColors[i] = NotificationColorUtil.ensureLargeTextContrast( colors[i], background); colors[i], background, mInNightMode); } textColor = new ColorStateList(textColor.getStates().clone(), newColors); Loading @@ -4736,7 +4749,7 @@ public class Notification implements Parcelable ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan; int foregroundColor = originalSpan.getForegroundColor(); foregroundColor = NotificationColorUtil.ensureLargeTextContrast( foregroundColor, background); foregroundColor, background, mInNightMode); resultSpan = new ForegroundColorSpan(foregroundColor); if (fullLength) { outResultColor[0] = ColorStateList.valueOf(foregroundColor); Loading Loading @@ -4831,7 +4844,7 @@ public class Notification implements Parcelable color = mSecondaryTextColor; } else { color = NotificationColorUtil.resolveContrastColor(mContext, mN.color, background); background, mInNightMode); } if (Color.alpha(color) < 255) { // alpha doesn't go well for color filters, so let's blend it manually Loading Loading @@ -5064,6 +5077,10 @@ public class Notification implements Parcelable return mN.isColorized(); } private boolean shouldTintActionButtons() { return mTintActionButtons; } private boolean textColorsNeedInversion() { if (mStyle == null || !MediaStyle.class.equals(mStyle.getClass())) { return false; Loading Loading @@ -6067,6 +6084,8 @@ public class Notification implements Parcelable BidiFormatter bidi = BidiFormatter.getInstance(); SpannableStringBuilder sb = new SpannableStringBuilder(); boolean colorize = builder.isColorized(); TextAppearanceSpan colorSpan; CharSequence messageName; if (TextUtils.isEmpty(m.mSender)) { CharSequence replyName = mUserDisplayName == null ? "" : mUserDisplayName; sb.append(bidi.unicodeWrap(replyName), Loading Loading @@ -6595,8 +6614,16 @@ public class Notification implements Parcelable RemoteViews button = new BuilderRemoteViews(mBuilder.mContext.getApplicationInfo(), R.layout.notification_material_media_action); button.setImageViewIcon(R.id.action0, action.getIcon()); button.setDrawableParameters(R.id.action0, false, -1, color, PorterDuff.Mode.SRC_ATOP, -1); // If the action buttons should not be tinted, then just use the default // notification color. Otherwise, just use the passed-in color. int tintColor = mBuilder.shouldTintActionButtons() || mBuilder.isColorized() ? color : NotificationColorUtil.resolveColor(mBuilder.mContext, Notification.COLOR_DEFAULT); button.setDrawableParameters(R.id.action0, false, -1, tintColor, PorterDuff.Mode.SRC_ATOP, -1); if (!tombstone) { button.setOnClickPendingIntent(R.id.action0, action.actionIntent); } Loading core/java/com/android/internal/util/NotificationColorUtil.java +35 −12 Original line number Diff line number Diff line Loading @@ -361,19 +361,27 @@ public class NotificationColorUtil { } /** * Finds a text color with sufficient contrast over bg that has the same hue as the original * color, assuming it is for large text. * Finds a large text color with sufficient contrast over bg that has the same or darker hue as * the original color, depending on the value of {@code isBgDarker}. * * @param isBgDarker {@code true} if {@code bg} is darker than {@code color}. */ public static int ensureLargeTextContrast(int color, int bg) { return findContrastColor(color, bg, true, 3); public static int ensureLargeTextContrast(int color, int bg, boolean isBgDarker) { return isBgDarker ? findContrastColorAgainstDark(color, bg, true, 3) : findContrastColor(color, bg, true, 3); } /** * Finds a text color with sufficient contrast over bg that has the same hue as the original * color. * Finds a text color with sufficient contrast over bg that has the same or darker hue as the * original color, depending on the value of {@code isBgDarker}. * * @param isBgDarker {@code true} if {@code bg} is darker than {@code color}. */ private static int ensureTextContrast(int color, int bg) { return findContrastColor(color, bg, true, 4.5); private static int ensureTextContrast(int color, int bg, boolean isBgDarker) { return isBgDarker ? findContrastColorAgainstDark(color, bg, true, 4.5) : findContrastColor(color, bg, true, 4.5); } /** Finds a background color for a text view with given text color and hint text color, that Loading @@ -400,24 +408,39 @@ public class NotificationColorUtil { return color; } /** * Resolves a Notification's color such that it has enough contrast to be used as the * color for the Notification's action and header text on a background that is lighter than * {@code notificationColor}. * * @see {@link #resolveContrastColor(Context, int, boolean)} */ public static int resolveContrastColor(Context context, int notificationColor, int backgroundColor) { return NotificationColorUtil.resolveContrastColor(context, notificationColor, backgroundColor, false /* isDark */); } /** * Resolves a Notification's color such that it has enough contrast to be used as the * color for the Notification's action and header text. * * @param notificationColor the color of the notification or {@link Notification#COLOR_DEFAULT} * @param backgroundColor the background color to ensure the contrast against. * @param isDark whether or not the {@code notificationColor} will be placed on a background * that is darker than the color itself * @return a color of the same hue with enough contrast against the backgrounds. */ public static int resolveContrastColor(Context context, int notificationColor, int backgroundColor) { int backgroundColor, boolean isDark) { final int resolvedColor = resolveColor(context, notificationColor); final int actionBg = context.getColor( com.android.internal.R.color.notification_action_list); int color = resolvedColor; color = NotificationColorUtil.ensureLargeTextContrast(color, actionBg); color = NotificationColorUtil.ensureTextContrast(color, backgroundColor); color = NotificationColorUtil.ensureLargeTextContrast(color, actionBg, isDark); color = NotificationColorUtil.ensureTextContrast(color, backgroundColor, isDark); if (color != resolvedColor) { if (DEBUG){ Loading core/res/res/values/config.xml +7 −0 Original line number Diff line number Diff line Loading @@ -2978,4 +2978,11 @@ <!-- An array of packages that need to be treated as type service in battery settings --> <string-array translatable="false" name="config_batteryPackageTypeService"/> <!-- Flag indicating whether or not to enable night mode detection. --> <bool name="config_enableNightMode">false</bool> <!-- Flag indicating that the actions buttons for a notification should be tinted with by the color supplied by the Notification.Builder if present. --> <bool name="config_tintNotificationActionButtons">true</bool> </resources> core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -1749,6 +1749,8 @@ <java-symbol type="bool" name="config_automatic_brightness_available" /> <java-symbol type="bool" name="config_autoBrightnessResetAmbientLuxAfterWarmUp" /> <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_dozeAfterScreenOff" /> <java-symbol type="bool" name="config_enableActivityRecognitionHardwareOverlay" /> <java-symbol type="bool" name="config_enableFusedLocationOverlay" /> Loading packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java +11 −2 Original line number Diff line number Diff line Loading @@ -214,15 +214,24 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mFakeShadow = findViewById(R.id.fake_shadow); mShadowHidden = mFakeShadow.getVisibility() != VISIBLE; mBackgroundDimmed = findViewById(R.id.backgroundDimmed); mBackgroundNormal.setCustomBackground(R.drawable.notification_material_bg); mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim); mDimmedAlpha = Color.alpha(mContext.getColor( R.color.notification_material_background_dimmed_color)); initBackground(); updateBackground(); updateBackgroundTint(); updateOutlineAlpha(); } /** * Sets the custom backgrounds on {@link #mBackgroundNormal} and {@link #mBackgroundDimmed}. * This method can also be used to reload the backgrounds on both of those views, which can * be useful in a configuration change. */ protected void initBackground() { mBackgroundNormal.setCustomBackground(R.drawable.notification_material_bg); mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim); } private final Runnable mTapTimeoutRunnable = new Runnable() { @Override public void run() { Loading Loading
core/java/android/app/Notification.java +34 −7 Original line number Diff line number Diff line Loading @@ -33,6 +33,8 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ShortcutInfo; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; Loading Loading @@ -2752,6 +2754,9 @@ public class Notification implements Parcelable private ArrayList<Action> mOriginalActions; private boolean mRebuildStyledRemoteViews; private boolean mTintActionButtons; private boolean mInNightMode; /** * Constructs a new Builder with the defaults: * Loading Loading @@ -2783,6 +2788,14 @@ public class Notification implements Parcelable */ public Builder(Context context, Notification toAdopt) { mContext = context; Resources res = mContext.getResources(); mTintActionButtons = res.getBoolean(R.bool.config_tintNotificationActionButtons); if (res.getBoolean(R.bool.config_enableNightMode)) { Configuration currentConfig = res.getConfiguration(); mInNightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; } if (toAdopt == null) { mN = new Notification(); Loading Loading @@ -4631,14 +4644,14 @@ public class Notification implements Parcelable // 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 && !isColorized()) { } else if (mN.color != COLOR_DEFAULT && !isColorized() && mTintActionButtons) { button.setTextColor(R.id.action0,resolveContrastColor()); } } else { button.setTextViewText(R.id.action0, processLegacyText(action.title)); if (isColorized() && !ambient) { setTextViewColorPrimary(button, R.id.action0); } else if (mN.color != COLOR_DEFAULT) { } else if (mN.color != COLOR_DEFAULT && mTintActionButtons) { button.setTextColor(R.id.action0, ambient ? resolveAmbientColor() : resolveContrastColor()); } Loading Loading @@ -4717,7 +4730,7 @@ public class Notification implements Parcelable int[] newColors = new int[colors.length]; for (int i = 0; i < newColors.length; i++) { newColors[i] = NotificationColorUtil.ensureLargeTextContrast( colors[i], background); colors[i], background, mInNightMode); } textColor = new ColorStateList(textColor.getStates().clone(), newColors); Loading @@ -4736,7 +4749,7 @@ public class Notification implements Parcelable ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan; int foregroundColor = originalSpan.getForegroundColor(); foregroundColor = NotificationColorUtil.ensureLargeTextContrast( foregroundColor, background); foregroundColor, background, mInNightMode); resultSpan = new ForegroundColorSpan(foregroundColor); if (fullLength) { outResultColor[0] = ColorStateList.valueOf(foregroundColor); Loading Loading @@ -4831,7 +4844,7 @@ public class Notification implements Parcelable color = mSecondaryTextColor; } else { color = NotificationColorUtil.resolveContrastColor(mContext, mN.color, background); background, mInNightMode); } if (Color.alpha(color) < 255) { // alpha doesn't go well for color filters, so let's blend it manually Loading Loading @@ -5064,6 +5077,10 @@ public class Notification implements Parcelable return mN.isColorized(); } private boolean shouldTintActionButtons() { return mTintActionButtons; } private boolean textColorsNeedInversion() { if (mStyle == null || !MediaStyle.class.equals(mStyle.getClass())) { return false; Loading Loading @@ -6067,6 +6084,8 @@ public class Notification implements Parcelable BidiFormatter bidi = BidiFormatter.getInstance(); SpannableStringBuilder sb = new SpannableStringBuilder(); boolean colorize = builder.isColorized(); TextAppearanceSpan colorSpan; CharSequence messageName; if (TextUtils.isEmpty(m.mSender)) { CharSequence replyName = mUserDisplayName == null ? "" : mUserDisplayName; sb.append(bidi.unicodeWrap(replyName), Loading Loading @@ -6595,8 +6614,16 @@ public class Notification implements Parcelable RemoteViews button = new BuilderRemoteViews(mBuilder.mContext.getApplicationInfo(), R.layout.notification_material_media_action); button.setImageViewIcon(R.id.action0, action.getIcon()); button.setDrawableParameters(R.id.action0, false, -1, color, PorterDuff.Mode.SRC_ATOP, -1); // If the action buttons should not be tinted, then just use the default // notification color. Otherwise, just use the passed-in color. int tintColor = mBuilder.shouldTintActionButtons() || mBuilder.isColorized() ? color : NotificationColorUtil.resolveColor(mBuilder.mContext, Notification.COLOR_DEFAULT); button.setDrawableParameters(R.id.action0, false, -1, tintColor, PorterDuff.Mode.SRC_ATOP, -1); if (!tombstone) { button.setOnClickPendingIntent(R.id.action0, action.actionIntent); } Loading
core/java/com/android/internal/util/NotificationColorUtil.java +35 −12 Original line number Diff line number Diff line Loading @@ -361,19 +361,27 @@ public class NotificationColorUtil { } /** * Finds a text color with sufficient contrast over bg that has the same hue as the original * color, assuming it is for large text. * Finds a large text color with sufficient contrast over bg that has the same or darker hue as * the original color, depending on the value of {@code isBgDarker}. * * @param isBgDarker {@code true} if {@code bg} is darker than {@code color}. */ public static int ensureLargeTextContrast(int color, int bg) { return findContrastColor(color, bg, true, 3); public static int ensureLargeTextContrast(int color, int bg, boolean isBgDarker) { return isBgDarker ? findContrastColorAgainstDark(color, bg, true, 3) : findContrastColor(color, bg, true, 3); } /** * Finds a text color with sufficient contrast over bg that has the same hue as the original * color. * Finds a text color with sufficient contrast over bg that has the same or darker hue as the * original color, depending on the value of {@code isBgDarker}. * * @param isBgDarker {@code true} if {@code bg} is darker than {@code color}. */ private static int ensureTextContrast(int color, int bg) { return findContrastColor(color, bg, true, 4.5); private static int ensureTextContrast(int color, int bg, boolean isBgDarker) { return isBgDarker ? findContrastColorAgainstDark(color, bg, true, 4.5) : findContrastColor(color, bg, true, 4.5); } /** Finds a background color for a text view with given text color and hint text color, that Loading @@ -400,24 +408,39 @@ public class NotificationColorUtil { return color; } /** * Resolves a Notification's color such that it has enough contrast to be used as the * color for the Notification's action and header text on a background that is lighter than * {@code notificationColor}. * * @see {@link #resolveContrastColor(Context, int, boolean)} */ public static int resolveContrastColor(Context context, int notificationColor, int backgroundColor) { return NotificationColorUtil.resolveContrastColor(context, notificationColor, backgroundColor, false /* isDark */); } /** * Resolves a Notification's color such that it has enough contrast to be used as the * color for the Notification's action and header text. * * @param notificationColor the color of the notification or {@link Notification#COLOR_DEFAULT} * @param backgroundColor the background color to ensure the contrast against. * @param isDark whether or not the {@code notificationColor} will be placed on a background * that is darker than the color itself * @return a color of the same hue with enough contrast against the backgrounds. */ public static int resolveContrastColor(Context context, int notificationColor, int backgroundColor) { int backgroundColor, boolean isDark) { final int resolvedColor = resolveColor(context, notificationColor); final int actionBg = context.getColor( com.android.internal.R.color.notification_action_list); int color = resolvedColor; color = NotificationColorUtil.ensureLargeTextContrast(color, actionBg); color = NotificationColorUtil.ensureTextContrast(color, backgroundColor); color = NotificationColorUtil.ensureLargeTextContrast(color, actionBg, isDark); color = NotificationColorUtil.ensureTextContrast(color, backgroundColor, isDark); if (color != resolvedColor) { if (DEBUG){ Loading
core/res/res/values/config.xml +7 −0 Original line number Diff line number Diff line Loading @@ -2978,4 +2978,11 @@ <!-- An array of packages that need to be treated as type service in battery settings --> <string-array translatable="false" name="config_batteryPackageTypeService"/> <!-- Flag indicating whether or not to enable night mode detection. --> <bool name="config_enableNightMode">false</bool> <!-- Flag indicating that the actions buttons for a notification should be tinted with by the color supplied by the Notification.Builder if present. --> <bool name="config_tintNotificationActionButtons">true</bool> </resources>
core/res/res/values/symbols.xml +2 −0 Original line number Diff line number Diff line Loading @@ -1749,6 +1749,8 @@ <java-symbol type="bool" name="config_automatic_brightness_available" /> <java-symbol type="bool" name="config_autoBrightnessResetAmbientLuxAfterWarmUp" /> <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_dozeAfterScreenOff" /> <java-symbol type="bool" name="config_enableActivityRecognitionHardwareOverlay" /> <java-symbol type="bool" name="config_enableFusedLocationOverlay" /> Loading
packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java +11 −2 Original line number Diff line number Diff line Loading @@ -214,15 +214,24 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mFakeShadow = findViewById(R.id.fake_shadow); mShadowHidden = mFakeShadow.getVisibility() != VISIBLE; mBackgroundDimmed = findViewById(R.id.backgroundDimmed); mBackgroundNormal.setCustomBackground(R.drawable.notification_material_bg); mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim); mDimmedAlpha = Color.alpha(mContext.getColor( R.color.notification_material_background_dimmed_color)); initBackground(); updateBackground(); updateBackgroundTint(); updateOutlineAlpha(); } /** * Sets the custom backgrounds on {@link #mBackgroundNormal} and {@link #mBackgroundDimmed}. * This method can also be used to reload the backgrounds on both of those views, which can * be useful in a configuration change. */ protected void initBackground() { mBackgroundNormal.setCustomBackground(R.drawable.notification_material_bg); mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim); } private final Runnable mTapTimeoutRunnable = new Runnable() { @Override public void run() { Loading