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