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