A nosy look into LiveWallpapers.apk

It first seemed that the Galaxy wallpaper was implemented in C + OpenGL (with Java calls, of course). From our tests, using Canvas was not an option, since there were just too many particles for poor humble Canvas.

And it also looked like it was using the NDK, I thought upon reading this post.

Then somebody at that forum suggested they are implemented with Processing, which made me kind of laugh internally. But the very same source he used (Romain Guy's blog post about live wallpapers) denies that and gives some details about the Android implementation:

The prototypes are written in Processing. I did port Processing to Android to run live wallpapers and performance was not on par with what we wanted, so we implemented something called RenderScript #

Digging deeper, I downloaded the /system/apps/LiveWallpaper.apk file from the phone to my computer (using the DDMS perspective from within Eclipse), uncompressed it (it's a ZIP file in disguise) and inspected its contents to see if I could locate where was the code the guy in the first post shown. And I indeed could :-)

The .rs files (for "RenderScript", I deduct) are all in res/raw. They have names such as galaxy.rs, grass.rs, nexus.rs and so on. And they look like this:


#pragma version(1)
#pragma stateVertex(PVBkOrtho)
#pragma stateRaster(parent)
#pragma stateFragment(PFBackground)
#pragma stateStore(PFSBackground)

#define ELLIPSE_RATIO 0.892f

#define PI 3.1415f
#define TWO_PI 6.283f
#define ELLIPSE_TWIST 0.023333333f

float angle;

/**
 * Script initialization. Called automatically.
 */
void init() {
    angle = 50.0f;
}

/**
 * Helper function to generate the stars.
 */
float randomGauss() {
    float x1;
    float x2;
    float w = 2.f;

    while (w >= 1.0f) {
        x1 = 2.0f * randf2(0.0f, 1.0f) - 1.0f;
        x2 = 2.0f * randf2(0.0f, 1.0f) - 1.0f;
        w = x1 * x1 + x2 * x2;
    }

    w = sqrtf(-2.0 * logf(w) / w);
    return x1 * w;
}

float gSpeed[12000];

/**
 * Generates the properties for a given star.
 */
void createParticle(struct Particles_s *part, int idx, float scale) {
    float d = fabsf(randomGauss()) * State->galaxyRadius * 0.5f + randf(64.0f);
    float id = d / State->galaxyRadius;
    float z = randomGauss() * 0.4f * (1.0f - id);
    float p = -d * ELLIPSE_TWIST;

    int r,g,b,a;
    if (d < State->galaxyRadius * 0.33f) {
        r = (int) (220 + id * 35);
        g = 220;
        b = 220;
    } else {
        r = 180;
        g = 180;
        b = (int) clampf(140.f + id * 115.f, 140.f, 255.f);
    }
    // Stash point size * 10 in Alpha
    a = (int) (randf2(1.2f, 2.1f) * 60);
    part->color = r | g<<8 | b<<16 | a<<24;

    if (d > State->galaxyRadius * 0.15f) {
        z *= 0.6f * (1.0f - id);
    } else {
        z *= 0.72f;
    }

    // Map to the projection coordinates (viewport.x = -1.0 -> 1.0)
    d = mapf(-4.0f, State->galaxyRadius + 4.0f, 0.0f, scale, d);

    part->position.x = randf(TWO_PI);
    part->position.y = d;
    gSpeed[idx] = randf2(0.0015f, 0.0025f) * (0.5f + (scale / d)) * 0.8f;

    part->position.z = z / 5.0f;
}

// etc

It might be baptised as RenderScript but it no doubt smells like C from a couple of miles away: #pragma's, #define's, struct's and ->'s for pointing to members? You can't help thinking it's C, no matter how hard you try.

More deductions: either this RenderScript uses a gcc compiler in the very phone (not that unlikely since it's a Linux system after all?) or it parses the contents of the script on loading time. Then it's "just" a wrapper for OpenGL calls and generally cumbersome stuff such as preparing textures, vertex shaders etc (I can see something related to vertex shaders in the galaxy wallpaper, for example).

I've copy-pasted the full galaxy.rs source code into a gist, just in case you want to see the whole thing but don't have a phone and a DDMS environment handy :-)