1 page.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 9 directly 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 11 handles the App 12 Widget 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 24 Intents</a></li> 25 </ol> 26 </li> 27 <li><a href="#Configuring">Creating an App Widget Configuration 28 Activity</a> 29 <ol> 30 <li><a href="#UpdatingFromTheConfiguration">Updating the App Widget 31 from 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 40 collections 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 57 href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget 58 Design 59 Guidelines</a></li> 60 <li><a 61 href="http://android-developers.blogspot.com/2009/04/introducing-home-screen- 62 widgets-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 70 applications 71 (such as the Home screen) and receive periodic updates. These views are 72 referred 73 to as Widgets in the user interface, 74 and you can publish one with an App Widget provider. An application component 75 that is 76 able to hold other App Widgets is called an App Widget host. The screenshot 77 below shows 78 the 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 83 provider.</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, 93 update 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 97 with the App Widget, 98 based on broadcast events. Through it, you will receive broadcasts when the 99 App 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 106 an optional 107 {@link android.app.Activity} that launches when the user adds your App Widget 108 and allows him or her 109 to 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 117 application'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> 132 attribute, which specifies the {@link android.appwidget.AppWidgetProvider} used 133 by the App Widget.</p> 134 135 <p>The <code><intent-filter></code> element must include an 136 <code><action></code> 137 element with the <code>android:name</code> attribute. This attribute specifies 138 that the {@link android.appwidget.AppWidgetProvider} accepts the {@link 139 android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE 140 ACTION_APPWIDGET_UPDATE} broadcast. 141 This is the only broadcast that you must explicitly declare. The {@link 142 android.appwidget.AppWidgetManager} 143 automatically sends all other App Widget broadcasts to the AppWidgetProvider as 144 necessary.</p> 145 146 <p>The <code><meta-data></code> element specifies the 147 {@link android.appwidget.AppWidgetProviderInfo} resource and requires the 148 following 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} 153 descriptor.</li> 154 <li><code>android:resource</code> - Specifies the {@link 155 android.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 163 qualities of an App Widget, such as its minimum layout dimensions, its initial 164 layout resource, 165 how often to update the App Widget, and (optionally) a configuration Activity to 166 launch at create-time. 167 Define 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> 170 folder.</p> 171 172 <p>For example:</p> 173 174 <pre> 175 <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" 176 android:minWidth="294dp" 177 android:minHeight="72dp" 178 android:updatePeriodMillis="86400000" 179 android:previewImage="@drawable/preview" 180 android:initialLayout="@layout/example_appwidget" 181 android:configure="com.example.android.ExampleAppWidgetConfigure" 182 android:resizeMode="horizontal|vertical"> 183 </appwidget-provider> 184 </pre> 185 186 <p>Here's a summary of the <code><appwidget-provider></code> attributes:</p> 187 <ul> 188 <li>The values for the <code>minWidth</code> and <code>minHeight</code> 189 attributes specify the minimum 190 area required by the App Widget's layout. 191 <p>The default Home screen positions App Widgets in its window based on a 192 grid of 193 cells that have a defined height and width. If the values for an App 194 Widget'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 198 href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget 199 Design 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) 202 can change, 203 as a rule of thumb, you should assume the worst-case cell size of 74 pixels 204 for the height 205 <em>and</em> width of a cell. However, you must subtract 2 from the final 206 dimension to account 207 for any integer rounding errors that occur in the pixel count. To find your 208 minimum 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 212 dp and for a width of four cells.</p> 213 <p class="note"><strong>Note:</strong> To make your app widget portable across 214 devices, your app widget's minimum size should never be larger than 4 x 4 cells. 215 See the <a 216 href="{@docRoot}guide/practices/ui_guidelines/widget_design.html#sizes">App 217 Widget 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 220 Widget framework should request an update from the {@link 221 android.appwidget.AppWidgetProvider} by calling the 222 {@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,android.appwidget.AppWidgetManager,int[]) onUpdate()} 223 callback method. The actual update 224 is not guaranteed to occur exactly on time with this value and we suggest 225 updating as infrequently as possible—perhaps no more than once an hour to 226 conserve the battery. You might also allow the user to adjust the frequency in a 227 configuration—some people might want a stock ticker to update every 15 228 minutes, or maybe only four times a day. 229 <p class="note"><strong>Note:</strong> If the device is asleep when it 230 is time for an update 231 (as defined by <code>updatePeriodMillis</code>), then the device will 232 wake up in order 233 to perform the update. If you don't update more than once per hour, this 234 probably won't 235 cause significant problems for the battery life. If, however, you need 236 to update more 237 frequently and/or you do not need to update while the device is asleep, 238 then you can instead 239 perform updates based on an alarm that will not wake the device. To do 240 so, set an alarm with 241 an Intent that your AppWidgetProvider receives, using the {@link 242 android.app.AlarmManager}. 243 Set the alarm type to either {@link 244 android.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 251 that defines the 252 App Widget layout.</li> 253 <li>The <code>configure</code> attribute defines the {@link 254 android.app.Activity} to launch when 255 the user adds the App Widget, in order for him or her to configure App 256 Widget properties. This is optional 257 (read <a href="#Configuring">Creating an App Widget Configuration 258 Activity</a> below).</li> 259 260 <li>The <code>previewImage</code> attribute specifies a preview of what the 261 app widget will look like after it's configured, which the user sees when 262 selecting the app widget. If not supplied, the user instead sees your 263 application's launcher icon. This field corresponds to the 264 <code>android:previewImage</code> attribute in the <code><receiver></code> 265 element in the <code>AndroidManifest.xml</code> file. For more discussion of 266 using <code>previewImage</code>, see <a href="#preview">Setting a Preview 267 Image</a>. Introduced in Android 3.0.</li> 268 269 <li>The <code>autoAdvanceViewId</code> attribute specifies the view ID of the 270 app 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 273 can be resized. You use this attribute to make homescreen widgets 274 resizeable—horizontally, vertically, or on both axes. Users touch-hold a 275 widget to show its resize handles, then drag the horizontal and/or vertical 276 handles to change the size on the layout grid. Values for the 277 <code>resizeMode</code> attribute include "horizontal", "vertical", and "none". 278 To 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 282 information on the 283 attributes 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 289 the project's 290 <code>res/layout/</code> directory. You can design your App Widget using the 291 View objects listed 292 below, but before you begin designing your App Widget, please read and 293 understand the 294 <a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget 295 Design 296 Guidelines</a>.</p> 297 298 <p>Creating the App Widget layout is simple if you're 299 familiar with <a 300 href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a>. 301 However, you must be aware that App Widget layouts are based on {@link 302 android.widget.RemoteViews}, 303 which 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 306 following 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 381 broadcast 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 388 BroadcastReceiver as a convenience 389 class to handle the App Widget broadcasts. The AppWidgetProvider receives only 390 the event broadcasts that 391 are relevant to the App Widget, such as when the App Widget is updated, deleted, 392 enabled, and disabled. 393 When these broadcast events occur, the AppWidgetProvider receives the following 394 method 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 407 configuration 408 Activity, <strong>this method is not called</strong> when the user adds the 409 App 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 412 done. 413 (See <a href="#Configuring">Creating an App Widget Configuration 414 Activity</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 417 host.</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 420 time. 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 423 occur 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 427 the 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 433 methods. 434 You normally don't need to implement this method because the default 435 AppWidgetProvider 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 441 in which the 442 <code>onDeleted()</code> method will not be called when it should be. To work 443 around this issue, 444 you can implement {@link 445 android.appwidget.AppWidgetProvider#onReceive(Context,Intent) 446 onReceive()} as described in this 447 <a 448 href="http://groups.google.com/group/android-developers/msg/e405ca19df2170e2"> 449 Group post</a> 450 to 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()} 455 because it is called when 456 each App Widget is added to a host (unless you use a configuration Activity). If 457 your App Widget accepts any user interaction events, then you need to register 458 the event handlers in this callback. If your App Widget doesn't create temporary 459 files 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()} 461 may be the only callback 462 method you need to define. For example, if you want an App Widget with a button 463 that launches an Activity when clicked, you could use the following 464 implementation of AppWidgetProvider:</p> 465 466 <pre> 467 public 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 494 android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[]) onUpdate()} 495 method for the purpose of 496 defining a {@link android.app.PendingIntent} that launches an {@link 497 android.app.Activity} and attaching it to the App Widget's button with {@link 498 android.widget.RemoteViews#setOnClickPendingIntent(int,PendingIntent)}. Notice 499 that it includes a loop that iterates through each entry in 500 <code>appWidgetIds</code>, which is an array of IDs that identify each App 501 Widget created by this provider. In this way, if the user creates more than one 502 instance of the App Widget, then they are all updated simultaneously. However, 503 only one <code>updatePeriodMillis</code> schedule will be managed for all 504 instances of the App Widget. For example, if the update schedule is defined to 505 be every two hours, and a second instance of the App Widget is added one hour 506 after the first one, then they will both be updated on the period defined by the 507 first one and the second update period will be ignored (they'll both be updated 508 every two hours, not every hour).</p> 509 510 <p class="note"><strong>Note:</strong> Because {@link 511 android.appwidget.AppWidgetProvider} is an extension of {@link 512 android.content.BroadcastReceiver}, your process is not guaranteed to keep 513 running after the callback methods return (see {@link 514 android.content.BroadcastReceiver} for information about the broadcast 515 lifecycle). If your App Widget setup process can take several seconds (perhaps 516 while performing web requests) and you require that your process continues, 517 consider starting a {@link android.app.Service} in the 518 {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) onUpdate()} 519 method. From within the Service, you can perform your own updates 520 to the App Widget without worrying about the AppWidgetProvider closing down due 521 to an <a href="{@docRoot}guide/practices/design/responsiveness.html">Application 522 Not Responding</a> (ANR) error. See the <a 523 href="http://code.google.com/p/wiktionary-android/source/browse/trunk/Wiktionary 524 /src/com/example/android/wiktionary/WordWidget.java">Wiktionary sample's 525 AppWidgetProvider</a> for an example of an App Widget running a {@link 526 android.app.Service}.</p> 527 528 <p>Also see the <a 529 href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/ 530 appwidget/ExampleAppWidgetProvider.html"> 531 ExampleAppWidgetProvider.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 537 you would like 538 to 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. 541 The 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 554 App Widget, 555 you can create an App Widget configuration Activity. This {@link 556 android.app.Activity} 557 will be automatically launched by the App Widget host and allows the user to 558 configure 559 available settings for the App Widget at create-time, such as the App Widget 560 color, size, 561 update period or other functionality settings.</p> 562 563 <p>The configuration Activity should be declared as a normal Activity in the 564 Android manifest file. 565 However, it will be launched by the App Widget host with the {@link 566 android.appwidget.AppWidgetManager#ACTION_APPWIDGET_CONFIGURE 567 ACTION_APPWIDGET_CONFIGURE} action, 568 so 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, 579 with the 580 <code>android:configure</code> attribute (see <a href="#MetaData">Adding 581 the AppWidgetProviderInfo Metadata</a> above). For example, the configuration 582 Activity 583 can 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, 594 because 595 it 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 598 need is the actual 599 Activity. There are, however, two important things to remember when you 600 implement the Activity:</p> 601 <ul> 602 <li>The App Widget host calls the configuration Activity and the configuration 603 Activity 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 606 as 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 611 is created 612 (the system will not send the ACTION_APPWIDGET_UPDATE broadcast when a 613 configuration Activity 614 is launched). It is the responsibility of the configuration Activity to 615 request 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 619 the first time.</li> 620 </ul> 621 622 <p>See the code snippets in the following section for an example of how to 623 return a result 624 from the configuration and update the App Widget.</p> 625 626 627 <h3 id="UpdatingFromTheConfiguration">Updating the App Widget from the 628 configuration Activity</h3> 629 630 <p>When an App Widget uses a configuration Activity, it is the responsibility of 631 the Activity 632 to update the App Widget when configuration is complete. 633 You 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 637 the configuration Activity:</p> 638 639 <ol> 640 <li>First, get the App Widget ID from the Intent that launched the Activity: 641 <pre> 642 Intent intent = getIntent(); 643 Bundle extras = intent.getExtras(); 644 if (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 653 AppWidgetManager by calling 654 {@link android.appwidget.AppWidgetManager#getInstance(Context)}: 655 <pre> 656 AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); 657 </pre> 658 </li> 659 <li>Update the App Widget with a {@link android.widget.RemoteViews} layout by 660 calling 661 {@link android.appwidget.AppWidgetManager#updateAppWidget(int,RemoteViews)}: 662 <pre> 663 RemoteViews views = new RemoteViews(context.getPackageName(), 664 R.layout.example_appwidget); 665 appWidgetManager.updateAppWidget(mAppWidgetId, views); 666 </pre> 667 </li> 668 <li>Finally, create the return Intent, set it with the Activity result, and 669 finish the Activity:</li> 670 <pre> 671 Intent resultValue = new Intent(); 672 resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); 673 setResult(RESULT_OK, resultValue); 674 finish(); 675 </pre> 676 </li> 677 </ol> 678 679 <p class="note"><strong>Tip:</strong> When your configuration Activity first 680 opens, set 681 the Activity result to RESULT_CANCELED. This way, if the user backs-out of the 682 Activity before 683 reaching the end, the App Widget host is notified that the configuration was 684 cancelled and the 685 App Widget will not be added.</p> 686 687 <p>See the <a 688 href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/ 689 appwidget/ExampleAppWidgetConfigure.html"> 690 ExampleAppWidgetConfigure.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 697 android.appwidget.AppWidgetProviderInfo#previewImage} field, which specifies a 698 preview of what the app widget looks like. This preview is shown to the user from the 699 widget picker. If this field is not supplied, the app widget's icon is used for 700 the 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 710 android.appwidget.AppWidgetProviderInfo#previewImage} field), the Android 711 emulator includes an application called "Widget Preview." To create a 712 preview image, launch this application, select the app widget for your 713 application and set it up how you'd like your preview image to appear, then save 714 it 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 719 Widgets use the {@link android.widget.RemoteViewsService} to display collections 720 that are backed by remote data, such as from a <a 721 href="{@docRoot}guide/topics/providers/content-providers.html">content 722 provider</a>. The data provided by the {@link android.widget.RemoteViewsService} 723 is presented in the App Widget using one of the following view types, which 724 well 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 729 vertically scrolling 730 list. For an example, see the Gmail app widget. </dd> 731 <dt>{@link android.widget.GridView}</dt> 732 <dd>A view that shows items in 733 two-dimensional scrolling grid. For an example, see the Bookmarks app 734 widget.</dd> 735 <dt>{@link android.widget.StackView}</dt> 736 <dd>A 737 stacked card view (kind of like a rolodex), where the user can flick the front 738 card up/down to see the previous/next card, respectively. Examples include 739 the YouTube and Books app widgets.</dd> 740 <dt>{@link android.widget.AdapterViewFlipper}</dt> 741 <dd>An adapter-backed simple 742 {@link 743 android.widget.ViewAnimator} that animates between two or more views. Only one 744 child is shown at a time. </dd> 745 </dl> 746 747 <p>As stated above, these collection views display collections backed by remote 748 data. This means that they use an {@link android.widget.Adapter} to bind their 749 user interface to their data. An {@link android.widget.Adapter} binds individual 750 items from a set of data into individual {@link android.view.View} objects. 751 Because these collection views are backed by adapters, the Android framework 752 must include extra architecture to support their use in app widgets. In the 753 context of an app widget, the {@link android.widget.Adapter} is replaced by a 754 {@link android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, 755 which is simply a thin wrapper around the {@link android.widget.Adapter} 756 interface. 757 When 758 requested for a specific item in the collection, the {@link 759 android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} creates 760 and returns the item for the collection as a {@link android.widget.RemoteViews} 761 object. 762 In order to include a collection view in your app widget, you 763 must implement {@link android.widget.RemoteViewsService} and {@link 764 android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}.</p> 765 766 <p> {@link android.widget.RemoteViewsService} is a service that allows a remote 767 adapter to request {@link 768 android.widget.RemoteViews} objects. {@link 769 android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} is an 770 interface for an adapter between a collection view (such as {@link 771 android.widget.ListView}, {@link android.widget.GridView}, and so on) and the 772 underlying data for that view. From the <a 773 href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 774 sample</a>, here is an example of the boilerplate code you use to implement 775 this service and interface: 776 </p> 777 778 <pre> 779 public class StackWidgetService extends RemoteViewsService { 780 @Override 781 public RemoteViewsFactory onGetViewFactory(Intent intent) { 782 return new StackRemoteViewsFactory(this.getApplicationContext(), intent); 783 } 784 } 785 786 class 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 796 href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 797 sample</a>:</p> 798 799 <p> 800 <img src="{@docRoot}resources/samples/images/StackWidget.png" alt="StackView 801 Widget" /> 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 806 app widget has these primary behaviors:</p> 807 808 <ul> 809 810 <li>The user can vertically fling the top view in the 811 app widget to display the next or previous view. This is a built-in StackView 812 behavior.</li> 813 814 <li>Without any user interaction, the app widget automatically advances 815 through 816 its 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 819 ID, 820 which 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 823 android.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 825 how 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 832 you would use to implement any app widget. The following sections describe the 833 additional steps you need to perform to implement an App Widget with 834 collections.</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 839 App Widget in the Manifest</a>, to make it possible for App Widgets with 840 collections to bind to your {@link android.widget.RemoteViewsService}, you must 841 declare the service in your manifest file with the permission {@link 842 android.Manifest.permission#BIND_REMOTEVIEWS}. This prevents other applications 843 from freely accessing your app widget's data. For example, when creating an App 844 Widget that uses {@link android.widget.RemoteViewsService} to populate a 845 collection view, the manifest entry may look like this:</p> 846 847 <pre><service android:name="MyWidgetService" 848 ... 849 android:permission="android.permission.BIND_REMOTEVIEWS" /></pre> 850 851 <p>The line <code>android:name="MyWidgetService"</code> 852 refers 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 857 include 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 861 the <a href="{@docRoot}resources/samples/StackWidget/index.html">StackView 862 Widget 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 888 empty view represents empty state. </p> 889 890 <p>In addition to the layout file for your entire app widget, you must create 891 another layout file that defines the layout for each item in the collection (for 892 example, a layout for each book in a collection of books). For example, the <a 893 href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 894 sample</a> only has one layout file, <code>widget_item.xml</code>, since all 895 items use the same layout. But the <a 896 href="{@docRoot}resources/samples/WeatherListWidget/index.html"> 897 WeatherListWidget 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 905 android.appwidget.AppWidgetProvider} subclass typically goes in {@link 906 android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, 907 android.appwidget.AppWidgetManager, int[]) onUpdate()}. The major difference in 908 your implementation for {@link 909 android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, 910 android.appwidget.AppWidgetManager, int[]) onUpdate()} when creating an app 911 widget with collections is that you must call {@link 912 android.widget.RemoteViews#setRemoteAdapter setRemoteAdapter()}. This tells the 913 collection view where to get its data. The {@link 914 android.widget.RemoteViewsService} can then return your implementation of {@link 915 android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, and 916 the widget can serve up the appropriate data. When you call this method, you 917 must pass an intent that points to your implementation of {@link 918 android.widget.RemoteViewsService} and the App Widget ID that specifies the app 919 widget to update.</p> 920 921 922 <p>For example, here's how the StackView Widget sample implements the {@link 923 android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, 924 android.appwidget.AppWidgetManager, int[]) onUpdate()} callback method to set 925 the {@link 926 android.widget.RemoteViewsService} as the remote adapter for the app widget 927 collection:</p> 928 929 <pre>public void onUpdate(Context context, AppWidgetManager appWidgetManager, 930 int[] 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 cant rely on a single instance of your service, or any data it 968 contains, to persist. You should therefore not store any data in your {@link 969 android.widget.RemoteViewsService} (unless it is static). If you want your 970 app widgets data to persist, the best approach is to use a {@link 971 android.content.ContentProvider} whose data persists beyond the process 972 lifecycle.</p> </div> 973 </div> 974 975 <p>As described above, your {@link android.widget.RemoteViewsService} subclass 976 provides the {@link android.widget.RemoteViewsService.RemoteViewsFactory 977 RemoteViewsFactory} used to populate the remote collection view.</p> 978 979 <p>Specifically, you need to 980 perform these steps:</p> 981 982 <ol> 983 <li>Subclass {@link android.widget.RemoteViewsService}. {@link 984 android.widget.RemoteViewsService} is the service through which 985 a remote adapter can request {@link android.widget.RemoteViews}. </li> 986 987 <li>In your {@link android.widget.RemoteViewsService} subclass, include a 988 class that implements the {@link 989 android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} 990 interface. {@link android.widget.RemoteViewsService.RemoteViewsFactory 991 RemoteViewsFactory} is an interface for an adapter between a remote collection 992 view (such as {@link android.widget.ListView}, {@link android.widget.GridView}, 993 and so on) and the underlying data for that view. Your implementation is 994 responsible for making a {@link android.widget.RemoteViews} object for each 995 item in the data set. This interface is a thin wrapper around {@link 996 android.widget.Adapter}.</li> 997 </ol> 998 999 <p>The primary contents of the {@link android.widget.RemoteViewsService} 1000 implementation is its {@link 1001 android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, 1002 described below.</p> 1003 1004 <h4>RemoteViewsFactory interface</h4> 1005 1006 <p>Your custom class that implements the {@link 1007 android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} 1008 interface provides the app widget with the data for the items in its collection. 1009 To 1010 do this, it combines your app widget item XML layout file with a source of data. 1011 This 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 1013 sample</a>, the data source is an array of <code>WidgetItems</code>. The {@link 1014 android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} 1015 functions 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} 1020 subclass are 1021 {@link android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() 1022 onCreate()} and 1023 {@link android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int) 1024 getViewAt()} 1025 .</p> 1026 1027 <p>The system calls {@link 1028 android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()} when 1029 creating your factory for the first time. This is where you set up any 1030 connections and/or cursors to your data source. For example, the <a 1031 href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 1032 sample</a> uses {@link 1033 android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()} to 1034 initialize an array of <code>WidgetItem</code> objects. When your app widget is 1035 active, the system accesses these objects using their index position in the 1036 array and the text they contain is displayed </p> 1037 1038 <p>Here is an excerpt from the the <a 1039 href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget</a> 1040 sample's 1041 {@link android.widget.RemoteViewsService.RemoteViewsFactory 1042 RemoteViewsFactory} implementation that shows portions of the {@link 1043 android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()} 1044 method:</p> 1045 1046 <pre>class StackRemoteViewsFactory implements 1047 RemoteViewsService.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 1071 RemoteViewsFactory} method {@link 1072 android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int) getViewAt()} 1073 returns a {@link android.widget.RemoteViews} object corresponding to the data at 1074 the specified <code>position</code> in the data set. Here is an excerpt from 1075 the <a 1076 href="http://developer.android.com/resources/samples/StackWidget/index.html"> 1077 StackView Widget</a> sample's {@link 1078 android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} 1079 implementation:</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 1096 collection. But what if you want to add dynamic behavior to the individual items 1097 in your collection view?</p> 1098 1099 <p> As described in <a href="#AppWidgetProvider">Using the AppWidgetProvider 1100 Class</a>, you normally use {@link 1101 android.widget.RemoteViews#setOnClickPendingIntent(int, 1102 android.app.PendingIntent) setOnClickPendingIntent()} to set an object's click 1103 behavior—such as to cause a button to launch an {@link 1104 android.app.Activity}. But this approach is not allowed for child views in an 1105 individual collection item (to clarify, you could use {@link 1106 android.widget.RemoteViews#setOnClickPendingIntent(int, 1107 android.app.PendingIntent) setOnClickPendingIntent()} to set up a global button 1108 in the Gmail app widget that launches the app, for example, but not on the 1109 individual list items). Instead, to add click behavior to individual items in a 1110 collection, you use {@link 1111 android.widget.RemoteViews#setOnClickFillInIntent(int, android.content.Intent) 1112 setOnClickFillInIntent()}. This entails setting up up a pending intent template 1113 for your collection view, and then setting a fill-in intent on each item in the 1114 collection via your {@link android.widget.RemoteViewsService.RemoteViewsFactory 1115 RemoteViewsFactory}.</p> 1116 <p>This section uses the <a 1117 href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 1118 sample</a> to describe how to add behavior to individual items. In the <a 1119 href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 1120 sample</a>, if the user touches the top view, the app widget displays the {@link 1121 android.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 1123 works:</p> 1124 1125 <ul> 1126 <li>The <code>StackWidgetProvider</code> (an {@link 1127 android.appwidget.AppWidgetProvider} subclass) creates a pending intent that has 1128 a 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, 1134 android.content.Intent) onReceive()} method, and the app widget displays the 1135 {@link 1136 android.widget.Toast} message for the touched view. The data for the collection 1137 items is provided by the {@link 1138 android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, via 1139 the {@link android.widget.RemoteViewsService}.</li> 1140 </ul> 1141 1142 <p class="note"><strong>Note:</strong> The <a 1143 href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 1144 sample</a> uses a broadcast, but typically an app widget would simply launch an 1145 activity 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 1150 android.appwidget.AppWidgetProvider} subclass) sets up a pending intent. 1151 Individuals items of a collection cannot set up their own pending intents. 1152 Instead, the collection as a whole sets up a pending intent template, and the 1153 individual items set a fill-in intent to create unique behavior on an 1154 item-by-item 1155 basis.</p> 1156 1157 <p>This class also receives the broadcast that is sent when the user touches a 1158 view. It processes this event in its {@link 1159 android.appwidget.AppWidgetProvider#onReceive(android.content.Context, 1160 android.content.Intent) onReceive()} method. If the intent's action is 1161 <code>TOAST_ACTION</code>, the app widget displays a {@link 1162 android.widget.Toast} 1163 message 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 1230 RemoteViewsFactory} must set a fill-in intent on each item in the collection. 1231 This makes it possible to distinguish the individual on-click action of a given 1232 item. The fill-in intent is then combined with the {@link 1233 android.app.PendingIntent} template in order to determine the final intent that 1234 will be executed when the item is clicked. </p> 1235 1236 <pre> 1237 public class StackWidgetService extends RemoteViewsService { 1238 @Override 1239 public RemoteViewsFactory onGetViewFactory(Intent intent) { 1240 return new StackRemoteViewsFactory(this.getApplicationContext(), intent); 1241 } 1242 } 1243 1244 class 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 1299 uses 1300 collections when updates occur. It shows how the App Widget code interacts with 1301 the {@link android.widget.RemoteViewsService.RemoteViewsFactory 1302 RemoteViewsFactory}, 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 1307 users with up-to-date content. For example, consider the Android 3.0 Gmail 1308 app widget, which provides users with a snapshot of their inbox. To make this 1309 possible, you need to be able to trigger your {@link 1310 android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} and 1311 collection view to fetch and display new data. You achieve this with the {@link 1312 android.appwidget.AppWidgetManager} call {@link 1313 android.appwidget.AppWidgetManager#notifyAppWidgetViewDataChanged(int, int) 1314 notifyAppWidgetViewDataChanged()}. This call results in a callback to your 1315 <code>RemoteViewsFactory</code>s {@link 1316 android.widget.RemoteViewsService.RemoteViewsFactory#onDataSetChanged() 1317 onDataSetChanged()} method, which gives you the opportunity to fetch any new 1318 data. Note that you can perform 1319 processing-intensive operations synchronously within the {@link 1320 android.widget.RemoteViewsService.RemoteViewsFactory#onDataSetChanged() 1321 onDataSetChanged()} callback. You are guaranteed that this call will be 1322 completed before the metadata or view data is fetched from the {@link 1323 android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}. In 1324 addition, you can perform processing-intensive operations within the {@link 1325 android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int) getViewAt()} 1326 method. If this call takes a long time, the loading view (specified by the 1327 <code>RemoteViewsFactory</code>s {@link 1328 android.widget.RemoteViewsService.RemoteViewsFactory#getLoadingView()} method) 1329 will be displayed in the corresponding position of the collection view until it 1330 returns.</p> 1331 1332 1333