summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTony Wickham <twickham@google.com>2017-01-27 23:34:19 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2017-01-27 23:34:19 +0000
commit72e1688019c4cf650fb533b38296a9442bedf72e (patch)
treecf7425298ef1c956a514d80a3514979044c73b18 /src
parentdec3a908bfa395095e80e4a532cff98612b624de (diff)
parentf79877c04c071b7ae1618395f0a1dce134fec36e (diff)
downloadandroid_packages_apps_Trebuchet-72e1688019c4cf650fb533b38296a9442bedf72e.tar.gz
android_packages_apps_Trebuchet-72e1688019c4cf650fb533b38296a9442bedf72e.tar.bz2
android_packages_apps_Trebuchet-72e1688019c4cf650fb533b38296a9442bedf72e.zip
Merge "Ensure notification icons have enough contrast with background." into ub-launcher3-master
Diffstat (limited to 'src')
-rw-r--r--src/com/android/launcher3/graphics/IconPalette.java102
-rw-r--r--src/com/android/launcher3/notification/NotificationFooterLayout.java6
-rw-r--r--src/com/android/launcher3/notification/NotificationInfo.java28
-rw-r--r--src/com/android/launcher3/notification/NotificationItemView.java6
-rw-r--r--src/com/android/launcher3/notification/NotificationMainView.java24
5 files changed, 148 insertions, 18 deletions
diff --git a/src/com/android/launcher3/graphics/IconPalette.java b/src/com/android/launcher3/graphics/IconPalette.java
index 58ad449d6..27aeaba34 100644
--- a/src/com/android/launcher3/graphics/IconPalette.java
+++ b/src/com/android/launcher3/graphics/IconPalette.java
@@ -16,14 +16,22 @@
package com.android.launcher3.graphics;
+import android.app.Notification;
+import android.content.Context;
import android.graphics.Color;
import android.support.v4.graphics.ColorUtils;
+import android.util.Log;
+
+import com.android.launcher3.R;
/**
* Contains colors based on the dominant color of an icon.
*/
public class IconPalette {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "IconPalette";
+
public int backgroundColor;
public int textColor;
public int secondaryColor;
@@ -36,6 +44,100 @@ public class IconPalette {
return palette;
}
+ /**
+ * Resolves a color such that it has enough contrast to be used as the
+ * color of an icon or text on the given background color.
+ *
+ * @return a color of the same hue with enough contrast against the background.
+ *
+ * This was copied from com.android.internal.util.NotificationColorUtil.
+ */
+ public static int resolveContrastColor(Context context, int color, int background) {
+ final int resolvedColor = resolveColor(context, color);
+
+ int contrastingColor = ensureTextContrast(resolvedColor, background);
+
+ if (contrastingColor != resolvedColor) {
+ if (DEBUG){
+ Log.w(TAG, String.format(
+ "Enhanced contrast of notification for %s " +
+ "%s (over background) by changing #%s to %s",
+ context.getPackageName(),
+ contrastChange(resolvedColor, contrastingColor, background),
+ Integer.toHexString(resolvedColor), Integer.toHexString(contrastingColor)));
+ }
+ }
+ return contrastingColor;
+ }
+
+ /**
+ * Resolves {@param color} to an actual color if it is {@link Notification#COLOR_DEFAULT}
+ *
+ * This was copied from com.android.internal.util.NotificationColorUtil.
+ */
+ private static int resolveColor(Context context, int color) {
+ if (color == Notification.COLOR_DEFAULT) {
+ return context.getColor(R.color.notification_icon_default_color);
+ }
+ return color;
+ }
+
+ /** For debugging. This was copied from com.android.internal.util.NotificationColorUtil. */
+ private static String contrastChange(int colorOld, int colorNew, int bg) {
+ return String.format("from %.2f:1 to %.2f:1",
+ ColorUtils.calculateContrast(colorOld, bg),
+ ColorUtils.calculateContrast(colorNew, bg));
+ }
+
+ /**
+ * Finds a text color with sufficient contrast over bg that has the same hue as the original
+ * color.
+ *
+ * This was copied from com.android.internal.util.NotificationColorUtil.
+ */
+ private static int ensureTextContrast(int color, int bg) {
+ return findContrastColor(color, bg, true, 4.5);
+ }
+ /**
+ * Finds a suitable color such that there's enough contrast.
+ *
+ * @param color the color to start searching from.
+ * @param other the color to ensure contrast against. Assumed to be lighter than {@param color}
+ * @param findFg if true, we assume {@param color} is a foreground, otherwise a background.
+ * @param minRatio the minimum contrast ratio required.
+ * @return a color with the same hue as {@param color}, potentially darkened to meet the
+ * contrast ratio.
+ *
+ * This was copied from com.android.internal.util.NotificationColorUtil.
+ */
+ private static int findContrastColor(int color, int other, boolean findFg, double minRatio) {
+ int fg = findFg ? color : other;
+ int bg = findFg ? other : color;
+ if (ColorUtils.calculateContrast(fg, bg) >= minRatio) {
+ return color;
+ }
+
+ double[] lab = new double[3];
+ ColorUtils.colorToLAB(findFg ? fg : bg, lab);
+
+ double low = 0, high = lab[0];
+ final double a = lab[1], b = lab[2];
+ for (int i = 0; i < 15 && high - low > 0.00001; i++) {
+ final double l = (low + high) / 2;
+ if (findFg) {
+ fg = ColorUtils.LABToColor(l, a, b);
+ } else {
+ bg = ColorUtils.LABToColor(l, a, b);
+ }
+ if (ColorUtils.calculateContrast(fg, bg) > minRatio) {
+ low = l;
+ } else {
+ high = l;
+ }
+ }
+ return ColorUtils.LABToColor(low, a, b);
+ }
+
private static int getMutedColor(int color) {
int alpha = (int) (255 * 0.15f);
return ColorUtils.compositeColors(ColorUtils.setAlphaComponent(color, alpha), Color.WHITE);
diff --git a/src/com/android/launcher3/notification/NotificationFooterLayout.java b/src/com/android/launcher3/notification/NotificationFooterLayout.java
index cd610bd3b..07178ce0c 100644
--- a/src/com/android/launcher3/notification/NotificationFooterLayout.java
+++ b/src/com/android/launcher3/notification/NotificationFooterLayout.java
@@ -61,6 +61,7 @@ public class NotificationFooterLayout extends LinearLayout {
LinearLayout.LayoutParams mIconLayoutParams;
private LinearLayout mIconRow;
+ private int mBackgroundColor;
private int mTextColor;
public NotificationFooterLayout(Context context) {
@@ -90,7 +91,8 @@ public class NotificationFooterLayout extends LinearLayout {
}
public void applyColors(IconPalette iconPalette) {
- setBackgroundTintList(ColorStateList.valueOf(iconPalette.backgroundColor));
+ mBackgroundColor = iconPalette.backgroundColor;
+ setBackgroundTintList(ColorStateList.valueOf(mBackgroundColor));
findViewById(R.id.divider).setBackgroundColor(iconPalette.secondaryColor);
mTextColor = iconPalette.textColor;
}
@@ -130,7 +132,7 @@ public class NotificationFooterLayout extends LinearLayout {
private void addNotificationIconForInfo(NotificationInfo info, boolean fromOverflow) {
View icon = new View(getContext());
- icon.setBackground(info.iconDrawable);
+ icon.setBackground(info.getIconForBackground(getContext(), mBackgroundColor));
icon.setOnClickListener(info);
int addIndex = mIconRow.getChildCount();
if (fromOverflow) {
diff --git a/src/com/android/launcher3/notification/NotificationInfo.java b/src/com/android/launcher3/notification/NotificationInfo.java
index bf57b2aff..af5e817f1 100644
--- a/src/com/android/launcher3/notification/NotificationInfo.java
+++ b/src/com/android/launcher3/notification/NotificationInfo.java
@@ -25,6 +25,7 @@ import android.service.notification.StatusBarNotification;
import android.view.View;
import com.android.launcher3.Launcher;
+import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.util.PackageUserKey;
@@ -41,11 +42,14 @@ public class NotificationInfo implements View.OnClickListener {
public final String notificationKey;
public final CharSequence title;
public final CharSequence text;
- public final Drawable iconDrawable;
public final PendingIntent intent;
public final boolean autoCancel;
public final boolean dismissable;
+ private final Drawable mIconDrawable;
+ private boolean mShouldTintIcon;
+ private int mIconColor;
+
/**
* Extracts the data that we need from the StatusBarNotification.
*/
@@ -60,10 +64,12 @@ public class NotificationInfo implements View.OnClickListener {
Icon icon = notification.getLargeIcon();
if (icon == null) {
icon = notification.getSmallIcon();
- iconDrawable = icon.loadDrawable(context);
- iconDrawable.setTint(statusBarNotification.getNotification().color);
+ mIconDrawable = icon.loadDrawable(context);
+ mIconColor = statusBarNotification.getNotification().color;
+ mShouldTintIcon = true;
} else {
- iconDrawable = icon.loadDrawable(context);
+ mIconDrawable = icon.loadDrawable(context);
+ mShouldTintIcon = false;
}
intent = notification.contentIntent;
autoCancel = (notification.flags & Notification.FLAG_AUTO_CANCEL) != 0;
@@ -83,4 +89,18 @@ public class NotificationInfo implements View.OnClickListener {
}
PopupContainerWithArrow.getOpen(launcher).close(true);
}
+
+ public Drawable getIconForBackground(Context context, int background) {
+ if (!mShouldTintIcon) {
+ return mIconDrawable;
+ }
+ mIconColor = IconPalette.resolveContrastColor(context, mIconColor, background);
+ Drawable icon = mIconDrawable.mutate();
+ // DrawableContainer ignores the color filter if it's already set, so clear it first to
+ // get it set and invalidated properly.
+ icon.setTintList(null);
+ icon.setTint(mIconColor);
+ mShouldTintIcon = false;
+ return icon;
+ }
}
diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java
index b74cd4e1e..422722d8c 100644
--- a/src/com/android/launcher3/notification/NotificationItemView.java
+++ b/src/com/android/launcher3/notification/NotificationItemView.java
@@ -35,7 +35,9 @@ import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.popup.PopupItemView;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import static com.android.launcher3.LauncherAnimUtils.animateViewHeight;
@@ -117,7 +119,7 @@ public class NotificationItemView extends PopupItemView {
mHeader.setBackgroundTintList(ColorStateList.valueOf(iconPalette.backgroundColor));
mHeader.setTextColor(ColorStateList.valueOf(iconPalette.textColor));
mDivider.setBackgroundColor(iconPalette.secondaryColor);
- mMainView.setBackgroundColor(iconPalette.backgroundColor);
+ mMainView.applyColors(iconPalette);
mFooter.applyColors(iconPalette);
}
@@ -135,7 +137,7 @@ public class NotificationItemView extends PopupItemView {
@Override
public void onIconAnimationEnd(NotificationInfo newMainNotification) {
if (newMainNotification != null) {
- mMainView.applyNotificationInfo(newMainNotification, mIconView, mIconPalette);
+ mMainView.applyNotificationInfo(newMainNotification, mIconView, true);
// Remove the animated notification from the footer by calling trim
// TODO: Remove the notification in NotificationFooterLayout directly
// instead of relying on this hack.
diff --git a/src/com/android/launcher3/notification/NotificationMainView.java b/src/com/android/launcher3/notification/NotificationMainView.java
index 2997d4010..76a84b7c6 100644
--- a/src/com/android/launcher3/notification/NotificationMainView.java
+++ b/src/com/android/launcher3/notification/NotificationMainView.java
@@ -41,6 +41,7 @@ public class NotificationMainView extends LinearLayout implements SwipeHelper.Ca
private NotificationInfo mNotificationInfo;
private TextView mTitleView;
private TextView mTextView;
+ private IconPalette mIconPalette;
public NotificationMainView(Context context) {
this(context, null, 0);
@@ -62,35 +63,38 @@ public class NotificationMainView extends LinearLayout implements SwipeHelper.Ca
mTextView = (TextView) findViewById(R.id.text);
}
+ public void applyColors(IconPalette iconPalette) {
+ setBackgroundColor(iconPalette.backgroundColor);
+ mIconPalette = iconPalette;
+ }
+
public void applyNotificationInfo(NotificationInfo mainNotification, View iconView) {
- applyNotificationInfo(mainNotification, iconView, null);
+ applyNotificationInfo(mainNotification, iconView, false);
}
/**
- * @param iconPalette if not null, indicates that the new info should be animated in,
- * and that part of this animation includes animating the background
- * from iconPalette.secondaryColor to iconPalette.backgroundColor.
+ * Sets the content of this view, animating it after a new icon shifts up if necessary.
*/
public void applyNotificationInfo(NotificationInfo mainNotification, View iconView,
- @Nullable IconPalette iconPalette) {
- boolean animate = iconPalette != null;
+ boolean animate) {
if (animate) {
mTitleView.setAlpha(0);
mTextView.setAlpha(0);
- setBackgroundColor(iconPalette.secondaryColor);
+ setBackgroundColor(mIconPalette.secondaryColor);
}
mNotificationInfo = mainNotification;
mTitleView.setText(mNotificationInfo.title);
mTextView.setText(mNotificationInfo.text);
- iconView.setBackground(mNotificationInfo.iconDrawable);
+ iconView.setBackground(mNotificationInfo.getIconForBackground(
+ getContext(), mIconPalette.backgroundColor));
setOnClickListener(mNotificationInfo);
setTranslationX(0);
if (animate) {
AnimatorSet animation = LauncherAnimUtils.createAnimatorSet();
Animator textFade = new LauncherViewPropertyAnimator(mTextView).alpha(1);
Animator titleFade = new LauncherViewPropertyAnimator(mTitleView).alpha(1);
- ValueAnimator colorChange = ValueAnimator.ofArgb(iconPalette.secondaryColor,
- iconPalette.backgroundColor);
+ ValueAnimator colorChange = ValueAnimator.ofArgb(mIconPalette.secondaryColor,
+ mIconPalette.backgroundColor);
colorChange.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {