| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 1 | page.title=App Widgets |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 2 | @jd:body |
| 3 | |
| 4 | <div id="qv-wrapper"> |
| 5 | <div id="qv"> |
| 6 | <h2>Key classes</h2> |
| 7 | <ol> |
| 8 | <li>{@link android.appwidget.AppWidgetProvider}</li> |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 9 | <li>{@link android.appwidget.AppWidgetProviderInfo}</li> |
| 10 | <li>{@link android.appwidget.AppWidgetManager}</li> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 11 | </ol> |
| 12 | <h2>In this document</h2> |
| 13 | <ol> |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 14 | <li><a href="#Basics">The Basics</a></li> |
| 15 | <li><a href="#Manifest">Declaring an App Widget in the Manifest</a></li> |
| 16 | <li><a href="#MetaData">Adding the AppWidgetProviderInfo Metadata</a></li> |
| 17 | <li><a href="#CreatingLayout">Creating the App Widget Layout</a></li> |
| 18 | <li><a href="#AppWidgetProvider">Using the AppWidgetProvider Class</a> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 19 | <ol> |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 20 | <li><a href="#ProviderBroadcasts">Receiving App Widget broadcast Intents</a></li> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 21 | </ol> |
| 22 | </li> |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 23 | <li><a href="#Configuring">Creating an App Widget Configuration Activity</a> |
| 24 | <ol> |
| 25 | <li><a href="#UpdatingFromTheConfiguration">Updating the App Widget from |
| 26 | the configuration Activity</a></li> |
| 27 | </ol> |
| 28 | </li> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 29 | </ol> |
| 30 | |
| 31 | <h2>See also</h2> |
| 32 | <ol> |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 33 | <li><a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget Design |
| 34 | Guidelines</a></li> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 35 | <li><a href="http://android-developers.blogspot.com/2009/04/introducing-home-screen-widgets-and.html">Introducing |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 36 | home screen widgets and the AppWidget framework »</a></li> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 37 | </ol> |
| 38 | </div> |
| 39 | </div> |
| 40 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 41 | |
| 42 | <p>App Widgets are miniature application views that can be embedded in other applications |
| 43 | (such as the Home screen) and receive periodic updates. These views are referred |
| 44 | to as Widgets in the user interface, |
| 45 | and you can publish one with an App Widget provider. An application component that is |
| 46 | able to hold other App Widgets is called an App Widget host. The screenshot below shows |
| 47 | the Music App Widget.</p> |
| 48 | |
| 49 | <img src="{@docRoot}images/appwidget.png" alt="" /> |
| 50 | |
| 51 | <p>This document describes how to publish an App Widget using an App Widget provider.</p> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 52 | |
| 53 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 54 | <h2 id="Basics">The Basics</h2> |
| 55 | |
| 56 | <p>To create an App Widget, you need the following:</p> |
| 57 | |
| 58 | <dl> |
| 59 | <dt>{@link android.appwidget.AppWidgetProviderInfo} object</dt> |
| 60 | <dd>Describes the metadata for an App Widget, such as the App Widget's layout, update frequency, |
| 61 | and the AppWidgetProvider class. This should be defined in XML.</dd> |
| 62 | <dt>{@link android.appwidget.AppWidgetProvider} class implementation</dt> |
| 63 | <dd>Defines the basic methods that allow you to programmatically interface with the App Widget, |
| 64 | based on broadcast events. Through it, you will receive broadcasts when the App Widget is updated, |
| 65 | enabled, disabled and deleted.</dd> |
| 66 | <dt>View layout</dt> |
| 67 | <dd>Defines the initial layout for the App Widget, defined in XML.</dd> |
| 68 | </dl> |
| 69 | |
| 70 | <p>Additionally, you can implement an App Widget configuration Activity. This is an optional |
| 71 | {@link android.app.Activity} that launches when the user adds your App Widget and allows him or her |
| 72 | to modify App Widget settings at create-time.</p> |
| 73 | |
| 74 | <p>The following sections describe how to setup each of these components.</p> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 75 | |
| 76 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 77 | <h2 id="Manifest">Declaring an App Widget in the Manifest</h2> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 78 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 79 | <p>First, declare the {@link android.appwidget.AppWidgetProvider} class in your application's |
| 80 | <code>AndroidManifest.xml</code> file. For example:</p> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 81 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 82 | <pre> |
| 83 | <receiver android:name="ExampleAppWidgetProvider" > |
| 84 | <intent-filter> |
| 85 | <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> |
| 86 | </intent-filter> |
| 87 | <meta-data android:name="android.appwidget.provider" |
| 88 | android:resource="@xml/example_appwidget_info" /> |
| 89 | </receiver> |
| 90 | </pre> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 91 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 92 | <p>The <code><receiver></code> element requires the <code>android:name</code> |
| 93 | attribute, which specifies the {@link android.appwidget.AppWidgetProvider} used |
| 94 | by the App Widget.</p> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 95 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 96 | <p>The <code><intent-filter></code> element must include an <code><action></code> |
| 97 | element with the <code>android:name</code> attribute. This attribute specifies |
| 98 | that the {@link android.appwidget.AppWidgetProvider} accepts the {@link |
| 99 | android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE ACTION_APPWIDGET_UPDATE} broadcast. |
| 100 | This is the only broadcast that you must explicitly declare. The {@link android.appwidget.AppWidgetManager} |
| 101 | automatically sends all other App Widget broadcasts to the AppWidgetProvider as necessary.</p> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 102 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 103 | <p>The <code><meta-data></code> element specifies the |
| 104 | {@link android.appwidget.AppWidgetProviderInfo} resource and requires the |
| 105 | following attributes:</p> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 106 | <ul> |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 107 | <li><code>android:name</code> - Specifies the metadata name. Use <code>android.appwidget.provider</code> |
| 108 | to identify the data as the {@link android.appwidget.AppWidgetProviderInfo} descriptor.</li> |
| 109 | <li><code>android:resource</code> - Specifies the {@link android.appwidget.AppWidgetProviderInfo} |
| 110 | resource location.</li> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 111 | </ul> |
| 112 | |
| 113 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 114 | <h2 id="MetaData">Adding the AppWidgetProviderInfo Metadata</h2> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 115 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 116 | <p>The {@link android.appwidget.AppWidgetProviderInfo} defines the essential |
| 117 | qualities of an App Widget, such as its minimum layout dimensions, its initial layout resource, |
| 118 | how often to update the App Widget, and (optionally) a configuration Activity to launch at create-time. |
| 119 | Define the AppWidgetProviderInfo object in an XML resource using a single |
| 120 | <code><appwidget-provider></code> element and save it in the project's <code>res/xml/</code> |
| 121 | folder.</p> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 122 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 123 | <p>For example:</p> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 124 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 125 | <pre> |
| 126 | <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" |
| Scott Main | 33e0f00 | 2009-12-03 11:33:25 -0800 | [diff] [blame] | 127 | android:minWidth="294dp" |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 128 | android:minHeight="72dp" |
| Scott Main | 33e0f00 | 2009-12-03 11:33:25 -0800 | [diff] [blame] | 129 | android:updatePeriodMillis="86400000" |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 130 | android:initialLayout="@layout/example_appwidget" |
| 131 | android:configure="com.example.android.ExampleAppWidgetConfigure" > |
| 132 | </appwidget-provider> |
| 133 | </pre> |
| 134 | |
| 135 | <p>Here's a summary of the <code><appwidget-provider></code> attributes:</p> |
| 136 | <ul> |
| 137 | <li>The values for the <code>minWidth</code> and <code>minHeight</code> attributes specify the minimum |
| 138 | area required by the App Widget's layout. |
| 139 | <p>The default Home screen positions App Widgets in its window based on a grid of |
| 140 | cells that have a defined height and width. If the values for an App Widget's minimum width |
| 141 | or height don't match the dimensions of the cells, |
| 142 | then the App Widget dimensions round <em>up</em> to the nearest cell size. |
| 143 | (See the <a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget Design |
| 144 | Guidelines</a> for more information on the Home screen cell sizes.)</p> |
| 145 | <p>Because the Home screen's layout orientation (and thus, the cell sizes) can change, |
| 146 | as a rule of thumb, you should assume the worst-case cell size of 74 pixels for the height |
| 147 | <em>and</em> width of a cell. However, you must subtract 2 from the final dimension to account |
| 148 | for any integer rounding errors that occur in the pixel count. To find your minimum width |
| 149 | and height in density-independent pixels (dp), use this formula:<br/> |
| 150 | <code>(number of cells * 74) - 2</code><br/> |
| 151 | Following this formula, you should use 72 dp for a height of one cell, 294 dp and for a width of four cells.</p> |
| 152 | </li> |
| Scott Main | e518606 | 2009-07-15 16:52:31 -0700 | [diff] [blame] | 153 | <li>The <code>updatePeriodMillis</code> attribute defines how often the App Widget framework should |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 154 | request an update from the {@link android.appwidget.AppWidgetProvider} by calling the |
| 155 | {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) |
| 156 | onUpdate()} method. The actual update is not guaranteed to occur exactly on time with this value |
| 157 | and we suggest updating as infrequently as possible—perhaps no more than once an hour to |
| 158 | conserve the battery. You might also allow the user to adjust the frequency in a |
| 159 | configuration—some people might want a stock ticker to update every 15 minutes, or maybe |
| Scott Main | e518606 | 2009-07-15 16:52:31 -0700 | [diff] [blame] | 160 | only four times a day. |
| 161 | <p class="note"><strong>Note:</strong> If the device is asleep when it is time for an update |
| 162 | (as defined by <code>updatePeriodMillis</code>), then the device will wake up in order |
| 163 | to perform the update. If you don't update more than once per hour, this probably won't |
| 164 | cause significant problems for the battery life. If, however, you need to update more |
| 165 | frequently and/or you do not need to update while the device is asleep, then you can instead |
| 166 | perform updates based on an alarm that will not wake the device. To do so, set an alarm with |
| 167 | an Intent that your AppWidgetProvider receives, using the {@link android.app.AlarmManager}. |
| 168 | Set the alarm type to either {@link android.app.AlarmManager#ELAPSED_REALTIME} or |
| 169 | {@link android.app.AlarmManager#RTC}, which will only |
| 170 | deliver the alarm when the device is awake. Then set <code>updatePeriodMillis</code> to |
| 171 | zero (<code>"0"</code>).</p> |
| 172 | </li> |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 173 | <li>The <code>initialLayout</code> attribute points to the layout resource that defines the |
| 174 | App Widget layout.</li> |
| 175 | <li>The <code>configure</code> attribute defines the {@link android.app.Activity} to launch when |
| 176 | the user adds the App Widget, in order for him or her to configure App Widget properties. This is optional |
| 177 | (read <a href="#Configuring">Creating an App Widget Configuration Activity</a> below).</li> |
| 178 | </ul> |
| 179 | |
| 180 | <p>See the {@link android.appwidget.AppWidgetProviderInfo} class for more information on the |
| 181 | attributes accepted by the <code><appwidget-provider></code> element.</p> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 182 | |
| 183 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 184 | <h2 id="CreatingLayout">Creating the App Widget Layout</h2> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 185 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 186 | <p>You must define an initial layout for your App Widget in XML and save it in the project's |
| 187 | <code>res/layout/</code> directory. You can design your App Widget using the View objects listed |
| 188 | below, but before you begin designing your App Widget, please read and understand the |
| 189 | <a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget Design |
| 190 | Guidelines</a>.</p> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 191 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 192 | <p>Creating the App Widget layout is simple if you're |
| 193 | familiar with <a href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout in XML</a>. |
| 194 | However, you must be aware that App Widget layouts are based on {@link android.widget.RemoteViews}, |
| 195 | which do not support every kind of layout or view widget.</p> |
| 196 | |
| 197 | <p>A RemoteViews object (and, consequently, an App Widget) can support the |
| 198 | following layout classes:</p> |
| 199 | |
| 200 | <ul class="nolist"> |
| 201 | <li>{@link android.widget.FrameLayout}</li> |
| 202 | <li>{@link android.widget.LinearLayout}</li> |
| 203 | <li>{@link android.widget.RelativeLayout}</li> |
| 204 | </ul> |
| 205 | |
| 206 | <p>And the following widget classes:</p> |
| 207 | <ul class="nolist"> |
| 208 | <li>{@link android.widget.AnalogClock}</li> |
| 209 | <li>{@link android.widget.Button}</li> |
| 210 | <li>{@link android.widget.Chronometer}</li> |
| 211 | <li>{@link android.widget.ImageButton}</li> |
| 212 | <li>{@link android.widget.ImageView}</li> |
| 213 | <li>{@link android.widget.ProgressBar}</li> |
| 214 | <li>{@link android.widget.TextView}</li> |
| 215 | </ul> |
| 216 | |
| 217 | <p>Descendants of these classes are not supported.</p> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 218 | |
| 219 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 220 | <h2 id="AppWidgetProvider">Using the AppWidgetProvider Class</h2> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 221 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 222 | <div class="sidebox-wrapper"> |
| Scott Main | f54574a | 2010-03-24 17:18:01 -0700 | [diff] [blame] | 223 | <div class="sidebox"> |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 224 | <p>You must declare your AppWidgetProvider class implementation as a broadcast receiver |
| 225 | using the <code><receiver></code> element in the AndroidManifest (see |
| 226 | <a href="#Manifest">Declaring an App Widget in the Manifest</a> above).</p> |
| 227 | </div> |
| 228 | </div> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 229 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 230 | <p>The {@link android.appwidget.AppWidgetProvider} class extends BroadcastReceiver as a convenience |
| 231 | class to handle the App Widget broadcasts. The AppWidgetProvider receives only the event broadcasts that |
| 232 | are relevant to the App Widget, such as when the App Widget is updated, deleted, enabled, and disabled. |
| 233 | When these broadcast events occur, the AppWidgetProvider receives the following method calls:</p> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 234 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 235 | <dl> |
| 236 | <dt>{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])}</dt> |
| 237 | <dd>This is called to update the App Widget at intervals defined by the <code>updatePeriodMillis</code> |
| 238 | attribute in the AppWidgetProviderInfo (see <a href="#MetaData">Adding the |
| 239 | AppWidgetProviderInfo Metadata</a> above). This method is also called |
| 240 | when the user adds the App Widget, so it should perform the essential setup, |
| 241 | such as define event handlers for Views and start a temporary |
| 242 | {@link android.app.Service}, if necessary. However, if you have declared a configuration |
| 243 | Activity, <strong>this method is not called</strong> when the user adds the App Widget, |
| 244 | but is called for the subsequent updates. It is the responsibility of the |
| 245 | configuration Activity to perform the first update when configuration is done. |
| 246 | (See <a href="#Configuring">Creating an App Widget Configuration Activity</a> below.)</dd> |
| 247 | <dt>{@link android.appwidget.AppWidgetProvider#onDeleted(Context,int[])}</dt> |
| 248 | <dd>This is called every time an App Widget is deleted from the App Widget host.</dd> |
| 249 | <dt>{@link android.appwidget.AppWidgetProvider#onEnabled(Context)}</dt> |
| 250 | <dd>This is called when an instance the App Widget is created for the first time. For example, if the user |
| 251 | adds two instances of your App Widget, this is only called the first time. |
| 252 | If you need to open a new database or perform other setup that only needs to occur once |
| 253 | for all App Widget instances, then this is a good place to do it.</dd> |
| 254 | <dt>{@link android.appwidget.AppWidgetProvider#onDisabled(Context)}</dt> |
| 255 | <dd>This is called when the last instance of your App Widget is deleted from the App Widget host. |
| 256 | This is where you should clean up any work done in |
| 257 | {@link android.appwidget.AppWidgetProvider#onEnabled(Context)}, |
| 258 | such as delete a temporary database.</dd> |
| 259 | <dt>{@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)}</dt> |
| 260 | <dd>This is called for every broadcast and before each of the above callback methods. |
| 261 | You normally don't need to implement this method because the default AppWidgetProvider |
| 262 | implementation filters all App Widget broadcasts and calls the above |
| 263 | methods as appropriate.</dd> |
| 264 | </dl> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 265 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 266 | <p class="warning"><strong>Note:</strong> In Android 1.5, there is a known issue in which the |
| 267 | <code>onDeleted()</code> method will not be called when it should be. To work around this issue, |
| 268 | you can implement {@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent) |
| 269 | onReceive()} as described in this |
| 270 | <a href="http://groups.google.com/group/android-developers/msg/e405ca19df2170e2">Group post</a> |
| 271 | to receive the <code>onDeleted()</code> callback. |
| 272 | </p> |
| 273 | |
| 274 | <p>The most important AppWidgetProvider callback is |
| 275 | {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) |
| 276 | onUpdated()} because it is called when each App Widget is added to a host (unless you use |
| 277 | a configuration Activity). If your App Widget accepts any |
| 278 | user interaction events, then you need to register the event handlers in this callback. |
| 279 | If your App Widget doesn't create temporary |
| 280 | files or databases, or perform other work that requires clean-up, then |
| 281 | {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) |
| 282 | onUpdated()} may be the only callback method you need to define. For example, if you want an App Widget |
| 283 | with a button that launches an Activity when clicked, you could use the following |
| 284 | implementation of AppWidgetProvider:</p> |
| 285 | |
| 286 | <pre> |
| 287 | public class ExampleAppWidgetProvider extends AppWidgetProvider { |
| 288 | |
| 289 | public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { |
| 290 | final int N = appWidgetIds.length; |
| 291 | |
| 292 | // Perform this loop procedure for each App Widget that belongs to this provider |
| 293 | for (int i=0; i<N; i++) { |
| 294 | int appWidgetId = appWidgetIds[i]; |
| 295 | |
| 296 | // Create an Intent to launch ExampleActivity |
| 297 | Intent intent = new Intent(context, ExampleActivity.class); |
| 298 | PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); |
| 299 | |
| 300 | // Get the layout for the App Widget and attach an on-click listener to the button |
| 301 | RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout); |
| 302 | views.setOnClickPendingIntent(R.id.button, pendingIntent); |
| 303 | |
| 304 | // Tell the AppWidgetManager to perform an update on the current App Widget |
| 305 | appWidgetManager.updateAppWidget(appWidgetId, views); |
| 306 | } |
| 307 | } |
| 308 | } |
| 309 | </pre> |
| 310 | |
| 311 | <p>This AppWidgetProvider defines only the |
| 312 | {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) |
| 313 | onUpdated()} method for the purpose |
| 314 | of defining a {@link android.app.PendingIntent} that launches an {@link android.app.Activity} |
| 315 | and attaching it to the App Widget's button |
| 316 | with {@link android.widget.RemoteViews#setOnClickPendingIntent(int,PendingIntent)}. |
| 317 | Notice that it includes a loop that iterates through each entry in <code>appWidgetIds</code>, which |
| 318 | is an array of IDs that identify each App Widget created by this provider. |
| 319 | In this way, if the user creates more than one instance of the App Widget, then they are |
| 320 | all updated simultaneously. However, only one <code>updatePeriodMillis</code> schedule will be |
| 321 | managed for all instances of the App Widget. For example, if the update schedule is defined |
| 322 | to be every two hours, and a second instance |
| 323 | of the App Widget is added one hour after the first one, then they will both be updated |
| 324 | on the period defined by the first one and the second update period will be ignored |
| 325 | (they'll both be updated every two hours, not every hour).</p> |
| 326 | |
| 327 | <p class="note"><strong>Note:</strong> Because the AppWidgetProvider is a BroadcastReceiver, |
| 328 | your process is not guaranteed to keep running after the callback methods return (see |
| 329 | <a href="{@docRoot}guide/topics/fundamentals.html#broadlife">Application Fundamentals > |
| 330 | Broadcast Receiver Lifecycle</a> for more information). If your App Widget setup process can take several |
| 331 | seconds (perhaps while performing web requests) and you require that your process continues, |
| 332 | consider starting a {@link android.app.Service} |
| 333 | in the {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) |
| 334 | onUpdated()} method. From within the Service, you can perform your own updates to the App Widget |
| 335 | without worrying about the AppWidgetProvider closing down due to an |
| 336 | <a href="{@docRoot}guide/practices/design/responsiveness.html">Application Not Responding</a> |
| 337 | (ANR) error. See the |
| 338 | <a href="http://code.google.com/p/wiktionary-android/source/browse/trunk/Wiktionary/src/com/example/android/wiktionary/WordWidget.java">Wiktionary |
| 339 | sample's AppWidgetProvider</a> for an example of an App Widget running a {@link android.app.Service}.</p> |
| 340 | |
| 341 | <p>Also see the <a |
| Dirk Dougherty | 22558d0 | 2009-12-10 16:25:06 -0800 | [diff] [blame] | 342 | href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetProvider.html"> |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 343 | ExampleAppWidgetProvider.java</a> sample class.</p> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 344 | |
| 345 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 346 | <h3 id="ProviderBroadcasts">Receiving App Widget broadcast Intents</h3> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 347 | |
| 348 | <p>{@link android.appwidget.AppWidgetProvider} is just a convenience class. If you would like |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 349 | to receive the App Widget broadcasts directly, you can implement your own |
| 350 | {@link android.content.BroadcastReceiver} or override the |
| 351 | {@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)} callback. |
| 352 | The four Intents you need to care about are:</p> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 353 | <ul> |
| 354 | <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE}</li> |
| 355 | <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DELETED}</li> |
| 356 | <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_ENABLED}</li> |
| 357 | <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DISABLED}</li> |
| 358 | </ul> |
| 359 | |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 360 | |
| 361 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 362 | <h2 id="Configuring">Creating an App Widget Configuration Activity</h2> |
| Scott Main | 620986a | 2009-04-22 18:58:13 -0700 | [diff] [blame] | 363 | |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 364 | <p>If you would like the user to configure settings when he or she adds a new App Widget, |
| 365 | you can create an App Widget configuration Activity. This {@link android.app.Activity} |
| 366 | will be automatically launched by the App Widget host and allows the user to configure |
| 367 | available settings for the App Widget at create-time, such as the App Widget color, size, |
| 368 | update period or other functionality settings.</p> |
| 369 | |
| 370 | <p>The configuration Activity should be declared as a normal Activity in the Android manifest file. |
| 371 | However, it will be launched by the App Widget host with the {@link |
| 372 | android.appwidget.AppWidgetManager#ACTION_APPWIDGET_CONFIGURE ACTION_APPWIDGET_CONFIGURE} action, |
| 373 | so the Activity needs to accept this Intent. For example:</p> |
| 374 | |
| 375 | <pre> |
| 376 | <activity android:name=".ExampleAppWidgetConfigure"> |
| 377 | <intent-filter> |
| 378 | <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" /> |
| 379 | </intent-filter> |
| 380 | </activity> |
| 381 | </pre> |
| 382 | |
| 383 | <p>Also, the Activity must be declared in the AppWidgetProviderInfo XML file, with the |
| 384 | <code>android:configure</code> attribute (see <a href="#MetaData">Adding |
| Elliott Hughes | 7f87706 | 2009-07-30 17:00:34 -0700 | [diff] [blame] | 385 | the AppWidgetProviderInfo Metadata</a> above). For example, the configuration Activity |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 386 | can be declared like this:</p> |
| 387 | |
| 388 | <pre> |
| 389 | <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" |
| 390 | ... |
| 391 | android:configure="com.example.android.ExampleAppWidgetConfigure" |
| 392 | ... > |
| 393 | </appwidget-provider> |
| 394 | </pre> |
| 395 | |
| 396 | <p>Notice that the Activity is declared with a fully-qualified namespace, because |
| 397 | it will be referenced from outside your package scope.</p> |
| 398 | |
| 399 | <p>That's all you need to get started with a configuration Activity. Now all you need is the actual |
| 400 | Activity. There are, however, two important things to remember when you implement the Activity:</p> |
| 401 | <ul> |
| 402 | <li>The App Widget host calls the configuration Activity and the configuration Activity should always |
| 403 | return a result. The result should include the App Widget ID |
| 404 | passed by the Intent that launched the Activity (saved in the Intent extras as |
| 405 | {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID}).</li> |
| 406 | <li>The {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) |
| 407 | onUpdate()} method <strong>will not be called</strong> when the App Widget is created |
| 408 | (the system will not send the ACTION_APPWIDGET_UPDATE broadcast when a configuration Activity |
| 409 | is launched). It is the responsibility of the configuration Activity to request an update from the |
| 410 | AppWidgetManager when the App Widget is first created. However, |
| 411 | {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) |
| 412 | onUpdate()} will be called for subsequent updates—it is only skipped the first time.</li> |
| 413 | </ul> |
| 414 | |
| 415 | <p>See the code snippets in the following section for an example of how to return a result |
| 416 | from the configuration and update the App Widget.</p> |
| 417 | |
| 418 | |
| 419 | <h3 id="UpdatingFromTheConfiguration">Updating the App Widget from the configuration Activity</h3> |
| 420 | |
| 421 | <p>When an App Widget uses a configuration Activity, it is the responsibility of the Activity |
| 422 | to update the App Widget when configuration is complete. |
| 423 | You can do so by requesting an update directly from the |
| 424 | {@link android.appwidget.AppWidgetManager}.</p> |
| 425 | |
| 426 | <p>Here's a summary of the procedure to properly update the App Widget and close |
| 427 | the configuration Activity:</p> |
| 428 | |
| 429 | <ol> |
| 430 | <li>First, get the App Widget ID from the Intent that launched the Activity: |
| 431 | <pre> |
| 432 | Intent intent = getIntent(); |
| 433 | Bundle extras = intent.getExtras(); |
| 434 | if (extras != null) { |
| 435 | mAppWidgetId = extras.getInt( |
| 436 | AppWidgetManager.EXTRA_APPWIDGET_ID, |
| 437 | AppWidgetManager.INVALID_APPWIDGET_ID); |
| 438 | } |
| 439 | </pre> |
| 440 | </li> |
| 441 | <li>Perform your App Widget configuration.</li> |
| 442 | <li>When the configuration is complete, get an instance of the AppWidgetManager by calling |
| 443 | {@link android.appwidget.AppWidgetManager#getInstance(Context)}: |
| 444 | <pre> |
| 445 | AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); |
| 446 | </pre> |
| 447 | </li> |
| 448 | <li>Update the App Widget with a {@link android.widget.RemoteViews} layout by calling |
| 449 | {@link android.appwidget.AppWidgetManager#updateAppWidget(int,RemoteViews)}: |
| 450 | <pre> |
| 451 | RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget); |
| 452 | appWidgetManager.updateAppWidget(mAppWidgetId, views); |
| 453 | </pre> |
| 454 | </li> |
| 455 | <li>Finally, create the return Intent, set it with the Activity result, and finish the Activity:</li> |
| 456 | <pre> |
| 457 | Intent resultValue = new Intent(); |
| 458 | resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); |
| 459 | setResult(RESULT_OK, resultValue); |
| 460 | finish(); |
| 461 | </pre> |
| 462 | </li> |
| 463 | </ol> |
| 464 | |
| 465 | <p class="note"><strong>Tip:</strong> When your configuration Activity first opens, set |
| 466 | the Activity result to RESULT_CANCELED. This way, if the user backs-out of the Activity before |
| 467 | reaching the end, the App Widget host is notified that the configuration was cancelled and the |
| 468 | App Widget will not be added.</p> |
| 469 | |
| 470 | <p>See the <a |
| Dirk Dougherty | 22558d0 | 2009-12-10 16:25:06 -0800 | [diff] [blame] | 471 | href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetConfigure.html"> |
| Scott Main | 04c72b4 | 2009-05-13 16:48:13 -0700 | [diff] [blame] | 472 | ExampleAppWidgetConfigure.java</a> sample class in ApiDemos for an example.</p> |
| 473 | |
| 474 | |
| 475 | |