Do TTML color parsing directly in Exoplayer.

- Added TtmlColorParser to workaround JellyBean issues with named colors.
- Support rgb and rgba expressions as well.
This commit is contained in:
Oliver Woodman 2015-10-12 17:57:10 +01:00
parent 414ad05314
commit 20e05a31b2
4 changed files with 294 additions and 25 deletions

View File

@ -0,0 +1,113 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer.text.ttml;
import android.graphics.Color;
import android.test.InstrumentationTestCase;
/**
* Unit test for <code>TtmlColorParser</code>.
*/
public class TtmlColorParserTest extends InstrumentationTestCase {
public void testHexCodeParsing() {
assertEquals(Color.WHITE, TtmlColorParser.parseColor("#ffffff"));
assertEquals(Color.WHITE, TtmlColorParser.parseColor("#ffffffff"));
assertEquals(Color.parseColor("#00ffffff"), TtmlColorParser.parseColor("#00ffffff"));
assertEquals(Color.parseColor("#12341234"), TtmlColorParser.parseColor("#12341234"));
}
public void testColorNameParsing() {
assertEquals(TtmlColorParser.TRANSPARENT, TtmlColorParser.parseColor("transparent"));
assertEquals(TtmlColorParser.BLACK, TtmlColorParser.parseColor("black"));
assertEquals(TtmlColorParser.GRAY, TtmlColorParser.parseColor("gray"));
assertEquals(TtmlColorParser.SILVER, TtmlColorParser.parseColor("silver"));
assertEquals(TtmlColorParser.WHITE, TtmlColorParser.parseColor("white"));
assertEquals(TtmlColorParser.MAROON, TtmlColorParser.parseColor("maroon"));
assertEquals(TtmlColorParser.RED, TtmlColorParser.parseColor("red"));
assertEquals(TtmlColorParser.PURPLE, TtmlColorParser.parseColor("purple"));
assertEquals(TtmlColorParser.FUCHSIA, TtmlColorParser.parseColor("fuchsia"));
assertEquals(TtmlColorParser.MAGENTA, TtmlColorParser.parseColor("magenta"));
assertEquals(TtmlColorParser.GREEN, TtmlColorParser.parseColor("green"));
assertEquals(TtmlColorParser.LIME, TtmlColorParser.parseColor("lime"));
assertEquals(TtmlColorParser.OLIVE, TtmlColorParser.parseColor("olive"));
assertEquals(TtmlColorParser.YELLOW, TtmlColorParser.parseColor("yellow"));
assertEquals(TtmlColorParser.NAVY, TtmlColorParser.parseColor("navy"));
assertEquals(TtmlColorParser.BLUE, TtmlColorParser.parseColor("blue"));
assertEquals(TtmlColorParser.TEAL, TtmlColorParser.parseColor("teal"));
assertEquals(TtmlColorParser.AQUA, TtmlColorParser.parseColor("aqua"));
assertEquals(TtmlColorParser.CYAN, TtmlColorParser.parseColor("cyan"));
}
public void testParseUnknownColor() {
try {
TtmlColorParser.parseColor("colorOfAnElectron");
fail();
} catch (IllegalArgumentException e) {
// expected
}
}
public void testParseNull() {
try {
TtmlColorParser.parseColor(null);
fail();
} catch (IllegalArgumentException e) {
// expected
}
}
public void testParseEmpty() {
try {
TtmlColorParser.parseColor("");
fail();
} catch (IllegalArgumentException e) {
// expected
}
}
public void testRgbColorParsing() {
assertEquals(Color.WHITE, TtmlColorParser.parseColor("rgb(255,255,255)"));
// spaces do not matter
assertEquals(Color.WHITE, TtmlColorParser.parseColor(" rgb ( 255, 255, 255)"));
}
public void testRgbColorParsing_rgbValuesOutOfBounds() {
int outOfBounds = TtmlColorParser.parseColor("rgb(999, 999, 999)");
int color = Color.rgb(999, 999, 999);
// behave like framework Color behaves
assertEquals(color, outOfBounds);
}
public void testRgbColorParsing_rgbValuesNegative() {
try {
TtmlColorParser.parseColor("rgb(-4, 55, 209)");
fail();
} catch (IllegalArgumentException e) {
// expected
}
}
public void testRgbaColorParsing() {
assertEquals(Color.WHITE, TtmlColorParser.parseColor("rgba(255,255,255,0)"));
assertEquals(Color.argb(0, 255, 255, 255), TtmlColorParser.parseColor("rgba(255,255,255,255)"));
assertEquals(Color.BLACK, TtmlColorParser.parseColor("rgba(0, 0, 0, 0)"));
assertEquals(Color.argb(0, 0, 0, 0), TtmlColorParser.parseColor("rgba(0, 0, 0, 255)"));
assertEquals(Color.RED, TtmlColorParser.parseColor("rgba(255, 0, 0, 0)"));
assertEquals(Color.argb(0, 255, 0, 0), TtmlColorParser.parseColor("rgba(255, 0, 0, 255)"));
assertEquals(Color.argb(205, 255, 0, 0), TtmlColorParser.parseColor("rgba(255, 0, 0, 50)"));
}
}

