October 22, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Handling User Interaction with Android App Widgets

  • September 8, 2009
  • By Lauren Darcey, Shane Conder
  • Send Email »
  • More Articles »

Download the source code here

Introduction

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,
PendingIntent.FLAG_UPDATE_CURRENT);
remoteView.
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);
configIntent.putExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
configIntent.setData(Uri.withAppendedPath(Uri.Parse
(ImagesWidgetProvider.URI_SCHEME + "://widget/id/"),
String.valueOf(appWidgetId)));

 

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();
active.setAction(ACTION_WIDGET_CONTROL);
active.putExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
Uri data = Uri.withAppendedPath(
Uri.parse(URI_SCHEME + "://widget/id/#"+command),
String.valueOf(appWidgetId));
active.setData(data);
return(PendingIntent.getBroadcast(context,
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(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
if (appWidgetId !=
AppWidgetManager.INVALID_APPWIDGET_ID) {
this.onHandleAction(
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.



Originally published on http://www.developer.com.

Page 1 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel