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,239
  • LiveWallpaperImage.zip
    8 KB · Views: 2,453
Last edited:

Prosg

Active Member
Licensed User
Longtime User
Hello,

Question 1 :
Is it possible in the first launch of the application to set the Live Wallpaper as default rather than tell users to put it themselves?

Question 2 :
I dw the image Live wallpaper example and is it normal than the picture choosen disapear after a few minutes?
 
Last edited:

NeoTechni

Well-Known Member
Licensed User
Longtime User
As for question 1, this sub will open the live wallpaper selector dialog.
You can't change it yourself

B4X:
Sub LWPselector As Boolean 
   Dim Intent1 As Intent
   Try
      Intent1.Initialize(Intent1.ACTION_MAIN, "")
      If APIlevel<15 Then
         Intent1.SetComponent("com.android.wallpaper.livepicker/.LiveWallpaperListActivity")
      Else
         Intent1.SetComponent("com.android.wallpaper.livepicker/.LiveWallpaperActivity")'this will work for android 4.0.4
      End If
      StartActivity(Intent1)
      Return True
   Catch
      Return False
   End Try
End Sub
 

Prosg

Active Member
Licensed User
Longtime User
thx for your help :)

Error description: Undeclared variable 'apilevel' is used before it was assigned any value.

Is apilevel come from a library ? i don't find in the forum where ?

forget it i find your code :

B4X:
Sub APIlevel As Int 
    Dim r As Reflector
    Return r.GetStaticField("android.os.Build$VERSION", "SDK_INT")
End Sub
Sub LWPselector 
    Dim Intent1 As Intent
    Intent1.Initialize(Intent1.ACTION_MAIN, "")
    If APIlevel<15 Then
        Intent1.SetComponent("com.android.wallpaper.livepicker/.LiveWallpaperListActivity")
    Else
        Intent1.SetComponent("com.android.wallpaper.livepicker/.LiveWallpaperActivity")'this will work for android 4.0.4
    End If
    StartActivity(Intent1)
End Sub
 
Last edited:

NeoTechni

Well-Known Member
Licensed User
Longtime User
Oops. Ive left home so i cant get it for you at the moment but im sure the code to get android's apilevel is on here somewhere. Sorry
 

Prosg

Active Member
Licensed User
Longtime User
Question 2 :
I dw the image Live wallpaper example and is it normal than the picture choosen disapear after a few minutes?

for this it's like the service restart automaticly every 5 mn because if i have no "default picture" i have a black screen and if i have this

B4X:
Sub Service_Create
   lwm.Initialize("lwm", False)
   image = LoadBitmap(File.DirAssets, "fond-appli.png")
End Sub

i have this picture reload

Don't know how to fix that ?

Is that correct that when you switch on your phone it's Sub Service_Create again ?

i believed that Sub Service_Create was only to the installation of the app
 
Last edited:

Prosg

Active Member
Licensed User
Longtime User
2 problems

Problem 1 :
I use LiveWallpaperImage.zip and with my SIII when the image is in wallpaper and when i change panel (to move between application) all works fine
I give my apk at 2 friends :
- sony
- SII
and when they move into panel, the wallapaper image move too... and it's horrible :p
Can i said to this wallpaper : DONT MOVE :p

Problem 2 :
When user choose my liveWallpaper as default wallpaper (.LiveWallpaperListActivity) i don't understand why it's not middle ?

bug.jpg





Thx for help
 
Last edited:

Prosg

Active Member
Licensed User
Longtime User
i think you want me to find this :p

The offset_changed event actually implements the scrolling. You can remove it (or always draw the same image relatively to 0, 0 instead of CurrentOffsetX, Y.

is that i have to do ?

B4X:
    Engine.Rect.Left = -0
        Engine.Rect.Top = -0
        Engine.Rect.Right = -0 + Engine.FullWallpaperWidth
        Engine.Rect.Bottom = -0 + Engine.FullWallpaperHeight
        Engine.Canvas.DrawBitmap(resized, Null, Engine.Rect)

cause the picture is not correct :)
 

