Android Live wallpaper Tutorial

Live Wallpapers are animated , interactive backgrounds for the Android home screen. A live wallpaper is similar to other Android applications and can use most of the same functionality.

How to create a live wallpaper

To create a live wallpaper, you need to create an XML file which describes your wallpaper. This file should contain a description of the application and can contain a preview and a link to a preference activity Activity which allow to customize the live wallpaper.

You also create a service which must extend the [su_highlight background=”#F7F7F7″ color=”#EA1F00″]WallpaperService [/su_highlight] class. This class is the base class for all live wallpapers in the system. You must implement the [su_highlight background=”#F7F7F7″ color=”#EA1F00″]onCreateEngine()[/su_highlight] method and return an object of type [su_highlight background=”#F7F7F7″ color=”#EA1F00″]android.service.wallpaper.WallpaperService.Engine[/su_highlight]. This objects handles the lifecycle events, animations and drawings of the wallpaper. The Engine class defines the life cycle methods, as for example onCreate(), onSurfaceCreated(), onVisibilityChanged(), onOffsetsChanged(), onTouchEvent() and onCommand().

The service requires the permission [su_highlight background=”#F7F7F7″ color=”#EA1F00″]android.permission.BIND_WALLPAPER[/su_highlight] and must be registered via an intent-filter for the [su_highlight background=”#F7F7F7″ color=”#EA1F00″]android.service.wallpaper.WallpaperService[/su_highlight] action.

You should also enter in the [su_highlight background=”#F7F7F7″ color=”#EA1F00″]AndroidManifest.xml[/su_highlight] file of the application that your application uses the [su_highlight background=”#F7F7F7″ color=”#EA1F00″]android.software.live_wallpaper[/su_highlight] feature. This will prevent that your wallpaper can be installed on devices which do not support live wallpapers.

 In this tutorial we will be creating a cube  which will rotate in 3D space. This can be set as live wallpaper from live wallpaper chooser.

 

[su_button url=”https://github.com/androidsrc/SimpleLiveWallpaper” target=”blank” style=”stroked” background=”#51d461″ color=”#ffffff” size=”6″ center=”yes” radius=”0″ icon=”icon: arrow-circle-o-down”]Download Full Source Code[/su_button]

 

[su_youtube url=”http://youtu.be/9eQf4EmKn9g”]

Lets get started :

1. Create a new project in Eclipse by navigating to File ⇒ New Android ⇒ Application Project and fill required details.

2. Now create file in res/xml/cube.xml. This will provide settings to android live wallpaper manager. For now we are not entering anything. It is just declaring a live wallpaper.

<?xml version="1.0" encoding="utf-8"?>
<!-- The attributes in this XML file provide configuration information -->

<wallpaper xmlns:android="http://schemas.android.com/apk/res/android"/>

3. Next we have to update AndroidManifest.xml so that it can include cube.xml file. We also have to declare the service which will provide animated cube to display as wallpaper. Update file looks like this.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.livewallpaper"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-feature android:name="android.software.live_wallpaper" />

    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="21" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <service
            android:name=".CubeWallpaper"
            android:label="Cube Live Wallpaper"
            android:permission="android.permission.BIND_WALLPAPER" >
            <intent-filter>
                <action android:name="android.service.wallpaper.WallpaperService" />
            </intent-filter>

            <meta-data
                android:name="android.service.wallpaper"
                android:resource="@xml/cube" />
        </service>
    </application>

</manifest>

3. Create [su_highlight background=”#F7F7F7″ color=”#EA1F00″]CubeWallpaper.java[/su_highlight] in your default package. This class do all the animation and construction of the cube.It extends [su_highlight background=”#F7F7F7″ color=”#EA1F00″]WallpaperService[/su_highlight] which is responsible for showing a live wallpaper behind applications that would like to sit on top of it. CubeWallpaper host another class [su_highlight background=”#F7F7F7″ color=”#EA1F00″]CubeEngine[/su_highlight] which extends the [su_highlight background=”#F7F7F7″ color=”#EA1F00″]Engine[/su_highlight]. This CubeEngine do all the dirty work where Engine super class provide all the callback methods which are used to handle the wallpaper drawing and interaction. Code of CubeWallpaper.java goes like this.

package com.example.livewallpaper;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Handler;
import android.os.SystemClock;
import android.service.wallpaper.WallpaperService;
import android.view.MotionEvent;
import android.view.SurfaceHolder;

/*
 * This animated wallpaper draws a rotating wireframe cube.
 */
public class CubeWallpaper extends WallpaperService {

	private final Handler mHandler = new Handler();

	@Override
	public void onCreate() {
		super.onCreate();
	}

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

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

	class CubeEngine extends Engine {

		private final Paint mPaint = new Paint();
		private float mOffset;
		private float mTouchX = -1;
		private float mTouchY = -1;
		private long mStartTime;
		private float mCenterX;
		private float mCenterY;

		private final Runnable mDrawCube = new Runnable() {
			public void run() {
				drawFrame();
			}
		};
		private boolean mVisible;

		CubeEngine() {
			// Create a Paint to draw the lines for our cube
			final Paint paint = mPaint;
			paint.setColor(0xffffffff);
			paint.setAntiAlias(true);
			paint.setStrokeWidth(2);
			paint.setStrokeCap(Paint.Cap.ROUND);
			paint.setStyle(Paint.Style.STROKE);

			mStartTime = SystemClock.elapsedRealtime();
		}

		@Override
		public void onCreate(SurfaceHolder surfaceHolder) {
			super.onCreate(surfaceHolder);

			// By default we don't get touch events, so enable them.
			setTouchEventsEnabled(true);
		}

		@Override
		public void onDestroy() {
			super.onDestroy();
			mHandler.removeCallbacks(mDrawCube);
		}

		@Override
		public void onVisibilityChanged(boolean visible) {
			mVisible = visible;
			if (visible) {
				drawFrame();
			} else {
				mHandler.removeCallbacks(mDrawCube);
			}
		}

		@Override
		public void onSurfaceChanged(SurfaceHolder holder, int format,
				int width, int height) {
			super.onSurfaceChanged(holder, format, width, height);
			// store the center of the surface, so we can draw the cube in the
			// right spot
			mCenterX = width / 2.0f;
			mCenterY = height / 2.0f;
			drawFrame();
		}

		@Override
		public void onSurfaceCreated(SurfaceHolder holder) {
			super.onSurfaceCreated(holder);
		}

		@Override
		public void onSurfaceDestroyed(SurfaceHolder holder) {
			super.onSurfaceDestroyed(holder);
			mVisible = false;
			mHandler.removeCallbacks(mDrawCube);
		}

		@Override
		public void onOffsetsChanged(float xOffset, float yOffset, float xStep,
				float yStep, int xPixels, int yPixels) {
			mOffset = xOffset;
			drawFrame();
		}

		/*
		 * Store the position of the touch event so we can use it for drawing
		 * later
		 */
		@Override
		public void onTouchEvent(MotionEvent event) {
			if (event.getAction() == MotionEvent.ACTION_MOVE) {
				mTouchX = event.getX();
				mTouchY = event.getY();
			} else {
				mTouchX = -1;
				mTouchY = -1;
			}
			super.onTouchEvent(event);
		}

		/*
		 * 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. This example draws a wireframe cube.
		 */
		void drawFrame() {
			final SurfaceHolder holder = getSurfaceHolder();

			Canvas c = null;
			try {
				c = holder.lockCanvas();
				if (c != null) {
					// draw something
					drawCube(c);
					drawTouchPoint(c);
				}
			} finally {
				if (c != null)
					holder.unlockCanvasAndPost(c);
			}

			// Reschedule the next redraw
			mHandler.removeCallbacks(mDrawCube);
			if (mVisible) {
				mHandler.postDelayed(mDrawCube, 1000 / 25);
			}
		}

		/*
		 * Draw a wireframe cube by drawing 12 3 dimensional lines between
		 * adjacent corners of the cube
		 */
		void drawCube(Canvas c) {
			c.save();
			c.translate(mCenterX, mCenterY);
			c.drawColor(0xff000000);
			drawLine(c, -400, -400, -400, 400, -400, -400);
			drawLine(c, 400, -400, -400, 400, 400, -400);
			drawLine(c, 400, 400, -400, -400, 400, -400);
			drawLine(c, -400, 400, -400, -400, -400, -400);

			drawLine(c, -400, -400, 400, 400, -400, 400);
			drawLine(c, 400, -400, 400, 400, 400, 400);
			drawLine(c, 400, 400, 400, -400, 400, 400);
			drawLine(c, -400, 400, 400, -400, -400, 400);

			drawLine(c, -400, -400, 400, -400, -400, -400);
			drawLine(c, 400, -400, 400, 400, -400, -400);
			drawLine(c, 400, 400, 400, 400, 400, -400);
			drawLine(c, -400, 400, 400, -400, 400, -400);
			c.restore();
		}

		/*
		 * Draw a 3 dimensional line on to the screen
		 */
		void drawLine(Canvas c, int x1, int y1, int z1, int x2, int y2, int z2) {
			long now = SystemClock.elapsedRealtime();
			float xrot = ((float) (now - mStartTime)) / 1000;
			float yrot = (0.5f - mOffset) * 2.0f;
			float zrot = 0;

			// 3D transformations

			// rotation around X-axis
			float newy1 = (float) (Math.sin(xrot) * z1 + Math.cos(xrot) * y1);
			float newy2 = (float) (Math.sin(xrot) * z2 + Math.cos(xrot) * y2);
			float newz1 = (float) (Math.cos(xrot) * z1 - Math.sin(xrot) * y1);
			float newz2 = (float) (Math.cos(xrot) * z2 - Math.sin(xrot) * y2);

			// rotation around Y-axis
			float newx1 = (float) (Math.sin(yrot) * newz1 + Math.cos(yrot) * x1);
			float newx2 = (float) (Math.sin(yrot) * newz2 + Math.cos(yrot) * x2);
			newz1 = (float) (Math.cos(yrot) * newz1 - Math.sin(yrot) * x1);
			newz2 = (float) (Math.cos(yrot) * newz2 - Math.sin(yrot) * x2);

			// 3D-to-2D projection
			float startX = newx1 / (4 - newz1 / 400);
			float startY = newy1 / (4 - newz1 / 400);
			float stopX = newx2 / (4 - newz2 / 400);
			float stopY = newy2 / (4 - newz2 / 400);

			c.drawLine(startX, startY, stopX, stopY, mPaint);
		}

		/*
		 * Draw a circle around the current touch point, if any.
		 */
		void drawTouchPoint(Canvas c) {
			if (mTouchX >= 0 && mTouchY >= 0) {
				c.drawCircle(mTouchX, mTouchY, 80, mPaint);
			}
		}

	}
}

4. Now build and run project.
5. To set livewallpaper go to Launcher > Menu > Home Screen Wallpaper > Live Wallpaper > Cube Live Wallpaper and press set live wallpaper.

GuRu

Technology enthusiast. Loves to tinker with things. Always trying to create something wonderful using technology. Loves coding for Android, Raspberry pi, Arduino , Opencv and much more.

You may also like...

1 Response

  1. Narendra Kakkad says:

    I tried your example. When I try to run it, it says that there is no default activity.
    Actually I am a newbie in android. And the post is also too old. But if you can reply, then it would be grt.

    Thanks in advance…

Leave a Reply

Your email address will not be published. Required fields are marked *