Hello Widget

Introduced in Android 1.5 (Cupcake), widgets are miniature application views that can be embedded in the Home screen. A few widgets are provided with Android including an analog clock, a music controller, and one that just shows a picture. Many developers have created interesting widgets to display the weather, news headlines, horoscopes, and more, and you can too. This section will show you how.

Creating Your First Widget

For this example we're going to create a widget that shows today's date. If you'd like a peek at the final result, see Figure 12.5, on page 242.

unfortunately, there is no special Eclipse wizard for making a widget, so we'll first create a regular "Hello, Android" application like we did in Section 1.2, Creating Your First Program, on page 23 and then tweak it a little. Select File > New > Project... to open the New Project dialog box. Then select Android > Android Project, and click Next. Enter the following information:

Project name: Widget Build Target: Android 2.2 Application name: Widget Package name: org.example.widget Min SDK Version: 8

Instead of entering a name for the Activity field, leave that field blank, and turn off the check mark next to Create Activity. When you're done, it should look something like Figure 12.1, on the following page.

Click Finish. The Android plug-in will create the project and fill it in with some default files. The files will not be correct for a widget project, so let's fix them up now.

Calling All Widgets!

Our first stop is the AndroidManifest.xml file. Although it's technically possible (and in fact common) to put widgets and activities in the same application, this example will have a widget only. We don't need an <activity> tag, but we do need to add a <receiver> to define the widget. Here is the revised manifest file:

Download Widget/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.example.widget" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <!-- Broadcast Receiver that will process AppWidget updates --> <receiver android:name= ".Widget"

android:label="@string/widget_name"> <intent-filter>

<action android:name=

"android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter>

<meta-data android:name="android.appwidget.provider" android:resource="@xml/widget" /> </receiver> </application>

<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="8" /> </manifest>

The <meta-data> tag tells Android it can find the widget definition in res/xml/widget.xml.

New Android Projecî

Create: s new Android Project resource, incül

Project name: Widget Contents

« Create new project in workspace

■ Create project from existing source m Use default location

Location.: C:/Develapment/warkspace/Widget

Create project from existing sample

Samples; ApiDemos

Build Target

Standard Android platform 2,2 Properties

Application name: Widget

