Working with App Widgets Android

Introduced officially in API Level 3, the App Widget provides a new level of application integration with the Android operating system previously not available to mobile developers. Applications that publish App Widgets are called App Widget providers. A component that can contain an App Widget is called an App Widget host. An App Widget is a lightweight, simply featured application (such as a desktop plug-in) that can be installed on a host such as the Home screen.

An App Widget is normally tied back to some underlying application. For example, a calendar application might have an App Widget that shows the current date and enables the user to view the scheduled events of the day. Clicking on a specific event might launch the full calendar application to that date, enabling the user to access the full range of application features. Similarly, a music application might provide a simple set of controls within an App Widget, enabling the user to easily start and stop music playback from his Home screen. We provide a simple App Widget implementation as part of the code that accompanies this book; this App Widget displays information about the United States Homeland Security Advisory System’s threat level (red/severe, orange/high, yellow/elevated, blue/guarded, green/low)—this type of App Widget might be appropriate for a travel application.

An App Widget can be updated at regular intervals with fresh content. This makes App Widgets ideal for secondary application features, whereas notifications that launch into the full application functionality might be more appropriate for events that require a speedy user response.

Creating an App Widget

Consider whether or not your application should include App Widget functionality. Although App Widgets are small in size and light on functionality, they allow the user access to application functionality straight from the Home screen. App Widgets also serve to keep users using the application, by reminding them that they installed it. Some applications allow only one instance of an App Widget to run (such as the music player), whereas others might allow multiple instances of the same App Widget to be placed simultaneously, though generally showing different content (such as a picture frame).

You need to make the following changes to your application in order to support App Widgets:

  • Provide an XML App Widget configuration.
  • Determine whether the App Widget requires a configuration activity.
  • Provide an AppWidgetProvider class implementation.
  • Provide a Service class implementation to handle AppWidget content updates, as needed.
  • Update the application Android manifest file to register the App Widget provider information, as well as any information about the update service.

Now let’s look at some of these requirements in greater detail.

Creating an App Widget Configuration

First, your application must provide an XML App Widget definition. You can store this definition within the project’s resources in the /res/xml directory. Let’s take a closer look at an example of an App Widget definition, as defined in/res/xml/simple_ widget_info.xml:

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="146dp"
android:minHeight="72dp"
android:updatePeriodMillis="28800000"
android:initialLayout="@layout/widget">
</appwidget-provider>

This simple App Widget definition is encapsulated within the <appwidget-provider> XML tag. The minWidth and minHeight attributes dictate the size of the App Widget (a dimension, here in dp), and the updatePeriodMillis attribute is used to define how often the App Widget content is refreshed (using the App Widget update service)—in this case, once every eight hours. Finally, the App Widget layout definition is referenced using the initialLayout attribute—we talk more about this layout file in a few moments.

To draw nicely on the Home screen, the App Widget dimensions must follow certain guidelines. The Home screen is divided into cells of a particular size. When the user attempts to install an App Widget, the system checks to make sure there is enough space (as dictated by the minimum width and height values of the App Widget).

Determining if the App Widget Requires a Configuration Activity

Generally speaking, if there is more than one instance of an App Widget, each instance should look or behave differently. This isn’t a strict requirement; if each instance of the App Widget looks and acts the same, users quickly catch on and only install one instance at a time.

However, if you want to differentiate between App Widget instances, you need to provide each with settings, and thus you must create a configuration activity. This configuration activity is a normal activity, but it will read in certain Intent extras upon launch. The configuration activity must be defined within the App Widget XML configuration.

Each time a new App Widget instance is created, the configuration Activity is launched. The Activity is launched with the unique App Widget identifier, passed in via the launch intent’s EXTRA_APPWIDGET_ID extra. The Activity, on completion, must set this value back in the result intent along with result status, such as RESULT_OK.

The configuration activity should not only let the user configure options on this particular AppWidget instance, but it should also update the RemoteViews object, as the AppWidget will not receive an update event when it’s first created with a configuration Activity set in the XML configuration. Subsequent updates receive the update event, though.

Creating an App Widget Provider

An App Widget is basically a BroadcastReceiver that handles particular actions. As with a broadcast receiver, the primary interaction with an App Widget happens through the onReceive() method. However, the default AppWidgetProvider class handles onReceive() and, in turn, delegates operations to the its other methods, which you then implement.

Implementing the AppWidgetProvider Class

