Android Tutorial Android Live Wallpaper tutorial

Using the new LiveWallpaper library you can now create your own live wallpapers. The user can set live wallpapers by long pressing on the home screen and choosing Wallpapers - Live Wallpapers.

Creating a live wallpaper is not too difficult.

A service is responsible for handling the wallpaper events and drawing the wallpaper.

There can be several instances of the same wallpaper at the same time. For example the user can set your wallpaper as the home screen wallpaper and also see a demo of your wallpaper in the wallpaper preview dialog.

LiveWallpaper library contains two objects: LWManager and LWEngine.
LWManager is responsible for raising the events.
The first parameter of each event is of type LWEngine. LWEngine represents a specific wallpaper instance.
LWEngine includes a Canvas property which is used to draw the wallpaper.
When you finish drawing you must call LWEngine.Refresh or LWEngine.RefreshAll. Otherwise the drawing will not appear.

The following example draws a blue background. Red circles are drawn when the user touches the screen:
B4X:
Sub Process_Globals
   Dim lwm As LWManager
End Sub

Sub Service_Create
   lwm.Initialize("lwm", True)
End Sub

Sub LWM_SizeChanged (Engine As LWEngine)
   Engine.Canvas.DrawColor(Colors.Blue)
   Engine.RefreshAll
End Sub

Sub LWM_Touch (Engine As LWEngine, Action As Int, X As Float, Y As Float)
   Engine.Canvas.DrawCircle(X, Y, 20dip, Colors.Red, True, 0)
   Engine.Rect.Left = X - 20dip
   Engine.Rect.Right = X + 20dip
   Engine.Rect.Top = Y - 20dip
   Engine.Rect.Bottom = Y + 20dip
   Engine.Refresh(Engine.Rect)
End Sub
SS-2011-11-15_11.11.45.png


As there could be several different engines, it is convenient to work with the local engine.
LWEngine includes a Tag property which you can use to store data specific to that engine.

LWManager includes an internal timer that you can use if you need to do animations. The Tick event will only be raised for visible wallpapers. This is important to conserve battery.

For example the following code draws the time on the wallpaper:
B4X:
Sub Process_Globals
   Dim lwm As LWManager
End Sub

Sub Service_Create
   lwm.Initialize("lwm", True)
   lwm.StartTicking(1000) 'tick every second
End Sub

Sub LWM_Tick (Engine As LWEngine)
   Engine.Canvas.DrawColor(Colors.Black) 'Erase the background
   Engine.Canvas.DrawText(DateTime.Time(DateTime.Now), _
      300dip, 100dip, Typeface.DEFAULT_BOLD, 40, Colors.White, "LEFT")
   Engine.RefreshAll
End Sub
SS-2011-11-15_11.23.06.png


Offsets
On most devices the wallpaper virtual size is wider than a single screen. When the user moves to a different screen the offset changes.
You can use the OffsetChanged event to handle those changes.
LWEngine.FullWallpaperWidth / Height return the full size of the wallpaper.
LWEngine.CurrentOffsetX / Y return the current position.
Note that the wallpaper scrolls less than the foreground layer with the icons.

The LiveWallpaperImage demonstrates how to use those properties to display an image over the full wallpaper.

LWManager events

SizeChanged - Raised when the engine is first ready and when the screen size changes (for example when the orientation changes).
VisibilityChanged - Raised when a wallpaper becomes visible or invisible.
Touch - Raised when the user touches the wallpaper.
Tick - The internal timer tick event.
OffsetChanged - Raised when the wallpaper offsets change.
EngineDestroyed - Raised when an engine is destroyed.

Configuration
Live wallpapers require some configuration.
1. You should add the inner service declaration to the manifest editor (Project -> Manifest Editor):
B4X:
AddApplicationText(
<!-- ******** Add the internal service declaration - you can change android:label  ******* -->
<service
        android:label="My Livewallpaper"
        android:name="anywheresoftware.b4a.objects.WallpaperInternalService"
        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/wallpaper" />
</service>
)
It is also recommended to change minSdkVersion to 7 (at the beginning of the manifest editor code).

2. Add wallpaper.xml to Objects\res\xml folder and set it to be readonly (otherwise it will be deleted during compilation).
You can find this file in both attached examples.

3. Your service must be named WallpaperService. Note that there is an additional service inside the library named anywheresoftware.b4a.objects.WallpaperInternalService. The internal service connects to your service.

