Android – Live Wallpaper

March 17th, 2012 by Paul Gregoire

Herein I shall walk you through the steps for creating a live wallpaper in Android. Before we begin any Android development, the SDK and ADT plugin for Eclipse will need to be installed. The best installation guide is here; Disregard this if you already have the SDK and plugin installed. For this first part, we will simply display a graphic and in the followups we will do some animation. Without further ado, let’s get started.

1. The first step, is to create the new project
File -> New -> Android Project

We will call it “goldstar” and target Android 2.1 (API 7); this version of Android was the first to support Live Wallpapers.

2. Open up the AndroidManifest.xml file and add the nodes that we will need to support our application. Here is the manifest before our additions were
made:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.infrared5.android.wallpaper"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk android:minSdkVersion="7" />
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".GoldstarActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

This is the “after” version, where we added our feature, permission, and service nodes:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.infrared5.android.wallpaper"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk android:minSdkVersion="7" />
    <uses-feature
        android:name="android.software.live_wallpaper"
        android:required="true" >
    </uses-feature>   
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <service
            android:enabled="true"
            android:label="@string/app_name"
            android:name="LiveWallpaper"
            android:permission="android.permission.BIND_WALLPAPER" >
            <intent-filter>
                <action android:name="android.service.wallpaper.WallpaperService" >
                </action>
            </intent-filter>
            <meta-data
                android:name="android.service.wallpaper"
                android:resource="@xml/metadata" >
            </meta-data>
        </service> 
    </application>
</manifest>

3. Create a metadata file for our service. This is accomplished by making an xml directory within the res folder of the project. Create a new file named “metadata.xml” in this folder with these contents:



<wallpaper 
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:thumbnail="@drawable/ic_launcher"
       android:description="@string/wallpaper_description"/>

4. Add a description for our application. Open the strings.xml file and add a string with a name of “wallpaper_description” and a value of “Goldstar Live”. You may actually use whatever value suits you, this one is just for the example.

5. Get the svg library and place it in the “libs” folder; this folder must be created manually, if it does not already exist in the project.
We are using svg-android library from http://code.google.com/p/svg-android/ for this example. This library was also used in the popular “Androidify” application.

6. Locate an SVG image file to use in our application, preferrably one that is not copyrighted. Remember that google is your friend

https://www.google.com/search?q=star%20svg&orq=star+filetype:+svg

Here’s a gold star on wikimedia that you can use: https://upload.wikimedia.org/wikipedia/commons/9/9c/Golden_star.svg

Once you have a suitable file, save it into the “raw” directory within the “res” directory of the project. Note that your resource may only contain this range of characters in its name: a-z0-9_.

7. Now for some code; create a new class in the wallpaper package and name it LiveWallpaper. Set the super class to android.service.wallpaper.WallpaperService and click Finish. Your new class should appear like this:



package com.infrared5.android.wallpaper;

import android.service.wallpaper.WallpaperService;

public class LiveWallpaper extends WallpaperService {

    @Override
    public Engine onCreateEngine() {
        return null;
    }

}

8. Create an internal class named StarEngine which extends Engine. The result of this should appear like so:



package com.infrared5.android.wallpaper;

import android.service.wallpaper.WallpaperService;

public class LiveWallpaper extends WallpaperService {

    @Override
    public Engine onCreateEngine() {
        return null;
    }

    private class StarEngine extends Engine {
    }

}

9. Right-click on StarEngine and select “Source -> Override/Implement Methods”. Now select the following methods:

onCreate
onDestroy
onVisibilityChanged
onSurfaceChanged

then click ok. This will create the method stubs that we are interested in.

10. Modify the onCreateEngine method to create a new instance of our engine.



/**
 * The frame rate we will attempt to achieve with the wallpaper
 */
public static final int FRAME_RATE = 12;

/**
 * The width of the wallpaper, as a percent of the height of the phone.
 */
public static final int SCENE_WIDTH = 150;

@Override
public Engine onCreateEngine() {
	return new StarEngine();
}

We have also added to static variables for the frame rate and scene width.

11. Load our svg asset. Create a local engine variable and modify the onCreate method like so:



private SVG goldstar;

public void onCreate(SurfaceHolder surfaceHolder) {
	super.onCreate(surfaceHolder);
	try {
		goldstar = SVGParser.getSVGFromResource(getResources(), R.raw.golden_star);
	} catch (Exception e) {
		e.printStackTrace();
	}
}

This will read the file resource and parse it to create an SVG image object.

12. Thread and handler must now be setup to take care of drawing on the canvas. We modify the engine like so:



private class StarEngine extends Engine {

    private final Handler handler = new Handler();
    private SVG goldstar;
    private boolean visible;
    private int width, height, maxWidth;

	private final Runnable drawer = new Runnable() {
		public void run() {
			drawFrame();
		}
	};

	public void onCreate(SurfaceHolder surfaceHolder) {
		super.onCreate(surfaceHolder);
		try {
			goldstar = SVGParser.getSVGFromResource(getResources(), R.raw.golden_star);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		handler.removeCallbacks(drawer);
	}

	@Override
	public void onVisibilityChanged(boolean visible) {
		this.visible = visible;
		if (visible) {
			postDraw();
		} else {
			handler.removeCallbacks(drawer);
		}
	}

	@Override
	public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
		super.onSurfaceChanged(holder, format, width, height);
		maxWidth = Math.max(width, height) * SCENE_WIDTH / 100;
		this.width = width;
		this.height = height;
		postDraw();
	}

	/**
	 * Posts a draw event to the handler.
	 */
	private void postDraw() {
		handler.removeCallbacks(drawer);
		if (visible) {
			handler.postDelayed(drawer, 1000 / FRAME_RATE);
		}
	} 

	/*
	 * Draw one frame of the animation. This method gets called repeatedly
	 * by posting a delayed Runnable. You can do any drawing you want in
	 * here.
	 */
	private void drawFrame() {
	}

}

13. Drawing on the canvas. In our drawFrame method we will use our svg asset and draw it into view.



private void drawFrame() {
	final SurfaceHolder holder = getSurfaceHolder();
	final Rect frame = holder.getSurfaceFrame();
	Canvas canvas = null;
	try {
		canvas = holder.lockCanvas();
		if (canvas != null) {
			canvas.drawColor(Color.BLACK);
			canvas.save();
			canvas.save(Canvas.MATRIX_SAVE_FLAG);
			goldstar.getPicture().draw(canvas);
			canvas.restore();
		}
	} finally {
		if (canvas != null) {
			holder.unlockCanvasAndPost(canvas);
		}
	}
	postDraw();
}

14. Build and run in the emulator; you should see something like this:

15. Lastly, if you want to have nicer launcher images for your application there are free services to utilize such as this one:

http://android-ui-utils.googlecode.com/hg/asset-studio/dist/icons-launcher.html

Just upload your image and do a little configuration and you get a zip containing all the launcher images you need.

Project Source

End of part one; for part two we will cover animation.

, , ,