Live WallPaper - How to Make Interactive Live Video Wallpapers Using Kotlin Android

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.