Monday, January 28, 2013

Creating Live Wallpaper with AndEngine


This tutorial covers creating a live wallpaper using andengine. It assumes you have eclipse, android sdk, and andengine installed. All of the source code for this project is available on github at https://github.com/RealWorldApplications/LiveWallpaperExample.

Here is a quick break down of the steps involved in this project.
1. Create a new project.
2. Edit the Android Manifest and create the file wallpaper.xml.
3. Add images to the assets folder.
4. Code the live wallpaper source file.
5. Create an AVD to run the application in the emulator.

First in eclipse create a new android application project. 
File-> New Project -> Android -> Android Application Project Next>

Add the following name and be sure that the minimum required SDK is at least 2.1

Click Next. You do not need to add a launcher icon instead we will add a logo. Remember to uncheck the box for creating an Activity now click finish.

Next we need to add the andengine libraries to the project. Right click on the project and choose Properties. In the window that pops up choose Android. Now add Andengine and AndengineLiveWallpaperExtension libraries to your project.
 

Now that you have your project created, the Android manifest file needs to be edited. Open the AndroidManifest.xml and edit the file to incorporate the following changes. You need to define the service called LiveWallpaperService. Also add the uses-feature to define the livewallpaper.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.ceecee.android.live"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="8" />
    <uses-feature  
        android:glEsVersion="0x00020000"
        android:required="true"
        android:name="android.software.live_wallpaper">
    </uses-feature>

    <application
        android:icon="@drawable/logo"
        android:label="@string/app_name" >
        <!--  Live Wallpaper Service -->
        <service android:name="com.ceecee.android.live.LiveWallpaperService"
            android:enabled="true"
            android:permission="android.permission.BIND_WALLPAPER" 
            android:icon="@drawable/logo" 
            android:description="@string/wallpaper_description">
            <intent-filter>
                <action android:name="android.service.wallpaper.WallpaperService"/>
            </intent-filter>
            <meta-data android:name="android.service.wallpaper" 
                android:resource="@xml/wallpaper"/>
        </service>
    </application>

</manifest>

Now create a new folder /res/xml. Create a file in that folder called wallpaper.xml. Add the following code to that file.

<?xml version="1.0" encoding="UTF-8"?>
<wallpaper
        xmlns:android="http://schemas.android.com/apk/res/android"  
        android:thumbnail="@drawable/logo"
        android:description="@string/wallpaper_description"
        />





Edit the strings.xml file that is located in the values folder.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Falling Petals LiveWallpaper</string>
    <string name="wallpaper_description">
         <Rose Petals fall from top of screen</string>
</resources>
Now add any images to the assets/gfx folder.  For this exercise you can just copy mine. 
 Ok now to get on to the coding. In the source folder create a file called LiveWallpaperService.java.
I have added extensive comments to this file which should explain all the code.

package com.ceecee.android.live;
package com.ceecee.android.live;


import org.andengine.engine.camera.Camera;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;

import org.andengine.entity.particle.SpriteParticleSystem;
import org.andengine.entity.particle.emitter.PointParticleEmitter;
import org.andengine.entity.particle.initializer.AccelerationParticleInitializer;
import org.andengine.entity.particle.initializer.RotationParticleInitializer;
import org.andengine.entity.particle.initializer.VelocityParticleInitializer;
import org.andengine.entity.particle.initializer.GravityParticleInitializer;
import org.andengine.entity.particle.modifier.ExpireParticleInitializer;
import org.andengine.entity.particle.modifier.RotationParticleModifier;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.Background;
import org.andengine.entity.sprite.Sprite;
import org.andengine.extension.ui.livewallpaper.BaseLiveWallpaperService;
import org.andengine.input.sensor.acceleration.AccelerationData;
import org.andengine.input.sensor.acceleration.IAccelerationListener;

import org.andengine.opengl.texture.TextureOptions;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.region.ITextureRegion;

import android.util.DisplayMetrics;
import android.view.WindowManager;

public class LiveWallpaperService extends BaseLiveWallpaperService
 implements IAccelerationListener{

//================================================================================
//                                  Fields
//================================================================================

private static int CAMERA_WIDTH = 480;
private static int CAMERA_HEIGHT = 720;
 
private Camera mCamera;
private Scene mScene;

private ITextureRegion mFlowerTextureRegion; 
private BitmapTextureAtlas mFlowerTexture; 
private VelocityParticleInitializer<Sprite> mVelocityParticleInitializer;
 
@Override
public EngineOptions onCreateEngineOptions() {
  
final DisplayMetrics displayMetrics = new DisplayMetrics();
 WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
 wm.getDefaultDisplay().getMetrics(displayMetrics);
 wm.getDefaultDisplay().getRotation();
 CAMERA_WIDTH = displayMetrics.widthPixels;
 CAMERA_HEIGHT = displayMetrics.heightPixels;
 this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
  
 return new EngineOptions(true, ScreenOrientation.PORTRAIT_FIXED,
 new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), this.mCamera);
 }