Prosg

Active Member
Licensed User
Longtime User
Dim ivs() As ImageView



ivs = Array As ImageView(ImageView1, ImageView2, ImageView3, ImageView4, _
ImageView5, ImageView6, ImageView7, ImageView8, ImageView9)

i use If Job.Success = True AND ImageIndex <= 8

B4X:
Sub ImagesJobDone (Job As HttpJob)
   If Job.Success = True AND ImageIndex <= 8 Then
      ivs(ImageIndex).Bitmap = Job.GetBitmap
      ivs(ImageIndex).Gravity = Gravity.FILL
      ivs(ImageIndex).Tag = Job.myParam
   End If
   ImageIndex = ImageIndex + 1
   ProgressDialogHide
End Sub
 
Last edited:

Prosg

Active Member
Licensed User
Longtime User
why can't we change this name in the manifest ?

android:name="anywheresoftware.b4a.objects.WallpaperInternalService"

To check the name of the current wallppaper i do this :
B4X:
'SetWallPaper(LoadBitmap(File.DirInternal, myImageName))
    Dim r As Reflector
    r.Target = r.RunStaticMethod("android.app.WallpaperManager", "getInstance", _
        Array As Object(r.GetContext), Array As String("android.content.Context"))
    Dim bg As String
    bg = r.RunMethod("getWallpaperInfo")
    Msgbox( bg,"")

it's return this :
WallpaperInfo{anywheresoftware.b4a.objects.WallpaperInternalService, settings: null}


As i want to check what is the current wallpaper to launch the lwpSelector if it's not my wallpaper this name could be a problem if the current wallpaper is another B4a devellopper.
 

sdixon

Member
Licensed User
Longtime User
problem with the LiveWallpaperImage examples

I downloaded both the ball and image samples in the LiveWallpaper tutorial (this thread) and cannot get the image sample to work (either on my phone or one of the many emulators).

B4X:
Sub ImageChanged
   If File.Exists(File.DirInternal, ImageName) Then
      Image = LoadBitmap(File.DirInternal, ImageName)
      If LiveEngine.IsInitialized Then 
         LWM_OffsetChanged(LiveEngine)
      End If
   End If
End Sub

When run in debug, the LiveEngine is never initialized and for the life of me I can't see where it needs to be initialized, or for that fact, how to initialize that object.

Has anyone had a similar problem and if you did, how did you resolve it?

Thanks
 

sdixon

Member
Licensed User
Longtime User
Yes I did. The image is given to the service correctly. (or at least appears to be).

Upon further investigation is appears that when I long click on the main screen and bring up the Wallpapers | Live Wallpapers I can set the background of the device, but it is still not what I want to do.

As I explained in the 'static wallpaper' thread, I want to have an image in my app, re-size it to the dimensions of the device and set that as the background (wallpaper).

pls help

Thanks
 

Attachments

  • test.zip
    165.1 KB · Views: 337
Last edited:

sdixon

Member
Licensed User
Longtime User
still not getting it

The WallpaperService starts up fine (according to the logs) but all I'm getting in the Live Wallpaper is the yellow background.

pressing on the image
B4X:
Sub imgCard_LongClick
   Dim TheFileName As String
   TheFileName = f.Sprintf("rw_%d.jpg", Array As Object(CurrentPage))
   SetWallPaper(TheFileName)
End Sub
which passes a valid file name to
B4X:
Sub SetWallPaper(aName As String)
  File.Copy(File.DirAssets, aName, File.DirInternal, WallpaperService.imageName)
   CallSub(WallpaperService, "ImageChanged") 'notify the service that the image was changed
   Vibrate.Vibrate (50) ' Vibrate phone for 50 ms
  ToastMessageShow(wpWallpaperSet, False)
