How to build an Android app to dynamically change wallpaper on every screen unlock

Varun Kumar
5 min readMay 13, 2020

--

Development is always fun, be that web or apps. If you can convert your idea into a working app then you have power :D
This weekend an idea struck to my mind- how about always changing my home screen wallpaper each time I unlock my phone. “Wow! This would be cool right?”, I asked to myself. This got me really excited, I mean it would definitely be pleasant to keep seeing your favourite pictures on your screen.

With these thoughts I quickly typed a few keywords like “Auto Wallpaper”, “Dynamic Wallpaper” etc on Google PlayStore and guess what, I found a tons of apps offering same or similar functionality.

They say that “these days, ideas are rarely unique”, and I couldn’t agree more :(
Nevertheless, I decided to build my own app for two reasons-
1. All of those apps are full of ads which I really hate
2. I am powerful, remember?

A demo GIF showing wallpaper change on screen unlock

The whole implementation can be divided into 3 parts-

  1. A background Service which will be running all the time
  2. Registration of a Broadcast Receiver by this Service which will listen for ACTION_USER_PRESENT intent (screen unlock event). This receiver will call our wallpaper changing code whenever screen gets unlocked
  3. A dedicated folder in phone, which will contain all the wallpapers and which app can refer to

You might wonder, why I am going for a Service initiated receiver when I can actually register a Broadcast Receiver to listen for ACTION_USER_PRESENT Intent in manifest.
You are right, I can register this Receiver in AndroidManifest and it will be invoked by Android System whenever screen gets unlocked, but this will only work in Android 7 or earlier versions. Beginning with Android 8 (Oreo), you cannot use the manifest to declare a receiver for most implicit broadcasts (broadcasts that don’t target your app specifically) and ACTION_USER_PRESENT is an implicit broadcast.

Always running Service in Android

A Service is an application component that can perform long-running operations in the background, and it doesn’t provide a user interface.
Implementing an always running service was the most challenging part of this app.

App will launch the Service for the first time and to restart it whenever it gets killed, I called a custom manifest registered Broadcast Receiver from onDestroy lifecycle method of Service. The job of this receiver is to restart the service if it’s not already running.

MyService onDestroy method-

@Override
public void onDestroy() {
Log.d(TAG, "onDestroy called");
isServiceRunning = false;
stopForeground(true);

// call MyReceiver which will restart this service
Intent broadcastIntent = new Intent(this, MyReceiver.class);
sendBroadcast(broadcastIntent);

super.onDestroy();
}

Custom Broadcast receiver MyReceiver-

public class MyReceiver extends BroadcastReceiver {
private String TAG = "MyReceiver";

@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive called");

Intent serviceIntent =
new Intent(context, MyService.class);
ContextCompat.startForegroundService(
context, serviceIntent
);

}
}

So far so good, but what will happen if onDestroy lifecycle method of MyService does not get called?
MyReceiver will not receive any boradcast intent and hence MyService will not be restarted. This is what happened with me for my MI device- Redmi Note 7S.

As a workaround, I scheduled a periodic Job in Background via WorkManager. This Job will run every 16 minutes and restart the service if not already running.

This will be called from onCreate method of MainActivity

Above Job invokes following doWork method of MyWorker-

This method will be invoked by Periodic Job every 16 minutes

Receiver to listen for Screen Unlock Intent

I created ScreenLockReceiver class and registered it from MyService class. This receiver is invoked whenever phone screen gets unlocked and calls wallpaper changing code.

Dynamically registering ScreenLock Receiver from MyService

ScreenLockReceiver class-

ACTION_USER_PRESENT is for screen unlock Intent

Changing wallpaper

Last piece of implementation is to change wallpaper. The following code looks for a random image file in a dedicated folder “dynamic-wallpaper” inside phone storage. It then sets it as home screen wallpaper if it’s size is less than 1 MB. If it does not find “dynamic-wallpaper” directory then it will create one. Of course both size limit and folder location should be configurable from app, but for now I just hardcoded them in code.

Conclusion

Notification Displayed by Foreground Service

Complete source code for this app is here- https://github.com/varunon9/DynamicWallpaper.
This app is working on my phone Redmi Note 7S (Android 9) as well as on two emulators (Android 6 & Android 8) and now I can keep seeing beautiful wallpapers on my Home screen :)

Though this is a working app, it’s not something that can be shipped to end users. As of now, I manually added wallpapers to “dynamic-wallpaper” folder and explicitly granted WRITE_EXTERNAL_STORAGE permission from my phone’s settings. But you cannot expect these from your app users. App must contain proper UI for all the features and configurable settings.

I made this app open source and if you like the idea, you are most welcome to raise a Pull Request. Thank you for reading (or just scrolling).

--

--