@Override
public void onCreateResources
  (OnCreateResourcesCallback createResourcesCallback)throws Exception {
   this.mFlowerTexture = new BitmapTextureAtlas
  (this.getTextureManager(),64,64, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
      this.mFlowerTextureRegion 
BitmapTextureAtlasTextureRegionFactory.createFromAsset  
(this.mFlowerTexture, this, "gfx/rosetrans64.png",0,0);      
  this.getEngine().getTextureManager().loadTexture(this.mFlowerTexture);
  this.enableAccelerationSensor(this);
   createResourcesCallback.onCreateResourcesFinished();
}


@Override
public void onCreateScene(OnCreateSceneCallback createSceneCallback) throws Exception {  
 mScene= new Scene();

//add the background to the scene 
// I chose a black background to accentuate the red rose color
 mScene.setBackground(new Background(0.0f, 0.0f, 0.0f)); 
  
// set the x y values of where the petals fall from
 final int mParticleX = CAMERA_WIDTH/2;
 final int mParticleY = 0;
//Set the max and min rates that particles are generated per second
 final int mParticleMinRate = 1;
 final int mParticleMaxRate = 2;
//Set a variable for the max particles in the system.
 final int mParticleMax = 40;
  
/* Create Particle System. */ 
final SpriteParticleSystem particleSystem = new SpriteParticleSystem
 (new PointParticleEmitter(mParticleX, mParticleY), 
 mParticleMinRate, mParticleMaxRate, mParticleMax,
 this.mFlowerTextureRegion, this.getVertexBufferObjectManager());
      
//set initial velocity  
this.mVelocityParticleInitializer =
   new VelocityParticleInitializer<Sprite>(-100, 100, 20, 190);
particleSystem.addParticleInitializer(this.mVelocityParticleInitializer);
   
//add gravity so the particles fall downward
particleSystem.addParticleInitializer
   (new GravityParticleInitializer<Sprite>());
//add acceleration so particles float 
particleSystem.addParticleInitializer
  (new AccelerationParticleInitializer<Sprite>(0, -10));
//add a rotation to particles
particleSystem.addParticleInitializer
   (new RotationParticleInitializer<Sprite>(0.0f, 90.0f));
//have particles expire after 20
particleSystem.addParticleInitializer
  (new ExpireParticleInitializer<Sprite>(40.0f));

//change rotation of particles at various times
particleSystem.addParticleModifier(new RotationParticleModifier<Sprite>
(0.0f, 10.0f, 0.0f, -180.0f));
particleSystem.addParticleModifier(new RotationParticleModifier<Sprite>
(10.0f, 20.0f, -180.0f, 90.0f));
particleSystem.addParticleModifier(new RotationParticleModifier<Sprite>
(20.0f, 30.0f, 90.0f, 0.0f));
particleSystem.addParticleModifier(new RotationParticleModifier<Sprite>
(30.0f, 40.0f, 0.0f, -90.0f));

  
//attach particle system to scene
this.mScene.attachChild(particleSystem);
  
createSceneCallback.onCreateSceneFinished(mScene);
 
}  

@Override
public void onPopulateScene(Scene arg0, 
OnPopulateSceneCallback populateSceneCallback)throws Exception {
 populateSceneCallback.onPopulateSceneFinished();
}

@Override
public void onAccelerationAccuracyChanged
(AccelerationData pAccelerationData) {
// TODO Auto-generated method stub  
}

// Change the petals to move along the axes of the accelerometer
@Override
public void onAccelerationChanged(AccelerationData pAccelerationData) {
 final float minVelocityX = (pAccelerationData.getX() + 2) * 2;
 final float maxVelocityX = (pAccelerationData.getX() - 2) * 2; 
 final float minVelocityY = (pAccelerationData.getY() - 4) * 5;
 final float maxVelocityY = (pAccelerationData.getY() - 6) * 5;
 this.mVelocityParticleInitializer.setVelocity(minVelocityX, 
maxVelocityX, minVelocityY, maxVelocityY); 
}
}


Now create an AVD with the hardware acceleration enable.

Run your project!

8 comments:

  1. This helped me implemented the accelerometer to my live wallpaper and much more. Thank you so much for taking the time to write this out.

    ReplyDelete
  2. Thank you so much for the tutorial! But I noticed the petals look really small on a tablet, how would you got about scaling them?

    ReplyDelete
  3. Hi, when I tried to export to APk, it gave me the "Conversion to Dalvik format failed with error 1" message, do you know why?

    ReplyDelete
  4. Here is the great collection of Free clock wallpaper.

    You can download free these apps to get different clock wallpaper.

    I have used both app and now enjoying with unlimited unique collection.

    Awesome and Superb collection.

    Here is the links of both android app.

    1. https://play.google.com/store/apps/details?id=com.vm.android.clockwork2.lite

    2. https://play.google.com/store/apps/details?id=com.vm.android.clockwork.black2.lite

    Thanks,

    ReplyDelete
  5. sorry but it is giving error .......... NO EGLConfig found

    ReplyDelete
  6. Innovative IT solutions helps freshers and experienced graduates and post graduates in getting placed in IT companies.

    ReplyDelete
  7. I have create a free wallpaper using andengine.. if you would like to see.. it has come out beautiful.


    https://play.google.com/store/apps/details?id=com.nightsky.lwp.free

    ReplyDelete