blob: 2cb23c1cdbbab69ba511c971858b185d4213704e [file] [log] [blame]
Scott Main04c72b42009-05-13 16:48:13 -07001page.title=App Widgets
Scott Main620986a2009-04-22 18:58:13 -07002@jd:body
3
4<div id="qv-wrapper">
5 <div id="qv">
Scott Mainec80d7f2010-09-24 16:17:27 -07006 <h2>Quickview</h2>
7 <ul>
8 <li>App Widgets provide users access to some of your application features
9directly from the Home screen (without the need to launch an activity)</li>
Katie McCormick566489d2011-03-28 17:08:08 -070010 <li>App Widgets are backed by a special kind of broadcast receiver that
11handles the App
Scott Mainec80d7f2010-09-24 16:17:27 -070012Widget lifecycle</li>
13 </ul>
14
Scott Main620986a2009-04-22 18:58:13 -070015 <h2>In this document</h2>
16 <ol>
Scott Main04c72b42009-05-13 16:48:13 -070017 <li><a href="#Basics">The Basics</a></li>
18 <li><a href="#Manifest">Declaring an App Widget in the Manifest</a></li>
19 <li><a href="#MetaData">Adding the AppWidgetProviderInfo Metadata</a></li>
20 <li><a href="#CreatingLayout">Creating the App Widget Layout</a></li>
21 <li><a href="#AppWidgetProvider">Using the AppWidgetProvider Class</a>
Scott Main620986a2009-04-22 18:58:13 -070022 <ol>
Katie McCormick566489d2011-03-28 17:08:08 -070023 <li><a href="#ProviderBroadcasts">Receiving App Widget broadcast
24Intents</a></li>
Scott Main620986a2009-04-22 18:58:13 -070025 </ol>
26 </li>
Katie McCormick566489d2011-03-28 17:08:08 -070027 <li><a href="#Configuring">Creating an App Widget Configuration
28Activity</a>
Scott Main04c72b42009-05-13 16:48:13 -070029 <ol>
Katie McCormick566489d2011-03-28 17:08:08 -070030 <li><a href="#UpdatingFromTheConfiguration">Updating the App Widget
31from
Scott Main04c72b42009-05-13 16:48:13 -070032 the configuration Activity</a></li>
33 </ol>
34 </li>
Katie McCormick566489d2011-03-28 17:08:08 -070035 <li><a href="#preview">Setting a Preview Image</a></li>
36 <li><a href="#collections">Using App Widgets with Collections</a>
37 <ol>
38 <li><a href="#collection_sample">Sample application</a></li>
39 <li><a href="#implementing_collections">Implementing app widgets with
40collections
41</a></li>
42 <li><a href="#fresh">Keeping Collection Data Fresh</a></li>
43 </ol>
44 </li>
Scott Main620986a2009-04-22 18:58:13 -070045 </ol>
46
Scott Mainec80d7f2010-09-24 16:17:27 -070047 <h2>Key classes</h2>
48 <ol>
49 <li>{@link android.appwidget.AppWidgetProvider}</li>
50 <li>{@link android.appwidget.AppWidgetProviderInfo}</li>
51 <li>{@link android.appwidget.AppWidgetManager}</li>
52 </ol>
53
Scott Main620986a2009-04-22 18:58:13 -070054 <h2>See also</h2>
55 <ol>
Katie McCormick566489d2011-03-28 17:08:08 -070056 <li><a
57href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget
58Design
Scott Main04c72b42009-05-13 16:48:13 -070059 Guidelines</a></li>
Katie McCormick566489d2011-03-28 17:08:08 -070060 <li><a
61href="http://android-developers.blogspot.com/2009/04/introducing-home-screen-
62widgets-and.html">Introducing
Scott Main04c72b42009-05-13 16:48:13 -070063 home screen widgets and the AppWidget framework &raquo;</a></li>
Scott Main620986a2009-04-22 18:58:13 -070064 </ol>
65 </div>
66</div>
67
Scott Main04c72b42009-05-13 16:48:13 -070068
Katie McCormick566489d2011-03-28 17:08:08 -070069<p>App Widgets are miniature application views that can be embedded in other
70applications
71(such as the Home screen) and receive periodic updates. These views are
72referred
Scott Main04c72b42009-05-13 16:48:13 -070073to as Widgets in the user interface,
Katie McCormick566489d2011-03-28 17:08:08 -070074and you can publish one with an App Widget provider. An application component
75that is
76able to hold other App Widgets is called an App Widget host. The screenshot
77below shows
Scott Main04c72b42009-05-13 16:48:13 -070078the Music App Widget.</p>
79
80<img src="{@docRoot}images/appwidget.png" alt="" />
81
Katie McCormick566489d2011-03-28 17:08:08 -070082<p>This document describes how to publish an App Widget using an App Widget
83provider.</p>
Scott Main620986a2009-04-22 18:58:13 -070084
85
Scott Main04c72b42009-05-13 16:48:13 -070086<h2 id="Basics">The Basics</h2>
87
88<p>To create an App Widget, you need the following:</p>
89
90<dl>
91 <dt>{@link android.appwidget.AppWidgetProviderInfo} object</dt>
Katie McCormick566489d2011-03-28 17:08:08 -070092 <dd>Describes the metadata for an App Widget, such as the App Widget's layout,
93update frequency,
Scott Main04c72b42009-05-13 16:48:13 -070094 and the AppWidgetProvider class. This should be defined in XML.</dd>
95 <dt>{@link android.appwidget.AppWidgetProvider} class implementation</dt>
Katie McCormick566489d2011-03-28 17:08:08 -070096 <dd>Defines the basic methods that allow you to programmatically interface
97with the App Widget,
98 based on broadcast events. Through it, you will receive broadcasts when the
99App Widget is updated,
Scott Main04c72b42009-05-13 16:48:13 -0700100 enabled, disabled and deleted.</dd>
101 <dt>View layout</dt>
102 <dd>Defines the initial layout for the App Widget, defined in XML.</dd>
103</dl>
104
Katie McCormick566489d2011-03-28 17:08:08 -0700105<p>Additionally, you can implement an App Widget configuration Activity. This is
106an optional
107{@link android.app.Activity} that launches when the user adds your App Widget
108and allows him or her
Scott Main04c72b42009-05-13 16:48:13 -0700109to modify App Widget settings at create-time.</p>
110
111<p>The following sections describe how to setup each of these components.</p>
Scott Main620986a2009-04-22 18:58:13 -0700112
113
Scott Main04c72b42009-05-13 16:48:13 -0700114<h2 id="Manifest">Declaring an App Widget in the Manifest</h2>
Scott Main620986a2009-04-22 18:58:13 -0700115
Katie McCormick566489d2011-03-28 17:08:08 -0700116<p>First, declare the {@link android.appwidget.AppWidgetProvider} class in your
117application's
Scott Main04c72b42009-05-13 16:48:13 -0700118<code>AndroidManifest.xml</code> file. For example:</p>
Scott Main620986a2009-04-22 18:58:13 -0700119
Scott Main04c72b42009-05-13 16:48:13 -0700120<pre>
121&lt;receiver android:name="ExampleAppWidgetProvider" >
122 &lt;intent-filter>
123 &lt;action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
124 &lt;/intent-filter>
125 &lt;meta-data android:name="android.appwidget.provider"
126 android:resource="@xml/example_appwidget_info" />
127&lt;/receiver>
128</pre>
Scott Main620986a2009-04-22 18:58:13 -0700129
Katie McCormick566489d2011-03-28 17:08:08 -0700130<p>The <code>&lt;receiver&gt;</code> element requires the
131<code>android:name</code>
Scott Main04c72b42009-05-13 16:48:13 -0700132attribute, which specifies the {@link android.appwidget.AppWidgetProvider} used
133by the App Widget.</p>
Scott Main620986a2009-04-22 18:58:13 -0700134
Katie McCormick566489d2011-03-28 17:08:08 -0700135<p>The <code>&lt;intent-filter&gt;</code> element must include an
136<code>&lt;action></code>
Scott Main04c72b42009-05-13 16:48:13 -0700137element with the <code>android:name</code> attribute. This attribute specifies
138that the {@link android.appwidget.AppWidgetProvider} accepts the {@link
Katie McCormick566489d2011-03-28 17:08:08 -0700139android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE
140ACTION_APPWIDGET_UPDATE} broadcast.
141This is the only broadcast that you must explicitly declare. The {@link
142android.appwidget.AppWidgetManager}
143automatically sends all other App Widget broadcasts to the AppWidgetProvider as
144necessary.</p>
Scott Main620986a2009-04-22 18:58:13 -0700145
Scott Main04c72b42009-05-13 16:48:13 -0700146<p>The <code>&lt;meta-data&gt;</code> element specifies the
147{@link android.appwidget.AppWidgetProviderInfo} resource and requires the
148following attributes:</p>
Scott Main620986a2009-04-22 18:58:13 -0700149<ul>
Katie McCormick566489d2011-03-28 17:08:08 -0700150 <li><code>android:name</code> - Specifies the metadata name. Use
151<code>android.appwidget.provider</code>
152 to identify the data as the {@link android.appwidget.AppWidgetProviderInfo}
153descriptor.</li>
154 <li><code>android:resource</code> - Specifies the {@link
155android.appwidget.AppWidgetProviderInfo}
Scott Main04c72b42009-05-13 16:48:13 -0700156 resource location.</li>
Scott Main620986a2009-04-22 18:58:13 -0700157</ul>
158
159
Scott Main04c72b42009-05-13 16:48:13 -0700160<h2 id="MetaData">Adding the AppWidgetProviderInfo Metadata</h2>
Scott Main620986a2009-04-22 18:58:13 -0700161
Scott Main04c72b42009-05-13 16:48:13 -0700162<p>The {@link android.appwidget.AppWidgetProviderInfo} defines the essential
Katie McCormick566489d2011-03-28 17:08:08 -0700163qualities of an App Widget, such as its minimum layout dimensions, its initial
164layout resource,
165how often to update the App Widget, and (optionally) a configuration Activity to
166launch at create-time.
Scott Main04c72b42009-05-13 16:48:13 -0700167Define the AppWidgetProviderInfo object in an XML resource using a single
Katie McCormick566489d2011-03-28 17:08:08 -0700168<code>&lt;appwidget-provider></code> element and save it in the project's
169<code>res/xml/</code>
Scott Main04c72b42009-05-13 16:48:13 -0700170folder.</p>
Scott Main620986a2009-04-22 18:58:13 -0700171
Scott Main04c72b42009-05-13 16:48:13 -0700172<p>For example:</p>
Scott Main620986a2009-04-22 18:58:13 -0700173
Scott Main04c72b42009-05-13 16:48:13 -0700174<pre>
175&lt;appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
Scott Main33e0f002009-12-03 11:33:25 -0800176 android:minWidth="294dp"
Scott Main04c72b42009-05-13 16:48:13 -0700177 android:minHeight="72dp"
Scott Main33e0f002009-12-03 11:33:25 -0800178 android:updatePeriodMillis="86400000"
Katie McCormick566489d2011-03-28 17:08:08 -0700179 android:previewImage="@drawable/preview"
Scott Main04c72b42009-05-13 16:48:13 -0700180 android:initialLayout="@layout/example_appwidget"
Katie McCormick566489d2011-03-28 17:08:08 -0700181 android:configure="com.example.android.ExampleAppWidgetConfigure"
182 android:resizeMode="horizontal|vertical">
Scott Main04c72b42009-05-13 16:48:13 -0700183&lt;/appwidget-provider>
184</pre>
185
186<p>Here's a summary of the <code>&lt;appwidget-provider></code> attributes:</p>
187<ul>
Katie McCormick566489d2011-03-28 17:08:08 -0700188 <li>The values for the <code>minWidth</code> and <code>minHeight</code>
189attributes specify the minimum
190 area required by the App Widget's layout.
191 <p>The default Home screen positions App Widgets in its window based on a
192grid of
193 cells that have a defined height and width. If the values for an App
194Widget's minimum width
Scott Main04c72b42009-05-13 16:48:13 -0700195 or height don't match the dimensions of the cells,
196 then the App Widget dimensions round <em>up</em> to the nearest cell size.
Katie McCormick566489d2011-03-28 17:08:08 -0700197 (See the <a
198href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget
199Design
Scott Main04c72b42009-05-13 16:48:13 -0700200 Guidelines</a> for more information on the Home screen cell sizes.)</p>
Katie McCormick566489d2011-03-28 17:08:08 -0700201 <p>Because the Home screen's layout orientation (and thus, the cell sizes)
202can change,
203 as a rule of thumb, you should assume the worst-case cell size of 74 pixels
204for the height
205 <em>and</em> width of a cell. However, you must subtract 2 from the final
206dimension to account
207 for any integer rounding errors that occur in the pixel count. To find your
208minimum width
Scott Main04c72b42009-05-13 16:48:13 -0700209 and height in density-independent pixels (dp), use this formula:<br/>
210 <code>(number of cells * 74) - 2</code><br/>
Katie McCormick566489d2011-03-28 17:08:08 -0700211 Following this formula, you should use 72 dp for a height of one cell, 294
212dp and for a width of four cells.</p>
213<p class="note"><strong>Note:</strong> To make your app widget portable across
214devices, your app widget's minimum size should never be larger than 4 x 4 cells.
215See the <a
Scott Mainbeeb7762011-06-20 17:17:39 -0700216href="{@docRoot}guide/practices/ui_guidelines/widget_design.html#sizes">App
Katie McCormick566489d2011-03-28 17:08:08 -0700217Widget Design Guidelines</a> for more discussion of Home screen cell sizes.</p>
Scott Main04c72b42009-05-13 16:48:13 -0700218 </li>
Katie McCormick566489d2011-03-28 17:08:08 -0700219 <li>The <code>updatePeriodMillis</code> attribute defines how often the App
220Widget framework should request an update from the {@link
221android.appwidget.AppWidgetProvider} by calling the
222{@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,android.appwidget.AppWidgetManager,int[]) onUpdate()}
223callback method. The actual update
224is not guaranteed to occur exactly on time with this value and we suggest
225updating as infrequently as possible&mdash;perhaps no more than once an hour to
226conserve the battery. You might also allow the user to adjust the frequency in a
227configuration&mdash;some people might want a stock ticker to update every 15
228minutes, or maybe only four times a day.
229 <p class="note"><strong>Note:</strong> If the device is asleep when it
230is time for an update
231 (as defined by <code>updatePeriodMillis</code>), then the device will
232wake up in order
233 to perform the update. If you don't update more than once per hour, this
234probably won't
235 cause significant problems for the battery life. If, however, you need
236to update more
237 frequently and/or you do not need to update while the device is asleep,
238then you can instead
239 perform updates based on an alarm that will not wake the device. To do
240so, set an alarm with
241 an Intent that your AppWidgetProvider receives, using the {@link
242android.app.AlarmManager}.
243 Set the alarm type to either {@link
244android.app.AlarmManager#ELAPSED_REALTIME} or
Scott Maine5186062009-07-15 16:52:31 -0700245 {@link android.app.AlarmManager#RTC}, which will only
Katie McCormick566489d2011-03-28 17:08:08 -0700246 deliver the alarm when the device is awake. Then set
247<code>updatePeriodMillis</code> to
Scott Maine5186062009-07-15 16:52:31 -0700248 zero (<code>"0"</code>).</p>
249 </li>
Katie McCormick566489d2011-03-28 17:08:08 -0700250 <li>The <code>initialLayout</code> attribute points to the layout resource
251that defines the
Scott Main04c72b42009-05-13 16:48:13 -0700252 App Widget layout.</li>
Katie McCormick566489d2011-03-28 17:08:08 -0700253 <li>The <code>configure</code> attribute defines the {@link
254android.app.Activity} to launch when
255 the user adds the App Widget, in order for him or her to configure App
256Widget properties. This is optional
257 (read <a href="#Configuring">Creating an App Widget Configuration
258Activity</a> below).</li>
259
260 <li>The <code>previewImage</code> attribute specifies a preview of what the
261app widget will look like after it's configured, which the user sees when
262selecting the app widget. If not supplied, the user instead sees your
263application's launcher icon. This field corresponds to the
264<code>android:previewImage</code> attribute in the <code>&lt;receiver&gt;</code>
265element in the <code>AndroidManifest.xml</code> file. For more discussion of
266using <code>previewImage</code>, see <a href="#preview">Setting a Preview
267Image</a>. Introduced in Android 3.0.</li>
Scott Main04c72b42009-05-13 16:48:13 -0700268
Katie McCormick566489d2011-03-28 17:08:08 -0700269 <li>The <code>autoAdvanceViewId</code> attribute specifies the view ID of the
270app widget subview that should be auto-advanced by the widget's host. Introduced in Android 3.0.</li>
271
272<li>The <code>resizeMode</code> attribute specifies the rules by which a widget
273can be resized. You use this attribute to make homescreen widgets
274resizeable&mdash;horizontally, vertically, or on both axes. Users touch-hold a
275widget to show its resize handles, then drag the horizontal and/or vertical
276handles to change the size on the layout grid. Values for the
277<code>resizeMode</code> attribute include "horizontal", "vertical", and "none".
278To declare a widget as resizeable horizontally and vertically, supply the value
279"horizontal|vertical". Introduced in Android 3.1.</li> </ul>
280
281<p>See the {@link android.appwidget.AppWidgetProviderInfo} class for more
282information on the
Scott Main04c72b42009-05-13 16:48:13 -0700283attributes accepted by the <code>&lt;appwidget-provider></code> element.</p>
Scott Main620986a2009-04-22 18:58:13 -0700284
285
Scott Main04c72b42009-05-13 16:48:13 -0700286<h2 id="CreatingLayout">Creating the App Widget Layout</h2>
Scott Main620986a2009-04-22 18:58:13 -0700287
Katie McCormick566489d2011-03-28 17:08:08 -0700288<p>You must define an initial layout for your App Widget in XML and save it in
289the project's
290<code>res/layout/</code> directory. You can design your App Widget using the
291View objects listed
292below, but before you begin designing your App Widget, please read and
293understand the
294<a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget
295Design
Scott Main04c72b42009-05-13 16:48:13 -0700296Guidelines</a>.</p>
Scott Main620986a2009-04-22 18:58:13 -0700297
Scott Main04c72b42009-05-13 16:48:13 -0700298<p>Creating the App Widget layout is simple if you're
Katie McCormick566489d2011-03-28 17:08:08 -0700299familiar with <a
Scott Mainb10b48f2011-09-13 16:40:52 -0700300href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a>.
Katie McCormick566489d2011-03-28 17:08:08 -0700301However, you must be aware that App Widget layouts are based on {@link
302android.widget.RemoteViews},
Scott Main04c72b42009-05-13 16:48:13 -0700303which do not support every kind of layout or view widget.</p>
304
305<p>A RemoteViews object (and, consequently, an App Widget) can support the
306following layout classes:</p>
307
308<ul class="nolist">
309 <li>{@link android.widget.FrameLayout}</li>
310 <li>{@link android.widget.LinearLayout}</li>
311 <li>{@link android.widget.RelativeLayout}</li>
312</ul>
313
314<p>And the following widget classes:</p>
315<ul class="nolist">
316 <li>{@link android.widget.AnalogClock}</li>
317 <li>{@link android.widget.Button}</li>
318 <li>{@link android.widget.Chronometer}</li>
319 <li>{@link android.widget.ImageButton}</li>
320 <li>{@link android.widget.ImageView}</li>
321 <li>{@link android.widget.ProgressBar}</li>
322 <li>{@link android.widget.TextView}</li>
Katie McCormick566489d2011-03-28 17:08:08 -0700323 <li>{@link android.widget.ViewFlipper}</li>
Katie McCormickf99c8872011-11-01 16:33:03 -0700324 <li>{@link android.widget.ListView}</li>
325 <li>{@link android.widget.GridView}</li>
326 <li>{@link android.widget.StackView}</li>
327 <li>{@link android.widget.AdapterViewFlipper}</li>
Scott Main04c72b42009-05-13 16:48:13 -0700328</ul>
329
330<p>Descendants of these classes are not supported.</p>
Scott Main620986a2009-04-22 18:58:13 -0700331
332
Roman Nurik2b15c002011-09-27 18:28:46 -0700333<h3 id="AddingMargins">Adding margins to App Widgets</h3>
334
335<p>Widgets should not generally extend to screen edges and should not visually be flush with other widgets, so you should add margins on all sides around your widget frame.</p>
336
337<p>As of Android 4.0, app widgets are automatically given padding between the widget frame and the app widget's bounding box to provide better alignment with other widgets and icons on the user's home screen. To take advantage of this strongly recommended behavior, set your application's <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">targetSdkVersion</a> to 14 or greater.</p>
338
339<p>It's easy to write a single layout that has custom margins applied for earlier versions of the platform, and has no extra margins for Android 4.0 and greater:</p>
340
341<ol>
342 <li>Set your application's <code>targetSdkVersion</code> to 14 or greater.</li>
343 <li>Create a layout such as the one below, that references a <a href="{@docRoot}guide/topics/resources/more-resources.html#Dimension">dimension resource</a> for its margins:
344
345<pre>
346&lt;FrameLayout
347 android:layout_width="match_parent"
348 android:layout_height="match_parent"
Roman Nurik061cf702011-11-29 10:02:19 -0800349 <strong>android:padding="@dimen/widget_margin"&gt;</strong>
Roman Nurik2b15c002011-09-27 18:28:46 -0700350
351 &lt;LinearLayout
352 android:layout_width="match_parent"
353 android:layout_height="match_parent"
354 android:orientation="horizontal"
355 android:background="@drawable/my_widget_background"&gt;
356 &hellip;
357 &lt;/LinearLayout&gt;
358
359&lt;/FrameLayout&gt;
360</pre>
361
362 </li>
363 <li>Create two dimensions resources, one in <code>res/values/</code> to provide the pre-Android 4.0 custom margins, and one in <code>res/values-v14/</code> to provide no extra padding for Android 4.0 widgets:
364
365 <p><strong>res/values/dimens.xml</strong>:<br>
Roman Nurik061cf702011-11-29 10:02:19 -0800366 <pre>&lt;dimen name="widget_margin"&gt;8dp&lt;/dimen&gt;</pre></p>
Roman Nurik2b15c002011-09-27 18:28:46 -0700367
368 <p><strong>res/values-v14/dimens.xml</strong>:<br>
369 <pre>&lt;dimen name="widget_margin"&gt;0dp&lt;/dimen&gt;</pre></p>
370 </li>
371</ol>
372
373<p>Another option is to simply build extra margins into your <a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">nine-patch</a> background assets by default, and provide different nine-patches with no margins for API level 14 or later.</p>
374
375
Scott Main04c72b42009-05-13 16:48:13 -0700376<h2 id="AppWidgetProvider">Using the AppWidgetProvider Class</h2>
Scott Main620986a2009-04-22 18:58:13 -0700377
Scott Main04c72b42009-05-13 16:48:13 -0700378<div class="sidebox-wrapper">
Scott Mainf54574a2010-03-24 17:18:01 -0700379<div class="sidebox">
Katie McCormick566489d2011-03-28 17:08:08 -0700380 <p>You must declare your AppWidgetProvider class implementation as a
381broadcast receiver
Scott Main04c72b42009-05-13 16:48:13 -0700382 using the <code>&lt;receiver></code> element in the AndroidManifest (see
383 <a href="#Manifest">Declaring an App Widget in the Manifest</a> above).</p>
384 </div>
385</div>
Scott Main620986a2009-04-22 18:58:13 -0700386
Katie McCormick566489d2011-03-28 17:08:08 -0700387<p>The {@link android.appwidget.AppWidgetProvider} class extends
388BroadcastReceiver as a convenience
389class to handle the App Widget broadcasts. The AppWidgetProvider receives only
390the event broadcasts that
391are relevant to the App Widget, such as when the App Widget is updated, deleted,
392enabled, and disabled.
393When these broadcast events occur, the AppWidgetProvider receives the following
394method calls:</p>
Scott Main620986a2009-04-22 18:58:13 -0700395
Scott Main04c72b42009-05-13 16:48:13 -0700396<dl>
Katie McCormick566489d2011-03-28 17:08:08 -0700397 <dt>
398 {@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,android.appwidget.AppWidgetManager,int[]) onUpdate()}
399</dt>
400 <dd>This is called to update the App Widget at intervals defined by the
401<code>updatePeriodMillis</code>
Scott Main04c72b42009-05-13 16:48:13 -0700402 attribute in the AppWidgetProviderInfo (see <a href="#MetaData">Adding the
403 AppWidgetProviderInfo Metadata</a> above). This method is also called
404 when the user adds the App Widget, so it should perform the essential setup,
405 such as define event handlers for Views and start a temporary
Katie McCormick566489d2011-03-28 17:08:08 -0700406 {@link android.app.Service}, if necessary. However, if you have declared a
407configuration
408 Activity, <strong>this method is not called</strong> when the user adds the
409App Widget,
Scott Main04c72b42009-05-13 16:48:13 -0700410 but is called for the subsequent updates. It is the responsibility of the
Katie McCormick566489d2011-03-28 17:08:08 -0700411 configuration Activity to perform the first update when configuration is
412done.
413 (See <a href="#Configuring">Creating an App Widget Configuration
414Activity</a> below.)</dd>
Scott Main04c72b42009-05-13 16:48:13 -0700415 <dt>{@link android.appwidget.AppWidgetProvider#onDeleted(Context,int[])}</dt>
Katie McCormick566489d2011-03-28 17:08:08 -0700416 <dd>This is called every time an App Widget is deleted from the App Widget
417host.</dd>
Scott Main04c72b42009-05-13 16:48:13 -0700418 <dt>{@link android.appwidget.AppWidgetProvider#onEnabled(Context)}</dt>
Katie McCormick566489d2011-03-28 17:08:08 -0700419 <dd>This is called when an instance the App Widget is created for the first
420time. For example, if the user
Scott Main04c72b42009-05-13 16:48:13 -0700421 adds two instances of your App Widget, this is only called the first time.
Katie McCormick566489d2011-03-28 17:08:08 -0700422 If you need to open a new database or perform other setup that only needs to
423occur once
Scott Main04c72b42009-05-13 16:48:13 -0700424 for all App Widget instances, then this is a good place to do it.</dd>
425 <dt>{@link android.appwidget.AppWidgetProvider#onDisabled(Context)}</dt>
Katie McCormick566489d2011-03-28 17:08:08 -0700426 <dd>This is called when the last instance of your App Widget is deleted from
427the App Widget host.
Scott Main04c72b42009-05-13 16:48:13 -0700428 This is where you should clean up any work done in
429 {@link android.appwidget.AppWidgetProvider#onEnabled(Context)},
430 such as delete a temporary database.</dd>
431 <dt>{@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)}</dt>
Katie McCormick566489d2011-03-28 17:08:08 -0700432 <dd>This is called for every broadcast and before each of the above callback
433methods.
434 You normally don't need to implement this method because the default
435AppWidgetProvider
Scott Main04c72b42009-05-13 16:48:13 -0700436 implementation filters all App Widget broadcasts and calls the above
437 methods as appropriate.</dd>
438</dl>
Scott Main620986a2009-04-22 18:58:13 -0700439
Katie McCormick566489d2011-03-28 17:08:08 -0700440<p class="warning"><strong>Note:</strong> In Android 1.5, there is a known issue
441in which the
442<code>onDeleted()</code> method will not be called when it should be. To work
443around this issue,
444you can implement {@link
445android.appwidget.AppWidgetProvider#onReceive(Context,Intent)
Scott Main04c72b42009-05-13 16:48:13 -0700446onReceive()} as described in this
Katie McCormick566489d2011-03-28 17:08:08 -0700447<a
448href="http://groups.google.com/group/android-developers/msg/e405ca19df2170e2">
449Group post</a>
Scott Main04c72b42009-05-13 16:48:13 -0700450to receive the <code>onDeleted()</code> callback.
451</p>
452
453<p>The most important AppWidgetProvider callback is
Katie McCormick566489d2011-03-28 17:08:08 -0700454{@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[]) onUpdate()}
455because it is called when
456each App Widget is added to a host (unless you use a configuration Activity). If
457your App Widget accepts any user interaction events, then you need to register
458the event handlers in this callback. If your App Widget doesn't create temporary
459files or databases, or perform other work that requires clean-up, then
460{@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[]) onUpdate()}
461may be the only callback
462method you need to define. For example, if you want an App Widget with a button
463that launches an Activity when clicked, you could use the following
Scott Main04c72b42009-05-13 16:48:13 -0700464implementation of AppWidgetProvider:</p>
465
466<pre>
467public class ExampleAppWidgetProvider extends AppWidgetProvider {
468
469 public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
470 final int N = appWidgetIds.length;
471
472 // Perform this loop procedure for each App Widget that belongs to this provider
473 for (int i=0; i&lt;N; i++) {
474 int appWidgetId = appWidgetIds[i];
475
476 // Create an Intent to launch ExampleActivity
477 Intent intent = new Intent(context, ExampleActivity.class);
478 PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
479
Katie McCormick566489d2011-03-28 17:08:08 -0700480 // Get the layout for the App Widget and attach an on-click listener
481 // to the button
Scott Main04c72b42009-05-13 16:48:13 -0700482 RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);
483 views.setOnClickPendingIntent(R.id.button, pendingIntent);
484
Katie McCormick566489d2011-03-28 17:08:08 -0700485 // Tell the AppWidgetManager to perform an update on the current app widget
Scott Main04c72b42009-05-13 16:48:13 -0700486 appWidgetManager.updateAppWidget(appWidgetId, views);
487 }
488 }
489}
490</pre>
491
492<p>This AppWidgetProvider defines only the
Katie McCormick566489d2011-03-28 17:08:08 -0700493{@link
494android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[]) onUpdate()}
495method for the purpose of
496defining a {@link android.app.PendingIntent} that launches an {@link
497android.app.Activity} and attaching it to the App Widget's button with {@link
498android.widget.RemoteViews#setOnClickPendingIntent(int,PendingIntent)}. Notice
499that it includes a loop that iterates through each entry in
500<code>appWidgetIds</code>, which is an array of IDs that identify each App
501Widget created by this provider. In this way, if the user creates more than one
502instance of the App Widget, then they are all updated simultaneously. However,
503only one <code>updatePeriodMillis</code> schedule will be managed for all
504instances of the App Widget. For example, if the update schedule is defined to
505be every two hours, and a second instance of the App Widget is added one hour
506after the first one, then they will both be updated on the period defined by the
507first one and the second update period will be ignored (they'll both be updated
508every two hours, not every hour).</p>
Scott Main04c72b42009-05-13 16:48:13 -0700509
Katie McCormick566489d2011-03-28 17:08:08 -0700510<p class="note"><strong>Note:</strong> Because {@link
511android.appwidget.AppWidgetProvider} is an extension of {@link
512android.content.BroadcastReceiver}, your process is not guaranteed to keep
513running after the callback methods return (see {@link
514android.content.BroadcastReceiver} for information about the broadcast
515lifecycle). If your App Widget setup process can take several seconds (perhaps
516while performing web requests) and you require that your process continues,
517consider starting a {@link android.app.Service} in the
518{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) onUpdate()}
519method. From within the Service, you can perform your own updates
520to the App Widget without worrying about the AppWidgetProvider closing down due
521to an <a href="{@docRoot}guide/practices/design/responsiveness.html">Application
522Not Responding</a> (ANR) error. See the <a
523href="http://code.google.com/p/wiktionary-android/source/browse/trunk/Wiktionary
524/src/com/example/android/wiktionary/WordWidget.java">Wiktionary sample's
525AppWidgetProvider</a> for an example of an App Widget running a {@link
526android.app.Service}.</p>
Scott Main04c72b42009-05-13 16:48:13 -0700527
528<p>Also see the <a
Katie McCormick566489d2011-03-28 17:08:08 -0700529href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/
530appwidget/ExampleAppWidgetProvider.html">
Scott Main04c72b42009-05-13 16:48:13 -0700531ExampleAppWidgetProvider.java</a> sample class.</p>
Scott Main620986a2009-04-22 18:58:13 -0700532
533
Scott Main04c72b42009-05-13 16:48:13 -0700534<h3 id="ProviderBroadcasts">Receiving App Widget broadcast Intents</h3>
Scott Main620986a2009-04-22 18:58:13 -0700535
Katie McCormick566489d2011-03-28 17:08:08 -0700536<p>{@link android.appwidget.AppWidgetProvider} is just a convenience class. If
537you would like
Scott Main04c72b42009-05-13 16:48:13 -0700538to receive the App Widget broadcasts directly, you can implement your own
539{@link android.content.BroadcastReceiver} or override the
540{@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)} callback.
541The four Intents you need to care about are:</p>
Scott Main620986a2009-04-22 18:58:13 -0700542<ul>
543 <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE}</li>
544 <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DELETED}</li>
545 <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_ENABLED}</li>
546 <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DISABLED}</li>
547</ul>
548
Scott Main620986a2009-04-22 18:58:13 -0700549
550
Scott Main04c72b42009-05-13 16:48:13 -0700551<h2 id="Configuring">Creating an App Widget Configuration Activity</h2>
Scott Main620986a2009-04-22 18:58:13 -0700552
Katie McCormick566489d2011-03-28 17:08:08 -0700553<p>If you would like the user to configure settings when he or she adds a new
554App Widget,
555you can create an App Widget configuration Activity. This {@link
556android.app.Activity}
557will be automatically launched by the App Widget host and allows the user to
558configure
559available settings for the App Widget at create-time, such as the App Widget
560color, size,
Scott Main04c72b42009-05-13 16:48:13 -0700561update period or other functionality settings.</p>
562
Katie McCormick566489d2011-03-28 17:08:08 -0700563<p>The configuration Activity should be declared as a normal Activity in the
564Android manifest file.
Scott Main04c72b42009-05-13 16:48:13 -0700565However, it will be launched by the App Widget host with the {@link
Katie McCormick566489d2011-03-28 17:08:08 -0700566android.appwidget.AppWidgetManager#ACTION_APPWIDGET_CONFIGURE
567ACTION_APPWIDGET_CONFIGURE} action,
Scott Main04c72b42009-05-13 16:48:13 -0700568so the Activity needs to accept this Intent. For example:</p>
569
570<pre>
571&lt;activity android:name=".ExampleAppWidgetConfigure">
572 &lt;intent-filter>
Katie McCormick566489d2011-03-28 17:08:08 -0700573 &lt;action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
Scott Main04c72b42009-05-13 16:48:13 -0700574 &lt;/intent-filter>
575&lt;/activity>
576</pre>
577
Katie McCormick566489d2011-03-28 17:08:08 -0700578<p>Also, the Activity must be declared in the AppWidgetProviderInfo XML file,
579with the
Scott Main04c72b42009-05-13 16:48:13 -0700580<code>android:configure</code> attribute (see <a href="#MetaData">Adding
Katie McCormick566489d2011-03-28 17:08:08 -0700581the AppWidgetProviderInfo Metadata</a> above). For example, the configuration
582Activity
Scott Main04c72b42009-05-13 16:48:13 -0700583can be declared like this:</p>
584
585<pre>
586&lt;appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
587 ...
588 android:configure="com.example.android.ExampleAppWidgetConfigure"
589 ... >
590&lt;/appwidget-provider>
591</pre>
592
Katie McCormick566489d2011-03-28 17:08:08 -0700593<p>Notice that the Activity is declared with a fully-qualified namespace,
594because
Scott Main04c72b42009-05-13 16:48:13 -0700595it will be referenced from outside your package scope.</p>
596
Katie McCormick566489d2011-03-28 17:08:08 -0700597<p>That's all you need to get started with a configuration Activity. Now all you
598need is the actual
599Activity. There are, however, two important things to remember when you
600implement the Activity:</p>
Scott Main04c72b42009-05-13 16:48:13 -0700601<ul>
Katie McCormick566489d2011-03-28 17:08:08 -0700602 <li>The App Widget host calls the configuration Activity and the configuration
603Activity should always
Scott Main04c72b42009-05-13 16:48:13 -0700604 return a result. The result should include the App Widget ID
Katie McCormick566489d2011-03-28 17:08:08 -0700605 passed by the Intent that launched the Activity (saved in the Intent extras
606as
Scott Main04c72b42009-05-13 16:48:13 -0700607 {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID}).</li>
Katie McCormick566489d2011-03-28 17:08:08 -0700608 <li>The
609 {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) onUpdate()}
610 method <strong>will not be called</strong> when the App Widget
611is created
612 (the system will not send the ACTION_APPWIDGET_UPDATE broadcast when a
613configuration Activity
614 is launched). It is the responsibility of the configuration Activity to
615request an update from the
Scott Main04c72b42009-05-13 16:48:13 -0700616 AppWidgetManager when the App Widget is first created. However,
Katie McCormick566489d2011-03-28 17:08:08 -0700617{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) onUpdate()}
618 will be called for subsequent updates&mdash;it is only skipped
619the first time.</li>
Scott Main04c72b42009-05-13 16:48:13 -0700620</ul>
621
Katie McCormick566489d2011-03-28 17:08:08 -0700622<p>See the code snippets in the following section for an example of how to
623return a result
Scott Main04c72b42009-05-13 16:48:13 -0700624from the configuration and update the App Widget.</p>
625
626
Katie McCormick566489d2011-03-28 17:08:08 -0700627<h3 id="UpdatingFromTheConfiguration">Updating the App Widget from the
628configuration Activity</h3>
Scott Main04c72b42009-05-13 16:48:13 -0700629
Katie McCormick566489d2011-03-28 17:08:08 -0700630<p>When an App Widget uses a configuration Activity, it is the responsibility of
631the Activity
Scott Main04c72b42009-05-13 16:48:13 -0700632to update the App Widget when configuration is complete.
633You can do so by requesting an update directly from the
634{@link android.appwidget.AppWidgetManager}.</p>
635
636<p>Here's a summary of the procedure to properly update the App Widget and close
637the configuration Activity:</p>
638
639<ol>
640 <li>First, get the App Widget ID from the Intent that launched the Activity:
641<pre>
642Intent intent = getIntent();
643Bundle extras = intent.getExtras();
644if (extras != null) {
645 mAppWidgetId = extras.getInt(
646 AppWidgetManager.EXTRA_APPWIDGET_ID,
647 AppWidgetManager.INVALID_APPWIDGET_ID);
648}
649</pre>
650 </li>
651 <li>Perform your App Widget configuration.</li>
Katie McCormick566489d2011-03-28 17:08:08 -0700652 <li>When the configuration is complete, get an instance of the
653AppWidgetManager by calling
Scott Main04c72b42009-05-13 16:48:13 -0700654 {@link android.appwidget.AppWidgetManager#getInstance(Context)}:
655<pre>
656AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
657</pre>
658 </li>
Katie McCormick566489d2011-03-28 17:08:08 -0700659 <li>Update the App Widget with a {@link android.widget.RemoteViews} layout by
660calling
Scott Main04c72b42009-05-13 16:48:13 -0700661 {@link android.appwidget.AppWidgetManager#updateAppWidget(int,RemoteViews)}:
662<pre>
Katie McCormick566489d2011-03-28 17:08:08 -0700663RemoteViews views = new RemoteViews(context.getPackageName(),
664R.layout.example_appwidget);
Scott Main04c72b42009-05-13 16:48:13 -0700665appWidgetManager.updateAppWidget(mAppWidgetId, views);
666</pre>
667 </li>
Katie McCormick566489d2011-03-28 17:08:08 -0700668 <li>Finally, create the return Intent, set it with the Activity result, and
669finish the Activity:</li>
Scott Main04c72b42009-05-13 16:48:13 -0700670<pre>
671Intent resultValue = new Intent();
672resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
673setResult(RESULT_OK, resultValue);
674finish();
675</pre>
676 </li>
677</ol>
678
Katie McCormick566489d2011-03-28 17:08:08 -0700679<p class="note"><strong>Tip:</strong> When your configuration Activity first
680opens, set
681the Activity result to RESULT_CANCELED. This way, if the user backs-out of the
682Activity before
683reaching the end, the App Widget host is notified that the configuration was
684cancelled and the
Scott Main04c72b42009-05-13 16:48:13 -0700685App Widget will not be added.</p>
686
687<p>See the <a
Katie McCormick566489d2011-03-28 17:08:08 -0700688href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/
689appwidget/ExampleAppWidgetConfigure.html">
Scott Main04c72b42009-05-13 16:48:13 -0700690ExampleAppWidgetConfigure.java</a> sample class in ApiDemos for an example.</p>
691
Katie McCormick566489d2011-03-28 17:08:08 -0700692<h2 id="preview">Setting a Preview Image</h2>
693
694<p>Android 3.0 introduces the {@link
695
696
697android.appwidget.AppWidgetProviderInfo#previewImage} field, which specifies a
698preview of what the app widget looks like. This preview is shown to the user from the
699widget picker. If this field is not supplied, the app widget's icon is used for
700the preview.</p>
701
702<p>This is how you specify this setting in XML:</p>
703
704<pre>&lt;appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
705 ...
706 android:previewImage="@drawable/preview">
707&lt;/appwidget-provider></pre>
708
709<p>To help create a preview image for your app widget (to specify in the {@link
710android.appwidget.AppWidgetProviderInfo#previewImage} field), the Android
711emulator includes an application called &quot;Widget Preview.&quot; To create a
712preview image, launch this application, select the app widget for your
713application and set it up how you'd like your preview image to appear, then save
714it and place it in your application's drawable resources.</p>
715
716<h2 id="collections">Using App Widgets with Collections</h2>
717
718<p>Android 3.0 introduces App Widgets with collections. These kinds of App
719Widgets use the {@link android.widget.RemoteViewsService} to display collections
720that are backed by remote data, such as from a <a
721href="{@docRoot}guide/topics/providers/content-providers.html">content
722provider</a>. The data provided by the {@link android.widget.RemoteViewsService}
723is presented in the App Widget using one of the following view types, which
724we’ll refer to as “collection views:”</p>
725
726<dl>
727 <dt>{@link android.widget.ListView}</dt>
728 <dd>A view that shows items in a
729vertically scrolling
730list. For an example, see the Gmail app widget. </dd>
731<dt>{@link android.widget.GridView}</dt>
732<dd>A view that shows items in
733two-dimensional scrolling grid. For an example, see the Bookmarks app
734widget.</dd>
735<dt>{@link android.widget.StackView}</dt>
736<dd>A
737stacked card view (kind of like a rolodex), where the user can flick the front
738card up/down to see the previous/next card, respectively. Examples include
739the YouTube and Books app widgets. </dd>
740<dt>{@link android.widget.AdapterViewFlipper}</dt>
741<dd>An adapter-backed simple
742{@link
743android.widget.ViewAnimator} that animates between two or more views. Only one
744child is shown at a time. </dd>
745</dl>
746
747<p>As stated above, these collection views display collections backed by remote
748data. This means that they use an {@link android.widget.Adapter} to bind their
749user interface to their data. An {@link android.widget.Adapter} binds individual
750items from a set of data into individual {@link android.view.View} objects.
751Because these collection views are backed by adapters, the Android framework
752must include extra architecture to support their use in app widgets. In the
753context of an app widget, the {@link android.widget.Adapter} is replaced by a
754{@link android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory},
755which is simply a thin wrapper around the {@link android.widget.Adapter}
756interface.
757 When
758requested for a specific item in the collection, the {@link
759android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} creates
760and returns the item for the collection as a {@link android.widget.RemoteViews}
761object.
762In order to include a collection view in your app widget, you
763must implement {@link android.widget.RemoteViewsService} and {@link
764android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}.</p>
765
766<p> {@link android.widget.RemoteViewsService} is a service that allows a remote
767adapter to request {@link
768android.widget.RemoteViews} objects. {@link
769android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} is an
770interface for an adapter between a collection view (such as {@link
771android.widget.ListView}, {@link android.widget.GridView}, and so on) and the
772underlying data for that view. From the <a
773href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
774sample</a>, here is an example of the boilerplate code you use to implement
775this service and interface:
776</p>
777
778<pre>
779public class StackWidgetService extends RemoteViewsService {
780 &#64;Override
781 public RemoteViewsFactory onGetViewFactory(Intent intent) {
782 return new StackRemoteViewsFactory(this.getApplicationContext(), intent);
783 }
784}
785
786class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
787
788//... include adapter-like methods here. See the StackView Widget sample.
789
790}
791</pre>
792
793<h3 id="collection_sample">Sample application</h3>
794
795<p>The code excerpts in this section are drawn from the <a
796href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
797sample</a>:</p>
798
799<p>
800<img src="{@docRoot}resources/samples/images/StackWidget.png" alt="StackView
801Widget" />
802</p>
803
804<p>This sample consists of a stack of 10 views, which display the values
805<code>&quot;0!&quot;</code> through <code>&quot;9!&quot;</code> The sample
806app widget has these primary behaviors:</p>
807
808<ul>
809
810 <li>The user can vertically fling the top view in the
811app widget to display the next or previous view. This is a built-in StackView
812behavior.</li>
813
814 <li>Without any user interaction, the app widget automatically advances
815through
816its views in sequence, like a slide show. This is due to the setting
817<code>android:autoAdvanceViewId=&quot;@id/stack_view&quot;</code> in the
818<code>res/xml/stackwidgetinfo.xml</code> file. This setting applies to the view
819ID,
820which in this case is the view ID of the stack view.</li>
821
822 <li>If the user touches the top view, the app widget displays the {@link
823android.widget.Toast} message &quot;Touched view <em>n</em>,&quot; where
824<em>n</em> is the index (position) of the touched view. For more discussion of
825how this is implemented, see
826<a href="#behavior">Adding behavior to individual items</a>.</li>
827
828</ul>
829<h3 id="implementing_collections">Implementing app widgets with collections</h3>
830
831<p>To implement an App Widget with collections, you follow the same basic steps
832you would use to implement any app widget. The following sections describe the
833additional steps you need to perform to implement an App Widget with
834collections.</p>
835
836<h4>Manifest for app widgets with collections</h4>
837
838<p> In addition to the requirements listed in <a href="#Manifest">Declaring an
839App Widget in the Manifest</a>, to make it possible for App Widgets with
840collections to bind to your {@link android.widget.RemoteViewsService}, you must
841declare the service in your manifest file with the permission {@link
842android.Manifest.permission#BIND_REMOTEVIEWS}. This prevents other applications
843from freely accessing your app widget's data. For example, when creating an App
844Widget that uses {@link android.widget.RemoteViewsService} to populate a
845collection view, the manifest entry may look like this:</p>
846
847<pre>&lt;service android:name=&quot;MyWidgetService&quot;
848...
849android:permission=&quot;android.permission.BIND_REMOTEVIEWS&quot; /&gt;</pre>
850
851<p>The line <code>android:name=&quot;MyWidgetService&quot;</code>
852refers to your subclass of {@link android.widget.RemoteViewsService}. </p>
853
854<h4>Layout for app widgets with collections</h4>
855
856<p>The main requirement for your app widget layout XML file is that it
857include one of the collection views: {@link android.widget.ListView},
858{@link android.widget.GridView}, {@link android.widget.StackView}, or
859{@link android.widget.AdapterViewFlipper}. Here is the
860<code>widget_layout.xml</code> for
861the <a href="{@docRoot}resources/samples/StackWidget/index.html">StackView
862Widget sample</a>:</p>
863
864<pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
865
866&lt;FrameLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
867    android:layout_width=&quot;match_parent&quot;
868    android:layout_height=&quot;match_parent&quot;&gt;
869    &lt;StackView xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
870        android:id=&quot;&#64;+id/stack_view&quot;
871        android:layout_width=&quot;match_parent&quot;
872        android:layout_height=&quot;match_parent&quot;
873        android:gravity=&quot;center&quot;
874        android:loopViews=&quot;true&quot; /&gt;
875    &lt;TextView xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
876        android:id=&quot;&#64;+id/empty_view&quot;
877        android:layout_width=&quot;match_parent&quot;
878        android:layout_height=&quot;match_parent&quot;
879        android:gravity=&quot;center&quot;
880        android:background=&quot;&#64;drawable/widget_item_background&quot;
881        android:textColor=&quot;#ffffff&quot;
882        android:textStyle=&quot;bold&quot;
883        android:text=&quot;&#64;string/empty_view_text&quot;
884        android:textSize=&quot;20sp&quot; /&gt;
885&lt;/FrameLayout&gt;</pre>
886
887<p> Note that empty views must be siblings of the collection view for which the
888empty view represents empty state. </p>
889
890<p>In addition to the layout file for your entire app widget, you must create
891another layout file that defines the layout for each item in the collection (for
892example, a layout for each book in a collection of books). For example, the <a
893href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
894sample</a> only has one layout file, <code>widget_item.xml</code>, since all
895items use the same layout. But the <a
896href="{@docRoot}resources/samples/WeatherListWidget/index.html">
897WeatherListWidget sample</a> has two layout files:
898<code>dark_widget_item.xml</code> and <code>light_widget_item.xml</code>.</p>
899
900
901
902<h4 id="AppWidgetProvider-collections">AppWidgetProvider class for app widgets with collections</h4>
903
904<p>As with a regular app widget, the bulk of your code in your {@link
905android.appwidget.AppWidgetProvider} subclass typically goes in {@link
906android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,
907android.appwidget.AppWidgetManager, int[]) onUpdate()}. The major difference in
908your implementation for {@link
909android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,
910android.appwidget.AppWidgetManager, int[]) onUpdate()} when creating an app
911widget with collections is that you must call {@link
912android.widget.RemoteViews#setRemoteAdapter setRemoteAdapter()}. This tells the
913collection view where to get its data. The {@link
914android.widget.RemoteViewsService} can then return your implementation of {@link
915android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, and
916the widget can serve up the appropriate data. When you call this method, you
917must pass an intent that points to your implementation of {@link
918android.widget.RemoteViewsService} and the App Widget ID that specifies the app
919widget to update.</p>
920
921
922<p>For example, here's how the StackView Widget sample implements the {@link
923android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,
924android.appwidget.AppWidgetManager, int[]) onUpdate()} callback method to set
925the {@link
926android.widget.RemoteViewsService} as the remote adapter for the app widget
927collection:</p>
928
929<pre>public void onUpdate(Context context, AppWidgetManager appWidgetManager,
930int[] appWidgetIds) {
931 // update each of the app widgets with the remote adapter
932 for (int i = 0; i &lt; appWidgetIds.length; ++i) {
933
934 // Set up the intent that starts the StackViewService, which will
935 // provide the views for this collection.
936 Intent intent = new Intent(context, StackWidgetService.class);
937 // Add the app widget ID to the intent extras.
938 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
939 intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
940 // Instantiate the RemoteViews object for the App Widget layout.
941 RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
942 // Set up the RemoteViews object to use a RemoteViews adapter.
943 // This adapter connects
944 // to a RemoteViewsService through the specified intent.
945 // This is how you populate the data.
946 rv.setRemoteAdapter(appWidgetIds[i], R.id.stack_view, intent);
947
948 // The empty view is displayed when the collection has no items.
949 // It should be in the same layout used to instantiate the RemoteViews
950 // object above.
951 rv.setEmptyView(R.id.stack_view, R.id.empty_view);
952
953 //
954 // Do additional processing specific to this app widget...
955 //
956
957 appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
958 }
959 super.onUpdate(context, appWidgetManager, appWidgetIds);
960}</pre>
961
962<h4>RemoteViewsService class</h4>
963
964<div class="sidebox-wrapper">
965<div class="sidebox">
966<h3>Persisting data</h3>
967 <p>You can’t rely on a single instance of your service, or any data it
968contains, to persist. You should therefore not store any data in your {@link
969android.widget.RemoteViewsService} (unless it is static). If you want your
970app widget’s data to persist, the best approach is to use a {@link
971android.content.ContentProvider} whose data persists beyond the process
972lifecycle.</p> </div>
973</div>
974
975<p>As described above, your {@link android.widget.RemoteViewsService} subclass
976provides the {@link android.widget.RemoteViewsService.RemoteViewsFactory
977RemoteViewsFactory} used to populate the remote collection view.</p>
978
979<p>Specifically, you need to
980perform these steps:</p>
981
982<ol>
983 <li>Subclass {@link android.widget.RemoteViewsService}. {@link
984android.widget.RemoteViewsService} is the service through which
985a remote adapter can request {@link android.widget.RemoteViews}. </li>
986
987 <li>In your {@link android.widget.RemoteViewsService} subclass, include a
988class that implements the {@link
989android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}
990interface. {@link android.widget.RemoteViewsService.RemoteViewsFactory
991RemoteViewsFactory} is an interface for an adapter between a remote collection
992view (such as {@link android.widget.ListView}, {@link android.widget.GridView},
993and so on) and the underlying data for that view. Your implementation is
994responsible for making a {@link android.widget.RemoteViews} object for each
995item in the data set. This interface is a thin wrapper around {@link
996android.widget.Adapter}.</li>
997</ol>
998
999<p>The primary contents of the {@link android.widget.RemoteViewsService}
1000implementation is its {@link
1001android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory},
1002described below.</p>
1003
1004<h4>RemoteViewsFactory interface</h4>
1005
1006<p>Your custom class that implements the {@link
1007android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}
1008interface provides the app widget with the data for the items in its collection.
1009To
1010do this, it combines your app widget item XML layout file with a source of data.
1011This source of data could be anything from a database to a simple array. In the
1012<a href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
1013sample</a>, the data source is an array of <code>WidgetItems</code>. The {@link
1014android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}
1015functions as an adapter to glue the data to the remote collection view.</p>
1016
1017<p>The two most important methods you need to implement for your
1018
1019{@link android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}
1020subclass are
1021{@link android.widget.RemoteViewsService.RemoteViewsFactory#onCreate()
1022onCreate()} and
1023{@link android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int)
1024getViewAt()}
1025.</p>
1026
1027<p>The system calls {@link
1028android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()} when
1029creating your factory for the first time. This is where you set up any
1030connections and/or cursors to your data source. For example, the <a
1031href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
1032sample</a> uses {@link
1033android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()} to
1034initialize an array of <code>WidgetItem</code> objects. When your app widget is
1035active, the system accesses these objects using their index position in the
1036array and the text they contain is displayed </p>
1037
1038<p>Here is an excerpt from the the <a
1039href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget</a>
1040sample's
1041{@link android.widget.RemoteViewsService.RemoteViewsFactory
1042RemoteViewsFactory} implementation that shows portions of the {@link
1043android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()}
1044method:</p>
1045
1046<pre>class StackRemoteViewsFactory implements
1047RemoteViewsService.RemoteViewsFactory {
1048    private static final int mCount = 10;
1049    private List&lt;WidgetItem&gt; mWidgetItems = new ArrayList&lt;WidgetItem&gt;();
1050    private Context mContext;
1051    private int mAppWidgetId;
1052
1053    public StackRemoteViewsFactory(Context context, Intent intent) {
1054        mContext = context;
1055        mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
1056                AppWidgetManager.INVALID_APPWIDGET_ID);
1057    }
1058
1059    public void onCreate() {
1060        // In onCreate() you setup any connections / cursors to your data source. Heavy lifting,
1061        // for example downloading or creating content etc, should be deferred to onDataSetChanged()
1062        // or getViewAt(). Taking more than 20 seconds in this call will result in an ANR.
1063        for (int i = 0; i &lt; mCount; i++) {
1064            mWidgetItems.add(new WidgetItem(i + &quot;!&quot;));
1065        }
1066        ...
1067    }
1068...</pre>
1069
1070<p>The {@link android.widget.RemoteViewsService.RemoteViewsFactory
1071RemoteViewsFactory} method {@link
1072android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int) getViewAt()}
1073returns a {@link android.widget.RemoteViews} object corresponding to the data at
1074the specified <code>position</code> in the data set. Here is an excerpt from
1075the <a
1076href="http://developer.android.com/resources/samples/StackWidget/index.html">
1077StackView Widget</a> sample's {@link
1078android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}
1079implementation:</p>
1080
1081<pre>public RemoteViews getViewAt(int position) {
1082
1083 // Construct a remote views item based on the app widget item XML file,
1084 // and set the text based on the position.
1085 RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item);
1086 rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text);
1087
1088 ...
1089 // Return the remote views object.
1090    return rv;
1091}</pre>
1092
1093<h4 id="behavior">Adding behavior to individual items</h4>
1094
1095<p>The above sections show you how to bind your data to your app widget
1096collection. But what if you want to add dynamic behavior to the individual items
1097in your collection view?</p>
1098
1099<p> As described in <a href="#AppWidgetProvider">Using the AppWidgetProvider
1100Class</a>, you normally use {@link
1101android.widget.RemoteViews#setOnClickPendingIntent(int,
1102android.app.PendingIntent) setOnClickPendingIntent()} to set an object's click
1103behavior&mdash;such as to cause a button to launch an {@link
1104android.app.Activity}. But this approach is not allowed for child views in an
1105individual collection item (to clarify, you could use {@link
1106android.widget.RemoteViews#setOnClickPendingIntent(int,
1107android.app.PendingIntent) setOnClickPendingIntent()} to set up a global button
1108in the Gmail app widget that launches the app, for example, but not on the
1109individual list items). Instead, to add click behavior to individual items in a
1110collection, you use {@link
1111android.widget.RemoteViews#setOnClickFillInIntent(int, android.content.Intent)
1112setOnClickFillInIntent()}. This entails setting up up a pending intent template
1113for your collection view, and then setting a fill-in intent on each item in the
1114collection via your {@link android.widget.RemoteViewsService.RemoteViewsFactory
1115RemoteViewsFactory}.</p>
1116<p>This section uses the <a
1117href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
1118sample</a> to describe how to add behavior to individual items. In the <a
1119href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
1120sample</a>, if the user touches the top view, the app widget displays the {@link
1121android.widget.Toast} message &quot;Touched view <em>n</em>,&quot; where
1122<em>n</em> is the index (position) of the touched view. This is how it
1123works:</p>
1124
1125<ul>
1126 <li>The <code>StackWidgetProvider</code> (an {@link
1127android.appwidget.AppWidgetProvider} subclass) creates a pending intent that has
1128a custom action called <code>TOAST_ACTION</code>.</li>
1129 <li>When the user touches a view, the intent is fired and it broadcasts
1130<code>TOAST_ACTION</code>.</li>
1131
1132 <li>This broadcast is intercepted by the <code>StackWidgetProvider</code>'s
1133{@link android.appwidget.AppWidgetProvider#onReceive(android.content.Context,
1134android.content.Intent) onReceive()} method, and the app widget displays the
1135{@link
1136android.widget.Toast} message for the touched view. The data for the collection
1137items is provided by the {@link
1138android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, via
1139the {@link android.widget.RemoteViewsService}.</li>
1140</ul>
1141
1142<p class="note"><strong>Note:</strong> The <a
1143href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
1144sample</a> uses a broadcast, but typically an app widget would simply launch an
1145activity in a scenario like this one.</p>
1146
1147<h5>Setting up the pending intent template</h5>
1148
1149<p>The <code>StackWidgetProvider</code> ({@link
1150android.appwidget.AppWidgetProvider} subclass) sets up a pending intent.
1151Individuals items of a collection cannot set up their own pending intents.
1152Instead, the collection as a whole sets up a pending intent template, and the
1153individual items set a fill-in intent to create unique behavior on an
1154item-by-item
1155basis.</p>
1156
1157<p>This class also receives the broadcast that is sent when the user touches a
1158view. It processes this event in its {@link
1159android.appwidget.AppWidgetProvider#onReceive(android.content.Context,
1160android.content.Intent) onReceive()} method. If the intent's action is
1161<code>TOAST_ACTION</code>, the app widget displays a {@link
1162android.widget.Toast}
1163message for the current view.</p>
1164
1165<pre>public class StackWidgetProvider extends AppWidgetProvider {
1166 public static final String TOAST_ACTION = &quot;com.example.android.stackwidget.TOAST_ACTION&quot;;
1167    public static final String EXTRA_ITEM = &quot;com.example.android.stackwidget.EXTRA_ITEM&quot;;
1168
1169    ...
1170
1171 // Called when the BroadcastReceiver receives an Intent broadcast.
1172 // Checks to see whether the intent's action is TOAST_ACTION. If it is, the app widget
1173 // displays a Toast message for the current item.
1174 &#64;Override
1175 public void onReceive(Context context, Intent intent) {
1176 AppWidgetManager mgr = AppWidgetManager.getInstance(context);
1177     if (intent.getAction().equals(TOAST_ACTION)) {
1178     int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
1179         AppWidgetManager.INVALID_APPWIDGET_ID);
1180         int viewIndex = intent.getIntExtra(EXTRA_ITEM, 0);
1181         Toast.makeText(context, &quot;Touched view &quot; + viewIndex, Toast.LENGTH_SHORT).show();
1182     }
1183     super.onReceive(context, intent);
1184 }
1185
1186 &#64;Override
1187 public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
1188 // update each of the app widgets with the remote adapter
1189     for (int i = 0; i &lt; appWidgetIds.length; ++i) {
1190
1191     // Sets up the intent that points to the StackViewService that will
1192     // provide the views for this collection.
1193     Intent intent = new Intent(context, StackWidgetService.class);
1194     intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
1195     // When intents are compared, the extras are ignored, so we need to embed the extras
1196     // into the data so that the extras will not be ignored.
1197     intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
1198     RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
1199     rv.setRemoteAdapter(appWidgetIds[i], R.id.stack_view, intent);
1200
1201     // The empty view is displayed when the collection has no items. It should be a sibling
1202     // of the collection view.
1203     rv.setEmptyView(R.id.stack_view, R.id.empty_view);
1204
1205     // This section makes it possible for items to have individualized behavior.
1206     // It does this by setting up a pending intent template. Individuals items of a collection
1207     // cannot set up their own pending intents. Instead, the collection as a whole sets
1208     // up a pending intent template, and the individual items set a fillInIntent
1209     // to create unique behavior on an item-by-item basis.
1210     Intent toastIntent = new Intent(context, StackWidgetProvider.class);
1211     // Set the action for the intent.
1212     // When the user touches a particular view, it will have the effect of
1213     // broadcasting TOAST_ACTION.
1214     toastIntent.setAction(StackWidgetProvider.TOAST_ACTION);
1215     toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
1216     intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
1217     PendingIntent toastPendingIntent = PendingIntent.getBroadcast(context, 0, toastIntent,
1218     PendingIntent.FLAG_UPDATE_CURRENT);
1219     rv.setPendingIntentTemplate(R.id.stack_view, toastPendingIntent);
1220
1221     appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
1222 }
1223 super.onUpdate(context, appWidgetManager, appWidgetIds);
1224 }
1225}</pre>
1226
1227<h5><strong>Setting the fill-in Intent</strong></h5>
1228
1229<p>Your {@link android.widget.RemoteViewsService.RemoteViewsFactory
1230RemoteViewsFactory} must set a fill-in intent on each item in the collection.
1231This makes it possible to distinguish the individual on-click action of a given
1232item. The fill-in intent is then combined with the {@link
1233android.app.PendingIntent} template in order to determine the final intent that
1234will be executed when the item is clicked. </p>
1235
1236<pre>
1237public class StackWidgetService extends RemoteViewsService {
1238    &#64;Override
1239    public RemoteViewsFactory onGetViewFactory(Intent intent) {
1240        return new StackRemoteViewsFactory(this.getApplicationContext(), intent);
1241    }
1242}
1243
1244class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
1245    private static final int mCount = 10;
1246    private List&lt;WidgetItem&gt; mWidgetItems = new ArrayList&lt;WidgetItem&gt;();
1247    private Context mContext;
1248    private int mAppWidgetId;
1249
1250    public StackRemoteViewsFactory(Context context, Intent intent) {
1251        mContext = context;
1252        mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
1253                AppWidgetManager.INVALID_APPWIDGET_ID);
1254    }
1255
1256 // Initialize the data set.
1257     public void onCreate() {
1258         // In onCreate() you set up any connections / cursors to your data source. Heavy lifting,
1259         // for example downloading or creating content etc, should be deferred to onDataSetChanged()
1260         // or getViewAt(). Taking more than 20 seconds in this call will result in an ANR.
1261         for (int i = 0; i &lt; mCount; i++) {
1262             mWidgetItems.add(new WidgetItem(i + &quot;!&quot;));
1263         }
1264        ...
1265     }
1266     ...
1267
1268 // Given the position (index) of a WidgetItem in the array, use the item's text value in
1269 // combination with the app widget item XML file to construct a RemoteViews object.
1270     public RemoteViews getViewAt(int position) {
1271         // position will always range from 0 to getCount() - 1.
1272
1273         // Construct a RemoteViews item based on the app widget item XML file, and set the
1274         // text based on the position.
1275         RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item);
1276         rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text);
1277
1278         // Next, set a fill-intent, which will be used to fill in the pending intent template
1279         // that is set on the collection view in StackWidgetProvider.
1280         Bundle extras = new Bundle();
1281         extras.putInt(StackWidgetProvider.EXTRA_ITEM, position);
1282         Intent fillInIntent = new Intent();
1283         fillInIntent.putExtras(extras);
1284 // Make it possible to distinguish the individual on-click
1285 // action of a given item
1286     rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent);
1287
1288     ...
1289
1290     // Return the RemoteViews object.
1291     return rv;
1292 }
1293 ...
1294 }</pre>
1295
1296<h3 id="fresh">Keeping Collection Data Fresh</h3>
1297
1298<p>The following figure illustrates the flow that occurs in an App Widget that
1299uses
1300collections when updates occur. It shows how the App Widget code interacts with
1301the {@link android.widget.RemoteViewsService.RemoteViewsFactory
1302RemoteViewsFactory}, and how you can trigger updates:</p>
1303
1304<img src="{@docRoot}images/appwidget_collections.png" alt="" />
1305
1306<p>One feature of App Widgets that use collections is the ability to provide
1307users with up-to-date content. For example, consider the Android 3.0 Gmail
1308app widget, which provides users with a snapshot of their inbox. To make this
1309possible, you need to be able to trigger your {@link
1310android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} and
1311collection view to fetch and display new data. You achieve this with the {@link
1312android.appwidget.AppWidgetManager} call {@link
1313android.appwidget.AppWidgetManager#notifyAppWidgetViewDataChanged(int, int)
1314notifyAppWidgetViewDataChanged()}. This call results in a callback to your
1315<code>RemoteViewsFactory</code>’s {@link
1316android.widget.RemoteViewsService.RemoteViewsFactory#onDataSetChanged()
1317onDataSetChanged()} method, which gives you the opportunity to fetch any new
1318data. Note that you can perform
1319processing-intensive operations synchronously within the {@link
1320android.widget.RemoteViewsService.RemoteViewsFactory#onDataSetChanged()
1321onDataSetChanged()} callback. You are guaranteed that this call will be
1322completed before the metadata or view data is fetched from the {@link
1323android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}. In
1324addition, you can perform processing-intensive operations within the {@link
1325android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int) getViewAt()}
1326method. If this call takes a long time, the loading view (specified by the
1327<code>RemoteViewsFactory</code>’s {@link
1328android.widget.RemoteViewsService.RemoteViewsFactory#getLoadingView()} method)
1329will be displayed in the corresponding position of the collection view until it
1330returns.</p>
Scott Main04c72b42009-05-13 16:48:13 -07001331
1332