2

I'm making a Live Wallpaper for Android API level 19+. My wallpaper consists of two layers.

  1. I want to play video on a background. It should to be transformable. I want to be able to change the scale and position of the video.

  2. In the foreground I need to draw a simple graphics like сanvas.drawCircle().

My attempts:

I started with MediaPlayer. The code below can play a video on wallpaper, but it can’t to draw graphics over the video. OR it can draw graphics, but can't the video. As I understood it's because MediaPlayer completely locks the Canvas. I tried this by running MediaPlayer into the single Surface, in which I drawn animation of circle in the draw() method. And I received BaseSurfaceHolder: Exception locking surface.

There is a global problem that limits me:

Wallpaper is a Service, not an Activity. This is limited by the fact that we have only one Surface, which is created by the class WallpaperService.Engine (I may be wrong). Also we can't use any View objects.

Desired wallpaper result:

  1. Play background video (WebM preferred)
  2. To have a possibility to transform video (scale, translate)
  3. Draw simple foreground graphics

Questions

Now I have some ideas to implement this, but I don't know if it is possible:

  1. Is there a possible way to transform Surface's content? (exactly Surface, not a SurfaceView)
  2. Is it possible to create an additional Surface and then draw both Surfaces one above the other like a second layer? (maybe SurfaceFlinger does that?)
  3. Is it possible to use MediaCodec (which I'll have to study) to decode video and draw it frame-by-frame in draw() method using lock/unlock canvas and draw simple graphics there?
  4. Is it possible to have a SurfaceView but don't attach it to window? I tried it and got "surface has been released" Exception. How can I attach it in my case? As I understand it must to be attached to a window. But I don't have a window.

Now my code can only draw video OR draw graphics, and I'm almost sure that I need to replace the MediaPlayer for something else:

package com.android.grafika;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Handler;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.SurfaceHolder;

import java.io.IOException;

import static java.lang.Math.PI;
import static java.lang.Math.cos;


public class MyWallpaperService extends WallpaperService{

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


    class MyEngine extends WallpaperService.Engine implements MediaPlayer.OnPreparedListener{

        private MediaPlayer player = null;
        private SurfaceHolder holder;
        private Handler handler = new Handler();
        private boolean visible = false;
        private Paint paint = new Paint();
        private int counter = 0;
        private int frameDelay = 30;
        private int rawVideoId = R.raw.mage_1sec;
        private Runnable drawFrame = new Runnable()
        {
            @Override
            public void run() {
                draw();
                counter++;
                if (visible) {
                    handler.postDelayed(this, frameDelay);
                }
            }
        };

        @Override
        public void onCreate(SurfaceHolder surfaceHolder) {
            super.onCreate(surfaceHolder);
            this.holder = surfaceHolder;
        }

        @Override
        public void onVisibilityChanged(boolean visible) {
            super.onVisibilityChanged(visible);
            this.visible = visible;
            if (visible) {
                handler.post(drawFrame);
                //playerStart();    // uncomment it and comment the statement above to draw the video
            } else {
                handler.removeCallbacks(drawFrame);
                //playerRelease();  // uncomment it and comment the statement above to draw the video
            }
        }

        private void draw() {
            Canvas canvas = holder.lockCanvas();
            canvas.drawColor(Color.CYAN);
            //mediaDecoder.drawVideoFrame(canvas); // this is my imaginary statement
            canvas.drawCircle(600f, (float) cos( (double) counter /30f * PI) * 200f + 400f, 30f, paint); // simple animation
            holder.unlockCanvasAndPost(canvas);
        }

        /**
         * MediaPlayer implementation
         */
        private void playerRelease() {
            player.release();
            player = null;
        }

        private void playerStart() {
            try {
                player = new MediaPlayer();
                player.setLooping(true);
                player.setSurface(holder.getSurface());
                player.setDataSource(getApplicationContext(), Uri.parse("android.resource://" + getPackageName() + "/" + rawVideoId));
                player.setOnPreparedListener(this);
                player.prepare();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onPrepared(MediaPlayer mediaPlayer) {
            player.start();
        }
    }
}

I'll be glad to any help: references, samples, advices or libs. Maybe I'm not doing everything right and you can say it to me.

Thank you for any help!

Community
  • 1
  • 1
WMax
  • 59
  • 3

0 Answers0