Make Interactive Live Video Wallpapers in Kotlin Android

Create interactive live video wallpapers in Android using Kotlin. Learn to implement dynamic backgrounds with smooth performance. Visit rrtutors.com.

Last updated Jan 23, 2020

Live Wallpapers are animated, interactive backgrounds for the Android home screen. A live wallpaper is similar to other Android applications and will use the same functionality

In this Example we are going to create Live Video Wall Paper

Let's Start

Step 1: Create new project "Live Video Wallpaper"

Step 2: Create VideoWallpaper service and add below code

import android.app.WallpaperManager;
import android.content.*;
import android.media.MediaPlayer;
import android.service.wallpaper.WallpaperService;
import android.text.TextUtils;
import android.view.SurfaceHolder;

import java.io.IOException;

public class WallPaper extends WallpaperService {
    private static final String TAG = WallPaper.class.getName();
    private static String sVideoPath;
     String VIDEO_PARAMS_CONTROL_ACTION = "com.rrtutors.livevideowallpaper";
     String ACTION = "action";
     int ACTION_VOICE_SILENCE = 1;
     int ACTION_VOICE_NORMAL = 2;
      String IS_SILENCE = "is_silence";
    /**
     * @param context
     */
    public  void setVoiceSilence(Context context){
        Intent intent = new Intent(VIDEO_PARAMS_CONTROL_ACTION);
        intent.putExtra(ACTION, ACTION_VOICE_SILENCE);
        context.sendBroadcast(intent);
    }

    /**
     *  @param context
     */
    public  void setVoiceNormal(Context context){
        Intent intent = new Intent(VIDEO_PARAMS_CONTROL_ACTION);
        intent.putExtra(ACTION, ACTION_VOICE_NORMAL);
        context.sendBroadcast(intent);
    }

    /**
     * @param context
     */
    public  void setToWallPaper(Context context, String videoPath){
        try {
            context.clearWallpaper();
        } catch (IOException e) {
            e.printStackTrace();
        }
        sVideoPath = videoPath;
        Intent intent = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
        intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,new ComponentName(context,WallPaper.class));
        context.startActivity(intent);
    }


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

    class VideoWallpagerEngine extends Engine {
        private MediaPlayer mMediaPlayer;
        private BroadcastReceiver mVideoVoiceControlReceiver;

        @Override
        public void onCreate(SurfaceHolder surfaceHolder) {
            super.onCreate(surfaceHolder);
            IntentFilter intentFilter = new IntentFilter(VIDEO_PARAMS_CONTROL_ACTION);
            mVideoVoiceControlReceiver = new VideoVoiceControlReceiver();
            registerReceiver(mVideoVoiceControlReceiver,intentFilter);
        }

        @Override
        public void onDestroy() {
            unregisterReceiver(mVideoVoiceControlReceiver);
            super.onDestroy();
        }

        @Override
        public void onVisibilityChanged(boolean visible) {
            if (visible){
                mMediaPlayer.start();
            }else {
                mMediaPlayer.pause();
            }
        }
        @Override
        public void onSurfaceCreated(SurfaceHolder holder) {
            super.onSurfaceCreated(holder);
            if (TextUtils.isEmpty(sVideoPath)) {
                throw  new NullPointerException("videoPath must not be null ");
            }else {
                mMediaPlayer = new MediaPlayer();
                mMediaPlayer.setSurface(holder.getSurface());

                try {

                    mMediaPlayer.setDataSource(sVideoPath);
                    mMediaPlayer.setLooping(true);
                    mMediaPlayer.setVolume(0f, 0f);
                    mMediaPlayer.prepare();
                    mMediaPlayer.start();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

        @Override
        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            super.onSurfaceChanged(holder, format, width, height);
        }

        @Override
        public void onSurfaceDestroyed(SurfaceHolder holder) {
            super.onSurfaceDestroyed(holder);
            if (mMediaPlayer != null){
                mMediaPlayer.release();
                mMediaPlayer = null;
            }
        }
        class VideoVoiceControlReceiver extends BroadcastReceiver {

            @Override
            public void onReceive(Context context, Intent intent) {
                int action = intent.getIntExtra(ACTION,-1);
                switch (action){
                    case 1:
                        mMediaPlayer.setVolume(1.0f,1.0f);
                        break;
                    case 2:
                        mMediaPlayer.setVolume(0,0);
                        break;
                }
            }
        }
    }
}

Now Configure Service in Manifest file

<service android:name=".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/videowallpaper" /> </service>

Here we need to create xml file with below code 

videowallpaper.xml

<?xml version="1.0" encoding="utf-8"?>
<wallpaper xmlns:android="https://schemas.android.com/apk/res/android"
    android:thumbnail="@mipmap/ic_launcher"
    >

</wallpaper>

 

Add below permissions in Manifest file

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.SET_WALLPAPER" />

Step 3:

Now add Required Resourses for the application, in this application i have added few mp4 files in raw folder

Step 4:

Now Its time to create our UI 

updated activity_main


    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="#FF5722"
    tools:context=".VideoListActivity">
            android:layout_width="match_parent"
        android:layout_height="?actionBarSize"
        android:text="Video Wallpaper"
        android:gravity="center"
        android:textColor="#FFF"
        android:textSize="25sp"
        android:background="#E70E57"
        android:textStyle="bold"
        />
            android:layout_width="match_parent"
        android:layout_height="wrap_content">
                    android:layout_width="wrap_content"
            android:layout_weight="1"
            android:layout_margin="10dp"
            android:background="#FFF"
            android:padding="2dp"
            android:layout_height="200dp">
                            android:id="@+id/imageview1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
               android:layout_gravity="center"
                />
                            android:layout_width="32dp"
                android:layout_height="32dp"
                android:layout_gravity="center"
                android:src="@android:drawable/ic_media_play"
                />
       
                    android:layout_width="wrap_content"
            android:layout_weight="1"
            android:layout_margin="10dp"
            android:background="#FFF"
            android:padding="2dp"
            android:layout_height="200dp">
                    android:id="@+id/imageview2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"

            />
                            android:layout_width="32dp"
                android:layout_height="32dp"
                android:layout_gravity="center"
                android:src="@android:drawable/ic_media_play"
                />
       
   

            android:layout_width="match_parent"
        android:layout_height="wrap_content">
                    android:layout_width="wrap_content"
            android:layout_weight="1"
            android:layout_margin="10dp"
            android:background="#FFF"
            android:padding="2dp"
            android:layout_height="200dp">
                    android:id="@+id/imageview3"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            />
                            android:layout_width="32dp"
                android:layout_height="32dp"
                android:layout_gravity="center"
                android:src="@android:drawable/ic_media_play"
                />
       
                    android:layout_width="wrap_content"
            android:layout_weight="1"
            android:layout_margin="10dp"
            android:background="#FFF"
            android:padding="2dp"
            android:layout_height="200dp">
                    android:id="@+id/imageview4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            />
                            android:layout_width="32dp"
                android:layout_height="32dp"
                android:layout_gravity="center"
                android:src="@android:drawable/ic_media_play"
                />
       
   

MainActivity.kt 

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy.NONE
import kotlinx.android.synthetic.main.activity_main.*

import kotlinx.android.synthetic.main.activity_main.view.*;
class MainActivity : AppCompatActivity(),View.OnClickListener {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        Glide.with(this).load(R.raw.krish3).diskCacheStrategy(NONE).into(imageview1)
        Glide.with(this).load(R.raw.thor_darkworld1).diskCacheStrategy(NONE).into(imageview2)
        Glide.with(this).load(R.raw.thor_darkworld2).diskCacheStrategy(NONE).into(imageview3)
        Glide.with(this).load(R.raw.chotabeem).diskCacheStrategy(NONE).into(imageview4)

        imageview1.setOnClickListener(this)
        imageview2.setOnClickListener(this)
        imageview3.setOnClickListener(this)
        imageview4.setOnClickListener(this)
    }

    override fun onClick(v: View?) {
        val `in` = Intent(applicationContext, MainActivity::class.java)
        when (v?.getId()) {
            R.id.imageview1 -> `in`.putExtra("filename", "krish3.mp4")
            R.id.imageview2 -> `in`.putExtra("filename", "thor_darkworld1.mp4")
            R.id.imageview3 -> `in`.putExtra("filename", "thor_darkworld2.mp4")
            R.id.imageview4 -> `in`.putExtra("filename", "chotabeem.mp4")
        }
        startActivity(`in`)
    }
}