The AppWidgetProvider class simplifies the handling of these actions by providing a framework for developers to implement App Widgets. An App Widget Provider implementation requires the following methods:

  • The onEnabled() method is called when the App Widget is created. This is a good place to perform any configuration shared for the entire widget provider. This method is called once for the first App Widget instance added to the widget host (usually the home screen).
  • The onDisabled() method is called when the App Widget is disabled. This method is called only after all App Widget instances for this provider are removed from the App Widget host. For example, if there were five App Widgets for this provider on the home screen, this method would only be called after the user removed the fifth and final App Widget.
  • The onUpdate() method is called at regular intervals, depending on the update frequency specified in the App Widget configuration file. This frequency uses an in-exact timer, so do not rely on this frequency being precise. If you need precision updates, consider scheduling updates using the AlarmManager class. This method is called with a list of widget identifiers. Each identifier references a unique App Widget instance within the App Widget host. The App Widget provider implementation must differentiate between each instance and, typically, store different configuration values for each as well.
  • The onDeleted() method is called when a particular instance of this App Widget is deleted.

Using Remote Views

Android App Widgets do not run within the application process, but in the host’s process. Therefore, the App Widget uses the RemoteViews class in order to define its user interface. The RemoteViews class supports a subset of the overall View hierarchy, for display within another process. Generally speaking, you want to configure the RemoteViews object and send it to the App Widget Manager during the onUpdate() method. However, you’ll also need to update it when an instance is created and a configuration activity exists.

View hierarchies defined using RemoteViews can only contain a limited set of controls, including Button, ImageButton, ImageView, TextView, AnalogClock, Chronometer, and ProgressBar controls and only within FrameLayout, LinearLayout, or RelativeLayout layouts. Objects derived from these controls cannot be used, either. The Remote Views configuration should be kept as simple as possible because access to its view hierarchy is controlled through helper methods, such as setImageViewResource(), setTextViewText(), setProgressbar(), setShort(), setString(), and setChronometer(). In short, you can generate an XML layout definition for an AppWidget, but you must be careful only to use controls that are supported by the RemoteViews class.

Let’s look at the incredibly simple layout definition used by the threat level App Widget, as defined in the resource file /res/layout/widget.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="@+id/widget_view">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/widget_text_threat"
android:layout_centerInParent="true">
</TextView>
</RelativeLayout>

Nothing too complex in this layout, eh? A single TextView control, which displays the threat level information, is encapsulated within a RelativeLayout control. Now your layout can be loaded programmatically into a RemoteViews object for use within the App Widget provider. Don’t worry, things get more complex when we cram that layout into a RemoteViews object and act upon it across processes.

In order to load a layout resource (such as widget.xml defined earlier) into a RemoteViews object, you can use the following code:

RemoteViews remoteView =
new RemoteViews(context.getPackageName(), R.layout.widget);

When you want to update the text in that layout’s TextView control, you need to use the setTextViewText() method of the RemoteViews class, like this:

