Loading core/java/android/app/Notification.java +3 −42 Original line number Diff line number Diff line Loading @@ -60,7 +60,6 @@ import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; import android.text.style.AbsoluteSizeSpan; import android.text.style.BackgroundColorSpan; import android.text.style.CharacterStyle; import android.text.style.ForegroundColorSpan; import android.text.style.RelativeSizeSpan; Loading Loading @@ -3923,7 +3922,7 @@ public class Notification implements Parcelable private CharSequence processTextSpans(CharSequence text) { if (hasForegroundColor()) { return clearColorSpans(text); return NotificationColorUtil.clearColorSpans(text); } return text; } Loading Loading @@ -4683,7 +4682,7 @@ public class Notification implements Parcelable CharSequence title = action.title; ColorStateList[] outResultColor = null; if (isLegacy()) { title = clearColorSpans(title); title = NotificationColorUtil.clearColorSpans(title); } else { outResultColor = new ColorStateList[1]; title = ensureColorSpanContrast(title, bgColor, outResultColor); Loading @@ -4710,45 +4709,6 @@ public class Notification implements Parcelable return button; } /** * Clears all color spans of a text * @param charSequence the input text * @return the same text but without color spans */ private CharSequence clearColorSpans(CharSequence charSequence) { if (charSequence instanceof Spanned) { Spanned ss = (Spanned) charSequence; Object[] spans = ss.getSpans(0, ss.length(), Object.class); SpannableStringBuilder builder = new SpannableStringBuilder(ss.toString()); for (Object span : spans) { Object resultSpan = span; if (resultSpan instanceof CharacterStyle) { resultSpan = ((CharacterStyle) span).getUnderlying(); } if (resultSpan instanceof TextAppearanceSpan) { TextAppearanceSpan originalSpan = (TextAppearanceSpan) resultSpan; if (originalSpan.getTextColor() != null) { resultSpan = new TextAppearanceSpan( originalSpan.getFamily(), originalSpan.getTextStyle(), originalSpan.getTextSize(), null, originalSpan.getLinkTextColor()); } } else if (resultSpan instanceof ForegroundColorSpan || (resultSpan instanceof BackgroundColorSpan)) { continue; } else { resultSpan = span; } builder.setSpan(resultSpan, ss.getSpanStart(span), ss.getSpanEnd(span), ss.getSpanFlags(span)); } return builder; } return charSequence; } /** * Ensures contrast on color spans against a background color. also returns the color of the * text if a span was found that spans over the whole text. Loading Loading @@ -7075,6 +7035,7 @@ public class Notification implements Parcelable // Need to clone customContent before adding, because otherwise it can no longer be // parceled independently of remoteViews. customContent = customContent.clone(); customContent.overrideTextColors(mBuilder.getPrimaryTextColor()); remoteViews.removeAllViews(id); remoteViews.addView(id, customContent); remoteViews.setReapplyDisallowed(); Loading core/java/android/widget/RemoteViews.java +63 −0 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ import android.view.ViewStub; import android.widget.AdapterView.OnItemClickListener; import com.android.internal.R; import com.android.internal.util.NotificationColorUtil; import com.android.internal.util.Preconditions; import libcore.util.Objects; Loading @@ -75,6 +76,7 @@ import java.lang.annotation.Target; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.Stack; import java.util.concurrent.Executor; /** Loading Loading @@ -118,6 +120,7 @@ public class RemoteViews implements Parcelable, Filter { private static final int TEXT_VIEW_DRAWABLE_COLOR_FILTER_ACTION_TAG = 17; private static final int SET_REMOTE_INPUTS_ACTION_TAG = 18; private static final int LAYOUT_PARAM_ACTION_TAG = 19; private static final int OVERRIDE_TEXT_COLORS_TAG = 20; /** * Application that hosts the remote views. Loading Loading @@ -220,6 +223,17 @@ public class RemoteViews implements Parcelable, Filter { } } /** * Override all text colors in this layout and replace them by the given text color. * * @param textColor The color to use. * * @hide */ public void overrideTextColors(int textColor) { addAction(new OverrideTextColorsAction(textColor)); } /** * Set that it is disallowed to reapply another remoteview with the same layout as this view. * This should be done if an action is destroying the view tree of the base layout. Loading Loading @@ -2248,6 +2262,52 @@ public class RemoteViews implements Parcelable, Filter { final Parcelable[] remoteInputs; } /** * Helper action to override all textViewColors */ private class OverrideTextColorsAction extends Action { private final int textColor; public OverrideTextColorsAction(int textColor) { this.textColor = textColor; } public OverrideTextColorsAction(Parcel parcel) { textColor = parcel.readInt(); } public void writeToParcel(Parcel dest, int flags) { dest.writeInt(OVERRIDE_TEXT_COLORS_TAG); dest.writeInt(textColor); } @Override public void apply(View root, ViewGroup rootParent, OnClickHandler handler) { // Let's traverse the viewtree and override all textColors! Stack<View> viewsToProcess = new Stack<>(); viewsToProcess.add(root); while (!viewsToProcess.isEmpty()) { View v = viewsToProcess.pop(); if (v instanceof TextView) { TextView textView = (TextView) v; textView.setText(NotificationColorUtil.clearColorSpans(textView.getText())); textView.setTextColor(textColor); } if (v instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) v; for (int i = 0; i < viewGroup.getChildCount(); i++) { viewsToProcess.push(viewGroup.getChildAt(i)); } } } } public String getActionName() { return "OverrideTextColorsAction"; } } /** * Simple class used to keep track of memory usage in a RemoteViews. * Loading Loading @@ -2443,6 +2503,9 @@ public class RemoteViews implements Parcelable, Filter { case LAYOUT_PARAM_ACTION_TAG: mActions.add(new LayoutParamAction(parcel)); break; case OVERRIDE_TEXT_COLORS_TAG: mActions.add(new OverrideTextColorsAction(parcel)); break; default: throw new ActionException("Tag " + tag + " not found"); } Loading core/java/com/android/internal/util/NotificationColorUtil.java +40 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import android.graphics.drawable.Icon; import android.graphics.drawable.VectorDrawable; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.BackgroundColorSpan; import android.text.style.CharacterStyle; import android.text.style.ForegroundColorSpan; import android.text.style.TextAppearanceSpan; Loading Loading @@ -240,6 +241,45 @@ public class NotificationColorUtil { return span; } /** * Clears all color spans of a text * @param charSequence the input text * @return the same text but without color spans */ public static CharSequence clearColorSpans(CharSequence charSequence) { if (charSequence instanceof Spanned) { Spanned ss = (Spanned) charSequence; Object[] spans = ss.getSpans(0, ss.length(), Object.class); SpannableStringBuilder builder = new SpannableStringBuilder(ss.toString()); for (Object span : spans) { Object resultSpan = span; if (resultSpan instanceof CharacterStyle) { resultSpan = ((CharacterStyle) span).getUnderlying(); } if (resultSpan instanceof TextAppearanceSpan) { TextAppearanceSpan originalSpan = (TextAppearanceSpan) resultSpan; if (originalSpan.getTextColor() != null) { resultSpan = new TextAppearanceSpan( originalSpan.getFamily(), originalSpan.getTextStyle(), originalSpan.getTextSize(), null, originalSpan.getLinkTextColor()); } } else if (resultSpan instanceof ForegroundColorSpan || (resultSpan instanceof BackgroundColorSpan)) { continue; } else { resultSpan = span; } builder.setSpan(resultSpan, ss.getSpanStart(span), ss.getSpanEnd(span), ss.getSpanFlags(span)); } return builder; } return charSequence; } private int processColor(int color) { return Color.argb(Color.alpha(color), 255 - Color.red(color), Loading Loading
core/java/android/app/Notification.java +3 −42 Original line number Diff line number Diff line Loading @@ -60,7 +60,6 @@ import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; import android.text.style.AbsoluteSizeSpan; import android.text.style.BackgroundColorSpan; import android.text.style.CharacterStyle; import android.text.style.ForegroundColorSpan; import android.text.style.RelativeSizeSpan; Loading Loading @@ -3923,7 +3922,7 @@ public class Notification implements Parcelable private CharSequence processTextSpans(CharSequence text) { if (hasForegroundColor()) { return clearColorSpans(text); return NotificationColorUtil.clearColorSpans(text); } return text; } Loading Loading @@ -4683,7 +4682,7 @@ public class Notification implements Parcelable CharSequence title = action.title; ColorStateList[] outResultColor = null; if (isLegacy()) { title = clearColorSpans(title); title = NotificationColorUtil.clearColorSpans(title); } else { outResultColor = new ColorStateList[1]; title = ensureColorSpanContrast(title, bgColor, outResultColor); Loading @@ -4710,45 +4709,6 @@ public class Notification implements Parcelable return button; } /** * Clears all color spans of a text * @param charSequence the input text * @return the same text but without color spans */ private CharSequence clearColorSpans(CharSequence charSequence) { if (charSequence instanceof Spanned) { Spanned ss = (Spanned) charSequence; Object[] spans = ss.getSpans(0, ss.length(), Object.class); SpannableStringBuilder builder = new SpannableStringBuilder(ss.toString()); for (Object span : spans) { Object resultSpan = span; if (resultSpan instanceof CharacterStyle) { resultSpan = ((CharacterStyle) span).getUnderlying(); } if (resultSpan instanceof TextAppearanceSpan) { TextAppearanceSpan originalSpan = (TextAppearanceSpan) resultSpan; if (originalSpan.getTextColor() != null) { resultSpan = new TextAppearanceSpan( originalSpan.getFamily(), originalSpan.getTextStyle(), originalSpan.getTextSize(), null, originalSpan.getLinkTextColor()); } } else if (resultSpan instanceof ForegroundColorSpan || (resultSpan instanceof BackgroundColorSpan)) { continue; } else { resultSpan = span; } builder.setSpan(resultSpan, ss.getSpanStart(span), ss.getSpanEnd(span), ss.getSpanFlags(span)); } return builder; } return charSequence; } /** * Ensures contrast on color spans against a background color. also returns the color of the * text if a span was found that spans over the whole text. Loading Loading @@ -7075,6 +7035,7 @@ public class Notification implements Parcelable // Need to clone customContent before adding, because otherwise it can no longer be // parceled independently of remoteViews. customContent = customContent.clone(); customContent.overrideTextColors(mBuilder.getPrimaryTextColor()); remoteViews.removeAllViews(id); remoteViews.addView(id, customContent); remoteViews.setReapplyDisallowed(); Loading
core/java/android/widget/RemoteViews.java +63 −0 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ import android.view.ViewStub; import android.widget.AdapterView.OnItemClickListener; import com.android.internal.R; import com.android.internal.util.NotificationColorUtil; import com.android.internal.util.Preconditions; import libcore.util.Objects; Loading @@ -75,6 +76,7 @@ import java.lang.annotation.Target; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.Stack; import java.util.concurrent.Executor; /** Loading Loading @@ -118,6 +120,7 @@ public class RemoteViews implements Parcelable, Filter { private static final int TEXT_VIEW_DRAWABLE_COLOR_FILTER_ACTION_TAG = 17; private static final int SET_REMOTE_INPUTS_ACTION_TAG = 18; private static final int LAYOUT_PARAM_ACTION_TAG = 19; private static final int OVERRIDE_TEXT_COLORS_TAG = 20; /** * Application that hosts the remote views. Loading Loading @@ -220,6 +223,17 @@ public class RemoteViews implements Parcelable, Filter { } } /** * Override all text colors in this layout and replace them by the given text color. * * @param textColor The color to use. * * @hide */ public void overrideTextColors(int textColor) { addAction(new OverrideTextColorsAction(textColor)); } /** * Set that it is disallowed to reapply another remoteview with the same layout as this view. * This should be done if an action is destroying the view tree of the base layout. Loading Loading @@ -2248,6 +2262,52 @@ public class RemoteViews implements Parcelable, Filter { final Parcelable[] remoteInputs; } /** * Helper action to override all textViewColors */ private class OverrideTextColorsAction extends Action { private final int textColor; public OverrideTextColorsAction(int textColor) { this.textColor = textColor; } public OverrideTextColorsAction(Parcel parcel) { textColor = parcel.readInt(); } public void writeToParcel(Parcel dest, int flags) { dest.writeInt(OVERRIDE_TEXT_COLORS_TAG); dest.writeInt(textColor); } @Override public void apply(View root, ViewGroup rootParent, OnClickHandler handler) { // Let's traverse the viewtree and override all textColors! Stack<View> viewsToProcess = new Stack<>(); viewsToProcess.add(root); while (!viewsToProcess.isEmpty()) { View v = viewsToProcess.pop(); if (v instanceof TextView) { TextView textView = (TextView) v; textView.setText(NotificationColorUtil.clearColorSpans(textView.getText())); textView.setTextColor(textColor); } if (v instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) v; for (int i = 0; i < viewGroup.getChildCount(); i++) { viewsToProcess.push(viewGroup.getChildAt(i)); } } } } public String getActionName() { return "OverrideTextColorsAction"; } } /** * Simple class used to keep track of memory usage in a RemoteViews. * Loading Loading @@ -2443,6 +2503,9 @@ public class RemoteViews implements Parcelable, Filter { case LAYOUT_PARAM_ACTION_TAG: mActions.add(new LayoutParamAction(parcel)); break; case OVERRIDE_TEXT_COLORS_TAG: mActions.add(new OverrideTextColorsAction(parcel)); break; default: throw new ActionException("Tag " + tag + " not found"); } Loading
core/java/com/android/internal/util/NotificationColorUtil.java +40 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import android.graphics.drawable.Icon; import android.graphics.drawable.VectorDrawable; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.BackgroundColorSpan; import android.text.style.CharacterStyle; import android.text.style.ForegroundColorSpan; import android.text.style.TextAppearanceSpan; Loading Loading @@ -240,6 +241,45 @@ public class NotificationColorUtil { return span; } /** * Clears all color spans of a text * @param charSequence the input text * @return the same text but without color spans */ public static CharSequence clearColorSpans(CharSequence charSequence) { if (charSequence instanceof Spanned) { Spanned ss = (Spanned) charSequence; Object[] spans = ss.getSpans(0, ss.length(), Object.class); SpannableStringBuilder builder = new SpannableStringBuilder(ss.toString()); for (Object span : spans) { Object resultSpan = span; if (resultSpan instanceof CharacterStyle) { resultSpan = ((CharacterStyle) span).getUnderlying(); } if (resultSpan instanceof TextAppearanceSpan) { TextAppearanceSpan originalSpan = (TextAppearanceSpan) resultSpan; if (originalSpan.getTextColor() != null) { resultSpan = new TextAppearanceSpan( originalSpan.getFamily(), originalSpan.getTextStyle(), originalSpan.getTextSize(), null, originalSpan.getLinkTextColor()); } } else if (resultSpan instanceof ForegroundColorSpan || (resultSpan instanceof BackgroundColorSpan)) { continue; } else { resultSpan = span; } builder.setSpan(resultSpan, ss.getSpanStart(span), ss.getSpanEnd(span), ss.getSpanFlags(span)); } return builder; } return charSequence; } private int processColor(int color) { return Color.argb(Color.alpha(color), 255 - Color.red(color), Loading