Now create SetWallPaperActivity

class WallPaperActivity : AppCompatActivity() {

    private val IS_VIDEO1: String="is_video1"
    lateinit var mVideoWallpaper:WallPaper;
    lateinit var filename:String;
    lateinit var mFile1:File;
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_wall_paper)
        mVideoWallpaper = WallPaper()

        filename = intent.getStringExtra("filename")
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!checkPermissionForStorage()) {
                ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 300)
                return
            }
        }
        initFile()
    }

    private fun initFile() {

        mFile1 = File(Environment.getExternalStorageDirectory().toString() + "/" + filename)
        if (!(mFile1.exists())) {
            try {
                var idname = filename
                idname = idname?.replace(".mp4", "")
                val id = resources.getIdentifier(
                    idname,
                    "raw", "com.rrtutors.livevideowallpaper"
                )
                mFile1.createNewFile()
                val `is` = resources.openRawResource(id)
                writeMp4ToNative(mFile1, `is`)
            } catch (e: IOException) {
                e.printStackTrace()
            }

        }
       // videoview.setVideoURI(Uri.fromFile(mFile1.getAbsoluteFile()))
       // val m = MediaController(this)

       // videoview.setMediaController(m)
       // videoview.start()

    }

    private fun writeMp4ToNative(file: File, istr: InputStream) {

        try {
            val os = FileOutputStream(file)
            var len = -1
            val buffer = ByteArray(1024)
            while ((istr.read(buffer)) != -1) {
                os.write(buffer, 0, buffer.size)
            }
            os.flush()
            os.close()
            istr.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }

    }

    fun setWallpaper(view: View) {
            mVideoWallpaper.setToWallPaper(this, mFile1.getAbsolutePath())
    }

    fun setSilence(view: View) {
        mVideoWallpaper.setVoiceSilence(this)
    }

    fun cancelSilence(view: View) {
        mVideoWallpaper.setVoiceNormal(this)
    }

    fun toBack(view: View) {
        finish()
    }

    private fun checkPermissionForStorage(): Boolean {
        val result = ContextCompat.checkSelfPermission(applicationContext, Manifest.permission.WRITE_EXTERNAL_STORAGE)
        return result == PackageManager.PERMISSION_GRANTED
    }

    override fun onRequestPermissionsResult(requestCode: Int, @NonNull permissions: Array, @NonNull grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (checkPermissionForStorage()) {
            initFile()
        }
    }
}

 

Step 5:

Now run the app and set your wall paper.

Related Tutorials & Resources