remoteView.setTextViewText(R.id.widget_text_threat, “Red alert!");

If you want the user to be able to click within the RelativeLayout control of the App Widget display and to launch the underlying application, use the set OnClick PendingIntent() method of the RemoteViews class. For example, the following code creates a pending intent that can launch the SimpleAppWidgetActivity activity:

Intent launchAppIntent =
new Intent(context, SimpleAppWidgetActivity.class);
PendingIntent launchAppPendingIntent = PendingIntent.getActivity(
context, 0, launchAppIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
remoteView.setOnClickPendingIntent
(R.id.widget_view, launchAppPendingIntent);

Finally, when the RemoteViews object is all set up, the App Widget provider needs to tell the App Widget Manager about the updated RemoteViews object:

ComponentName simpleWidget = new ComponentName(context,
SimpleAppWidgetProvider.class);
AppWidgetManager appWidgetManager =
AppWidgetManager.getInstance(context);
appWidgetManager.updateAppWidget(simpleWidget, remoteView);

To update the appropriate App Widget, the AppWidgetManager object requires its component name. The App Widget Manager will then update the content of the specific named App Widget using the contents of the RemoteViews object you provide in the updateAppWidget() method. Each time the RemoteViews object is updated, it is rebuilt. Although this usually happens infrequently, keep them simple for good performance.

Updating an App Widget

When the onUpdate() method of the App Widget provider is called, a list of identifiers are passed in. Each identifier references a particular App Widget instance for this provider. That is, a user can add any number of App Widgets of a particular kind to a host. It’s up to you, though, how they will differ. During the update event, each identifier must be iterated over and update each of the RemoteViews objects individually (that is, if you support different instances simultaneously).

An App Widget must be very responsive during the update event because it is being executed from the UI thread of the host process. When the updates are done, there is no guarantee that the App Widget Provider object stays around. Therefore, if an App Widget refresh requires any lengthy blocking operations, it must use a service so that it can create a thread to perform these operations in the background.

In our threat level App Widget example, we already have a service that performs some network operations in order to download updated threat level data. This service is perfect for the needs of an App Widget as well as the application, so they can share this service. Convenient, huh?

Creating a App Widget Update Service

Most App Widgets do not contain static content, but are updated from time to time. Normally, an Android service is used to enable App Widget content updates. The service performs any necessary update-related tasks, including spawning threads, connecting to the Internet, and so on. The App Widget provider’s onUpdate() method, which is called at the App Widget update interval, is a great place to start this update service. After the service has done its job, it should shut itself down until the next time fresh content is needed. Let’s revisit the threat level App Widget, which uses two services:

  • The SimpleDataUpdateService class runs at the App Widget update interval (started in the onUpdate() method of the App Widget provider).The service connects to the Internet, checks the current threat level, and stores the result in the application’s shared preferences. Finally, the service shuts itself down. It might be helpful to consider the application as the “owner” of this service—it provides information for both the application and the App Widget by saving data to the shared preferences.
  • The PrefListenerService class listens for changes in the application’s shared preferences. In addition to using the onUpdate() method, this service is started when the App Widget is enabled, thus allowing it to be updated whenever the data changes (for example, when the underlying application modifies the shared preference by checking the threat level itself).When the threat level preference changes, this service triggers a call to the updateAppWidget() method of the App Widget provider, which updates the RemoteViews object for the App Widget—bypassing the frequency limitations of the App Widget Manager. It might be helpful to consider the App Widget as the “owner” of this service—it runs within the App Widget lifecycle and exists only to update the content of the App Widget. Certainly, there are simpler ways to update your App Widget. For example, the App Widget could use its one service to do all the work of downloading the threat level data and updating the App Widget content, but then the application is left to do its own thing. The method described here illustrates how you can bypass some of the update frequency limitations of App Widgets and still share content between App Widgets and their underlying application.

Configuring the Android Manifest File for App Widgets

In order for the Android system to know about your application’s App Widget, you must include a <receiver> tag in the application’s Android manifest file to register it as an App Widget provider. App Widgets often use services, and these services must be registered within the Android manifest file with a <service> tag like any other service. Here is an excerpt of the Android manifest file from the SimpleAppWidget project:

<receiver android:name="SimpleAppWidgetProvider"
android:label="@string/widget_desc"
android:icon="@drawable/threat_levels_descriptions">
<intent-filter>
<action android:name=
“android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/simple_widget_info" />
</receiver>
<service android:name="SimpleDataUpdateService" />
<service android:name="SimpleAppWidgetProvider$PrefListenerService" />

Notice that, unlike a typical <receiver> definition, a <meta-data> section references an XML file resource. The <receiver> tag includes several bits of information about the App Widget configuration, including a label and icon for the App Widget, which is displayed on the App Widget picker (where the user chooses from available App Widgets on the system).The <receiver> tag also includes an intent filter to handle the android.appwidget.action.APPWIDGET_UPDATE intent action, as well as a <meta-data> tag that references the App Widget configuration file stored in the XML resource directory. Finally, the services used to update the App Widget are registered.

Installing an App Widget

After your application has implemented App Widget functionality, a user (who has installed your application) can install it to the Home screen using the following steps:

  1. Long-press on the Home Screen.
  2. From the menu, choose the Widgets option, as shown in Figure(left).
  3. Using the Widget picker to install an App Widget on the Home screen.

    Using the Widget picker to install an App Widget on the Home screen.

  4. From the Widget menu, choose the App Widget you want to include, as shown in Figure (right).
  5. Provided there is room for it, the App Widget is placed on the screen, as shown in. The following figure. You can move the App Widget around on the screen or remove it by dragging it onto the trash icon at the bottom of the Home screen.

Becoming an App Widget Host

Although somewhat less common, applications might also become App Widget hosts. App Widget hosts (android.appWidget.AppWidgetHost) are simply containers that can embed and display App Widgets. The most commonly used App Widget host is the Home screen. For more information on developing an App Widget host, see the Android SDK documentation.

A Simple App Widget on the Home screen that displays the security threat level.

A Simple App Widget on the Home screen that displays the security threat level.


All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

Android Topics