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 WallpaperService class. This class is the base class for all live wallpapers in the system. You must implement the onCreateEngine() method and return an object of type android.service.wallpaper.WallpaperService.Engine . 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 android.permission.BIND_WALLPAPER and must be registered via an intent-filter for the android.service.wallpaper.WallpaperService action.
You should also enter in the AndroidManifest.xml file of the application that your application uses the android.software.live_wallpaper 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.
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.
1 2 3 4 |
<?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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<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 CubeWallpaper.java in your default package. This class do all the animation and construction of the cube.It extends WallpaperService which is responsible for showing a live wallpaper behind applications that would like to sit on top of it. CubeWallpaper host another class CubeEngine which extends the Engine . 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
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.