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