Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issue with ComposeShader on Android 4.1.1

I'm just trying to implement a color picker for my android application, and ran into a strange issue on Android 4.1.1. The following code does not create the expected gradients on Android 4.1.1, but it does on 2.3.7:

Shader fadeInRight = new LinearGradient(0, 0, pWidth, 0, 0x00000000, 0xFF000000, Shader.TileMode.CLAMP);
Shader blackToWhite = new LinearGradient(0, 0, 0, pHeight, 0xFF000000, 0xFFFFFFFF, Shader.TileMode.CLAMP);
Shader whiteMask = new ComposeShader(blackToWhite, fadeInRight, PorterDuff.Mode.DST_IN);
Shader blackToColor = new LinearGradient(0, 0, pWidth, 0, 0xFF000000, hue, Shader.TileMode.CLAMP);
Shader shader = new ComposeShader(blackToColor, whiteMask, PorterDuff.Mode.SCREEN);
paint.setShader(shader);
...
canvas.drawRect(new Rect(0, 0, pWidth, pHeight), paint);

Here's the problem: enter image description here

(ignore the red box below on Android 4.1.1. I just talk about the gradient above)

Any Idea what's wrong? I think there is something missing in my code, but I don't have any idea, what.

EDIT #1: If I just use whiteMask for setShader, I also get different results for both systems: On the 2.3.7 I can see the text of the configuration menu (which is behind the popup) shining through the gradient rectangle. Furthermore there is a gradient from the upper left edge to the lower right edge (black to white), but the gradient on the 4.1.1 goes horizontally from left to right. So it seems to be a problem with ComposeShader

EDIT #2: I found a more simpler example to describe the problem:

Shader shader1 = new LinearGradient(0, 0, 0, pHeight, hue, 0xffffffff, Shader.TileMode.CLAMP);
Shader shader2 = new LinearGradient(0, 0, pWidth, 0, 0xff000000, 0xffffffff, Shader.TileMode.CLAMP);
Shader shader = new ComposeShader(shader1, shader2, PorterDuff.Mode.MULTIPLY);

So, we have just a vertical linear gradient from any color to black and a horizontal linear gradient from black to white. If we multiply these two layers, we should get the correct rectangle (as in the left screenshot above). But on Android 4.1.1 I see only the gradient of shader2. I also tried this in Gimp with two layers and the result was the same as on Android 2.3.7.

like image 585
Ethan Leroy Avatar asked Sep 16 '12 08:09

Ethan Leroy


1 Answers

Found the problem: Seems that it has to do with the hardware acceleration. As described here 'ComposeShader can only contain shaders of different types (a BitmapShader and a LinearGradient for instance, but not two instances of BitmapShader)'. But, 'If your application is affected by any of these missing features or limitations, you can turn off hardware acceleration for just the affected portion of your application by calling setLayerType(View.LAYER_TYPE_SOFTWARE, null).'

I saw, that this method is available since SDK 11. My App supports all versions starting with SDK 7, so I have to check if the method is available:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

Now everything's fine.

like image 191
Ethan Leroy Avatar answered Sep 17 '22 20:09

Ethan Leroy