Original link: https://xuyisheng.top/android_wallpaper/
The function of setting the system wallpaper does not actually have many scenes for the application layer App, but in the surrounding activities of some scenes, it is indeed a way to enhance the brand stickiness, just like the beautiful wallpaper of a character created in a certain activity. Figure, these can add a function of setting wallpaper.
Since the original Android, the system supports setting wallpapers in two ways, one is static wallpaper and the other is dynamic wallpaper.
static wallpaper
There is nothing to say about static wallpapers, and it is done with one line of code through the API provided by the system.
The simplest code is shown below.
val wallpaperManager = WallpaperManager.getInstance(this) try { val bitmap = ContextCompat.getDrawable(this, R.drawable.ic_launcher_background)?.toBitmap() wallpaperManager.setBitmap(bitmap) } catch (e: Exception) { e.printStackTrace() }
In addition to setBitmap, the system also provides setResource, setStream, a total of three ways to set static wallpaper.
The three methods have the same goal, all set a Bitmap to the system API.
dynamic wallpaper
Live wallpapers are a bit interesting. Many mobile phone ROMs also have built-in live wallpapers. Don’t think these are new features. Since Android 1.5, this method has been supported. It’s just that there are fewer people doing it. Why? Mainly because there are no particularly suitable scenes, and dynamic wallpapers consume more power than static wallpapers, so most of the time, we don’t use this method.
As a system service, when the system starts, whether it is a dynamic wallpaper or a static wallpaper, it will run in the background as a Service – WallpaperService, its Window type is TYPE_WALLPAPER, and WallpaperService provides a SurfaceHolder to expose it to the outside world. The picture is rendered, which is the basic principle of setting the wallpaper.
To create a dynamic wallpaper, you need to inherit the system’s WallpaperService and provide a WallpaperService.Engin for rendering. The following is a template code.
class MyWallpaperService : WallpaperService() { override fun onCreateEngine(): Engine = WallpaperEngine() inner class WallpaperEngine : WallpaperService.Engine() { lateinit var mediaPlayer: MediaPlayer override fun onSurfaceCreated(holder: SurfaceHolder?) { super.onSurfaceCreated(holder) } override fun onCommand(action: String?, x: Int, y: Int, z: Int, extras: Bundle?, resultRequested: Boolean): Bundle { try { Log.d("xys", "onCommand: $action----$x---$y---$z") if ("android.wallpaper.tap" == action) { } } catch (e: Exception) { e.printStackTrace() } return super.onCommand(action, x, y, z, extras, resultRequested) } override fun onVisibilityChanged(visible: Boolean) { if (visible) { } else { } } override fun onDestroy() { super.onDestroy() } } }
Then register the Service in the manifest.
<service android:name=".MyWallpaperService" android:exported="true" android:label="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/my_wallpaper" /> </service>
In addition, you need to apply for the appropriate permissions.
<uses-permission android:name="android.permission.SET_WALLPAPER" />
Finally, add a description file in the xml folder, corresponding to the file of the resource tag above.
<?xml version="1.0" encoding="utf-8"?> <wallpaper xmlns:android="http://schemas.android.com/apk/res/android" android:description="@string/app_name" android:thumbnail="@mipmap/ic_launcher" />
Live wallpapers can only be set through the system’s wallpaper preview interface.
val localIntent = Intent() localIntent.action = WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER localIntent.putExtra( WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, ComponentName(applicationContext.packageName, MyWallpaperService::class.java.name)) startActivity(localIntent)
So we can set a live wallpaper.
play with flowers
Since the provided SurfaceHolder is used for rendering, all of our scenes that can use the SurfaceHolder can be used to create dynamic wallpapers.
Generally speaking, there are three common usage scenarios.
- MediaPlayer
- Camera
- SurfaceView
These three are also common usage scenarios for SurfaceHolder.
Let’s first look at MediaPlayer, which is the easiest way to set up a video to loop on the desktop.
inner class WallpaperEngine : WallpaperService.Engine() { lateinit var mediaPlayer: MediaPlayer override fun onSurfaceCreated(holder: SurfaceHolder?) { super.onSurfaceCreated(holder) mediaPlayer = MediaPlayer.create(applicationContext, R.raw.testwallpaper).also { it.setSurface(holder!!.surface) it.isLooping = true } } override fun onVisibilityChanged(visible: Boolean) { if (visible) { mediaPlayer.start() } else { mediaPlayer.pause() } } override fun onDestroy() { super.onDestroy() if (mediaPlayer.isPlaying) { mediaPlayer.stop() } mediaPlayer.release() } }
Next, let’s take a look at using the Camera to refresh the Surface.
inner class WallpaperEngine : WallpaperService.Engine() { lateinit var camera: Camera override fun onVisibilityChanged(visible: Boolean) { if (visible) { startPreview() } else { stopPreview() } } override fun onDestroy() { super.onDestroy() stopPreview() } private fun startPreview() { camera = Camera.open() camera.setDisplayOrientation(90) try { camera.setPreviewDisplay(surfaceHolder) camera.startPreview() } catch (e: IOException) { e.printStackTrace() } } private fun stopPreview() { try { camera.stopPreview() camera.release() } catch (e: Exception) { e.printStackTrace() } } }
At the same time, you need to add the permission of Camera.
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.SET_WALLPAPER" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" />
Due to being lazy here, the latest CameraAPI is not used, and there is no dynamic application for permissions, so you need to manually authorize it yourself.
The last one is self-drawn rendering through Surface.
val holder = surfaceHolder var canvas: Canvas? = null try { canvas = holder.lockCanvas() if (canvas != null) { canvas.save() // Draw Something } } finally { if (canvas != null) holder.unlockCanvasAndPost(canvas) }
Here you can completely use the Canvas API to draw.
Here is a more complex drawing Demo for your reference.
https://www.developer.com/design/building-an-android-live-wallpaper/
interesting way
Although WallpaperService is a system service, it also provides some useful callback functions to help us do some interesting things.
onOffsetsChanged
When the user slides on the mobile phone desktop, some wallpaper pictures will move left and right. This function is realized through this callback. This method will be called back every frame of the gesture sliding.
xOffset: The percentage of the x-axis sliding
yOffset: y-axis sliding percentage
xOffsetStep: progress of the number of pages on the x-axis desktop
yOffsetStep: y-axis desktop Page number progress
xPixelOffset: x-axis pixel offset
Through this function, you can get the movement inertia of the gesture, so as to make some changes to the picture.
onTouchEvent, onCommand
Both of these two methods can obtain the user’s click behavior. By judging the click type, you can do some logic processing for the user’s special click behavior, such as when clicking on some specific places, arouse the App, or open a certain interface, etc. Wait.
class MyWallpaperService : WallpaperService() { override fun onCreateEngine(): Engine = WallpaperEngine() private inner class WallpaperEngine : WallpaperService.Engine() { override fun onTouchEvent(event: MotionEvent?) { // on finder press events if (event?.action == MotionEvent.ACTION_DOWN) { // get the canvas from the Engine or leave val canvas = surfaceHolder?.lockCanvas() ?: return // TODO // update the surface surfaceHolder.unlockCanvasAndPost(canvas) } } } }
How does station B play?
I have to say that Station B is playing with real flowers in this regard. Recently, Station B has added a series of whimsical girls. You can set a live wallpaper with interaction at the same time, which is a bit interesting.
In fact, interactions like this are basically implemented through OpenGL or RenderScript, and rendered through GLSurfaceView, thus realizing some complex interactions. The following examples are some practices.
https://github.com/PavelDoGreat/Unity-Android-Live-Wallpaper
https://github.com/jinkg/live-wallpaper
https://www.cnblogs.com/YFEYI/category/1425066.html
https://code.tutsplus.com/tutorials/creating-live-wallpapers-on-android–mobile-9516
However, the effect of station B is obviously more mature and complete than the above scheme. Therefore, through research, it can be found that they use the Live2D scheme.
The Demo of the live wallpaper is as follows.
https://github.com/Live2D/CubismAndroidLiveWallpaper
This thing is an SDK from Xiaotian, specializing in making 2D interactive paper people. This thing has been out for a long time. Before the front end, it was used as a kanban girl for web pages. Now the client side uses it as a dynamic wallpaper. Feng Shui takes turns. , if you want to use it, you can refer to their official Demo.
However, the official live wallpaper Demo has bugs on the client side, and there will be various flashing problems. Since I don’t understand OpenGL, I can’t solve it. By rolling back Commit, I found that this CommitID can be used directly: Merge pull request # 2 from Live2D/create-new-function, there is no flash problem.
a9040ddbf99d9a130495e4a6190592068f2f7a77
Well, station B YYDS, but I think the usage scenarios of this thing are too limited, and the special card greatly affects the power consumption, so, whether to roll it like this, you can decide.
This article is reproduced from: https://xuyisheng.top/android_wallpaper/
This site is for inclusion only, and the copyright belongs to the original author.