Sunday, February 9, 2014

A Mission to Android - Registering the Widget

If you recall I have created the classes for my widget and have created a basic layout. Although the code in github already contains all necessary code snippets for running the widget I still have not officially added the widget provider meta data and registered the widget in the android manifest. So lets dive into today's post and complete the walk through of the basics for a widget.

Overview

In today's post we will provide the meta data for our widget and register the widget with android. After this post all elements for a widget should be in place and you should have a very basic widget running. You should have a clear understanding of the metadata for the widget and how widgets are registered in the manifest file.

The Widget Provider Meta File

Before adding the widget to the manifest android has to know what my widget looks like and where it can find it. This is done with the appwidget-provider file. This file describes to android how the widget is to be initially displayed and what dimension the widget has. Further it provides an icon to be displayed in the widget selection screen. This is also the place to describe where the widget can be added.

Let's have a look at a basic file and go over it step for step.

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
                    android:minHeight="120dp"
                    android:minWidth="120dp"
                    android:previewImage="@drawable/ic_launcher"
                    android:updatePeriodMillis="0"
                    android:initialLayout="@layout/clock_layout"
                    android:widgetCategory="home_screen|keyguard"
                    android:initialKeyguardLayout="@layout/clock_layout">
</appwidget-provider>

In line 2 and 3 the minimum height and minimum width of the widget is described. This will determine how many cells the widget takes up on the screen. The size of a cell is determined by the size of the screen and its density. To be compatible on all android devices your widget should never be bigger then 4x4 cells as this is the bare minimum each android device has to support. From there you can always make your widget scalable (Android SDK Level > 13). If you use higher sizes your widget might not be available on all devices so make sure to check your target devices. Although not done in the above example it is a good idea to externalize the dimension to the dimens.xml file and provide adapted ones for different target devices.

In line 4 I provide the launcher icon for my widget. This is an iconic view displayed in the widget selection activity. It should indicate to the user what kind of widget he is about to add to his desktop. Additionally this launcher icon's outline is used to show the user where the widget is placed on the screen.

Line 5 specifies the update interval at which your widget is automatically updated by the OS. Once this period has passed android will send an update event to your widget. This interval is not intended to do short term updates and allows as a minimum value 30 minutes. Any update intervals below this have to be done manually via the AlarmManager or by using a Handler in your code.

Line 6 specifies the initial layout for your widget. Android will inflate this layout and use it to depict your widget until your classes have been initialized and custom code has been executed. So be sure to have a nice default layout or present a "widget loading" layout until the widget has been initialized and your code can present the actual widget.

Line 7 specifies where your widget can be added. At the current time the options are:

  • home_screen - the widget can be added to the home screen
  • keyguard - the widget can be added to the lock screen.
You can combine the two options using the "|" operator.

If you specify keyguard you can specify a separate initial layout for the lock screen using android:initialKeyguardLayout. For now I simply use the same layout for the lock screen as I use for the home screen (Line 8).

Registering the Widget

With the app widget provider file in place I'm all set to add the widget to the android manifest. As we recall from the beginning a widget is nothing else but a special intent receiver. So in order to get the widget selectable through android we need to register it in the AndroidManifest.xml as a receiver and specify that it will receive widget update events. These update events will cause the widgets onUpdate method to be called and trigger our layout logic. Taking our manifest file from "A Mission to Android - Creating a Widget" we simply add the receiver as follows:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="de.element34.e34clock"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        
        <receiver
            android:name=".E34ClockWidget"
            android:label="@string/widget_label">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/e34clock_widgetprovider" />
        </receiver>
    </application>

</manifest>

Intents

Intents are the cardiovascular system of android. They provide the means to communicate between components (activities, services receivers) or to setup a tight bindings between processes. As they are a huge topic on their own I will provide a separate post about them in the future. For now we can think of an Intent as a container to carry data to components.

Lines 17 and 18 specify the class representing the widget and the label it will appear under. As a good android developer I have externalized the label of course ;-). For the class we can either specify the complete class name or when the package of the class is the same as the package specified in the manifest (Line 2) we can simply leave that part of and specify the rest of the package and the class name starting with a dot. Android will automatically add the appropriate package when looking up the class.

Line 22 to 24 tell android where it can find the app widget provider file. This data is used by android to add the widget to the widget selection dialog and make it available to the user. If you do not specify this section the widget will never be displayed in the widget selection dialog.

Line 19 to 21 register the receiver for the APPWDIGET_UPDATE intent which provides the glue between android and our code. Whenever somebody adds a widget to the home screen or the OS needs to update the widget a APPWIDGET_UPDATE event is sent. Our class will then convert this event into a call to the appropriate on-method call allowing customization in code.

Summary

First we created the necessary classes. Then we created the layout and now we have create the widget provider file and added it to the manifest. All parts have been put in place and the widget can now be deployed to a device. Running it on the emulator results in

Resources

You can find further and more detailed information about developing widgets at App Widgets | Android Developers. The section on AppWidgetProviderInfo describes the widget meta data in details.

Outlook

In future posts I will go into details about certain aspects of my widget. The things I plan on covering are using services to update widget informations, creating custom intents to transfer this information between the different widgets. Making sure that the widget doesn't drain battery by switching it off when it is not displaying.

As always if you like this post or you have criticism, found errors or have suggestions feel free to contact me. I'm always happy to hear from you.

Yours truely

Stefan Langer

Creative Commons License

No comments:

Post a Comment