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