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