Android Tutorial Android home screen widgets tutorial - part I

Status
Not open for further replies.
Edit: widgets are handled with receivers now. See the attached example.

This tutorial will explain how to implement your own home screen widgets (also named App Widgets).

It is important to understand that the widgets are created and managed in another process, different than the process that your application is running in. The home screen application is hosting your widgets.
This means that it is not possible to directly access the widgets views. Instead we are using a special object named RemoteViews which gives us indirect access to the widget views.

Widgets do not support all views types. The following views are supported:
- Button (default drawable)
- Label (ColorDrawable or GradientDrawable)
- Panel (ColorDrawable or GradientDrawable)
- ImageView
- ProgressBar (both modes)

All views support the Click event and no other event.

The widget layout and configuration must be defined with XML files. During compilation Basic4android reads the layout file created with the designer and generates the required XML files.

Each widget is tied to a Service module. Through this module the widget is created and updated.

Creating a widget - step by step guide

- Add a Service module. Note that the service module handling the widget is a standard service.
- Design the widget layout with the designer. First add a Panel and then add the other views to this Panel.
The widget layout will be made from this panel.
- Add code similar to the following code the service module:
B4X:
Sub Process_Globals
    Dim rv As RemoteViews
End Sub

Sub Service_Create
    rv = ConfigureHomeWidget("LayoutFile", "rv", 0, "Widget Name")
End Sub

Sub Service_Start (StartingIntent As Intent)
     RV.HandleWidgetEvents(StartingIntent)
    Sleep(0)
    Service.StopAutomaticForeground
End Sub

Sub rv_RequestUpdate
    rv.UpdateWidget
End Sub

Sub rv_Disabled
    StopService("")
End Sub

Sub Service_Destroy

End Sub
- Compile and run your application. Go to the home screen, long press on the screen and you will see your widget listed on the widgets list.

ConfigureHomeWidget is a special keyword. At runtime it creates the RemoteViews object from the layout and set the events. At compile time the compiler generates the required files based on the arguments of this keyword.
The four parameters are: layout file, event name, update interval and the widget name.
Event name sets the subs that will handle the RequestUpdate and Disabled events.
The widget can be configured to update itself automatically. The interval, measured in minutes, defines how often will the widget request to update itself. Set to 0 to disable automatic updates. Updating the widget too often will have a bad impact on the battery. The minimum value is 30 minutes.
Widget name - the name that will appear in the widgets list.

As these arguments are read by the compiler, only strings or numbers are accepted.

Events:
B4X:
Sub Service_Start (StartingIntent As Intent)
    If rv.HandleWidgetEvents(StartingIntent) Then Return
End Sub
The above code checks the Intent message that caused this service to start and is responsible for raising the events related to the widget. It returns true if an event was raised.
The widget raises two events. RequestUpdate is raised when the widget needs to update itself. It will fire after adding the widget to the screen, after the device has booted, based on the scheduled updating interval (if set) or after the application was updated.
The Disabled event is raised when the last instance of our widget is removed from the screen.

As mentioned above all views support the Click event. All that needs to be done in order to handle the click event of a button named Button1 is to add a sub named Button1_Click (the sub name should actually match the EventName property which is by default the same as the name).

[/code]Modifying the widget:
It is not possible to directly access the widget views. Instead we need to use one of the RemoteView.Set methods.
If we want to change the text of a label named Label1 then we need to write the following code:
B4X:
rv.SetText("Label1", "This is the new text.")
'do more changes if needed
rv.UpdateWidget
After writing all the changes we call rv.UpdateWidget to send the updates to the widget.

A simple example is attached.
The example adds a simple widget. The widget doesn't do anything useful.
SS-2011.07.11-12.55.04.png

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

Attachments

  • HomeWidgets.zip
    24.6 KB · Views: 797
Last edited:

alfcen

Well-Known Member
Licensed User
Longtime User
Hi
I believe the following is rather related to my phone. Anyway, perhaps there is someone out there
knowing of this and then I'd appreciate a reply.

There are two widgets, one 160 x 200, another 160 x 100. Both show the expected proportions on the scale=2 screen.
Now when I try to move the Sun widget over to the screen where the moon widget is located, then I get an error
insisting that there is insufficient space on the screen, which is obviously not true, since the smaller widget
should fit perfectly underneath the larger.

Nothing life-critical, but if anyone has an idea please be so kind as to share it with me.

Thanks
Robert


sunwidget.png



moonwidget.png
 
D

Deleted member 103

Guest
Hi Robert,

There are two widgets, one 160 x 200, another 160 x 100. Both show the expected proportions on the scale=2 screen.
Now when I try to move the Sun widget over to the screen where the moon widget is located, then I get an error
insisting that there is insufficient space on the screen, which is obviously not true, since the smaller widget
should fit perfectly underneath the larger.
Ich glaube das ist normal, das gleiche passiert bei andere widget auch.

I think this is normal, the same happens with other widget as well.

Dein widget sieht einfach geil aus. :sign0098:
Your widget simply looks cool.


Ciao,
Filippo
 

alfcen

Well-Known Member
Licensed User
Longtime User
Ciao Filippo

Danke bestens fuer Deine Ansicht. Ich hoffe immer noch, dass ich irgendwas uebersehen habe. Widgets von anderen Anbietern werden nicht abgelehnt, also muss bei mir was falsch laufen. Vielleicht sollte ich die beiden widgets in eines packen.

