{"id":15,"date":"2011-08-02T15:56:43","date_gmt":"2011-08-02T18:56:43","guid":{"rendered":"http:\/\/mdqinc.com\/?p=15"},"modified":"2012-11-29T16:36:01","modified_gmt":"2012-11-29T19:36:01","slug":"using-andengine-to-create-an-android-live-wallpaper","status":"publish","type":"post","link":"https:\/\/mdqinc.com\/blog\/2011\/08\/using-andengine-to-create-an-android-live-wallpaper\/","title":{"rendered":"Using Andengine to create an Android Live Wallpaper"},"content":{"rendered":"<p>So, I got one of those wonderful Asus Transformers\u2026I had to see if I could make something for it. <a href=\"https:\/\/market.android.com\/details?id=org.anddev.wallpaper.live.donprimerizowp\" target=\"_blank\">And so I did!<\/a> Having some Android experience from the 1.x days, I started looking around for a quick way to get something done, and it was then that I found the amazing <a href=\"http:\/\/www.andengine.org\/\" target=\"_blank\">AndEngine<\/a> and its <a href=\"http:\/\/code.google.com\/p\/andenginelivewallpaperextension\/\" target=\"_blank\">Live Wallpaper Extension<\/a> . While the documentation is sparse (specially when it comes down to the newer changes in the engine), there\u2019s a big enough community that if you search around in the forums and over the net you will find what you are looking for. Getting it all in place turned out to be quite simple once I figured out what changes needed to be done to adapt the <a href=\"http:\/\/code.google.com\/p\/andenginelivewallpaperextensionexample\/\" target=\"_blank\">provided example<\/a> to the latest modifications done to the engine.<\/p>\n<p>All in all, it\u2019s pretty simple:<\/p>\n<p>(LiveWallpaperService.java)<\/p>\n<pre class=\"brush:java\">package org.anddev.wallpaper.live.donprimerizowp;\r\n\r\nimport java.io.File;\r\nimport java.util.Random;\r\n\r\nimport net.rbgrn.opengl.GLWallpaperService.GLEngine;\r\n\r\nimport org.anddev.andengine.engine.camera.Camera;\r\nimport org.anddev.andengine.engine.handler.timer.ITimerCallback;\r\nimport org.anddev.andengine.engine.handler.timer.TimerHandler;\r\nimport org.anddev.andengine.engine.options.EngineOptions;\r\nimport org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;\r\nimport org.anddev.andengine.engine.options.resolutionpolicy.FillResolutionPolicy;\r\nimport org.anddev.andengine.entity.particle.ParticleSystem;\r\nimport org.anddev.andengine.entity.particle.modifier.AlphaModifier;\r\nimport org.anddev.andengine.entity.particle.modifier.ExpireModifier;\r\nimport org.anddev.andengine.entity.scene.Scene;\r\nimport org.anddev.andengine.entity.sprite.AnimatedSprite.IAnimationListener;\r\nimport org.anddev.andengine.entity.sprite.Sprite;\r\nimport org.anddev.andengine.entity.sprite.AnimatedSprite;\r\nimport org.anddev.andengine.extension.ui.livewallpaper.BaseLiveWallpaperService;\r\nimport org.anddev.andengine.opengl.texture.Texture;\r\nimport org.anddev.andengine.opengl.texture.TextureOptions;\r\nimport org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;\r\nimport org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;\r\nimport org.anddev.andengine.opengl.texture.region.TextureRegion;\r\nimport org.anddev.andengine.opengl.texture.region.TextureRegionFactory;\r\nimport org.anddev.andengine.opengl.texture.region.TiledTextureRegion;\r\nimport org.anddev.andengine.opengl.view.GLSurfaceView.Renderer;\r\nimport org.anddev.andengine.opengl.view.RenderSurfaceView;\r\nimport org.anddev.andengine.sensor.accelerometer.AccelerometerData;\r\nimport org.anddev.andengine.sensor.accelerometer.IAccelerometerListener;\r\nimport org.anddev.andengine.sensor.orientation.IOrientationListener;\r\nimport org.anddev.andengine.sensor.orientation.OrientationSensorOptions;\r\n\r\nimport android.app.WallpaperManager;\r\nimport android.content.res.Configuration;\r\nimport android.os.Bundle;\r\n\r\npublic class LiveWallpaperService extends BaseLiveWallpaperService implements IAccelerometerListener, IOffsetsChanged {\r\n\r\n    protected class MyBaseWallpaperGLEngine extends GLEngine {\r\n        \/\/ ===========================================================\r\n        \/\/ Fields\r\n        \/\/ ===========================================================\r\n\r\n        private Renderer mRenderer;\r\n\r\n        private IOffsetsChanged mOffsetsChangedListener = null;\r\n\r\n        \/\/ ===========================================================\r\n        \/\/ Constructors\r\n        \/\/ ===========================================================\r\n\r\n        public MyBaseWallpaperGLEngine(IOffsetsChanged pOffsetsChangedListener) {\r\n                this.setEGLConfigChooser(false);\r\n                this.mRenderer = new RenderSurfaceView.Renderer(LiveWallpaperService.this.mEngine);\r\n                this.setRenderer(this.mRenderer);\r\n                this.setRenderMode(RENDERMODE_CONTINUOUSLY);\r\n                this.mOffsetsChangedListener = pOffsetsChangedListener;\r\n        }\r\n\r\n        \/\/ ===========================================================\r\n        \/\/ Methods for\/from SuperClass\/Interfaces\r\n        \/\/ ===========================================================\r\n\r\n        @Override\r\n        public Bundle onCommand(final String pAction, final int pX, final int pY, final int pZ, final Bundle pExtras, final boolean pResultRequested) {\r\n                if(pAction.equals(WallpaperManager.COMMAND_TAP)) {\r\n                    LiveWallpaperService.this.onTap(pX, pY);\r\n                } else if (pAction.equals(WallpaperManager.COMMAND_DROP)) {\r\n                    LiveWallpaperService.this.onDrop(pX, pY);\r\n                }\r\n\r\n                return super.onCommand(pAction, pX, pY, pZ, pExtras, pResultRequested);\r\n        }\r\n\r\n        @Override\r\n        public void onResume() {\r\n                super.onResume();\r\n                LiveWallpaperService.this.getEngine().onResume();\r\n                LiveWallpaperService.this.onResume();\r\n        }\r\n\r\n        @Override\r\n        public void onPause() {\r\n                super.onPause();\r\n                LiveWallpaperService.this.getEngine().onPause();\r\n                LiveWallpaperService.this.onPause();\r\n        }\r\n\r\n        @Override\r\n        public void onDestroy() {\r\n                super.onDestroy();\r\n                if (this.mRenderer != null) {\r\n                        \/\/ mRenderer.release();\r\n                }\r\n                this.mRenderer = null;\r\n        }\r\n\r\n        @Override\r\n        public void onOffsetsChanged(float xOffset, float yOffset,\r\n                        float xOffsetStep, float yOffsetStep, int xPixelOffset,\r\n                        int yPixelOffset) {\r\n                \/\/ TODO Auto-generated method stub\r\n                super.onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep,\r\n                                xPixelOffset, yPixelOffset);\r\n\r\n                if(this.mOffsetsChangedListener != null)\r\n                        this.mOffsetsChangedListener.offsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep, xPixelOffset, yPixelOffset);\r\n\r\n        }\r\n\r\n    }\r\n\r\n    \/\/ ===========================================================\r\n    \/\/ Constants\r\n    \/\/ ===========================================================\r\n\r\n    private static final int CAMERA_WIDTH = 1280;\r\n    private static final int CAMERA_HEIGHT = 800;\r\n\r\n    \/\/ ===========================================================\r\n    \/\/ Fields\r\n    \/\/ ===========================================================\r\n\r\n    private BitmapTextureAtlas mTexture;\r\n    private BitmapTextureAtlas mTexture2;\r\n    private BitmapTextureAtlas mTexture3;\r\n    private BitmapTextureAtlas mTexture4;\r\n    private BitmapTextureAtlas mTexture5;\r\n\r\n    private TextureRegion mPulperia;\r\n    private TextureRegion mCarreta;\r\n    private TiledTextureRegion mPibito;\r\n    private TiledTextureRegion mMosca;\r\n    private TiledTextureRegion mDPSeq1;\r\n    private TiledTextureRegion mDPSeq2;\r\n\r\n    private Sprite mPulperiaSprite;\r\n    private AnimatedSprite mPibitoSprite;\r\n    private Sprite mCarretaSprite;\r\n    private AnimatedSprite mMoscaSprite;\r\n    private AnimatedSprite mDP1Sprite;\r\n    private AnimatedSprite mDP2Sprite;\r\n\r\n    private ScreenOrientation mScreenOrientation;\r\n    private Camera mCamera;\r\n    private Scene mScene;\r\n\r\n    private IAnimationListener mDP1ListenerF, mDP1ListenerB, mDP2Listener; \r\n\r\n    \/\/ ===========================================================\r\n    \/\/ Constructors\r\n    \/\/ ===========================================================\r\n\r\n    \/\/ ===========================================================\r\n    \/\/ Getter &amp; Setter\r\n    \/\/ ===========================================================\r\n\r\n    \/\/ ===========================================================\r\n    \/\/ Methods for\/from SuperClass\/Interfaces\r\n    \/\/ ===========================================================\r\n\r\n    @Override\r\n    public org.anddev.andengine.engine.Engine onLoadEngine() {\r\n        mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);\r\n        return new org.anddev.andengine.engine.Engine(new EngineOptions(true, this.mScreenOrientation, new FillResolutionPolicy(), mCamera));\r\n    }\r\n\r\n    @Override\r\n    public void onLoadResources() {\r\n        this.getEngine().disableOrientationSensor(this);\r\n        this.mTexture = new BitmapTextureAtlas(2048, 2048, TextureOptions.BILINEAR);\r\n        this.mTexture2 = new BitmapTextureAtlas(2048, 2048, TextureOptions.BILINEAR);\r\n        this.mTexture3 = new BitmapTextureAtlas(2048, 2048, TextureOptions.BILINEAR);\r\n        this.mTexture4 = new BitmapTextureAtlas(1024, 1024, TextureOptions.BILINEAR);\r\n        this.mTexture5 = new BitmapTextureAtlas(1024, 2048, TextureOptions.BILINEAR);\r\n\r\n        \/* Creates the needed texture-regions on the texture. *\/\r\n        this.mPulperia = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mTexture, this, \"gfx\/pulperia.png\", 0, 0); \/\/ 1280x800\r\n        this.mCarreta = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mTexture, this, \"gfx\/carreta.png\", 0, 801); \/\/ 263x386\r\n        this.mPibito = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mTexture2, this, \"gfx\/pibito.png\", 0, 0, 6, 6); \/\/ 2048x1980\r\n        this.mMosca = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mTexture3, this, \"gfx\/mosca.png\", 0, 0, 11, 5); \/\/ 1980x1070\r\n        this.mDPSeq1 = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mTexture4, this, \"gfx\/dpseq1.png\", 0, 0, 7, 4); \/\/ 1022x1000\r\n        this.mDPSeq2 = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mTexture5, this, \"gfx\/dpseq2.png\", 0, 0, 10, 7); \/\/ 990x1393\r\n\r\n        this.getEngine().getTextureManager().loadTexture(this.mTexture);\r\n        this.getEngine().getTextureManager().loadTexture(this.mTexture2);\r\n        this.getEngine().getTextureManager().loadTexture(this.mTexture3);\r\n        this.getEngine().getTextureManager().loadTexture(this.mTexture4);\r\n        this.getEngine().getTextureManager().loadTexture(this.mTexture5);\r\n        this.enableAccelerometerSensor(this);\r\n    }\r\n\r\n    @Override\r\n    public Scene onLoadScene() {\r\n        mScene = new Scene();\r\n        mPulperiaSprite = new Sprite(0, 0, this.mPulperia);\r\n        mScene.attachChild(mPulperiaSprite);\r\n        mPibitoSprite = new AnimatedSprite(88, 200, this.mPibito);\r\n        mPibitoSprite.setScale((float) 1.6);\r\n\r\n        mMoscaSprite = new AnimatedSprite(700, 550, this.mMosca);\r\n\r\n        mDP1Sprite = new AnimatedSprite(530, 260, this.mDPSeq1);\r\n        mDP2Sprite = new AnimatedSprite(530, 310, this.mDPSeq2);\r\n\r\n        mDP1ListenerF = new IAnimationListener () {\r\n            @Override\r\n            public void onAnimationEnd(final AnimatedSprite pAnimatedSprite) {\r\n                runOnUpdateThread(new Runnable() {\r\n                    @Override\r\n                    public void run() {\r\n                        \/\/ Stop the animation, play it backwards\r\n                        mDP1Sprite.stopAnimation();\r\n                        mDP1Sprite.animate(\r\n                                new long[]\r\n                                {100,100,100,100,100,100,100,\r\n                                 100,100,100,100,100,100,100,\r\n                                 100,100,100,100,100,100,100,\r\n                                 100,100,100,100,100,100,100,},\r\n                                new int[] {27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}, 0, mDP1ListenerB);\r\n\r\n                    }\r\n                });\r\n           }\r\n        };\r\n\r\n        mDP1ListenerB = new IAnimationListener () {\r\n            @Override\r\n            public void onAnimationEnd(final AnimatedSprite pAnimatedSprite) {\r\n                runOnUpdateThread(new Runnable() {\r\n                    @Override\r\n                    public void run() {\r\n                        mScene.detachChild(mDP1Sprite);\r\n                        mDP1Sprite.stopAnimation();\r\n                        mDP2Sprite.animate(100, false, mDP2Listener);\r\n                        mScene.attachChild(mDP2Sprite);\r\n\r\n                    }\r\n                });\r\n           }\r\n        };\r\n\r\n        mDP2Listener = new IAnimationListener () {\r\n            @Override\r\n            public void onAnimationEnd(final AnimatedSprite pAnimatedSprite) {\r\n                runOnUpdateThread(new Runnable() {\r\n                    @Override\r\n                    public void run() {\r\n                        mScene.detachChild(mDP2Sprite);\r\n                        mDP2Sprite.stopAnimation();\r\n                        mDP1Sprite.animate(100, false, mDP1ListenerF);\r\n                        mScene.attachChild(mDP1Sprite);\r\n                    }\r\n                });\r\n           }\r\n        };\r\n\r\n        mDP1Sprite.animate(100, false, mDP1ListenerF);\r\n        mScene.attachChild(mDP1Sprite);\r\n\r\n        mCarretaSprite = new Sprite(-30, 414, this.mCarreta);\r\n        mScene.attachChild(mCarretaSprite);\r\n\r\n        \/\/this.mVelocityInitializer = new VelocityInitializer(-20, 20, -100, -120);\r\n\r\n\/\/      this.getEngine().registerPreFrameHandler(new FPSCounter());\r\n\r\n        mScene.registerUpdateHandler(new TimerHandler(10f, true, new ITimerCallback() {\r\n            Random randomSrc = new Random();\r\n            @Override\r\n            public void onTimePassed(final TimerHandler pTimerHandler) {\r\n                try {\r\n\r\n                    int x = randomSrc.nextInt(10);\r\n\r\n                    \/\/Pibito runs 3 out of 10 times\r\n                    if (x5 &amp;&amp; ! mMoscaSprite.isAnimationRunning()) {\r\n                        mScene.attachChild(mMoscaSprite);\r\n                        mMoscaSprite.animate(100, false, new IAnimationListener () {\r\n                            @Override\r\n                            public void onAnimationEnd(final AnimatedSprite pAnimatedSprite) {\r\n                                runOnUpdateThread(new Runnable() {\r\n                                    @Override\r\n                                    public void run() {\r\n                                        mScene.detachChild(mMoscaSprite);\r\n                                    }\r\n                                });\r\n                           }\r\n                        });\r\n                    }\r\n\r\n                } catch (Exception e) {}\r\n            }\r\n        })); \r\n\r\n        return mScene;\r\n    }\r\n\r\n    @Override\r\n    public void onLoadComplete() {\r\n\r\n    }\r\n\r\n    @Override\r\n    public Engine onCreateEngine() {\r\n            \/\/ TODO Auto-generated method stub\r\n            return new MyBaseWallpaperGLEngine(this);\r\n    }\r\n\r\n    @Override\r\n    public void offsetsChanged(float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset) {\r\n           \/* if(mCamera != null){\r\n                \/\/ Emulator has 3 screens\r\n                mCamera.setCenter( ((960 * xOffset ) - 240) , mCamera.getCenterY() );\r\n                \/ *formel                mCamera.setCenter(( (Camera-WIDTH * (screensCount-1)) * xOffset ) - (Camera-WIDTH \/ 2) ,mCamera.getCenterY() ); * \/\r\n            }*\/\r\n\r\n        mCarretaSprite.setPosition(-xOffset*80, 414);\r\n        mMoscaSprite.setPosition(-xOffset*300+700, 550);\r\n    }\r\n\r\n    @Override\r\n    public void onAccelerometerChanged(final AccelerometerData pAccelerometerData) {\r\n    \/*  final float minVelocityX = (pAccelerometerData.getX() + 2) * 5;\r\n        final float maxVelocityX = (pAccelerometerData.getX() - 2) * 5;\r\n\r\n        final float minVelocityY = (pAccelerometerData.getY() - 8) * 10;\r\n        final float maxVelocityY = (pAccelerometerData.getY() - 10) * 10;\r\n        this.mVelocityInitializer.setVelocity(minVelocityX, maxVelocityX, minVelocityY, maxVelocityY);*\/\r\n    }\r\n\r\n    @Override\r\n    public void onUnloadResources() {\r\n        \/\/ TODO Auto-generated method stub\r\n\r\n    }\r\n\r\n    @Override\r\n    public void onPauseGame() {\r\n        super.onPause();\r\n        LiveWallpaperService.this.getEngine().onPause();\r\n        LiveWallpaperService.this.onPause();\r\n    }\r\n\r\n    @Override\r\n    public void onResumeGame() {\r\n        super.onResume();\r\n        LiveWallpaperService.this.getEngine().onResume();\r\n        LiveWallpaperService.this.onResume();\r\n\r\n    }\r\n\r\n    @Override\r\n    public void onConfigurationChanged (Configuration newConfig){\r\n                    if(newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)\r\n                    {\r\n                            mScene.setScaleX(1280.0f\/800.0f);\r\n                            mScene.setScaleY(1.0f);\r\n                    }\r\n                    else if(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)\r\n                    {\r\n                        mScene.setScale(1);\r\n                    }\r\n\r\n    }\r\n\r\n    \/\/ ===========================================================\r\n    \/\/ Methods\r\n    \/\/ ===========================================================\r\n\r\n    \/\/ ===========================================================\r\n    \/\/ Inner and Anonymous Classes\r\n    \/\/ ===========================================================\r\n\r\n}<\/pre>\n<p>(IOffsetsChanged.java)<\/p>\n<pre class=\"brush:python\">package org.anddev.wallpaper.live.donprimerizowp;\r\npublic interface IOffsetsChanged{\r\n\r\n    public void offsetsChanged(float xOffset, float yOffset,\r\n                    float xOffsetStep, float yOffsetStep, int xPixelOffset,\r\n                    int yPixelOffset);\r\n\r\n}<\/pre>\n<p>I\u2019m making the full project available <a href=\"http:\/\/mdqinc.com\/blog\/uploads\/DonPrimerizoWallpaper.7z\" target=\"_blank\">here<\/a> . The Live Wallpaper is available from the <a href=\"https:\/\/market.android.com\/details?id=org.anddev.wallpaper.live.donprimerizowp\" target=\"_blank\">Android Market<\/a>.<\/p>\n<p>The license for the code is \u201cdo as you please\u201d, for the art it\u2019s \u201cAll rights reserved under Creative Commons License\u201d. All art is from the defunct (oh really? I hear him breathing!) \u201cEpopeya de Don Primerizo Lata\u201d and was created by the great Leonardo Falaschini, you should check his stuff at <a href=\"http:\/\/liondart.com\" target=\"_blank\">liondart.com<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>So, I got one of those wonderful Asus Transformers\u2026I had to see if I could make something for it. And so I did! Having some Android experience from the 1.x days, I started looking around for a quick way to get something done, and it was then that I found the amazing AndEngine and its [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[5,3],"tags":[],"_links":{"self":[{"href":"https:\/\/mdqinc.com\/blog\/wp-json\/wp\/v2\/posts\/15"}],"collection":[{"href":"https:\/\/mdqinc.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mdqinc.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mdqinc.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mdqinc.com\/blog\/wp-json\/wp\/v2\/comments?post=15"}],"version-history":[{"count":6,"href":"https:\/\/mdqinc.com\/blog\/wp-json\/wp\/v2\/posts\/15\/revisions"}],"predecessor-version":[{"id":49,"href":"https:\/\/mdqinc.com\/blog\/wp-json\/wp\/v2\/posts\/15\/revisions\/49"}],"wp:attachment":[{"href":"https:\/\/mdqinc.com\/blog\/wp-json\/wp\/v2\/media?parent=15"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mdqinc.com\/blog\/wp-json\/wp\/v2\/categories?post=15"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mdqinc.com\/blog\/wp-json\/wp\/v2\/tags?post=15"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}