Android Color stuff

At one project of mine we had to play with colors quite a lot. The customer has high claims when it comes to the quality of visual appeal and user interfaces. So the things have to be shaded, animated, properly rounded, darkened lightened and so on. All this plays together with a web service witch dictated themes and so on. Now, most of the graphics was implemented by my nice college Georg Bachmann who is a real expert on that. However, currently I do some bug fixing, and so had my chance to also dig into this field of Android developement.

Parsing colors:

Ok, here is the situation: we get colors from the web, in form of a rrggbb string, which represents the hex number of the color. Goal is to convert that into a proper Android color. Our first approach was the typical stack overflow solution: find a code, and use it [I would like to coin the term stack overflow based programming here {I do that a lot too}]:

1
2
3
4
5
6
7
8
9
10
11
12
public static int stringToColor(String colorString) {
    int color = 0xffffffff;
    try {
        color = Integer.parseInt(colorString, 16);
        color = color & 0xffffff;
        color += 0xff000000;
    } catch (Exception e) {
        color = 0x00000000;
        MMLog.i(Global.MMLOG_TAG, "color string was empty");
    }
    return color;
}

now, actually, I think this code performed quite well. Lets explain it a little bit:

Android uses the Color object to represent colors in Android. A color is actually just an integer. this integer has the following form 0xAARRGGBB what means that the first two hex (4 bytes) are the alpha channel, the next are read, then green, then blue. The Alpha Channel ranges from 00 (completely opaque) to ff (completely transparent), the rgb values range too from 00 to ff with FF meaning full contribution of the color channel to the resulting color, and 00 meaning no contribution. so 0xff000000 would be black, 0xffffffff would be white and blue would be 0xff0000ff (first ff for the opaqueness of the alpha channel, and then 0000 for not using green and red, and then ff for a full blue).

So, with that knowledge, we are ready to understand the code:
in line 2: we set the color to some the default value. since we overwrite it, it wouldn’t really be necessary, but that we have a fixed start it is fine.
in line 3: We parse the hex number into a in. fortunately, Integer.parseInt(colorString, 16); already does that for us.
in line 4: We clear the first four bytes (the first two hex digits) to 00, and let the rest of the number intact, using a binary &&.
in line 5: We set the color to a complete opaque color.

in case an exception is thrown we return a completely transparent color as the default.

While this code performed quite well actually, we were not always sure, the colors were correctly parsed (I actually think it was the case, but was to busy to proof that). The easiest way is it if you use a official function from google android to parse the color, so you can claim an official implementation. Since we where not sure if the colors where right, I googled a little bit, to see if there is an utility function for that provided already. Actually, I found one:  Color.parseColor(string); or  public static int parseColor(String colorString);.

Now, my first try to implement that was:

1
2
3
4
5
6
7
8
9
10
11
12
// ATTENTION: NOT WORKING CODE
public static int stringToColor(String colorString) {
    if (colorString == null || colorString.trim().equalsIgnoreCase(""))
        return 0x00000000;
   
    // ATTENTION: NOT WORKING CODE
    if (colorString.startsWith("0x")) {
        return Color.parseColor(colorString.startsWith);
    }
   
    return Color.parseColor("0x" + colorString);
}

Now, that didn’t work. What was the problem. Actually: the hex string has to be prefixed, as I thought. But it has to be prefixed with a # like for most CSS colors in the web. So I changed the implementation to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static int stringToColor(String colorString) {
    if (colorString == null || colorString.trim().equalsIgnoreCase(""))
        return 0x00000000;
       
    if (colorString.startsWith("0x")) {
        String tmp = new String("#" + colorString.substring(2));
        return Color.parseColor(tmp);
    }
    if (colorString.startsWith("#")) {
        return Color.parseColor(colorString.toUpperCase()));
    }
   
    return Color.parseColor("#" + colorString.toUpperCase());
}

Now, I guess the implementation is quite straight foreword for you do read with your knowledge now. We check if we get a string with content, and if not, we return our transparent color. if we get a string, we assume it is a hex string. We just check if he starts with a wrong prefix, if yes, we change that. then we check if it starts with the right prefix, then we just parse the color. if it has no prefix, we add it, and parse the color now.

The main problem with that implementation is, that it creates a lot of temporary strings. if you have a lot of colors to parse, but they don’t vary that much, a cache would be nice for that. Currently I didn’t notice any problems with the memory in our app on that part, but it might be a room for improvement.

How to get the color back? Stefan, also a Member of our team, wrote this nice method:

1
2
3
4
public static String colorToString(int color) {
    int colorWithoutAlpha = 0x00ffffff & color;
    return String.format("%06x", colorWithoutAlpha);
}

So, I guess next post will be about shaders and shadows or so Smilie: ;) Stay tuned.

Category(s): android, mobile developement, professional, Uncategorized

Leave a Reply