Thanks a lot for your thoughts. Still hoping that I did overlook something. Third party widgets are not refused by the home screen, thus something went wrong on my side. Perhaps I should pack both widgets into a single widget.

Ciao
Robert
 

alfcen

Well-Known Member
Licensed User
Longtime User
Thanks a lot, Andrew, I just tried this.

Indeed, both widgets can then be placed onto the same home screen with penalty in size, thus readability, though.

Since both widgets, after this size correction, do not align (snap) next to each other, I decided to merge them into a single widget - a fine compromise.

all-in-one-widget.png
 

corwin42

Expert
Licensed User
Longtime User
Thanks a lot, Andrew, I just tried this.

Indeed, both widgets can then be placed onto the same home screen with penalty in size, thus readability, though.

There is some confusion with Android widget sizes even in the Android documentation. For Portrait, one documentation says that the cell size is 80x100. In another documentation you will find a formula that the maximum size should be calculated with the formula mentioned by Andrew.

In reality it is true that the cell size is 80x100 (portrait) but in a low resolution device (240x320) the cells will overlap then. If you want to use the full size in B4A you will have to tweak the generated XMLs and make them read only.

I do the following:

Change the MinWidth and MinHeight properties in Objects\res\xml\<widget>_info.xml to values calculated by the formula.

Additionally I add two surrounding LinearLayouts with CENTER_HORIZONTAL and CENTER_VERTICAL to the widget layout files so the widget gets centered correctly on the homescreen.

If you want to get most out of the available space you have to tweak the XMLs manually. Even a different layout for landscape mode is only possible creating a layout-land folder and putting a second layout for landscape there. I hope Erel will improve the widget support in the future.

Though B4A does not support everything directly you can get what you want with some tricks. :)
 

alfcen

Well-Known Member
Licensed User
Longtime User
Yes, Corwin, the Android documentation is everything else but conclusive on this issue. Personally, I am not really content with the idea of tweaking the XML manually. It should not make any difference whether you enter the widget panel dimensions manually or have this job performed by B4A as long as the dimensions comply to the Android standard.

Anyway, as you wrote, there is always a workaround. It appears to be good practice to leave a thin transparent frame around the widget panel. I will tinker a bit more with dimensions but I am sure that Erel will come up with something magnificent before I'm getting smart.

After all, widgets are pretty exciting considering they could be designed as parent-independent applications for the home screen.

The widget on the screen snap in my last post is 160 x 300dips. I can place third party widgets around it without any issues. Since my phone does not assume landscape mode, I can't tell.

Thanks a lot for your thoughts,

Robert
 

corwin42

Expert
Licensed User
Longtime User
The widget on the screen snap in my last post is 160 x 300dips. I can place third party widgets around it without any issues.

Are you shure? I think that this dimensions will create a 3x4 size widget and not 2x3 as you want to have.
 

alfcen

Well-Known Member
Licensed User
Longtime User
Hi Markus,
Hmm, the screen snap shows correct and as expected. The phone is equipped with a 640 x 960px scale = 2 display. Looks to me like a 2 x 3 widget.
 

corwin42

Expert
Licensed User
Longtime User
Hi Markus,
Hmm, the screen snap shows correct and as expected. The phone is equipped with a 640 x 960px scale = 2 display. Looks to me like a 2 x 3 widget.

Hmm, perhaps it fits on a scale=2 device. Try your app on a smaller screen with 320x480 and I bet it will create a 3x4 widget.

Have you tried to delete the widget and create it again? If the widget was placed in an older (smaller) version it does not change size.
 

alfcen

Well-Known Member
Licensed User
Longtime User
Thanks for looking deeper into this, Markus.
I do not have a small screen device for testing.
The widget is made with the Designer on a 320x480 layout. My scale=2 phone stretches it correctly, so, I expect (hope) that Android scales the widget on scale=1 or scale=1.5 phones as advertised.
Actually, my widget measures 160 x 270 pixels, not exactly a multiple of widget cells, but it does show correct. Removal/recreation...no difference. Third party (small widgets) fit underneath.
I do understand and agree with your worries about other phone scales, but, sorry I am unable to test.
 

JesseW

Active Member
Licensed User
Longtime User
On a side note, I also do my designing and initial testing on an HVGA (320x480) emulator, but I also test on a QVGA (240x320) emulator just to be sure buttons aren't hidden, etc...
 

alfcen

Well-Known Member
Licensed User
Longtime User
Thanks a lot, Jesse.
Well, my widget sized as-is won't fit on a 240 x 320 screen, unless Android would scale it down to 0.5
Apart from that, what is the share of QVGA Android phones? How many are out there?
 

JesseW

Active Member
Licensed User
Longtime User
I understand the % of qvga phones is nil to nonexistent... My rationale is an extra minute or two of testing might help prevent a bad rating or two. I've actually found a few gotchas doing this...
 

valerio

New Member
hello! how i can use RemoteViews? there is a particular lib? when i compiling your source code the program give me this:
Compiling code. Error
Error parsing program.
Error description: Unknown type: remoteviews
Are you missing a library reference?
Occurred on line: 3
Dim rv As RemoteViews
 

valerio

New Member
well, now i've the full version of basic4android but the program gives me the same error. I have to include some library?:BangHead:
 
Status
Not open for further replies.
Top