View File

@ -17,7 +17,6 @@ package com.google.android.exoplayer.text.ttml;
import com.google.android.exoplayer.text.Cue; import com.google.android.exoplayer.text.Cue;
import android.graphics.Color;
import android.test.InstrumentationTestCase; import android.test.InstrumentationTestCase;
import android.text.Layout; import android.text.Layout;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
@ -67,8 +66,8 @@ public final class TtmlParserTest extends InstrumentationTestCase {
TtmlNode body = queryChildrenForTag(root, TtmlNode.TAG_BODY, 0); TtmlNode body = queryChildrenForTag(root, TtmlNode.TAG_BODY, 0);
TtmlNode firstDiv = queryChildrenForTag(body, TtmlNode.TAG_DIV, 0); TtmlNode firstDiv = queryChildrenForTag(body, TtmlNode.TAG_DIV, 0);
TtmlStyle firstPStyle = queryChildrenForTag(firstDiv, TtmlNode.TAG_P, 0).style; TtmlStyle firstPStyle = queryChildrenForTag(firstDiv, TtmlNode.TAG_P, 0).style;
assertEquals(Color.parseColor("yellow"), firstPStyle.getColor()); assertEquals(TtmlColorParser.parseColor("yellow"), firstPStyle.getColor());
assertEquals(Color.parseColor("blue"), firstPStyle.getBackgroundColor()); assertEquals(TtmlColorParser.parseColor("blue"), firstPStyle.getBackgroundColor());
assertEquals("serif", firstPStyle.getFontFamily()); assertEquals("serif", firstPStyle.getFontFamily());
assertEquals(TtmlStyle.STYLE_BOLD_ITALIC, firstPStyle.getStyle()); assertEquals(TtmlStyle.STYLE_BOLD_ITALIC, firstPStyle.getStyle());
assertTrue(firstPStyle.isUnderline()); assertTrue(firstPStyle.isUnderline());
@ -78,24 +77,43 @@ public final class TtmlParserTest extends InstrumentationTestCase {
TtmlSubtitle subtitle = getSubtitle(INLINE_ATTRIBUTES_TTML_FILE); TtmlSubtitle subtitle = getSubtitle(INLINE_ATTRIBUTES_TTML_FILE);
assertEquals(4, subtitle.getEventTimeCount()); assertEquals(4, subtitle.getEventTimeCount());
assertSpans(subtitle, 20, "text 2", "sansSerif", TtmlStyle.STYLE_ITALIC, assertSpans(subtitle, 20, "text 2", "sansSerif", TtmlStyle.STYLE_ITALIC,
Color.CYAN, Color.parseColor("lime"), false, true, null); TtmlColorParser.CYAN, TtmlColorParser.parseColor("lime"), false, true, null);
}
/**
* regression test for devices on JellyBean where some named colors are not correctly defined
* on framework level. Tests that <i>lime</i> resolves to <code>#FF00FF00</code> not
* <code>#00FF00</code>.
*
* See: https://github.com/android/platform_frameworks_base/blob/jb-mr2-release/
* graphics/java/android/graphics/Color.java#L414
* https://github.com/android/platform_frameworks_base/blob/kitkat-mr2.2-release/
* graphics/java/android/graphics/Color.java#L414
*
* @throws IOException thrown if reading subtitle file fails.
*/
public void testLime() throws IOException {
TtmlSubtitle subtitle = getSubtitle(INLINE_ATTRIBUTES_TTML_FILE);
assertEquals(4, subtitle.getEventTimeCount());
assertSpans(subtitle, 20, "text 2", "sansSerif", TtmlStyle.STYLE_ITALIC,
TtmlColorParser.CYAN, TtmlColorParser.LIME, false, true, null);
} }
public void testInheritGlobalStyle() throws IOException { public void testInheritGlobalStyle() throws IOException {
TtmlSubtitle subtitle = getSubtitle(INHERIT_STYLE_TTML_FILE); TtmlSubtitle subtitle = getSubtitle(INHERIT_STYLE_TTML_FILE);
assertEquals(2, subtitle.getEventTimeCount()); assertEquals(2, subtitle.getEventTimeCount());
assertSpans(subtitle, 10, "text 1", "serif", TtmlStyle.STYLE_BOLD_ITALIC, assertSpans(subtitle, 10, "text 1", "serif", TtmlStyle.STYLE_BOLD_ITALIC,
Color.BLUE, Color.YELLOW, true, false, null); TtmlColorParser.BLUE, TtmlColorParser.YELLOW, true, false, null);
} }
public void testInheritGlobalStyleOverriddenByInlineAttributes() throws IOException { public void testInheritGlobalStyleOverriddenByInlineAttributes() throws IOException {
TtmlSubtitle subtitle = getSubtitle(INHERIT_STYLE_OVERRIDE_TTML_FILE); TtmlSubtitle subtitle = getSubtitle(INHERIT_STYLE_OVERRIDE_TTML_FILE);
assertEquals(4, subtitle.getEventTimeCount()); assertEquals(4, subtitle.getEventTimeCount());
assertSpans(subtitle, 10, "text 1", "serif", TtmlStyle.STYLE_BOLD_ITALIC, Color.BLUE, assertSpans(subtitle, 10, "text 1", "serif", TtmlStyle.STYLE_BOLD_ITALIC, TtmlColorParser.BLUE,
Color.YELLOW, true, false, null); TtmlColorParser.YELLOW, true, false, null);
assertSpans(subtitle, 20, "text 2", "sansSerif", TtmlStyle.STYLE_ITALIC, Color.RED, assertSpans(subtitle, 20, "text 2", "sansSerif", TtmlStyle.STYLE_ITALIC, TtmlColorParser.RED,
Color.YELLOW, true, false, null); TtmlColorParser.YELLOW, true, false, null);
} }
public void testInheritGlobalAndParent() throws IOException { public void testInheritGlobalAndParent() throws IOException {
@ -103,9 +121,10 @@ public final class TtmlParserTest extends InstrumentationTestCase {
assertEquals(4, subtitle.getEventTimeCount()); assertEquals(4, subtitle.getEventTimeCount());
assertSpans(subtitle, 10, "text 1", "sansSerif", TtmlStyle.STYLE_NORMAL, assertSpans(subtitle, 10, "text 1", "sansSerif", TtmlStyle.STYLE_NORMAL,
Color.RED, Color.parseColor("lime"), false, true, Layout.Alignment.ALIGN_CENTER); TtmlColorParser.RED, TtmlColorParser.parseColor("lime"), false, true,
Layout.Alignment.ALIGN_CENTER);
assertSpans(subtitle, 20, "text 2", "serif", TtmlStyle.STYLE_BOLD_ITALIC, assertSpans(subtitle, 20, "text 2", "serif", TtmlStyle.STYLE_BOLD_ITALIC,
Color.BLUE, Color.YELLOW, true, true, Layout.Alignment.ALIGN_CENTER); TtmlColorParser.BLUE, TtmlColorParser.YELLOW, true, true, Layout.Alignment.ALIGN_CENTER);
} }
public void testInheritMultipleStyles() throws IOException { public void testInheritMultipleStyles() throws IOException {
@ -113,7 +132,7 @@ public final class TtmlParserTest extends InstrumentationTestCase {
assertEquals(12, subtitle.getEventTimeCount()); assertEquals(12, subtitle.getEventTimeCount());
assertSpans(subtitle, 10, "text 1", "sansSerif", TtmlStyle.STYLE_BOLD_ITALIC, assertSpans(subtitle, 10, "text 1", "sansSerif", TtmlStyle.STYLE_BOLD_ITALIC,
Color.BLUE, Color.YELLOW, false, true, null); TtmlColorParser.BLUE, TtmlColorParser.YELLOW, false, true, null);
} }
public void testInheritMultipleStylesWithoutLocalAttributes() throws IOException { public void testInheritMultipleStylesWithoutLocalAttributes() throws IOException {
@ -121,7 +140,7 @@ public final class TtmlParserTest extends InstrumentationTestCase {
assertEquals(12, subtitle.getEventTimeCount()); assertEquals(12, subtitle.getEventTimeCount());
assertSpans(subtitle, 20, "text 2", "sansSerif", TtmlStyle.STYLE_BOLD_ITALIC, assertSpans(subtitle, 20, "text 2", "sansSerif", TtmlStyle.STYLE_BOLD_ITALIC,
Color.BLUE, Color.BLACK, false, true, null); TtmlColorParser.BLUE, TtmlColorParser.BLACK, false, true, null);
} }
@ -130,7 +149,7 @@ public final class TtmlParserTest extends InstrumentationTestCase {
assertEquals(12, subtitle.getEventTimeCount()); assertEquals(12, subtitle.getEventTimeCount());
assertSpans(subtitle, 30, "text 2.5", "sansSerifInline", TtmlStyle.STYLE_ITALIC, assertSpans(subtitle, 30, "text 2.5", "sansSerifInline", TtmlStyle.STYLE_ITALIC,
Color.RED, Color.YELLOW, true, true, null); TtmlColorParser.RED, TtmlColorParser.YELLOW, true, true, null);
} }
public void testEmptyStyleAttribute() throws IOException { public void testEmptyStyleAttribute() throws IOException {
@ -175,16 +194,16 @@ public final class TtmlParserTest extends InstrumentationTestCase {
TtmlStyle style = globalStyles.get("s2"); TtmlStyle style = globalStyles.get("s2");
assertEquals("serif", style.getFontFamily()); assertEquals("serif", style.getFontFamily());
assertEquals(Color.RED, style.getBackgroundColor()); assertEquals(TtmlColorParser.RED, style.getBackgroundColor());
assertEquals(Color.BLACK, style.getColor()); assertEquals(TtmlColorParser.BLACK, style.getColor());
assertEquals(TtmlStyle.STYLE_BOLD_ITALIC, style.getStyle()); assertEquals(TtmlStyle.STYLE_BOLD_ITALIC, style.getStyle());
assertTrue(style.isLinethrough()); assertTrue(style.isLinethrough());
style = globalStyles.get("s3"); style = globalStyles.get("s3");
// only difference: color must be RED // only difference: color must be RED
assertEquals(Color.RED, style.getColor()); assertEquals(TtmlColorParser.RED, style.getColor());
assertEquals("serif", style.getFontFamily()); assertEquals("serif", style.getFontFamily());
assertEquals(Color.RED, style.getBackgroundColor()); assertEquals(TtmlColorParser.RED, style.getBackgroundColor());
assertEquals(TtmlStyle.STYLE_BOLD_ITALIC, style.getStyle()); assertEquals(TtmlStyle.STYLE_BOLD_ITALIC, style.getStyle());
assertTrue(style.isLinethrough()); assertTrue(style.isLinethrough());
} }
@ -224,8 +243,8 @@ public final class TtmlParserTest extends InstrumentationTestCase {
TtmlStyle style = queryChildrenForTag(div, TtmlNode.TAG_P, 0).style; TtmlStyle style = queryChildrenForTag(div, TtmlNode.TAG_P, 0).style;
assertNotNull(style); assertNotNull(style);
assertEquals(Color.BLACK, style.getBackgroundColor()); assertEquals(TtmlColorParser.BLACK, style.getBackgroundColor());
assertEquals(Color.YELLOW, style.getColor()); assertEquals(TtmlColorParser.YELLOW, style.getColor());
assertEquals(TtmlStyle.STYLE_ITALIC, style.getStyle()); assertEquals(TtmlStyle.STYLE_ITALIC, style.getStyle());
assertEquals("sansSerif", style.getFontFamily()); assertEquals("sansSerif", style.getFontFamily());
assertFalse(style.isUnderline()); assertFalse(style.isUnderline());
@ -243,8 +262,8 @@ public final class TtmlParserTest extends InstrumentationTestCase {
TtmlStyle style = queryChildrenForTag(div, TtmlNode.TAG_P, 0).style; TtmlStyle style = queryChildrenForTag(div, TtmlNode.TAG_P, 0).style;
assertNotNull(style); assertNotNull(style);
assertEquals(Color.BLACK, style.getBackgroundColor()); assertEquals(TtmlColorParser.BLACK, style.getBackgroundColor());
assertEquals(Color.YELLOW, style.getColor()); assertEquals(TtmlColorParser.YELLOW, style.getColor());
assertEquals(TtmlStyle.STYLE_ITALIC, style.getStyle()); assertEquals(TtmlStyle.STYLE_ITALIC, style.getStyle());
assertEquals("sansSerif", style.getFontFamily()); assertEquals("sansSerif", style.getFontFamily());
assertFalse(style.isUnderline()); assertFalse(style.isUnderline());

View File

@ -0,0 +1,138 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer.text.ttml;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.Util;
import android.text.TextUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Parser to parse ttml color value expression
* (http://www.w3.org/TR/ttml1/#style-value-color)
*/
/*package*/ final class TtmlColorParser {
private static final String RGB = "rgb";
private static final String RGBA = "rgba";
private static final Pattern RGB_PATTERN = Pattern.compile(
"^rgb\\((\\d{1,3}),(\\d{1,3}),(\\d{1,3})\\)$");
private static final Pattern RGBA_PATTERN = Pattern.compile(
"^rgba\\((\\d{1,3}),(\\d{1,3}),(\\d{1,3}),(\\d{1,3})\\)$");
static final int TRANSPARENT = 0x00000000;
static final int BLACK = 0xFF000000;
static final int SILVER = 0xFFC0C0C0;
static final int GRAY = 0xFF808080;
static final int WHITE = 0xFFFFFFFF;
static final int MAROON = 0xFF800000;
static final int RED = 0xFFFF0000;
static final int PURPLE = 0xFF800080;
static final int FUCHSIA = 0xFFFF00FF;
static final int MAGENTA = FUCHSIA;
static final int GREEN = 0xFF008000;
static final int LIME = 0xFF00FF00;
static final int OLIVE = 0xFF808000;
static final int YELLOW = 0xFFFFFF00;
static final int NAVY = 0xFF000080;
static final int BLUE = 0xFF0000FF;
static final int TEAL = 0xFF008080;
static final int AQUA = 0x00FFFFFF;
static final int CYAN = 0xFF00FFFF;
private static final Map<String, Integer> COLOR_NAME_MAP;
static {
COLOR_NAME_MAP = new HashMap<>();
COLOR_NAME_MAP.put("transparent", TRANSPARENT);
COLOR_NAME_MAP.put("black", BLACK);
COLOR_NAME_MAP.put("silver", SILVER);
COLOR_NAME_MAP.put("gray", GRAY);
COLOR_NAME_MAP.put("white", WHITE);
COLOR_NAME_MAP.put("maroon", MAROON);
COLOR_NAME_MAP.put("red", RED);
COLOR_NAME_MAP.put("purple", PURPLE);
COLOR_NAME_MAP.put("fuchsia", FUCHSIA);
COLOR_NAME_MAP.put("magenta", MAGENTA);
COLOR_NAME_MAP.put("green", GREEN);
COLOR_NAME_MAP.put("lime", LIME);
COLOR_NAME_MAP.put("olive", OLIVE);
COLOR_NAME_MAP.put("yellow", YELLOW);
COLOR_NAME_MAP.put("navy", NAVY);
COLOR_NAME_MAP.put("blue", BLUE);
COLOR_NAME_MAP.put("teal", TEAL);
COLOR_NAME_MAP.put("aqua", AQUA);
COLOR_NAME_MAP.put("cyan", CYAN);
}
public static int parseColor(String colorExpression) {
Assertions.checkArgument(!TextUtils.isEmpty(colorExpression));
colorExpression = colorExpression.replace(" ", "");
if (colorExpression.charAt(0) == '#') {
// Use a long to avoid rollovers on #ffXXXXXX
long color = Long.parseLong(colorExpression.substring(1), 16);
if (colorExpression.length() == 7) {
// Set the alpha value
color |= 0x00000000ff000000;
} else if (colorExpression.length() != 9) {
throw new IllegalArgumentException();
}
return (int) color;
} else if (colorExpression.startsWith(RGBA)) {
Matcher matcher = RGBA_PATTERN.matcher(colorExpression);
if (matcher.matches()) {
return argb(
255 - Integer.parseInt(matcher.group(4), 10),
Integer.parseInt(matcher.group(1), 10),
Integer.parseInt(matcher.group(2), 10),
Integer.parseInt(matcher.group(3), 10)
);
}
} else if (colorExpression.startsWith(RGB)) {
Matcher matcher = RGB_PATTERN.matcher(colorExpression);
if (matcher.matches()) {
return rgb(
Integer.parseInt(matcher.group(1), 10),
Integer.parseInt(matcher.group(2), 10),
Integer.parseInt(matcher.group(3), 10)
);
}
} else {
// we use our own color map
Integer color = COLOR_NAME_MAP.get(Util.toLowerInvariant(colorExpression));
if (color != null) {
return color;
}
}
throw new IllegalArgumentException();
}
private static int argb(int alpha, int red, int green, int blue) {
return (alpha << 24) | (red << 16) | (green << 8) | blue;
}
private static int rgb(int red, int green, int blue) {
return argb(0xFF, red, green, blue);
}
}

View File

@ -23,7 +23,6 @@ import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.ParserUtil; import com.google.android.exoplayer.util.ParserUtil;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
import android.graphics.Color;
import android.text.Layout; import android.text.Layout;
import android.util.Log; import android.util.Log;
@ -207,7 +206,7 @@ public final class TtmlParser implements SubtitleParser {
case TtmlNode.ATTR_TTS_BACKGROUND_COLOR: case TtmlNode.ATTR_TTS_BACKGROUND_COLOR:
style = createIfNull(style); style = createIfNull(style);
try { try {
style.setBackgroundColor(Color.parseColor(attributeValue)); style.setBackgroundColor(TtmlColorParser.parseColor(attributeValue));
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Log.w(TAG, "failed parsing background value: '" + attributeValue + "'"); Log.w(TAG, "failed parsing background value: '" + attributeValue + "'");
} }
@ -215,7 +214,7 @@ public final class TtmlParser implements SubtitleParser {
case TtmlNode.ATTR_TTS_COLOR: case TtmlNode.ATTR_TTS_COLOR:
style = createIfNull(style); style = createIfNull(style);
try { try {
style.setColor(Color.parseColor(attributeValue)); style.setColor(TtmlColorParser.parseColor(attributeValue));
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Log.w(TAG, "failed parsing color value: '" + attributeValue + "'"); Log.w(TAG, "failed parsing color value: '" + attributeValue + "'");
} }