Handling User Interaction with Android App Widgets

by Lauren Darcey

Handling User Interaction with Android App Widgets

Download the source code here


The App Widget interface for Android is very powerful. Through it, developers can create simple controls that can be hosted on the Home Screen or in any application that provides similar host functionality. In Creating a Home Screen App Widget on Android, you learned how to create and configure an App Widget. This simple App Widget displays a slideshow of images with a time interval configured by the user up-front. But what if the user wants to change this interval? What if they want to pause the slideshow or skip to the next image immediately? In this article, you will learn how to add user controls to the App Widget for handing these actions.

In order to handle user interaction with an App Widget, the following tasks must be performed:


  1. Set a unique click handler for each App Widget control
  2. Have the click handler send a command to a registered receiver
  3. Process the command received and perform any action necessary
  4. Update the App Widget to reflect the changes


For this example, we will modify the App Widget created in the previous article (Figure 1, top App Widget) to include a button bar with three controls (Figure 1, bottom App Widgets). Each of the buttons on the button bar will perform a specific action and clicking anywhere else in the App Widget will hide the button bar. The left-hand button (tool set) will launch the configuration Activity so users can change the time interval between image transitions in the slideshow. The middle button will pause or resume, the slideshow. The right-hand button allows the user to skip to the next image immediately.

Figure 1: Three different states of the App Widget

Working with RemoteViews

An App Widget uses a special display control called RemoteViews. Unlike a regular View, a RemoteViews control is designed to display a collection of View controls in another process. Consequently, you can't simply add a button handler because that code would run in your application process, not in the process displaying the RemoteViews object (in this case, the Home Screen process).

In order to enable user interaction with a RemoteViews control, you must register for a PendingIntent to be triggered when a specific View within the RemoteViews object is clicked. This is done with a call to the setOnClickPendingIntent() method of the RemoteViews object. For instance, to add the PendingIntent for launching the Activity to configure the slideshow time interval, we would add the following code:


  PendingIntent pendingIntent = PendingIntent.getActivity
(context, 0, configIntent,
setOnClickPendingIntent(R.id.config, pendingIntent);


Next, let's look more closely at the inner Intent called configIntent, which is wrapped by the PendingIntent.


Visit the Android Dev Center


Working with PendingIntents

A PendingIntent is basically a wrapper object combining an Intent with its target action, such as startActivity() or broadcastIntent(). In the previous article, we used a PendingIntent to enable an alarm to trigger the App Widget to change the image being displayed. If you recall, the Intent had to be unique in order for the application to differentiate between specific instances of the App Widget, since more than one might exist (three are shown in Figure 1). This was achieved by including the App Widget identifier in the Uri field, allowing each App Widget to have its own time interval.

The following code uses this same methodology to create the configIntent which launches the time delay configuration Activity. Each App Widget will launch with the correct appWidgetId.


  Intent configIntent =
new Intent(context, ImagesWidgetConfiguration.class);
AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
(ImagesWidgetProvider.URI_SCHEME + "://widget/id/"),


Now that the configuration button works, we can add the other button bar functions, such as skipping to the next image. In order to signal the RemoteViews control to skip to the next image, we will need to broadcast back to the App Widget to change the state.

At first, it might seem like the state information could be encoded as part of the Intent being sent by the button handler. Remember, however, that the App Widget will also be updating on a regular schedule with the Intent sent by the Alarm. That Intent won't be changing and won't know the new state. In order to solve this problem, we create a new action type for the App Widget called ACTION_WIDGET_CONTROL and append the command to the Uri of the Intent. We then store the state of the App Widget in the SharedPreferences. In practice, App Widget implementations usually have simple enough structures so that this can be done without a noticeable delay to the user.

The following helper method demonstrates the creation of the PendingIntent to handle the new action type ACTION_WIDGET_CONTROL:


  private PendingIntent makeControlPendingIntent
(Context context, String command, int appWidgetId) {
Intent active = new Intent();
AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
Uri data = Uri.withAppendedPath(
Uri.parse(URI_SCHEME + "://widget/id/#"+command),
0, active, PendingIntent.FLAG_UPDATE_CURRENT));


The block of code above creates a new Intent with an action of ACTION_WIDGET_CONTROL, which is simply a string. We then set the Intent Extra value to the App Widget unique identifier. The unique Uri is built, incorporating the desired command. This Intent is ready to be broadcast to the Android system by the App Widget host. It will be handled by the same broadcast receiver that handles the ordinary App Widget commands.

The App Widget will be able to receive these broadcasts in its onReceive() handler method like so:


  else if (ACTION_WIDGET_CONTROL.equals(action)) {
final int appWidgetId = intent.getIntExtra(
if (appWidgetId !=
context, appWidgetId, intent.getData());


We handle any incoming broadcasts of the appropriate action by comparing to our new action type. When we find a match, we dispatch the command to the appropriate App Widget instance.

Handling the State

Now that you understand how the user triggers an Intent object to be passed to the App Widget and how it's caught, you can handle the requested operation. This involves:


  1. Getting the appropriate RemoteViews instance
  2. Retrieving and changing its state
  3. Applying these changes to the RemoteViews control
  4. Calling the updateAppWidget() method to apply the changes to the appropriate App Widget.


The code for handling each of these tasks is found in the implementations of the onHandleAction() and updateDisplayState() methods in the source code available for download with this article.

Each time the RemoteViews control is updated, it is re- created from the original layout. Now, however, click handlers are used. Based on the current state of the App Widget, the required click handlers are added in the same way as we added the configuration Activity action earlier. These handlers are also available for review within the updateDisplayState() method of the source code.

Updating the Layout

To achieve the effect of the button bar drawing over the bottom of the widget, we employ two FrameLayout controls. The outer FrameLayout--comprising the entire App Widget-- contains the ImageView to display and another FrameLayout for the button bar. This second FrameLayout is set to draw at the bottom of its parent and it contains the three ImageButton controls for Settings, Play/Pause, and Next Image. The button bar FrameLayout can be hidden from view by simply setting its visibility attribute to GONE. The complete layout file (widget.xml) can be viewed in the sample code provided with this article.

Updating the Android Manifest File

Finally, the system won't know that this can handle our new action type unless we update the AndroidManifest.xml file to include the appropriate intent filter:


  <receiver android:name=".ImagesWidgetProvider">
        <action android:name=
           "com.mamlambo.ImagesWidget.WIDGET_CONTROL" />
        <data android:scheme="images_widget" />


This intent filter instructs the application to watch for the broadcast Intents with the action type of ACTION_WIDGET_CONTROL, whose value is "com.mamlambo.ImagesWidget.WIDGET_CONTROL".


App Widgets add a whole new dimension to the Android user experience. These App Widgets needn't be static, but can contain interactive features and react to user events like clicks. In this article, you learned how to add user interaction to an Android App Widget. In doing so, you learned how to interact with RemoteViews using a PendingIntent. Finally, you learned about the limitations of the Intent mechanism and how to work you can around them to create a App Widget users can control without leaving the comfort of their Home Screen.

Read part 1: Creating a Home Screen App Widget on Android here.

About the Authors

Shane Conder is a software developer focused on mobile and web technologies. He is currently working at a small mobile software company. With almost two decades of experience in software production, Lauren Darcey specializes in the development of commercial grade mobile applications. Recently, Shane and Lauren coauthored an in-depth programming book entitled Android Wireless Application Development, available from Addison-Wesley (ISBN: 0321627091). They can be reached at androidwirelessdev+a4@gmail.com and via their blog at http://androidbook .blogspot.com.

This article was originally published on Tuesday Sep 8th 2009
Mobile Site | Full Site