index.jd revision b10b48f62d3cac684424e4181d4e8ec61f227e95
1page.title=App Widgets 2@jd:body 3 4<div id="qv-wrapper"> 5 <div id="qv"> 6 <h2>Quickview</h2> 7 <ul> 8 <li>App Widgets provide users access to some of your application features 9directly from the Home screen (without the need to launch an activity)</li> 10 <li>App Widgets are backed by a special kind of broadcast receiver that 11handles the App 12Widget lifecycle</li> 13 </ul> 14 15 <h2>In this document</h2> 16 <ol> 17 <li><a href="#Basics">The Basics</a></li> 18 <li><a href="#Manifest">Declaring an App Widget in the Manifest</a></li> 19 <li><a href="#MetaData">Adding the AppWidgetProviderInfo Metadata</a></li> 20 <li><a href="#CreatingLayout">Creating the App Widget Layout</a></li> 21 <li><a href="#AppWidgetProvider">Using the AppWidgetProvider Class</a> 22 <ol> 23 <li><a href="#ProviderBroadcasts">Receiving App Widget broadcast 24Intents</a></li> 25 </ol> 26 </li> 27 <li><a href="#Configuring">Creating an App Widget Configuration 28Activity</a> 29 <ol> 30 <li><a href="#UpdatingFromTheConfiguration">Updating the App Widget 31from 32 the configuration Activity</a></li> 33 </ol> 34 </li> 35 <li><a href="#preview">Setting a Preview Image</a></li> 36 <li><a href="#collections">Using App Widgets with Collections</a> 37 <ol> 38 <li><a href="#collection_sample">Sample application</a></li> 39 <li><a href="#implementing_collections">Implementing app widgets with 40collections 41</a></li> 42 <li><a href="#fresh">Keeping Collection Data Fresh</a></li> 43 </ol> 44 </li> 45 </ol> 46 47 <h2>Key classes</h2> 48 <ol> 49 <li>{@link android.appwidget.AppWidgetProvider}</li> 50 <li>{@link android.appwidget.AppWidgetProviderInfo}</li> 51 <li>{@link android.appwidget.AppWidgetManager}</li> 52 </ol> 53 54 <h2>See also</h2> 55 <ol> 56 <li><a 57href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget 58Design 59 Guidelines</a></li> 60 <li><a 61href="http://android-developers.blogspot.com/2009/04/introducing-home-screen- 62widgets-and.html">Introducing 63 home screen widgets and the AppWidget framework »</a></li> 64 </ol> 65 </div> 66</div> 67 68 69<p>App Widgets are miniature application views that can be embedded in other 70applications 71(such as the Home screen) and receive periodic updates. These views are 72referred 73to as Widgets in the user interface, 74and you can publish one with an App Widget provider. An application component 75that is 76able to hold other App Widgets is called an App Widget host. The screenshot 77below shows 78the Music App Widget.</p> 79 80<img src="{@docRoot}images/appwidget.png" alt="" /> 81 82<p>This document describes how to publish an App Widget using an App Widget 83provider.</p> 84 85 86<h2 id="Basics">The Basics</h2> 87 88<p>To create an App Widget, you need the following:</p> 89 90<dl> 91 <dt>{@link android.appwidget.AppWidgetProviderInfo} object</dt> 92 <dd>Describes the metadata for an App Widget, such as the App Widget's layout, 93update frequency, 94 and the AppWidgetProvider class. This should be defined in XML.</dd> 95 <dt>{@link android.appwidget.AppWidgetProvider} class implementation</dt> 96 <dd>Defines the basic methods that allow you to programmatically interface 97with the App Widget, 98 based on broadcast events. Through it, you will receive broadcasts when the 99App Widget is updated, 100 enabled, disabled and deleted.</dd> 101 <dt>View layout</dt> 102 <dd>Defines the initial layout for the App Widget, defined in XML.</dd> 103</dl> 104 105<p>Additionally, you can implement an App Widget configuration Activity. This is 106an optional 107{@link android.app.Activity} that launches when the user adds your App Widget 108and allows him or her 109to modify App Widget settings at create-time.</p> 110 111<p>The following sections describe how to setup each of these components.</p> 112 113 114<h2 id="Manifest">Declaring an App Widget in the Manifest</h2> 115 116<p>First, declare the {@link android.appwidget.AppWidgetProvider} class in your 117application's 118<code>AndroidManifest.xml</code> file. For example:</p> 119 120<pre> 121<receiver android:name="ExampleAppWidgetProvider" > 122 <intent-filter> 123 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> 124 </intent-filter> 125 <meta-data android:name="android.appwidget.provider" 126 android:resource="@xml/example_appwidget_info" /> 127</receiver> 128</pre> 129 130<p>The <code><receiver></code> element requires the 131<code>android:name</code> 132attribute, which specifies the {@link android.appwidget.AppWidgetProvider} used 133by the App Widget.</p> 134 135<p>The <code><intent-filter></code> element must include an 136<code><action></code> 137element with the <code>android:name</code> attribute. This attribute specifies 138that the {@link android.appwidget.AppWidgetProvider} accepts the {@link 139android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE 140ACTION_APPWIDGET_UPDATE} broadcast. 141This is the only broadcast that you must explicitly declare. The {@link 142android.appwidget.AppWidgetManager} 143automatically sends all other App Widget broadcasts to the AppWidgetProvider as 144necessary.</p> 145 146<p>The <code><meta-data></code> element specifies the 147{@link android.appwidget.AppWidgetProviderInfo} resource and requires the 148following attributes:</p> 149<ul> 150 <li><code>android:name</code> - Specifies the metadata name. Use 151<code>android.appwidget.provider</code> 152 to identify the data as the {@link android.appwidget.AppWidgetProviderInfo} 153descriptor.</li> 154 <li><code>android:resource</code> - Specifies the {@link 155android.appwidget.AppWidgetProviderInfo} 156 resource location.</li> 157</ul> 158 159 160<h2 id="MetaData">Adding the AppWidgetProviderInfo Metadata</h2> 161 162<p>The {@link android.appwidget.AppWidgetProviderInfo} defines the essential 163qualities of an App Widget, such as its minimum layout dimensions, its initial 164layout resource, 165how often to update the App Widget, and (optionally) a configuration Activity to 166launch at create-time. 167Define the AppWidgetProviderInfo object in an XML resource using a single 168<code><appwidget-provider></code> element and save it in the project's 169<code>res/xml/</code> 170folder.</p> 171 172<p>For example:</p> 173 174<pre> 175<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" 176 android:minWidth="294dp" 177 android:minHeight="72dp" 178 android:updatePeriodMillis="86400000" 179 android:previewImage="@drawable/preview" 180 android:initialLayout="@layout/example_appwidget" 181 android:configure="com.example.android.ExampleAppWidgetConfigure" 182 android:resizeMode="horizontal|vertical"> 183</appwidget-provider> 184</pre> 185 186<p>Here's a summary of the <code><appwidget-provider></code> attributes:</p> 187<ul> 188 <li>The values for the <code>minWidth</code> and <code>minHeight</code> 189attributes specify the minimum 190 area required by the App Widget's layout. 191 <p>The default Home screen positions App Widgets in its window based on a 192grid of 193 cells that have a defined height and width. If the values for an App 194Widget's minimum width 195 or height don't match the dimensions of the cells, 196 then the App Widget dimensions round <em>up</em> to the nearest cell size. 197 (See the <a 198href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget 199Design 200 Guidelines</a> for more information on the Home screen cell sizes.)</p> 201 <p>Because the Home screen's layout orientation (and thus, the cell sizes) 202can change, 203 as a rule of thumb, you should assume the worst-case cell size of 74 pixels 204for the height 205 <em>and</em> width of a cell. However, you must subtract 2 from the final 206dimension to account 207 for any integer rounding errors that occur in the pixel count. To find your 208minimum width 209 and height in density-independent pixels (dp), use this formula:<br/> 210 <code>(number of cells * 74) - 2</code><br/> 211 Following this formula, you should use 72 dp for a height of one cell, 294 212dp and for a width of four cells.</p> 213<p class="note"><strong>Note:</strong> To make your app widget portable across 214devices, your app widget's minimum size should never be larger than 4 x 4 cells. 215See the <a 216href="{@docRoot}guide/practices/ui_guidelines/widget_design.html#sizes">App 217Widget Design Guidelines</a> for more discussion of Home screen cell sizes.</p> 218 </li> 219 <li>The <code>updatePeriodMillis</code> attribute defines how often the App 220Widget framework should request an update from the {@link 221android.appwidget.AppWidgetProvider} by calling the 222{@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,android.appwidget.AppWidgetManager,int[]) onUpdate()} 223callback method. The actual update 224is not guaranteed to occur exactly on time with this value and we suggest 225updating as infrequently as possible—perhaps no more than once an hour to 226conserve the battery. You might also allow the user to adjust the frequency in a 227configuration—some people might want a stock ticker to update every 15 228minutes, or maybe only four times a day. 229 <p class="note"><strong>Note:</strong> If the device is asleep when it 230is time for an update 231 (as defined by <code>updatePeriodMillis</code>), then the device will 232wake up in order 233 to perform the update. If you don't update more than once per hour, this 234probably won't 235 cause significant problems for the battery life. If, however, you need 236to update more 237 frequently and/or you do not need to update while the device is asleep, 238then you can instead 239 perform updates based on an alarm that will not wake the device. To do 240so, set an alarm with 241 an Intent that your AppWidgetProvider receives, using the {@link 242android.app.AlarmManager}. 243 Set the alarm type to either {@link 244android.app.AlarmManager#ELAPSED_REALTIME} or 245 {@link android.app.AlarmManager#RTC}, which will only 246 deliver the alarm when the device is awake. Then set 247<code>updatePeriodMillis</code> to 248 zero (<code>"0"</code>).</p> 249 </li> 250 <li>The <code>initialLayout</code> attribute points to the layout resource 251that defines the 252 App Widget layout.</li> 253 <li>The <code>configure</code> attribute defines the {@link 254android.app.Activity} to launch when 255 the user adds the App Widget, in order for him or her to configure App 256Widget properties. This is optional 257 (read <a href="#Configuring">Creating an App Widget Configuration 258Activity</a> below).</li> 259 260 <li>The <code>previewImage</code> attribute specifies a preview of what the 261app widget will look like after it's configured, which the user sees when 262selecting the app widget. If not supplied, the user instead sees your 263application's launcher icon. This field corresponds to the 264<code>android:previewImage</code> attribute in the <code><receiver></code> 265element in the <code>AndroidManifest.xml</code> file. For more discussion of 266using <code>previewImage</code>, see <a href="#preview">Setting a Preview 267Image</a>. Introduced in Android 3.0.</li> 268 269 <li>The <code>autoAdvanceViewId</code> attribute specifies the view ID of the 270app widget subview that should be auto-advanced by the widget's host. Introduced in Android 3.0.</li> 271 272<li>The <code>resizeMode</code> attribute specifies the rules by which a widget 273can be resized. You use this attribute to make homescreen widgets 274resizeable—horizontally, vertically, or on both axes. Users touch-hold a 275widget to show its resize handles, then drag the horizontal and/or vertical 276handles to change the size on the layout grid. Values for the 277<code>resizeMode</code> attribute include "horizontal", "vertical", and "none". 278To declare a widget as resizeable horizontally and vertically, supply the value 279"horizontal|vertical". Introduced in Android 3.1.</li> </ul> 280 281<p>See the {@link android.appwidget.AppWidgetProviderInfo} class for more 282information on the 283attributes accepted by the <code><appwidget-provider></code> element.</p> 284 285 286<h2 id="CreatingLayout">Creating the App Widget Layout</h2> 287 288<p>You must define an initial layout for your App Widget in XML and save it in 289the project's 290<code>res/layout/</code> directory. You can design your App Widget using the 291View objects listed 292below, but before you begin designing your App Widget, please read and 293understand the 294<a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget 295Design 296Guidelines</a>.</p> 297 298<p>Creating the App Widget layout is simple if you're 299familiar with <a 300href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a>. 301However, you must be aware that App Widget layouts are based on {@link 302android.widget.RemoteViews}, 303which do not support every kind of layout or view widget.</p> 304 305<p>A RemoteViews object (and, consequently, an App Widget) can support the 306following layout classes:</p> 307 308<ul class="nolist"> 309 <li>{@link android.widget.FrameLayout}</li> 310 <li>{@link android.widget.LinearLayout}</li> 311 <li>{@link android.widget.RelativeLayout}</li> 312</ul> 313 314<p>And the following widget classes:</p> 315<ul class="nolist"> 316 <li>{@link android.widget.AnalogClock}</li> 317 <li>{@link android.widget.Button}</li> 318 <li>{@link android.widget.Chronometer}</li> 319 <li>{@link android.widget.ImageButton}</li> 320 <li>{@link android.widget.ImageView}</li> 321 <li>{@link android.widget.ProgressBar}</li> 322 <li>{@link android.widget.TextView}</li> 323 <li>{@link android.widget.ViewFlipper}</li> 324</ul> 325 326<p>Descendants of these classes are not supported.</p> 327 328 329<h2 id="AppWidgetProvider">Using the AppWidgetProvider Class</h2> 330 331<div class="sidebox-wrapper"> 332<div class="sidebox"> 333 <p>You must declare your AppWidgetProvider class implementation as a 334broadcast receiver 335 using the <code><receiver></code> element in the AndroidManifest (see 336 <a href="#Manifest">Declaring an App Widget in the Manifest</a> above).</p> 337 </div> 338</div> 339 340<p>The {@link android.appwidget.AppWidgetProvider} class extends 341BroadcastReceiver as a convenience 342class to handle the App Widget broadcasts. The AppWidgetProvider receives only 343the event broadcasts that 344are relevant to the App Widget, such as when the App Widget is updated, deleted, 345enabled, and disabled. 346When these broadcast events occur, the AppWidgetProvider receives the following 347method calls:</p> 348 349<dl> 350 <dt> 351 {@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,android.appwidget.AppWidgetManager,int[]) onUpdate()} 352</dt> 353 <dd>This is called to update the App Widget at intervals defined by the 354<code>updatePeriodMillis</code> 355 attribute in the AppWidgetProviderInfo (see <a href="#MetaData">Adding the 356 AppWidgetProviderInfo Metadata</a> above). This method is also called 357 when the user adds the App Widget, so it should perform the essential setup, 358 such as define event handlers for Views and start a temporary 359 {@link android.app.Service}, if necessary. However, if you have declared a 360configuration 361 Activity, <strong>this method is not called</strong> when the user adds the 362App Widget, 363 but is called for the subsequent updates. It is the responsibility of the 364 configuration Activity to perform the first update when configuration is 365done. 366 (See <a href="#Configuring">Creating an App Widget Configuration 367Activity</a> below.)</dd> 368 <dt>{@link android.appwidget.AppWidgetProvider#onDeleted(Context,int[])}</dt> 369 <dd>This is called every time an App Widget is deleted from the App Widget 370host.</dd> 371 <dt>{@link android.appwidget.AppWidgetProvider#onEnabled(Context)}</dt> 372 <dd>This is called when an instance the App Widget is created for the first 373time. For example, if the user 374 adds two instances of your App Widget, this is only called the first time. 375 If you need to open a new database or perform other setup that only needs to 376occur once 377 for all App Widget instances, then this is a good place to do it.</dd> 378 <dt>{@link android.appwidget.AppWidgetProvider#onDisabled(Context)}</dt> 379 <dd>This is called when the last instance of your App Widget is deleted from 380the App Widget host. 381 This is where you should clean up any work done in 382 {@link android.appwidget.AppWidgetProvider#onEnabled(Context)}, 383 such as delete a temporary database.</dd> 384 <dt>{@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)}</dt> 385 <dd>This is called for every broadcast and before each of the above callback 386methods. 387 You normally don't need to implement this method because the default 388AppWidgetProvider 389 implementation filters all App Widget broadcasts and calls the above 390 methods as appropriate.</dd> 391</dl> 392 393<p class="warning"><strong>Note:</strong> In Android 1.5, there is a known issue 394in which the 395<code>onDeleted()</code> method will not be called when it should be. To work 396around this issue, 397you can implement {@link 398android.appwidget.AppWidgetProvider#onReceive(Context,Intent) 399onReceive()} as described in this 400<a 401href="http://groups.google.com/group/android-developers/msg/e405ca19df2170e2"> 402Group post</a> 403to receive the <code>onDeleted()</code> callback. 404</p> 405 406<p>The most important AppWidgetProvider callback is 407{@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[]) onUpdate()} 408because it is called when 409each App Widget is added to a host (unless you use a configuration Activity). If 410your App Widget accepts any user interaction events, then you need to register 411the event handlers in this callback. If your App Widget doesn't create temporary 412files or databases, or perform other work that requires clean-up, then 413{@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[]) onUpdate()} 414may be the only callback 415method you need to define. For example, if you want an App Widget with a button 416that launches an Activity when clicked, you could use the following 417implementation of AppWidgetProvider:</p> 418 419<pre> 420public class ExampleAppWidgetProvider extends AppWidgetProvider { 421 422 public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 423 final int N = appWidgetIds.length; 424 425 // Perform this loop procedure for each App Widget that belongs to this provider 426 for (int i=0; i<N; i++) { 427 int appWidgetId = appWidgetIds[i]; 428 429 // Create an Intent to launch ExampleActivity 430 Intent intent = new Intent(context, ExampleActivity.class); 431 PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); 432 433 // Get the layout for the App Widget and attach an on-click listener 434 // to the button 435 RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout); 436 views.setOnClickPendingIntent(R.id.button, pendingIntent); 437 438 // Tell the AppWidgetManager to perform an update on the current app widget 439 appWidgetManager.updateAppWidget(appWidgetId, views); 440 } 441 } 442} 443</pre> 444 445<p>This AppWidgetProvider defines only the 446{@link 447android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[]) onUpdate()} 448method for the purpose of 449defining a {@link android.app.PendingIntent} that launches an {@link 450android.app.Activity} and attaching it to the App Widget's button with {@link 451android.widget.RemoteViews#setOnClickPendingIntent(int,PendingIntent)}. Notice 452that it includes a loop that iterates through each entry in 453<code>appWidgetIds</code>, which is an array of IDs that identify each App 454Widget created by this provider. In this way, if the user creates more than one 455instance of the App Widget, then they are all updated simultaneously. However, 456only one <code>updatePeriodMillis</code> schedule will be managed for all 457instances of the App Widget. For example, if the update schedule is defined to 458be every two hours, and a second instance of the App Widget is added one hour 459after the first one, then they will both be updated on the period defined by the 460first one and the second update period will be ignored (they'll both be updated 461every two hours, not every hour).</p> 462 463<p class="note"><strong>Note:</strong> Because {@link 464android.appwidget.AppWidgetProvider} is an extension of {@link 465android.content.BroadcastReceiver}, your process is not guaranteed to keep 466running after the callback methods return (see {@link 467android.content.BroadcastReceiver} for information about the broadcast 468lifecycle). If your App Widget setup process can take several seconds (perhaps 469while performing web requests) and you require that your process continues, 470consider starting a {@link android.app.Service} in the 471{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) onUpdate()} 472method. From within the Service, you can perform your own updates 473to the App Widget without worrying about the AppWidgetProvider closing down due 474to an <a href="{@docRoot}guide/practices/design/responsiveness.html">Application 475Not Responding</a> (ANR) error. See the <a 476href="http://code.google.com/p/wiktionary-android/source/browse/trunk/Wiktionary 477/src/com/example/android/wiktionary/WordWidget.java">Wiktionary sample's 478AppWidgetProvider</a> for an example of an App Widget running a {@link 479android.app.Service}.</p> 480 481<p>Also see the <a 482href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/ 483appwidget/ExampleAppWidgetProvider.html"> 484ExampleAppWidgetProvider.java</a> sample class.</p> 485 486 487<h3 id="ProviderBroadcasts">Receiving App Widget broadcast Intents</h3> 488 489<p>{@link android.appwidget.AppWidgetProvider} is just a convenience class. If 490you would like 491to receive the App Widget broadcasts directly, you can implement your own 492{@link android.content.BroadcastReceiver} or override the 493{@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)} callback. 494The four Intents you need to care about are:</p> 495<ul> 496 <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE}</li> 497 <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DELETED}</li> 498 <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_ENABLED}</li> 499 <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DISABLED}</li> 500</ul> 501 502 503 504<h2 id="Configuring">Creating an App Widget Configuration Activity</h2> 505 506<p>If you would like the user to configure settings when he or she adds a new 507App Widget, 508you can create an App Widget configuration Activity. This {@link 509android.app.Activity} 510will be automatically launched by the App Widget host and allows the user to 511configure 512available settings for the App Widget at create-time, such as the App Widget 513color, size, 514update period or other functionality settings.</p> 515 516<p>The configuration Activity should be declared as a normal Activity in the 517Android manifest file. 518However, it will be launched by the App Widget host with the {@link 519android.appwidget.AppWidgetManager#ACTION_APPWIDGET_CONFIGURE 520ACTION_APPWIDGET_CONFIGURE} action, 521so the Activity needs to accept this Intent. For example:</p> 522 523<pre> 524<activity android:name=".ExampleAppWidgetConfigure"> 525 <intent-filter> 526 <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/> 527 </intent-filter> 528</activity> 529</pre> 530 531<p>Also, the Activity must be declared in the AppWidgetProviderInfo XML file, 532with the 533<code>android:configure</code> attribute (see <a href="#MetaData">Adding 534the AppWidgetProviderInfo Metadata</a> above). For example, the configuration 535Activity 536can be declared like this:</p> 537 538<pre> 539<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" 540 ... 541 android:configure="com.example.android.ExampleAppWidgetConfigure" 542 ... > 543</appwidget-provider> 544</pre> 545 546<p>Notice that the Activity is declared with a fully-qualified namespace, 547because 548it will be referenced from outside your package scope.</p> 549 550<p>That's all you need to get started with a configuration Activity. Now all you 551need is the actual 552Activity. There are, however, two important things to remember when you 553implement the Activity:</p> 554<ul> 555 <li>The App Widget host calls the configuration Activity and the configuration 556Activity should always 557 return a result. The result should include the App Widget ID 558 passed by the Intent that launched the Activity (saved in the Intent extras 559as 560 {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID}).</li> 561 <li>The 562 {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) onUpdate()} 563 method <strong>will not be called</strong> when the App Widget 564is created 565 (the system will not send the ACTION_APPWIDGET_UPDATE broadcast when a 566configuration Activity 567 is launched). It is the responsibility of the configuration Activity to 568request an update from the 569 AppWidgetManager when the App Widget is first created. However, 570{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) onUpdate()} 571 will be called for subsequent updates—it is only skipped 572the first time.</li> 573</ul> 574 575<p>See the code snippets in the following section for an example of how to 576return a result 577from the configuration and update the App Widget.</p> 578 579 580<h3 id="UpdatingFromTheConfiguration">Updating the App Widget from the 581configuration Activity</h3> 582 583<p>When an App Widget uses a configuration Activity, it is the responsibility of 584the Activity 585to update the App Widget when configuration is complete. 586You can do so by requesting an update directly from the 587{@link android.appwidget.AppWidgetManager}.</p> 588 589<p>Here's a summary of the procedure to properly update the App Widget and close 590the configuration Activity:</p> 591 592<ol> 593 <li>First, get the App Widget ID from the Intent that launched the Activity: 594<pre> 595Intent intent = getIntent(); 596Bundle extras = intent.getExtras(); 597if (extras != null) { 598 mAppWidgetId = extras.getInt( 599 AppWidgetManager.EXTRA_APPWIDGET_ID, 600 AppWidgetManager.INVALID_APPWIDGET_ID); 601} 602</pre> 603 </li> 604 <li>Perform your App Widget configuration.</li> 605 <li>When the configuration is complete, get an instance of the 606AppWidgetManager by calling 607 {@link android.appwidget.AppWidgetManager#getInstance(Context)}: 608<pre> 609AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); 610</pre> 611 </li> 612 <li>Update the App Widget with a {@link android.widget.RemoteViews} layout by 613calling 614 {@link android.appwidget.AppWidgetManager#updateAppWidget(int,RemoteViews)}: 615<pre> 616RemoteViews views = new RemoteViews(context.getPackageName(), 617R.layout.example_appwidget); 618appWidgetManager.updateAppWidget(mAppWidgetId, views); 619</pre> 620 </li> 621 <li>Finally, create the return Intent, set it with the Activity result, and 622finish the Activity:</li> 623<pre> 624Intent resultValue = new Intent(); 625resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); 626setResult(RESULT_OK, resultValue); 627finish(); 628</pre> 629 </li> 630</ol> 631 632<p class="note"><strong>Tip:</strong> When your configuration Activity first 633opens, set 634the Activity result to RESULT_CANCELED. This way, if the user backs-out of the 635Activity before 636reaching the end, the App Widget host is notified that the configuration was 637cancelled and the 638App Widget will not be added.</p> 639 640<p>See the <a 641href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/ 642appwidget/ExampleAppWidgetConfigure.html"> 643ExampleAppWidgetConfigure.java</a> sample class in ApiDemos for an example.</p> 644 645<h2 id="preview">Setting a Preview Image</h2> 646 647<p>Android 3.0 introduces the {@link 648 649 650android.appwidget.AppWidgetProviderInfo#previewImage} field, which specifies a 651preview of what the app widget looks like. This preview is shown to the user from the 652widget picker. If this field is not supplied, the app widget's icon is used for 653the preview.</p> 654 655<p>This is how you specify this setting in XML:</p> 656 657<pre><appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" 658 ... 659 android:previewImage="@drawable/preview"> 660</appwidget-provider></pre> 661 662<p>To help create a preview image for your app widget (to specify in the {@link 663android.appwidget.AppWidgetProviderInfo#previewImage} field), the Android 664emulator includes an application called "Widget Preview." To create a 665preview image, launch this application, select the app widget for your 666application and set it up how you'd like your preview image to appear, then save 667it and place it in your application's drawable resources.</p> 668 669<h2 id="collections">Using App Widgets with Collections</h2> 670 671<p>Android 3.0 introduces App Widgets with collections. These kinds of App 672Widgets use the {@link android.widget.RemoteViewsService} to display collections 673that are backed by remote data, such as from a <a 674href="{@docRoot}guide/topics/providers/content-providers.html">content 675provider</a>. The data provided by the {@link android.widget.RemoteViewsService} 676is presented in the App Widget using one of the following view types, which 677we’ll refer to as “collection views:”</p> 678 679<dl> 680 <dt>{@link android.widget.ListView}</dt> 681 <dd>A view that shows items in a 682vertically scrolling 683list. For an example, see the Gmail app widget. </dd> 684<dt>{@link android.widget.GridView}</dt> 685<dd>A view that shows items in 686two-dimensional scrolling grid. For an example, see the Bookmarks app 687widget.</dd> 688<dt>{@link android.widget.StackView}</dt> 689<dd>A 690stacked card view (kind of like a rolodex), where the user can flick the front 691card up/down to see the previous/next card, respectively. Examples include 692the YouTube and Books app widgets. </dd> 693<dt>{@link android.widget.AdapterViewFlipper}</dt> 694<dd>An adapter-backed simple 695{@link 696android.widget.ViewAnimator} that animates between two or more views. Only one 697child is shown at a time. </dd> 698</dl> 699 700<p>As stated above, these collection views display collections backed by remote 701data. This means that they use an {@link android.widget.Adapter} to bind their 702user interface to their data. An {@link android.widget.Adapter} binds individual 703items from a set of data into individual {@link android.view.View} objects. 704Because these collection views are backed by adapters, the Android framework 705must include extra architecture to support their use in app widgets. In the 706context of an app widget, the {@link android.widget.Adapter} is replaced by a 707{@link android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, 708which is simply a thin wrapper around the {@link android.widget.Adapter} 709interface. 710 When 711requested for a specific item in the collection, the {@link 712android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} creates 713and returns the item for the collection as a {@link android.widget.RemoteViews} 714object. 715In order to include a collection view in your app widget, you 716must implement {@link android.widget.RemoteViewsService} and {@link 717android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}.</p> 718 719<p> {@link android.widget.RemoteViewsService} is a service that allows a remote 720adapter to request {@link 721android.widget.RemoteViews} objects. {@link 722android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} is an 723interface for an adapter between a collection view (such as {@link 724android.widget.ListView}, {@link android.widget.GridView}, and so on) and the 725underlying data for that view. From the <a 726href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 727sample</a>, here is an example of the boilerplate code you use to implement 728this service and interface: 729</p> 730 731<pre> 732public class StackWidgetService extends RemoteViewsService { 733 @Override 734 public RemoteViewsFactory onGetViewFactory(Intent intent) { 735 return new StackRemoteViewsFactory(this.getApplicationContext(), intent); 736 } 737} 738 739class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { 740 741//... include adapter-like methods here. See the StackView Widget sample. 742 743} 744</pre> 745 746<h3 id="collection_sample">Sample application</h3> 747 748<p>The code excerpts in this section are drawn from the <a 749href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 750sample</a>:</p> 751 752<p> 753<img src="{@docRoot}resources/samples/images/StackWidget.png" alt="StackView 754Widget" /> 755</p> 756 757<p>This sample consists of a stack of 10 views, which display the values 758<code>"0!"</code> through <code>"9!"</code> The sample 759app widget has these primary behaviors:</p> 760 761<ul> 762 763 <li>The user can vertically fling the top view in the 764app widget to display the next or previous view. This is a built-in StackView 765behavior.</li> 766 767 <li>Without any user interaction, the app widget automatically advances 768through 769its views in sequence, like a slide show. This is due to the setting 770<code>android:autoAdvanceViewId="@id/stack_view"</code> in the 771<code>res/xml/stackwidgetinfo.xml</code> file. This setting applies to the view 772ID, 773which in this case is the view ID of the stack view.</li> 774 775 <li>If the user touches the top view, the app widget displays the {@link 776android.widget.Toast} message "Touched view <em>n</em>," where 777<em>n</em> is the index (position) of the touched view. For more discussion of 778how this is implemented, see 779<a href="#behavior">Adding behavior to individual items</a>.</li> 780 781</ul> 782<h3 id="implementing_collections">Implementing app widgets with collections</h3> 783 784<p>To implement an App Widget with collections, you follow the same basic steps 785you would use to implement any app widget. The following sections describe the 786additional steps you need to perform to implement an App Widget with 787collections.</p> 788 789<h4>Manifest for app widgets with collections</h4> 790 791<p> In addition to the requirements listed in <a href="#Manifest">Declaring an 792App Widget in the Manifest</a>, to make it possible for App Widgets with 793collections to bind to your {@link android.widget.RemoteViewsService}, you must 794declare the service in your manifest file with the permission {@link 795android.Manifest.permission#BIND_REMOTEVIEWS}. This prevents other applications 796from freely accessing your app widget's data. For example, when creating an App 797Widget that uses {@link android.widget.RemoteViewsService} to populate a 798collection view, the manifest entry may look like this:</p> 799 800<pre><service android:name="MyWidgetService" 801... 802android:permission="android.permission.BIND_REMOTEVIEWS" /></pre> 803 804<p>The line <code>android:name="MyWidgetService"</code> 805refers to your subclass of {@link android.widget.RemoteViewsService}. </p> 806 807<h4>Layout for app widgets with collections</h4> 808 809<p>The main requirement for your app widget layout XML file is that it 810include one of the collection views: {@link android.widget.ListView}, 811{@link android.widget.GridView}, {@link android.widget.StackView}, or 812{@link android.widget.AdapterViewFlipper}. Here is the 813<code>widget_layout.xml</code> for 814the <a href="{@docRoot}resources/samples/StackWidget/index.html">StackView 815Widget sample</a>:</p> 816 817<pre><?xml version="1.0" encoding="utf-8"?> 818 819<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 820 android:layout_width="match_parent" 821 android:layout_height="match_parent"> 822 <StackView xmlns:android="http://schemas.android.com/apk/res/android" 823 android:id="@+id/stack_view" 824 android:layout_width="match_parent" 825 android:layout_height="match_parent" 826 android:gravity="center" 827 android:loopViews="true" /> 828 <TextView xmlns:android="http://schemas.android.com/apk/res/android" 829 android:id="@+id/empty_view" 830 android:layout_width="match_parent" 831 android:layout_height="match_parent" 832 android:gravity="center" 833 android:background="@drawable/widget_item_background" 834 android:textColor="#ffffff" 835 android:textStyle="bold" 836 android:text="@string/empty_view_text" 837 android:textSize="20sp" /> 838</FrameLayout></pre> 839 840<p> Note that empty views must be siblings of the collection view for which the 841empty view represents empty state. </p> 842 843<p>In addition to the layout file for your entire app widget, you must create 844another layout file that defines the layout for each item in the collection (for 845example, a layout for each book in a collection of books). For example, the <a 846href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 847sample</a> only has one layout file, <code>widget_item.xml</code>, since all 848items use the same layout. But the <a 849href="{@docRoot}resources/samples/WeatherListWidget/index.html"> 850WeatherListWidget sample</a> has two layout files: 851<code>dark_widget_item.xml</code> and <code>light_widget_item.xml</code>.</p> 852 853 854 855<h4 id="AppWidgetProvider-collections">AppWidgetProvider class for app widgets with collections</h4> 856 857<p>As with a regular app widget, the bulk of your code in your {@link 858android.appwidget.AppWidgetProvider} subclass typically goes in {@link 859android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, 860android.appwidget.AppWidgetManager, int[]) onUpdate()}. The major difference in 861your implementation for {@link 862android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, 863android.appwidget.AppWidgetManager, int[]) onUpdate()} when creating an app 864widget with collections is that you must call {@link 865android.widget.RemoteViews#setRemoteAdapter setRemoteAdapter()}. This tells the 866collection view where to get its data. The {@link 867android.widget.RemoteViewsService} can then return your implementation of {@link 868android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, and 869the widget can serve up the appropriate data. When you call this method, you 870must pass an intent that points to your implementation of {@link 871android.widget.RemoteViewsService} and the App Widget ID that specifies the app 872widget to update.</p> 873 874 875<p>For example, here's how the StackView Widget sample implements the {@link 876android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, 877android.appwidget.AppWidgetManager, int[]) onUpdate()} callback method to set 878the {@link 879android.widget.RemoteViewsService} as the remote adapter for the app widget 880collection:</p> 881 882<pre>public void onUpdate(Context context, AppWidgetManager appWidgetManager, 883int[] appWidgetIds) { 884 // update each of the app widgets with the remote adapter 885 for (int i = 0; i < appWidgetIds.length; ++i) { 886 887 // Set up the intent that starts the StackViewService, which will 888 // provide the views for this collection. 889 Intent intent = new Intent(context, StackWidgetService.class); 890 // Add the app widget ID to the intent extras. 891 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); 892 intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); 893 // Instantiate the RemoteViews object for the App Widget layout. 894 RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout); 895 // Set up the RemoteViews object to use a RemoteViews adapter. 896 // This adapter connects 897 // to a RemoteViewsService through the specified intent. 898 // This is how you populate the data. 899 rv.setRemoteAdapter(appWidgetIds[i], R.id.stack_view, intent); 900 901 // The empty view is displayed when the collection has no items. 902 // It should be in the same layout used to instantiate the RemoteViews 903 // object above. 904 rv.setEmptyView(R.id.stack_view, R.id.empty_view); 905 906 // 907 // Do additional processing specific to this app widget... 908 // 909 910 appWidgetManager.updateAppWidget(appWidgetIds[i], rv); 911 } 912 super.onUpdate(context, appWidgetManager, appWidgetIds); 913}</pre> 914 915<h4>RemoteViewsService class</h4> 916 917<div class="sidebox-wrapper"> 918<div class="sidebox"> 919<h3>Persisting data</h3> 920 <p>You can’t rely on a single instance of your service, or any data it 921contains, to persist. You should therefore not store any data in your {@link 922android.widget.RemoteViewsService} (unless it is static). If you want your 923app widget’s data to persist, the best approach is to use a {@link 924android.content.ContentProvider} whose data persists beyond the process 925lifecycle.</p> </div> 926</div> 927 928<p>As described above, your {@link android.widget.RemoteViewsService} subclass 929provides the {@link android.widget.RemoteViewsService.RemoteViewsFactory 930RemoteViewsFactory} used to populate the remote collection view.</p> 931 932<p>Specifically, you need to 933perform these steps:</p> 934 935<ol> 936 <li>Subclass {@link android.widget.RemoteViewsService}. {@link 937android.widget.RemoteViewsService} is the service through which 938a remote adapter can request {@link android.widget.RemoteViews}. </li> 939 940 <li>In your {@link android.widget.RemoteViewsService} subclass, include a 941class that implements the {@link 942android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} 943interface. {@link android.widget.RemoteViewsService.RemoteViewsFactory 944RemoteViewsFactory} is an interface for an adapter between a remote collection 945view (such as {@link android.widget.ListView}, {@link android.widget.GridView}, 946and so on) and the underlying data for that view. Your implementation is 947responsible for making a {@link android.widget.RemoteViews} object for each 948item in the data set. This interface is a thin wrapper around {@link 949android.widget.Adapter}.</li> 950</ol> 951 952<p>The primary contents of the {@link android.widget.RemoteViewsService} 953implementation is its {@link 954android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, 955described below.</p> 956 957<h4>RemoteViewsFactory interface</h4> 958 959<p>Your custom class that implements the {@link 960android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} 961interface provides the app widget with the data for the items in its collection. 962To 963do this, it combines your app widget item XML layout file with a source of data. 964This source of data could be anything from a database to a simple array. In the 965<a href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 966sample</a>, the data source is an array of <code>WidgetItems</code>. The {@link 967android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} 968functions as an adapter to glue the data to the remote collection view.</p> 969 970<p>The two most important methods you need to implement for your 971 972{@link android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} 973subclass are 974{@link android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() 975onCreate()} and 976{@link android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int) 977getViewAt()} 978.</p> 979 980<p>The system calls {@link 981android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()} when 982creating your factory for the first time. This is where you set up any 983connections and/or cursors to your data source. For example, the <a 984href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 985sample</a> uses {@link 986android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()} to 987initialize an array of <code>WidgetItem</code> objects. When your app widget is 988active, the system accesses these objects using their index position in the 989array and the text they contain is displayed </p> 990 991<p>Here is an excerpt from the the <a 992href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget</a> 993sample's 994{@link android.widget.RemoteViewsService.RemoteViewsFactory 995RemoteViewsFactory} implementation that shows portions of the {@link 996android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()} 997method:</p> 998 999<pre>class StackRemoteViewsFactory implements 1000RemoteViewsService.RemoteViewsFactory { 1001 private static final int mCount = 10; 1002 private List<WidgetItem> mWidgetItems = new ArrayList<WidgetItem>(); 1003 private Context mContext; 1004 private int mAppWidgetId; 1005 1006 public StackRemoteViewsFactory(Context context, Intent intent) { 1007 mContext = context; 1008 mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 1009 AppWidgetManager.INVALID_APPWIDGET_ID); 1010 } 1011 1012 public void onCreate() { 1013 // In onCreate() you setup any connections / cursors to your data source. Heavy lifting, 1014 // for example downloading or creating content etc, should be deferred to onDataSetChanged() 1015 // or getViewAt(). Taking more than 20 seconds in this call will result in an ANR. 1016 for (int i = 0; i < mCount; i++) { 1017 mWidgetItems.add(new WidgetItem(i + "!")); 1018 } 1019 ... 1020 } 1021...</pre> 1022 1023<p>The {@link android.widget.RemoteViewsService.RemoteViewsFactory 1024RemoteViewsFactory} method {@link 1025android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int) getViewAt()} 1026returns a {@link android.widget.RemoteViews} object corresponding to the data at 1027the specified <code>position</code> in the data set. Here is an excerpt from 1028the <a 1029href="http://developer.android.com/resources/samples/StackWidget/index.html"> 1030StackView Widget</a> sample's {@link 1031android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} 1032implementation:</p> 1033 1034<pre>public RemoteViews getViewAt(int position) { 1035 1036 // Construct a remote views item based on the app widget item XML file, 1037 // and set the text based on the position. 1038 RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item); 1039 rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text); 1040 1041 ... 1042 // Return the remote views object. 1043 return rv; 1044}</pre> 1045 1046<h4 id="behavior">Adding behavior to individual items</h4> 1047 1048<p>The above sections show you how to bind your data to your app widget 1049collection. But what if you want to add dynamic behavior to the individual items 1050in your collection view?</p> 1051 1052<p> As described in <a href="#AppWidgetProvider">Using the AppWidgetProvider 1053Class</a>, you normally use {@link 1054android.widget.RemoteViews#setOnClickPendingIntent(int, 1055android.app.PendingIntent) setOnClickPendingIntent()} to set an object's click 1056behavior—such as to cause a button to launch an {@link 1057android.app.Activity}. But this approach is not allowed for child views in an 1058individual collection item (to clarify, you could use {@link 1059android.widget.RemoteViews#setOnClickPendingIntent(int, 1060android.app.PendingIntent) setOnClickPendingIntent()} to set up a global button 1061in the Gmail app widget that launches the app, for example, but not on the 1062individual list items). Instead, to add click behavior to individual items in a 1063collection, you use {@link 1064android.widget.RemoteViews#setOnClickFillInIntent(int, android.content.Intent) 1065setOnClickFillInIntent()}. This entails setting up up a pending intent template 1066for your collection view, and then setting a fill-in intent on each item in the 1067collection via your {@link android.widget.RemoteViewsService.RemoteViewsFactory 1068RemoteViewsFactory}.</p> 1069<p>This section uses the <a 1070href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 1071sample</a> to describe how to add behavior to individual items. In the <a 1072href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 1073sample</a>, if the user touches the top view, the app widget displays the {@link 1074android.widget.Toast} message "Touched view <em>n</em>," where 1075<em>n</em> is the index (position) of the touched view. This is how it 1076works:</p> 1077 1078<ul> 1079 <li>The <code>StackWidgetProvider</code> (an {@link 1080android.appwidget.AppWidgetProvider} subclass) creates a pending intent that has 1081a custom action called <code>TOAST_ACTION</code>.</li> 1082 <li>When the user touches a view, the intent is fired and it broadcasts 1083<code>TOAST_ACTION</code>.</li> 1084 1085 <li>This broadcast is intercepted by the <code>StackWidgetProvider</code>'s 1086{@link android.appwidget.AppWidgetProvider#onReceive(android.content.Context, 1087android.content.Intent) onReceive()} method, and the app widget displays the 1088{@link 1089android.widget.Toast} message for the touched view. The data for the collection 1090items is provided by the {@link 1091android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, via 1092the {@link android.widget.RemoteViewsService}.</li> 1093</ul> 1094 1095<p class="note"><strong>Note:</strong> The <a 1096href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 1097sample</a> uses a broadcast, but typically an app widget would simply launch an 1098activity in a scenario like this one.</p> 1099 1100<h5>Setting up the pending intent template</h5> 1101 1102<p>The <code>StackWidgetProvider</code> ({@link 1103android.appwidget.AppWidgetProvider} subclass) sets up a pending intent. 1104Individuals items of a collection cannot set up their own pending intents. 1105Instead, the collection as a whole sets up a pending intent template, and the 1106individual items set a fill-in intent to create unique behavior on an 1107item-by-item 1108basis.</p> 1109 1110<p>This class also receives the broadcast that is sent when the user touches a 1111view. It processes this event in its {@link 1112android.appwidget.AppWidgetProvider#onReceive(android.content.Context, 1113android.content.Intent) onReceive()} method. If the intent's action is 1114<code>TOAST_ACTION</code>, the app widget displays a {@link 1115android.widget.Toast} 1116message for the current view.</p> 1117 1118<pre>public class StackWidgetProvider extends AppWidgetProvider { 1119 public static final String TOAST_ACTION = "com.example.android.stackwidget.TOAST_ACTION"; 1120 public static final String EXTRA_ITEM = "com.example.android.stackwidget.EXTRA_ITEM"; 1121 1122 ... 1123 1124 // Called when the BroadcastReceiver receives an Intent broadcast. 1125 // Checks to see whether the intent's action is TOAST_ACTION. If it is, the app widget 1126 // displays a Toast message for the current item. 1127 @Override 1128 public void onReceive(Context context, Intent intent) { 1129 AppWidgetManager mgr = AppWidgetManager.getInstance(context); 1130 if (intent.getAction().equals(TOAST_ACTION)) { 1131 int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 1132 AppWidgetManager.INVALID_APPWIDGET_ID); 1133 int viewIndex = intent.getIntExtra(EXTRA_ITEM, 0); 1134 Toast.makeText(context, "Touched view " + viewIndex, Toast.LENGTH_SHORT).show(); 1135 } 1136 super.onReceive(context, intent); 1137 } 1138 1139 @Override 1140 public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 1141 // update each of the app widgets with the remote adapter 1142 for (int i = 0; i < appWidgetIds.length; ++i) { 1143 1144 // Sets up the intent that points to the StackViewService that will 1145 // provide the views for this collection. 1146 Intent intent = new Intent(context, StackWidgetService.class); 1147 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); 1148 // When intents are compared, the extras are ignored, so we need to embed the extras 1149 // into the data so that the extras will not be ignored. 1150 intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); 1151 RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout); 1152 rv.setRemoteAdapter(appWidgetIds[i], R.id.stack_view, intent); 1153 1154 // The empty view is displayed when the collection has no items. It should be a sibling 1155 // of the collection view. 1156 rv.setEmptyView(R.id.stack_view, R.id.empty_view); 1157 1158 // This section makes it possible for items to have individualized behavior. 1159 // It does this by setting up a pending intent template. Individuals items of a collection 1160 // cannot set up their own pending intents. Instead, the collection as a whole sets 1161 // up a pending intent template, and the individual items set a fillInIntent 1162 // to create unique behavior on an item-by-item basis. 1163 Intent toastIntent = new Intent(context, StackWidgetProvider.class); 1164 // Set the action for the intent. 1165 // When the user touches a particular view, it will have the effect of 1166 // broadcasting TOAST_ACTION. 1167 toastIntent.setAction(StackWidgetProvider.TOAST_ACTION); 1168 toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); 1169 intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); 1170 PendingIntent toastPendingIntent = PendingIntent.getBroadcast(context, 0, toastIntent, 1171 PendingIntent.FLAG_UPDATE_CURRENT); 1172 rv.setPendingIntentTemplate(R.id.stack_view, toastPendingIntent); 1173 1174 appWidgetManager.updateAppWidget(appWidgetIds[i], rv); 1175 } 1176 super.onUpdate(context, appWidgetManager, appWidgetIds); 1177 } 1178}</pre> 1179 1180<h5><strong>Setting the fill-in Intent</strong></h5> 1181 1182<p>Your {@link android.widget.RemoteViewsService.RemoteViewsFactory 1183RemoteViewsFactory} must set a fill-in intent on each item in the collection. 1184This makes it possible to distinguish the individual on-click action of a given 1185item. The fill-in intent is then combined with the {@link 1186android.app.PendingIntent} template in order to determine the final intent that 1187will be executed when the item is clicked. </p> 1188 1189<pre> 1190public class StackWidgetService extends RemoteViewsService { 1191 @Override 1192 public RemoteViewsFactory onGetViewFactory(Intent intent) { 1193 return new StackRemoteViewsFactory(this.getApplicationContext(), intent); 1194 } 1195} 1196 1197class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { 1198 private static final int mCount = 10; 1199 private List<WidgetItem> mWidgetItems = new ArrayList<WidgetItem>(); 1200 private Context mContext; 1201 private int mAppWidgetId; 1202 1203 public StackRemoteViewsFactory(Context context, Intent intent) { 1204 mContext = context; 1205 mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 1206 AppWidgetManager.INVALID_APPWIDGET_ID); 1207 } 1208 1209 // Initialize the data set. 1210 public void onCreate() { 1211 // In onCreate() you set up any connections / cursors to your data source. Heavy lifting, 1212 // for example downloading or creating content etc, should be deferred to onDataSetChanged() 1213 // or getViewAt(). Taking more than 20 seconds in this call will result in an ANR. 1214 for (int i = 0; i < mCount; i++) { 1215 mWidgetItems.add(new WidgetItem(i + "!")); 1216 } 1217 ... 1218 } 1219 ... 1220 1221 // Given the position (index) of a WidgetItem in the array, use the item's text value in 1222 // combination with the app widget item XML file to construct a RemoteViews object. 1223 public RemoteViews getViewAt(int position) { 1224 // position will always range from 0 to getCount() - 1. 1225 1226 // Construct a RemoteViews item based on the app widget item XML file, and set the 1227 // text based on the position. 1228 RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item); 1229 rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text); 1230 1231 // Next, set a fill-intent, which will be used to fill in the pending intent template 1232 // that is set on the collection view in StackWidgetProvider. 1233 Bundle extras = new Bundle(); 1234 extras.putInt(StackWidgetProvider.EXTRA_ITEM, position); 1235 Intent fillInIntent = new Intent(); 1236 fillInIntent.putExtras(extras); 1237 // Make it possible to distinguish the individual on-click 1238 // action of a given item 1239 rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent); 1240 1241 ... 1242 1243 // Return the RemoteViews object. 1244 return rv; 1245 } 1246 ... 1247 }</pre> 1248 1249<h3 id="fresh">Keeping Collection Data Fresh</h3> 1250 1251<p>The following figure illustrates the flow that occurs in an App Widget that 1252uses 1253collections when updates occur. It shows how the App Widget code interacts with 1254the {@link android.widget.RemoteViewsService.RemoteViewsFactory 1255RemoteViewsFactory}, and how you can trigger updates:</p> 1256 1257<img src="{@docRoot}images/appwidget_collections.png" alt="" /> 1258 1259<p>One feature of App Widgets that use collections is the ability to provide 1260users with up-to-date content. For example, consider the Android 3.0 Gmail 1261app widget, which provides users with a snapshot of their inbox. To make this 1262possible, you need to be able to trigger your {@link 1263android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} and 1264collection view to fetch and display new data. You achieve this with the {@link 1265android.appwidget.AppWidgetManager} call {@link 1266android.appwidget.AppWidgetManager#notifyAppWidgetViewDataChanged(int, int) 1267notifyAppWidgetViewDataChanged()}. This call results in a callback to your 1268<code>RemoteViewsFactory</code>’s {@link 1269android.widget.RemoteViewsService.RemoteViewsFactory#onDataSetChanged() 1270onDataSetChanged()} method, which gives you the opportunity to fetch any new 1271data. Note that you can perform 1272processing-intensive operations synchronously within the {@link 1273android.widget.RemoteViewsService.RemoteViewsFactory#onDataSetChanged() 1274onDataSetChanged()} callback. You are guaranteed that this call will be 1275completed before the metadata or view data is fetched from the {@link 1276android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}. In 1277addition, you can perform processing-intensive operations within the {@link 1278android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int) getViewAt()} 1279method. If this call takes a long time, the loading view (specified by the 1280<code>RemoteViewsFactory</code>’s {@link 1281android.widget.RemoteViewsService.RemoteViewsFactory#getLoadingView()} method) 1282will be displayed in the corresponding position of the collection view until it 1283returns.</p> 1284 1285 1286