How to Make an Interactive Live Wallpaper Using Kotlin For Android

Android offers a number of personalization features to help developers customize many aspects of their mobile app user experience. One of these features is live wallpaper for Android.

Live wallpapers are animated. They don’t remain as static background images and have interactive features.

A live wallpaper for Android is usually used as a background on the home screen that changes over time or animates in some way. If you own an Android device, you’ve probably seen a couple of built-in live wallpapers.

Now, as a mobile app developers company, you can also create and publish live wallpapers for Android. The process is not difficult. However, creating a live wallpaper that does not drain user’s device battery and is fascinating is something of a challenge.

But, in today’s Android application development tutorial, we’ll walk you through the process of creating a live wallpaper for Android that works well.

Let’s Get Started

Create a new project “Live Wallpaper”.

Add an Activity to mobile => Select Empty Activity.

Select-Activity

Configure the project.

Configure-project


Step 1
: Add dependencies in-app level build.gradle

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
}

Step 2: add below source in SetWallpaperActivity file

class SetWallpaperActivity : Activity() {

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

    fun onClick(view: View) {
        val intent = Intent(
            WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER
        )
        intent.putExtra(
            WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
            ComponentName(this, MyWallpaperService::class.java)
        )
        startActivity(intent)
    }
}

Step 3: add below source in SetWallpaperActivity file

<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.ConstraintLayout

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:app="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="match_parent">

 
<Button

app:layout_constraintBottom_toBottomOf="parent"

app:layout_constraintLeft_toLeftOf="parent"

app:layout_constraintRight_toRightOf="parent"

app:layout_constraintTop_toTopOf="parent"

android:id="@+id/btnWallPaper"

android:paddingStart="@dimen/dimen_25dp"

android:paddingEnd="@dimen/dimen_25dp"

android:onClick="onClick"

style="@style/button_style"

android:text="@string/lable_click_here"

android:layout_marginTop="@dimen/dimen_10dp"/>

</android.support.constraint.ConstraintLayout>

Step 4: add below source in MyWallpaperService file

class MyWallpaperService : WallpaperService() {

    override fun onCreateEngine(): WallpaperService.Engine {
        return MyWallpaperEngine()
    }

    private inner class MyWallpaperEngine : WallpaperService.Engine() {
        private val handler = Handler()
        private val drawRunner = Runnable { draw() }
        private val circles: MutableList
        private val paint = Paint()
        private var width: Int = 0
        internal var height: Int = 0
        private var visible = true
        private val maxNumber: Int
        private val touchEnabled: Boolean

        init {
            val prefs = PreferenceManager
                .getDefaultSharedPreferences(this@MyWallpaperService)
            maxNumber = Integer
                .valueOf(prefs.getString(resources.getString(R.string.lable_number_of_circles), "4")!!)
            touchEnabled = prefs.getBoolean("touch", false)
            circles = ArrayList()
            paint.isAntiAlias = true
            paint.color = Color.WHITE
            paint.style = Paint.Style.STROKE
            paint.strokeJoin = Paint.Join.ROUND
            paint.strokeWidth = 10f
            handler.post(drawRunner)
        }

        override fun onVisibilityChanged(visible: Boolean) {
            this.visible = visible
            if (visible) {
                handler.post(drawRunner)
            } else {
                handler.removeCallbacks(drawRunner)
            }
        }

        override fun onSurfaceDestroyed(holder: SurfaceHolder) {
            super.onSurfaceDestroyed(holder)
            this.visible = false
            handler.removeCallbacks(drawRunner)
        }

        override fun onSurfaceChanged(
            holder: SurfaceHolder, format: Int,
            width: Int, height: Int
        ) {
            this.width = width
            this.height = height
            super.onSurfaceChanged(holder, format, width, height)
        }

        override fun onTouchEvent(event: MotionEvent) {
            if (touchEnabled) {

                val x = event.x
                val y = event.y
                val holder = surfaceHolder
                var canvas: Canvas? = null

                canvas = holder.lockCanvas()
                if (canvas != null) {
                    canvas.drawColor(Color.BLACK)
                    circles.clear()
                    circles.add(MyPoint((circles.size + 1).toString(), x, y))
                    drawCircles(canvas, circles)

                }

                if (canvas != null)
                    holder.unlockCanvasAndPost(canvas)

                super.onTouchEvent(event)
            }
        }

        private fun draw() {
            val holder = surfaceHolder
            var canvas: Canvas? = null

            canvas = holder.lockCanvas()
            if (canvas != null) {
                if (circles.size >= maxNumber) {
                    circles.clear()
                }
                val x = (width * Math.random()).toInt()
                val y = (height * Math.random()).toInt()
                circles.add(
                    MyPoint(
                        (circles.size + 1).toString(),
                        x.toFloat(), y.toFloat()
                    )
                )
                drawCircles(canvas, circles)
            }

            if (canvas != null)
                holder.unlockCanvasAndPost(canvas)

            handler.removeCallbacks(drawRunner)
            if (visible) {
                handler.postDelayed(drawRunner, 5000)
            }
        }

        // Surface view requires that all elements are drawn completely
        private fun drawCircles(canvas: Canvas, circles: List) {
            canvas.drawColor(Color.BLACK)
            for (point in circles) {
                canvas.drawCircle(point.x, point.y, 20.0f, paint)
            }
        }
    }


}