Examples
LiveWallpaperImage - The user can select an image from the activity. This image is set as the wallpaper. When the user changes the wallpaper offset the image is updated accordingly.

LiveWallpaperBall - A bouncing smiley. Clicking on the smiley will change its direction.
Before running the examples you need to set Object\res\xml\wallpaper.xml to be readonly. Otherwise it will be deleted.

Note that it is recommended to test live wallpapers in Release mode (the wallpaper will fail in debug mode when the process is started by the OS).
 

Attachments

  • LiveWallpaperBall.zip
    8.3 KB · Views: 2,225
  • LiveWallpaperImage.zip
    8 KB · Views: 2,432
Last edited:

holdemadvantage

Active Member
Licensed User
Longtime User
I have to debug wireless to the phone. In the log all that i see is
B4X:
LogCat connected to: B4A-Bridge: samsung SM-N9005-359093057791073
--------- beginning of /dev/log/main
** Activity (main) Create, isFirst = false **
running waiting messages (1)
** Activity (main) Resume **
** Service (service1) Destroy **
** Service (service1) Create **
** Service (service1) Start **
** Service (service1) Destroy **
** Service (service1) Create **
** Service (service1) Start **
Connected to B4A-Bridge (Wifi)
Installing file.
** Activity (main) Pause, UserClosed = false **
PackageAdded: package:anywheresoftware.b4a.samples.livewallpaperimage
** Activity (main) Create, isFirst = true **
main_activity_create (B4A line: 24)
Activity.LoadLayout("1")
java.io.FileNotFoundException: 1.bal
    at android.content.res.AssetManager.openAsset(Native Method)
    at android.content.res.AssetManager.open(AssetManager.java:316)
    at android.content.res.AssetManager.open(AssetManager.java:290)
    at anywheresoftware.b4a.objects.streams.File.OpenInput(File.java:191)
    at anywheresoftware.b4a.keywords.LayoutBuilder.loadLayout(LayoutBuilder.java:75)
    at anywheresoftware.b4a.objects.ActivityWrapper.LoadLayout(ActivityWrapper.java:204)
    at anywheresoftware.b4a.samples.livewallpaperimage.main._activity_create(main.java:322)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:170)
    at anywheresoftware.b4a.samples.livewallpaperimage.main.afterFirstLayout(main.java:98)
    at anywheresoftware.b4a.samples.livewallpaperimage.main.access$100(main.java:16)
    at anywheresoftware.b4a.samples.livewallpaperimage.main$WaitForLayout.run(main.java:76)
    at android.os.Handler.handleCallback(Handler.java:730)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:5450)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1187)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
    at dalvik.system.NativeStart.main(Native Method)
java.io.FileNotFoundException: 1.bal
** Activity (main) Resume **
Installing file.
** Activity (main) Pause, UserClosed = false **
PackageAdded: package:anywheresoftware.b4a.samples.livewallpaperimage
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
** Service (wallpaperservice) Create **
** Service (wallpaperservice) Start **
** Service (wallpaperservice) Destroy **
Installing file.
PackageAdded: package:anywheresoftware.b4a.samples.livewallpaperimage
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
** Service (wallpaperservice) Create **
** Service (wallpaperservice) Start **
** Service (wallpaperservice) Destroy **
Installing file.
PackageAdded: package:anywheresoftware.b4a.samples.livewallpaperimage
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
sending message to waiting queue (OnActivityResult)
running waiting messages (1)
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
** Service (wallpaperservice) Create **
** Service (wallpaperservice) Start **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = true **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = true **
** Service (wallpaperservice) Destroy **
Installing file.
PackageAdded: package:anywheresoftware.b4a.samples.livewallpaperimage
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
** Service (wallpaperservice) Create **
** Service (wallpaperservice) Start **


with no error, when i go to Live Wallpaper and then click on settings i see this

Screenshot1.png
 

holdemadvantage

Active Member
Licensed User
Longtime User
Ye it works, thanks a lot!!! :)

Tho questions:

1) for some reason one of my project did't restart the LWP when i restart the phone. I have to set it again. The manifest is

B4X:
'This code will be applied to the manifest file during compilation.
'You do not need to modify it in most cases.
'See this link for for more information: http://www.b4x.com/forum/showthread.php?p=78136
AddManifestText(
<uses-sdk android:minSdkVersion="4" />
<supports-screens android:largeScreens="true"
    android:normalScreens="true"
    android:smallScreens="true"
    android:anyDensity="true"/>)
