Ok, it's cleary some kind of shader bug (...edit: or maybe not...see post below...). Not in the shader code itself but in the shader compiler of some devices. Or in the GPU...I don't know...
Here's what it does (that's not the exact same code that's used by the engine, but it has the same issue):
vec3 specPart = specularColors * pow(max(0.0, dot(normalize(-vertexPos.xyz), reflect(-surface2Light, normalEye))), shininess);
vertexColor += vec4((diffuseColors * angle + specPart)*(1.0/(1.0+length(lightPositions - vertexPos.xyz)*attenuation)), 1);
As you can see, it calculates a vertex' color. For this, it also takes the specular color into account. If there is none (i.e. specular on the object is off, which is the default), shininess is 1 and specularColors is vec3(0.0, 0.0, 0.0), i.e. zeroed out. A zero vector multiplied by some value (in this case the result of the pow()-calculation) should be...a zero vector. Because, as we all know, 0 times something is still 0. Turns out, that some devices beg to differ.
We can modify the code to make this more clear:
vec3 specPart = vec3(0.0, 0.0, 0.0) * pow(max(0.0, dot(normalize(-vertexPos.xyz), reflect(-surface2Light, normalEye))), shininess);
vertexColor += vec4((diffuseColors * angle + specPart)*(1.0/(1.0+length(lightPositions - vertexPos.xyz) * attenuation)), 1);
Here, specularColors is gone and has been replaced by a static zero vector. Clearly, specPart has to be a zero vector as well in all cases. But it's not. shininess on the other hand is set to 1. However, it too seems to fluctuate in value as well while the shader is executing, which is actually impossible. It's supposed to stay fixed once the shader is executed for a given mesh, hence the name "uniform". Or maybe it doesn't fluctuate but evaluating it in the shader goes wrong for the same reasons that 0 times something is something else rather than 0.
Anyway, if we do this:
vec3 specPart = vec3(0.0, 0.0, 0.0) * pow(max(0.0, dot(normalize(-vertexPos.xyz), reflect(-surface2Light, normalEye))), 1.0);
vertexColor += vec4((diffuseColors * angle + specPart)*(1.0/(1.0+length(lightPositions - vertexPos.xyz)*attenuation)), 1);
i.e. replace shininess with a fixed value (doesn't matter which one, 0,1,10...they all work and give the same results), all of a sudden, 0 times something is 0 again.
However, we can't do that because we need both uniforms in case somebody is acutally using specular lighting. I also tried to split the term into smaller parts, which helped in similar situations in the past, but to no avail.
The fact that the behaviour changes when using a single texture is a red herring IMHO. It also changes/works if you are assigning the red texture to the ball instead of the white one.
I'm not sure what to do here. Are you by any chance already using your own shaders? I that case, we could just cut the specular part (if not used, that is) and call it a day. If not, it might be worth considering to do so.
To be sure: Which device are you using that has this issue? As said, I tried it on a S7 and it works fine. It also works fine in the emulator. I fails on the LG G4.