Step 5: add below source in MyPoint file

class MyPoint(var text: String, var x: Float, var y: Float)

Step 6: add below source in MyPreferencesActivity file

class MyPreferencesActivity : PreferenceActivity() {

    /**
     * Checks that a preference is a valid numerical value
     */
    internal var numberCheckListener: Preference.OnPreferenceChangeListener =
        Preference.OnPreferenceChangeListener { preference, newValue ->
            // check that the string is an integer
            if (newValue != null && newValue.toString().length > 0
                && newValue.toString().matches("\\d*".toRegex())
            ) {
                return@OnPreferenceChangeListener true
            }
            // If now create a message to the user
            Toast.makeText(
                this@MyPreferencesActivity, resources.getString(R.string.lable_invalid_input),
                Toast.LENGTH_SHORT
            ).show()
            false
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        addPreferencesFromResource(R.xml.prefs)

        // add a validator to the "numberofCircles" preference so that it only
        // accepts numbers
        val circlePreference = preferenceScreen.findPreference(resources.getString(R.string.lable_number_of_circles))

        // add the validator
        circlePreference.onPreferenceChangeListener = numberCheckListener
    }
}

Step 7: add below source in XML.prefs file

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
	xmlns:android="http://schemas.android.com/apk/res/android">
	<CheckBoxPreference android:key="@string/lable_touch"
                        android:title="@string/lable_enable_touch"/>
	<EditTextPreference android:key="@string/lable_number_of_circles"
                        android:title="@string/lable_number_circles"/>
</PreferenceScreen>

Step 8: add below source in AndroidManifest.xml file

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="spaceo.livewallpaperdemo">

<application

android:allowBackup="true"

android:icon="@mipmap/ic_launcher"

android:label="@string/app_name"

android:supportsRtl="true"

android:theme="@style/AppTheme">

<service

android:name="spaceo.livewallpaperdemo.MyWallpaperService"

android:enabled="true"

android:label="Wallpaper Example"

android:permission="android.permission.BIND_WALLPAPER">

<intent-filter>

<action android:name="android.service.wallpaper.WallpaperService">

</action>

</intent-filter>

<meta-data

android:name="android.service.wallpaper"

android:resource="@xml/mywallpaper">

</meta-data>

</service>

<activity

android:name="spaceo.livewallpaperdemo.MyPreferencesActivity"

android:exported="true"

android:label="@string/app_name">

</activity>

<activity

android:name="spaceo.livewallpaperdemo.SetWallpaperActivity"

android:label="@string/app_name">

<intent-filter>

<action android:name="android.intent.action.MAIN"/>

<category android:name="android.intent.category.LAUNCHER"/>

</intent-filter>

</activity>

</application>

<uses-feature

android:name="android.software.live_wallpaper"

android:required="true">

</uses-feature>

</manifest>

And done!

Once you successfully implement this code, you can easily create live wallpaper for Android.

Remember, live wallpapers are a useful way to expand your app beyond typical boundaries. However, while making the live wallpaper, make sure to render to the screen so that the user’s experience with their device does not suffer. And if you still face difficulty or any query like how much does it cost to make live wallpaper Android /HD live wallpaper/3D moving wallpapers, or how to make a live wallpaper android or 3D animation wallpapers, text live wallpaper, then you can consult with Android app development company to make your live wallpaper work smoothly in Android device.

Get a free copy of Android Live Wallpaper Demo from Github.

This page was last edited on April 10th, 2019, at 8:36.
 
 

Have an Idea for Android App? Let's Discuss!

Get your free consultation now

Leave a Reply

Your email address will not be published. Required fields are marked *