SetApplicationAttribute(android:icon, "@drawable/icon")
SetApplicationAttribute(android:label, "$LABEL$")
'End of default text.

AddApplicationText(
<!-- ******** Add the internal service declaration - you can change android:label  ******* -->
<service
        android:label="Christmas 2014 LiveWallpaper"
        android:name="anywheresoftware.b4a.objects.WallpaperInternalService"
        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/wallpaper" />
</service>
<!-- End of internal service declaration -->
)
SetActivityAttribute(main1, android:exported, true)

should i add some line to do it?

2) in Settings i select a background image, the name is saved in a text file
Into Service_create i read this name and set the new background image. It doesn'c change , is there a way to restart wallaper service ? i have to destroy it and call service_create?
 

holdemadvantage

Active Member
Licensed User
Longtime User
2) in Settings i select a background image, the name is saved in a text file
Into Service_create i read this name and set the new background image. It doesn'c change , is there a way to restart wallaper service ? i have to destroy it and call service_create?
Problem 2 solved, i call saved settings into LWM_OffsetChanged and not into Service_Create and it works

But problem 1 is still alive, the LWP didn't remain after a restart of the phone, i have to select it another time
 

sorex

Expert
Licensed User
Longtime User
Sorry for the n00By question but I never found the need to install a live wall paper.

I compiled'n ran the app over usb on my phone and I was able to select an image and set it.

I read Erel's tip on how to add the LWP as "running" LWP but...

On my phone which runs 2.2...

when I long press the home I get some kind of overview of the last used apps
and a link to a taskmanager app

When I long press the background I get "Add to home screen" with the options
Widgets, Shortcuts, Folder, Wallpapers. No Live Wallpapers either.

According to http://www.webopedia.com/TERM/A/android_live_wallpaper.html
it is supported since 2.1 so it should work.

So what am I missing here?
 

sorex

Expert
Licensed User
Longtime User
solved it.

if anyone has the same issue this is what you need to do..

root your phone (search for super one click)
copy the LivewallpapersPicker.apk to /system/app (I used Total Commander for it since I'm used to it from PC)

now when pressing the background and select Wallpapers there's a Live Wallpapers option.

now I'm gone to test the possibilities of these LWP :)
 

jroriz

Active Member
Licensed User
Longtime User
You can only draw on LiveWallpapers.

I'd like to set a webpage as wallpaper...

Is there a way, maybe, to save a snapshot of the page, and then set this snapshot as the wallpaper?
 

ChrisH

Member
Licensed User
Longtime User
Yes, it is possible.
You have two options:
- You can update the live wallpaper from a regular activity as done in LiveWallpaperImage.
- You can also add a special settings activity and then the user will have a "settings" button in the preview screen.
You should edit wallpaper.xml and add the full activity name:
B4X:
<?xml version="1.0" encoding="utf-8"?>
<wallpaper xmlns:android="http://schemas.android.com/apk/res/android"
  android:thumbnail="@drawable/icon"
  android:settingsActivity="anywheresoftware.b4a.samples.livewallpaperimage.main"
/>

Hello Erel, I am confused now.
Should this really be done via the "common" main activity?
I thought to stay Android compliant it should be done with the Preferences screen and maybe using statemanager object....(?).
( http://www.b4x.com/android/forum/threads/preferenceactivity-tutorial.10608/ )
Many thanks for a short answer....
 

ChrisH

Member
Licensed User
Longtime User
Hello Erel, Many thanks. I interpret your message to mean, that both versions are "valid". My problem is, that I do not get the settings button (in preview mode) even if I enter the
B4X:
.....android:settingsActivity="xyz.packagename.abs.Main"
(my main activity is uppercase) directive to the wallpaper.xml file as described above. Is this statement really the only thing that should be necessary?
 

wahyuway

Member
Licensed User
Longtime User
Hi erel,
I'm just new to B4A, before i used to use eclipse alot to dev my apps.

I created LWP, then use setting preference. I made several setting option.
How can i refresh the option i choose into Live Wallpaper Preview automatically?

Tks
 

wahyuway

Member
Licensed User
Longtime User
Hi erel, i've already done that. Thank you for your help. Now my animation works in preview mode.
 
Top