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