Package name: org.example.widget E [Create Artivit^j

Min SDK Version: 3

Browse.,

Build Target

Target Name

Vendor

Platform

API,..

Android 1,1

Android Open

Source Project

1.1

2

Android 1.5

Android Open

Source Project

1.5

3

Google APIs

Googlelnc.

1.5

3

Android 1,6

Android Open

Source Project

1.6

4

Google APIs

Googlelnc.

1.6

4

Android ¿,0

Android Open

Source Project

2.0

5

Google APIs

Googlelnc.

2.0

5

Android 2,0,1

Android Open

Source Project

2.0,1

6

Google APIs

Googlelnc.

2.0.1

6

Android 2.1-upda...

Android Open

Source Project

2.1-upd...

7

Google APIs

Googlelnc.

2.1-upd...

7

m

Android 22

Android Open

Source Project

2 2

8

Google APIs

Googlelnc.

22

Finish

Cancel

Figure 12.1: New Android widget project

Here's the definition:

Download Widget/res/xml/widget.xml

<?xml version="1.0" encoding="utf-8"?>

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="146dip" android:minHeight="72dip" android:updatePeriodMillis="1800000"

android:initialLayout= "@layout/main"

This specifies a minimum size for the widget, how often it should be updated (more on that later), and a reference to its starting layout.

The layout is defined in res/layout/main.xml:

Download Widget/res/layout/main.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation= "vertical" android:layout_width= "fill_parent" android:layout_height="fill_parent"

android:background="@drawable/widget_bg"

<TextView android:id="@+id/text"

android:layout_width= "fill_parent" android:layout_height="fill_parent" android:text="@string/hello" android:textSize="18sp" android:gravity="center" android:textColor="@android:color/black" />

</LinearLayout>

You may have noticed that this layout is almost the same as the one we used for the "Hello, Android" example except that this version specifies centered black text and a background image.

Stretch to Fit

For the background, we could have used any Android Drawable, such as a solid color or a bitmap (see Section 4.1, Drawable, on page 76). We could have even left it off to get a completely transparent background. But for this example, I wanted to show you how to use a NinePatch image.

Figure 12.2: Defining a stretchable background with the Draw 9-patch tool

A NinePatch image is a stretchable PNG image often used for the background of resizable buttons. You use the Draw 9-patch tool1 included with the SDK to create one, as shown in Figure 12.2.

A 1-pixel border around the real image contains additional information about how to stretch the image and insert padded content. Lines on the bottom and right edges tell Android where content should go. If the content doesn't fit in that area (which is usually the case), then the lines on the left and top edges tell Android which pixel rows and columns should be duplicated in order to stretch the image.

The resulting file must use the extension .9.png and be placed in the project's res/drawable directory.

1. http://d.android.com/guide/developing/tools/draw9patch.html

Figure 12.3: Customizing your Home screen with widgets

The next thing we need is the Widget class.

Embrace and Extend

The Widget needs to extend the AppWidgetProvider class provided by Android. By using that class, we get a bunch of built-in functionality for free, which is always a plus. So, here's the definition for the Widget class:

Download Widget/src/org/example/widget/Widget.java

package org.example.widget;

import android.appwidget.AppWidgetProvider;

public class Widget extends AppWidgetProvider { // ...

We'll come back to fill in this class in a moment, but for now we can just use the default behavior provided by AppWidgetProvider.

Finally, let's get rid of a few pesky error messages by defining these string values:

Download Widget/res/values/strings.xml

<?xml version="1.0" encoding="utf-8"?> <resources>

<string name="hello">Hello World!</string> <string name="app_name">Widget</string> <string name="widget_name">Widget</string> </resources>

All that's left now is to run it. Running the Widget

To run your new widget, go to the Package Explorer window, right-click the Widget project, and select Run As > Android Application. Nothing much will appear to happen as Eclipse builds and installs the widget on your emulator or device.

To see the new widget, open the Home screen's context menu: press and hold your finger (or mouse) on the Home screen. A menu will appear with options listing all the types of things you can add (see Figure 12.3, on the previous page).

Select Widgets from the menu, and then select the widget named Widget (clever, huh?). At last, your widget should appear (see Figure 12.4, on the following page).

Try moving it around by pressing and holding your finger on the widget. Rotate the display to see how the widget automatically resizes itself. To remove it, drag it to the trash can icon at the bottom of the screen.

As exciting as that was, let's do it one better by displaying the current date and time in our widget.

Keeping Up-to-Date

In Android 1.5, widget hosts (programs like the Home screen that can contain widgets) send a message to all their little widget kids whenever the widgets should display something. The Android way to send a message is to broadcast an intent. In this case, the intent is android. appwidget.action.APPWIDGET_UPDATE.

Hello World!

Figure 12.4: Hello, Widget

Back when we set up the AndroidManifest.xml file, we told Android that we could receive that intent and do something interesting with it. Now it's time to fill out the Widget class to do just that:

Download Widget/src/org/example/widget/Widget.java Line 1 package org.example.widget;

- import java.text.SimpleDateFormat;

- import java.util.Date;

- import android.appwidget.AppWidgetManager;

- import android.appwidget.AppWidgetProvider;

- import android.content.Context;

- import android.widget.RemoteViews;

- public class Widget extends AppWidgetProvider {

- // Define the format string for the date private SimpleDateFormat formatter = new SimpleDateFormat(

15 "EEEEEEEEE\nd MMM yyyy");

@Override

- public void onUpdate(Context context,

- AppWidgetManager appWidgetManager, int[] appWidgetlds) { 20 // Retrieve and format the current date

String now = formatter.format(new Date());

- // Change the text in the widget RemoteViews updateViews = new RemoteViews(

25 context.getPackageName(), R.layout.main);

- updateViews.setTextViewText(R.id.text, now); appWidgetManager.updateAppWidget(appWidgetIds, updateViews);

- // Not really necessary, just a habit

30 super.onUpdate(context, appWidgetManager, appWidgetlds);

Whenever the APPWIDGET_UPDATE intent comes in, Android calls our onUpdate() method. On line 21, we format the current date using a Sim-pleDateFormat created on line 14. This shows the day of the week, day of the month, month name, and year on the first row of the widget, and then the hour, minute, second, and milliseconds on the second row.

Next, on line 24, we create a RemoteViews instance for the new view layout that the widget will display. It just so happens that this example uses the same layout, R.layout.main, when updating as it did when it was started. Line 26 replaces the original "Hello, World" text with the current date and time.

Finally, on line 27, we send our updated view to replace the current contents of the widget. The call to super.onUpdate() on line 30 is just there for code hygiene.

Remove the widget from your Home screen, and reinstall it from Eclipse. When you add it back to the Home screen, you should see something like Figure 12.5, on the next page.

The frequency of updates is controlled by the android:updatePeriodMillis= parameter in res/xml/widget.xml. A value of 1800000 represents 30 minutes, so our widget will be updated twice an hour. Note that this is only an approximate number. The actual update event may be delayed (possibly a long time) because of other things happening on the phone.

Google recommends you set widgets to update infrequently, such as once a day or once an hour, in order to conserve battery power. Starting in Android 1.6, the android:updatePeriodMillis= parameter will not honor any values under thirty minutes. If you need more frequent updates, you'll have to set up your own timer using the AlarmManager class. This is left as an exercise for the reader.

Figure 12.5: Displaying the date and time

Go Wild

Now that you know the basics of widget building, there's no end to the interesting doodads you can create. If you need more advanced features such as responding to events, background processing, and specifying an initial activity for configuration, consult the online documentation.2 Try to keep your widgets simple and useful, though. By cleverly using widgets, you can make the Android experience more personal and dynamic for your users.

Do you find yourself wishing for a bit more room to express than a widget provides? Then follow the yellow brick road to the land of live wallpapers.

0 0

Post a comment