Ensure notification color contrast

Ensure we have at least 3:1 contrast for the
action buttons. Also ensures that the inline
reply box background has 4.5:1 contrast to white.

Further modifies the color of the inline reply
background to satisfy a 4.5:1 contrast ratio for
the entered text.

Bug: 26831312
Change-Id: If42b1c99d1adee547d0a583c1a69c48ef7287c23
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index cb1bee5..8423de8 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -24,7 +24,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.ColorStateList;
 import android.graphics.Bitmap;
@@ -568,6 +567,12 @@
     public static final int COLOR_DEFAULT = 0; // AKA Color.TRANSPARENT
 
     /**
+     * Special value of {@link #color} used as a place holder for an invalid color.
+     */
+    @ColorInt
+    private static final int COLOR_INVALID = 1;
+
+    /**
      * Sphere of visibility of this notification, which affects how and when the SystemUI reveals 
      * the notification's presence and contents in untrusted situations (namely, on the secure 
      * lockscreen).
@@ -2092,6 +2097,12 @@
         private boolean mColorUtilInited = false;
 
         /**
+         * Caches a contrast-enhanced version of {@link #mCachedContrastColorIsFor}.
+         */
+        private int mCachedContrastColor = COLOR_INVALID;
+        private int mCachedContrastColorIsFor = COLOR_INVALID;
+
+        /**
          * Constructs a new Builder with the defaults:
          *
 
@@ -3074,7 +3085,7 @@
                         R.id.progress, ColorStateList.valueOf(mContext.getColor(
                                 R.color.notification_progress_background_color)));
                 if (mN.color != COLOR_DEFAULT) {
-                    ColorStateList colorStateList = ColorStateList.valueOf(mN.color);
+                    ColorStateList colorStateList = ColorStateList.valueOf(resolveContrastColor());
                     contentView.setProgressTintList(R.id.progress, colorStateList);
                     contentView.setProgressIndeterminateTintList(R.id.progress, colorStateList);
                 }
@@ -3135,10 +3146,10 @@
         }
 
         private void bindExpandButton(RemoteViews contentView) {
-            contentView.setDrawableParameters(R.id.expand_button, false, -1, resolveColor(),
+            contentView.setDrawableParameters(R.id.expand_button, false, -1, resolveContrastColor(),
                     PorterDuff.Mode.SRC_ATOP, -1);
             contentView.setInt(R.id.notification_header, "setOriginalNotificationColor",
-                    resolveColor());
+                    resolveContrastColor());
         }
 
         private void bindHeaderChronometerAndTime(RemoteViews contentView) {
@@ -3180,7 +3191,7 @@
                 return;
             }
             contentView.setTextViewText(R.id.app_name_text, appName);
-            contentView.setTextColor(R.id.app_name_text, resolveColor());
+            contentView.setTextColor(R.id.app_name_text, resolveContrastColor());
         }
 
         private void bindSmallIcon(RemoteViews contentView) {
@@ -3405,7 +3416,7 @@
                 button.setRemoteInputs(R.id.action0, action.mRemoteInputs);
             }
             if (mN.color != COLOR_DEFAULT) {
-                button.setTextColor(R.id.action0, mN.color);
+                button.setTextColor(R.id.action0, resolveContrastColor());
             }
             return button;
         }
@@ -3432,12 +3443,12 @@
         private void processSmallIconColor(Icon smallIcon, RemoteViews contentView) {
             boolean colorable = !isLegacy() || getColorUtil().isGrayscaleIcon(mContext, smallIcon);
             if (colorable) {
-                contentView.setDrawableParameters(R.id.icon, false, -1, resolveColor(),
+                contentView.setDrawableParameters(R.id.icon, false, -1, resolveContrastColor(),
                         PorterDuff.Mode.SRC_ATOP, -1);
 
             }
             contentView.setInt(R.id.notification_header, "setOriginalIconColor",
-                    colorable ? resolveColor() : NotificationHeaderView.NO_COLOR);
+                    colorable ? resolveContrastColor() : NotificationHeaderView.NO_COLOR);
         }
 
         /**
@@ -3449,7 +3460,7 @@
             if (largeIcon != null && isLegacy()
                     && getColorUtil().isGrayscaleIcon(mContext, largeIcon)) {
                 // resolve color will fall back to the default when legacy
-                contentView.setDrawableParameters(R.id.icon, false, -1, resolveColor(),
+                contentView.setDrawableParameters(R.id.icon, false, -1, resolveContrastColor(),
                         PorterDuff.Mode.SRC_ATOP, -1);
             }
         }
@@ -3460,11 +3471,14 @@
             }
         }
 
-        int resolveColor() {
-            if (mN.color == COLOR_DEFAULT) {
-                return mContext.getColor(R.color.notification_icon_default_color);
+        int resolveContrastColor() {
+            if (mCachedContrastColorIsFor == mN.color && mCachedContrastColor != COLOR_INVALID) {
+                return mCachedContrastColor;
             }
-            return mN.color;
+            final int contrasted = NotificationColorUtil.resolveContrastColor(mContext, mN.color);
+
+            mCachedContrastColorIsFor = mN.color;
+            return mCachedContrastColor = contrasted;
         }
 
         /**
@@ -4427,7 +4441,7 @@
 
                     final Action action = mBuilder.mActions.get(mActionsToShowInCompact[i]);
                     final RemoteViews button = generateMediaActionButton(action,
-                            mBuilder.resolveColor());
+                            mBuilder.resolveContrastColor());
                     view.addView(com.android.internal.R.id.media_actions, button);
                 }
             }
@@ -4460,7 +4474,7 @@
                 big.removeAllViews(com.android.internal.R.id.media_actions);
                 for (int i = 0; i < actionCount; i++) {
                     final RemoteViews button = generateMediaActionButton(mBuilder.mActions.get(i),
-                            mBuilder.resolveColor());
+                            mBuilder.resolveContrastColor());
                     big.addView(com.android.internal.R.id.media_actions, button);
                 }
             }