End Sub
which then calls
B4X:
Sub ImageChanged
   If File.Exists(File.DirInternal, ImageName) Then
      If LiveEngine.IsInitialized Then
         Dim Bmp As Bitmap
         Dim intHeight As Int
         Dim intWidth As Int
         Bmp = LoadBitmap(File.DirInternal, ImageName)
         intHeight = LiveEngine.FullWallpaperHeight
         intWidth = (Bmp.Width * intHeight) / Bmp.Height
         Bmp = CreateScaledBitmap(Bmp, intWidth, intHeight, False)
         Image.Initialize3(Bmp)
         LWM_OffsetChanged(LiveEngine)
      End If
   End If
End Sub
scales the bitmap to the size of the device
B4X:
Sub CreateScaledBitmap(Original As Bitmap, Width As Int, Height As Int, Filter As Boolean) As Bitmap
   Dim r As Reflector
   Dim b As Bitmap
   b = r.RunStaticMethod("android.graphics.Bitmap", "createScaledBitmap", _
   Array As Object(Original, Width, Height, Filter), _
   Array As String("android.graphics.Bitmap", "java.lang.int", "java.lang.int", "java.lang.boolean"))
   Return b
End Sub
places the bitmap as the wallpaper
B4X:
Sub LWM_OffsetChanged(Engine As LWEngine)
   If Image.IsInitialized Then
      Dim intWidth As Int
      Dim intLeft As Int
      Dim intRight As Int
      Dim intBottom As Int
      
      intWidth = Image.Width
      intLeft = ((Engine.FullWallpaperWidth / 2) - intWidth) / 2
      intRight = intLeft + intWidth
      intBottom = Engine.FullWallpaperHeight
      Engine.Rect.Left = intLeft
      Engine.Rect.Top = 0
      Engine.Rect.Right = intRight
      Engine.Rect.Bottom = intBottom
      Engine.Canvas.DrawBitmap(Image, Null, Engine.Rect)
   Else
      Engine.Canvas.DrawColor(Colors.Yellow)
   End If
   Engine.RefreshAll
End Sub
However, all I get to see in the LiveWallpaper is a yellow background
B4X:
         Else
      Engine.Canvas.DrawColor(Colors.Yellow)
In debug I can step through all of the code and it runs properly through each line of code, except there is no image placed in the LiveWallpaper and all I get is a yellow background.

I've also attached my manifest file.

Does anyone have any idea why this isn't working?

Thanks :BangHead::BangHead:

added later:

If I leave my app running the wallpaper is displayed properly. The question now is, how do I leave the wallpaper on the phone after turning my app off?
 

Attachments

  • AndroidManifest.xml.txt
    3 KB · Views: 285
Last edited:

shashkiranr

Active Member
Licensed User
Longtime User
Unable to open any live wallpaper application

Hi ,

I am getting the below error when ever i try to open the live wallpaper examples.

I am using B4a 2.52 and livewallpaper v1.01

Kindly let me know how to resolve this issue.


java.lang.NoSuchFieldError: anywheresoftware.b4a.BA.isService
at anywheresoftware.b4a.objects.WallpaperInternalServ ice$LWManager.Initialize(WallpaperInternalService. java:62)
at anywheresoftware.b4a.samples.livewallpaperball.wal lpaperservice._service_create(wallpaperservice.jav a:234)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:165)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:149)
at anywheresoftware.b4a.samples.livewallpaperball.wal lpaperservice.onCreate(wallpaperservice.java:38)
at android.app.ActivityThread.handleCreateService(Act ivityThread.java:2264)
at android.app.ActivityThread.access$1600(ActivityThr ead.java:127)
at android.app.ActivityThread$H.handleMessage(Activit yThread.java:1212)
at android.os.Handler.dispatchMessage(Handler.java:99 )
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.jav a:4511)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCa ller.run(ZygoteInit.java:980)
at com.android.internal.os.ZygoteInit.main(ZygoteInit .java:747)
at dalvik.system.NativeStart.main(Native Method)



Thanks,
SK
 
Top