Unable to animate on Canvas in Live Wallpaper
<p>I'm working on a bubbles live wallpaper with lot of bubbles animating arround but I'm a little stuck.</p>

<p>Here is my code: When i run this project is only draw bubbles in center of screen and stays there. while i want to animate them through out the screen. </p>

<pre><code>package com.ralph.bubbles;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Handler;
import android.service.wallpaper.WallpaperService;
import android.view.SurfaceHolder;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;

public class BubblesService extends WallpaperService {

    private final Handler mHandler = new Handler();

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

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

    @Override
    public Engine onCreateEngine() {
        // TODO Auto-generated method stub
        return new BubblesEngine();
    }


    class BubblesEngine extends Engine{

        int x = 0, y = 0;

        private BitmapFactory.Options opt = new BitmapFactory.Options();                    
        private Bitmap bubble;      
        private int currentBubbleCount = 0, totalBubblesCount = 20;

        Paint paint;
        RotateAnimation rotate;
        AlphaAnimation blend;
        ScaleAnimation scale;
        AnimationSet spriteAnimation;

        float centerX;
        float centerY;
        float offsetX;
        float offsetY;      


        BubblesEngine(){
            opt.inPreferredConfig = Bitmap.Config.ARGB_8888;
            bubble = BitmapFactory.decodeResource(getResources(), com.ralph.bubbles.R.drawable.bubble, opt);
            offsetX = bubble.getWidth() / 2;
            offsetY = bubble.getHeight() / 2;

            paint  = new Paint();
            paint.setAntiAlias(true);
            paint.setFilterBitmap(true);
        }

        public Runnable mDrawBubbles = new Runnable(){
            public void run(){
                drawFrame();
            }
        };

        private boolean mVisible;

        public void onCreate(SurfaceHolder sh){
            super.onCreate(sh);

            //By Default we wont get Touch Events so Enable touch Events
        }

        public void onDestroy(){
            super.onDestroy();
            mHandler.removeCallbacks(mDrawBubbles);
        }


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

        }


        @Override
        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            // TODO Auto-generated method stub
            super.onSurfaceChanged(holder, format, width, height);


        }

        @Override
        public void onSurfaceCreated(SurfaceHolder holder) {
            // TODO Auto-generated method stub
            super.onSurfaceCreated(holder);
        }

        @Override
        public void onSurfaceDestroyed(SurfaceHolder holder) {
            // TODO Auto-generated method stub
            super.onSurfaceDestroyed(holder);
            mVisible = false;
            mHandler.removeCallbacks(mDrawBubbles);
        }


        @Override
        public void onOffsetsChanged(float xOffset, float yOffset,
                float xOffsetStep, float yOffsetStep, int xPixelOffset,
                int yPixelOffset) {

            drawFrame();

        }


        void drawFrame(){
            tick();
            final SurfaceHolder holder = getSurfaceHolder();
            Canvas c = null;

            try{
                c = holder.lockCanvas();
                if(c != null){
                    drawBubbles(c);
                }
            }finally{
                if (c != null) holder.unlockCanvasAndPost(c);
            }
            //Reschedule the next ReDraw
            mHandler.removeCallbacks(mDrawBubbles);
            if(mVisible){
                if(currentBubbleCount &lt; totalBubblesCount){
                    mHandler.postDelayed(mDrawBubbles, 1000 / 25);
                }
            }
        }

        void tick(){
            x += 10;
            y += 10;
            currentBubbleCount += 1;
        }

        void drawBubbles(Canvas c){

            //First save canvas
            c.save();

            if(spriteAnimation == null){
                centerX = c.getWidth() / 2;
                centerY = c.getHeight() / 2;
                createAnimation(c);
            }           

            c.drawBitmap(bubble, centerX - offsetX, centerY - offsetY, paint);          
            c.restore();

        }


        public void createAnimation(final Canvas canvas){

            rotate = new RotateAnimation(0, 360, centerX, centerY);
            rotate.setRepeatMode(Animation.REVERSE);
            rotate.setRepeatCount(Animation.INFINITE);

            scale = new ScaleAnimation(0, 2, 0, 2, centerX, centerY);
            scale.setRepeatMode(Animation.REVERSE);
            scale.setRepeatCount(Animation.INFINITE);
            scale.setInterpolator(new AccelerateDecelerateInterpolator());


            spriteAnimation = new AnimationSet(true);
            spriteAnimation.addAnimation(rotate);
            spriteAnimation.addAnimation(scale);
            spriteAnimation.setDuration(10000L);

            spriteAnimation.start();

        }


    }//Engine


}
</code></pre>
