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