blob: a7f77921c0279c7dff17f8de4b65e61d78d48c9d [file] [log] [blame]
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.appwidget;
18
19import android.content.ComponentName;
20import android.content.Context;
Winson Chung81f39eb2011-01-11 18:05:01 -080021import android.content.Intent;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070022import android.os.IBinder;
23import android.os.RemoteException;
24import android.os.ServiceManager;
Mitsuru Oshima8f25c422009-07-01 00:10:43 -070025import android.util.DisplayMetrics;
Mitsuru Oshima8f25c422009-07-01 00:10:43 -070026import android.util.TypedValue;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070027import android.widget.RemoteViews;
28
29import com.android.internal.appwidget.IAppWidgetService;
30
31import java.lang.ref.WeakReference;
32import java.util.List;
33import java.util.WeakHashMap;
34
35/**
36 * Updates AppWidget state; gets information about installed AppWidget providers and other
37 * AppWidget related state.
Joe Fernandez3aef8e1d2011-12-20 10:38:34 -080038 *
39 * <div class="special reference">
40 * <h3>Developer Guides</h3>
41 * <p>For more information about creating app widgets, read the
42 * <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widgets</a> developer guide.</p>
43 * </div>
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070044 */
45public class AppWidgetManager {
46 static final String TAG = "AppWidgetManager";
47
48 /**
49 * Send this from your {@link AppWidgetHost} activity when you want to pick an AppWidget to display.
50 * The AppWidget picker activity will be launched.
51 * <p>
52 * You must supply the following extras:
53 * <table>
54 * <tr>
55 * <td>{@link #EXTRA_APPWIDGET_ID}</td>
56 * <td>A newly allocated appWidgetId, which will be bound to the AppWidget provider
57 * once the user has selected one.</td>
58 * </tr>
59 * </table>
60 *
61 * <p>
62 * The system will respond with an onActivityResult call with the following extras in
63 * the intent:
64 * <table>
65 * <tr>
66 * <td>{@link #EXTRA_APPWIDGET_ID}</td>
67 * <td>The appWidgetId that you supplied in the original intent.</td>
68 * </tr>
69 * </table>
70 * <p>
71 * When you receive the result from the AppWidget pick activity, if the resultCode is
72 * {@link android.app.Activity#RESULT_OK}, an AppWidget has been selected. You should then
73 * check the AppWidgetProviderInfo for the returned AppWidget, and if it has one, launch its configuration
74 * activity. If {@link android.app.Activity#RESULT_CANCELED} is returned, you should delete
75 * the appWidgetId.
76 *
77 * @see #ACTION_APPWIDGET_CONFIGURE
78 */
79 public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK";
80
81 /**
82 * Sent when it is time to configure your AppWidget while it is being added to a host.
83 * This action is not sent as a broadcast to the AppWidget provider, but as a startActivity
84 * to the activity specified in the {@link AppWidgetProviderInfo AppWidgetProviderInfo meta-data}.
85 *
86 * <p>
87 * The intent will contain the following extras:
88 * <table>
89 * <tr>
90 * <td>{@link #EXTRA_APPWIDGET_ID}</td>
91 * <td>The appWidgetId to configure.</td>
92 * </tr>
93 * </table>
94 *
95 * <p>If you return {@link android.app.Activity#RESULT_OK} using
96 * {@link android.app.Activity#setResult Activity.setResult()}, the AppWidget will be added,
97 * and you will receive an {@link #ACTION_APPWIDGET_UPDATE} broadcast for this AppWidget.
98 * If you return {@link android.app.Activity#RESULT_CANCELED}, the host will cancel the add
99 * and not display this AppWidget, and you will receive a {@link #ACTION_APPWIDGET_DELETED} broadcast.
100 */
101 public static final String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE";
102
103 /**
104 * An intent extra that contains one appWidgetId.
105 * <p>
106 * The value will be an int that can be retrieved like this:
107 * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetHostActivity.java getExtra_EXTRA_APPWIDGET_ID}
108 */
109 public static final String EXTRA_APPWIDGET_ID = "appWidgetId";
110
111 /**
112 * An intent extra that contains multiple appWidgetIds.
113 * <p>
114 * The value will be an int array that can be retrieved like this:
115 * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetProvider.java getExtra_EXTRA_APPWIDGET_IDS}
116 */
117 public static final String EXTRA_APPWIDGET_IDS = "appWidgetIds";
118
119 /**
The Android Open Source Project10592532009-03-18 17:39:46 -0700120 * An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of
121 * {@link AppWidgetProviderInfo} objects to mix in to the list of AppWidgets that are
122 * installed. (This is how the launcher shows the search widget).
123 */
124 public static final String EXTRA_CUSTOM_INFO = "customInfo";
125
126 /**
127 * An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of
128 * {@link android.os.Bundle} objects to mix in to the list of AppWidgets that are
129 * installed. It will be added to the extras object on the {@link android.content.Intent}
130 * that is returned from the picker activity.
131 *
132 * {@more}
133 */
134 public static final String EXTRA_CUSTOM_EXTRAS = "customExtras";
135
136 /**
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700137 * A sentiel value that the AppWidget manager will never return as a appWidgetId.
138 */
139 public static final int INVALID_APPWIDGET_ID = 0;
140
141 /**
142 * Sent when it is time to update your AppWidget.
143 *
144 * <p>This may be sent in response to a new instance for this AppWidget provider having
145 * been instantiated, the requested {@link AppWidgetProviderInfo#updatePeriodMillis update interval}
146 * having lapsed, or the system booting.
147 *
148 * <p>
149 * The intent will contain the following extras:
150 * <table>
151 * <tr>
152 * <td>{@link #EXTRA_APPWIDGET_IDS}</td>
153 * <td>The appWidgetIds to update. This may be all of the AppWidgets created for this
154 * provider, or just a subset. The system tries to send updates for as few AppWidget
155 * instances as possible.</td>
156 * </tr>
157 * </table>
Christian Mehlmauer10c543d2010-06-25 19:27:04 +0200158 *
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700159 * @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
160 */
161 public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
162
163 /**
164 * Sent when an instance of an AppWidget is deleted from its host.
165 *
166 * @see AppWidgetProvider#onDeleted AppWidgetProvider.onDeleted(Context context, int[] appWidgetIds)
167 */
168 public static final String ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED";
169
170 /**
171 * Sent when an instance of an AppWidget is removed from the last host.
Christian Mehlmauer10c543d2010-06-25 19:27:04 +0200172 *
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700173 * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
174 */
175 public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
176
177 /**
178 * Sent when an instance of an AppWidget is added to a host for the first time.
179 * This broadcast is sent at boot time if there is a AppWidgetHost installed with
180 * an instance for this provider.
Christian Mehlmauer10c543d2010-06-25 19:27:04 +0200181 *
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700182 * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
183 */
184 public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
185
186 /**
187 * Field for the manifest meta-data tag.
188 *
189 * @see AppWidgetProviderInfo
190 */
191 public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";
Christian Mehlmauer10c543d2010-06-25 19:27:04 +0200192
Christian Mehlmauer10c543d2010-06-25 19:27:04 +0200193 static WeakHashMap<Context, WeakReference<AppWidgetManager>> sManagerCache =
194 new WeakHashMap<Context, WeakReference<AppWidgetManager>>();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700195 static IAppWidgetService sService;
Christian Mehlmauer10c543d2010-06-25 19:27:04 +0200196
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700197 Context mContext;
198
Mitsuru Oshima8f25c422009-07-01 00:10:43 -0700199 private DisplayMetrics mDisplayMetrics;
200
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700201 /**
202 * Get the AppWidgetManager instance to use for the supplied {@link android.content.Context
203 * Context} object.
204 */
205 public static AppWidgetManager getInstance(Context context) {
206 synchronized (sManagerCache) {
207 if (sService == null) {
208 IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
209 sService = IAppWidgetService.Stub.asInterface(b);
210 }
211
212 WeakReference<AppWidgetManager> ref = sManagerCache.get(context);
213 AppWidgetManager result = null;
214 if (ref != null) {
215 result = ref.get();
216 }
217 if (result == null) {
218 result = new AppWidgetManager(context);
Christian Mehlmauer10c543d2010-06-25 19:27:04 +0200219 sManagerCache.put(context, new WeakReference<AppWidgetManager>(result));
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700220 }
221 return result;
222 }
223 }
224
225 private AppWidgetManager(Context context) {
226 mContext = context;
Mitsuru Oshima8f25c422009-07-01 00:10:43 -0700227 mDisplayMetrics = context.getResources().getDisplayMetrics();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700228 }
229
230 /**
231 * Set the RemoteViews to use for the specified appWidgetIds.
232 *
Adam Cohen2dd21972010-08-15 18:20:04 -0700233 * Note that the RemoteViews parameter will be cached by the AppWidgetService, and hence should
234 * contain a complete representation of the widget. For performing partial widget updates, see
235 * {@link #partiallyUpdateAppWidget(int[], RemoteViews)}.
236 *
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700237 * <p>
238 * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
239 * and outside of the handler.
240 * This method will only work when called from the uid that owns the AppWidget provider.
241 *
242 * @param appWidgetIds The AppWidget instances for which to set the RemoteViews.
243 * @param views The RemoteViews object to show.
244 */
245 public void updateAppWidget(int[] appWidgetIds, RemoteViews views) {
246 try {
247 sService.updateAppWidgetIds(appWidgetIds, views);
248 }
249 catch (RemoteException e) {
250 throw new RuntimeException("system server dead?", e);
251 }
252 }
253
254 /**
255 * Set the RemoteViews to use for the specified appWidgetId.
256 *
Adam Cohen2dd21972010-08-15 18:20:04 -0700257 * Note that the RemoteViews parameter will be cached by the AppWidgetService, and hence should
258 * contain a complete representation of the widget. For performing partial widget updates, see
259 * {@link #partiallyUpdateAppWidget(int, RemoteViews)}.
260 *
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700261 * <p>
262 * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
263 * and outside of the handler.
264 * This method will only work when called from the uid that owns the AppWidget provider.
265 *
266 * @param appWidgetId The AppWidget instance for which to set the RemoteViews.
267 * @param views The RemoteViews object to show.
268 */
269 public void updateAppWidget(int appWidgetId, RemoteViews views) {
270 updateAppWidget(new int[] { appWidgetId }, views);
271 }
272
273 /**
Adam Cohen2dd21972010-08-15 18:20:04 -0700274 * Perform an incremental update or command on the widget(s) specified by appWidgetIds.
275 *
276 * This update differs from {@link #updateAppWidget(int[], RemoteViews)} in that the
277 * RemoteViews object which is passed is understood to be an incomplete representation of the
278 * widget, and hence is not cached by the AppWidgetService. Note that because these updates are
279 * not cached, any state that they modify that is not restored by restoreInstanceState will not
280 * persist in the case that the widgets are restored using the cached version in
281 * AppWidgetService.
282 *
283 * Use with {@link RemoteViews#showNext(int)}, {@link RemoteViews#showPrevious(int)},
284 * {@link RemoteViews#setScrollPosition(int, int)} and similar commands.
285 *
286 * <p>
287 * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
288 * and outside of the handler.
289 * This method will only work when called from the uid that owns the AppWidget provider.
290 *
291 * @param appWidgetIds The AppWidget instances for which to set the RemoteViews.
292 * @param views The RemoteViews object containing the incremental update / command.
293 */
294 public void partiallyUpdateAppWidget(int[] appWidgetIds, RemoteViews views) {
295 try {
296 sService.partiallyUpdateAppWidgetIds(appWidgetIds, views);
297 } catch (RemoteException e) {
298 throw new RuntimeException("system server dead?", e);
299 }
300 }
301
302 /**
303 * Perform an incremental update or command on the widget specified by appWidgetId.
304 *
305 * This update differs from {@link #updateAppWidget(int, RemoteViews)} in that the RemoteViews
306 * object which is passed is understood to be an incomplete representation of the widget, and
307 * hence is not cached by the AppWidgetService. Note that because these updates are not cached,
308 * any state that they modify that is not restored by restoreInstanceState will not persist in
309 * the case that the widgets are restored using the cached version in AppWidgetService.
310 *
311 * Use with {@link RemoteViews#showNext(int)}, {@link RemoteViews#showPrevious(int)},
312 * {@link RemoteViews#setScrollPosition(int, int)} and similar commands.
313 *
314 * <p>
315 * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
316 * and outside of the handler.
317 * This method will only work when called from the uid that owns the AppWidget provider.
318 *
319 * @param appWidgetId The AppWidget instance for which to set the RemoteViews.
320 * @param views The RemoteViews object containing the incremental update / command.
321 */
322 public void partiallyUpdateAppWidget(int appWidgetId, RemoteViews views) {
323 partiallyUpdateAppWidget(new int[] { appWidgetId }, views);
324 }
325
326 /**
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700327 * Set the RemoteViews to use for all AppWidget instances for the supplied AppWidget provider.
328 *
329 * <p>
330 * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
331 * and outside of the handler.
332 * This method will only work when called from the uid that owns the AppWidget provider.
333 *
334 * @param provider The {@link ComponentName} for the {@link
335 * android.content.BroadcastReceiver BroadcastReceiver} provider
336 * for your AppWidget.
337 * @param views The RemoteViews object to show.
338 */
339 public void updateAppWidget(ComponentName provider, RemoteViews views) {
340 try {
341 sService.updateAppWidgetProvider(provider, views);
342 }
343 catch (RemoteException e) {
344 throw new RuntimeException("system server dead?", e);
345 }
346 }
347
348 /**
Winson Chung499cb9f2010-07-16 11:18:17 -0700349 * Notifies the specified collection view in all the specified AppWidget instances
350 * to invalidate their currently data.
351 *
352 * @param appWidgetIds The AppWidget instances for which to notify of view data changes.
Winson Chung499cb9f2010-07-16 11:18:17 -0700353 * @param viewId The collection view id.
354 */
Winson Chung6394c0e2010-08-16 10:14:56 -0700355 public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) {
Winson Chung499cb9f2010-07-16 11:18:17 -0700356 try {
Winson Chung6394c0e2010-08-16 10:14:56 -0700357 sService.notifyAppWidgetViewDataChanged(appWidgetIds, viewId);
Winson Chung499cb9f2010-07-16 11:18:17 -0700358 }
359 catch (RemoteException e) {
360 throw new RuntimeException("system server dead?", e);
361 }
362 }
363
364 /**
365 * Notifies the specified collection view in all the specified AppWidget instance
366 * to invalidate it's currently data.
367 *
368 * @param appWidgetId The AppWidget instance for which to notify of view data changes.
Winson Chung499cb9f2010-07-16 11:18:17 -0700369 * @param viewId The collection view id.
370 */
Winson Chung6394c0e2010-08-16 10:14:56 -0700371 public void notifyAppWidgetViewDataChanged(int appWidgetId, int viewId) {
372 notifyAppWidgetViewDataChanged(new int[] { appWidgetId }, viewId);
Winson Chung499cb9f2010-07-16 11:18:17 -0700373 }
374
375 /**
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700376 * Return a list of the AppWidget providers that are currently installed.
377 */
378 public List<AppWidgetProviderInfo> getInstalledProviders() {
379 try {
Patrick Dubroy5d140912010-07-12 10:25:27 -0700380 List<AppWidgetProviderInfo> providers = sService.getInstalledProviders();
381 for (AppWidgetProviderInfo info : providers) {
382 // Converting complex to dp.
383 info.minWidth =
384 TypedValue.complexToDimensionPixelSize(info.minWidth, mDisplayMetrics);
385 info.minHeight =
386 TypedValue.complexToDimensionPixelSize(info.minHeight, mDisplayMetrics);
Adam Cohen324afba2011-07-22 11:51:45 -0700387 info.minResizeWidth =
388 TypedValue.complexToDimensionPixelSize(info.minResizeWidth, mDisplayMetrics);
389 info.minResizeHeight =
390 TypedValue.complexToDimensionPixelSize(info.minResizeHeight, mDisplayMetrics);
Patrick Dubroy5d140912010-07-12 10:25:27 -0700391 }
392 return providers;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700393 }
394 catch (RemoteException e) {
395 throw new RuntimeException("system server dead?", e);
396 }
397 }
398
399 /**
400 * Get the available info about the AppWidget.
401 *
402 * @return A appWidgetId. If the appWidgetId has not been bound to a provider yet, or
403 * you don't have access to that appWidgetId, null is returned.
404 */
405 public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
406 try {
Mitsuru Oshima8f25c422009-07-01 00:10:43 -0700407 AppWidgetProviderInfo info = sService.getAppWidgetInfo(appWidgetId);
408 if (info != null) {
409 // Converting complex to dp.
Christian Mehlmauer10c543d2010-06-25 19:27:04 +0200410 info.minWidth =
Mitsuru Oshima8f25c422009-07-01 00:10:43 -0700411 TypedValue.complexToDimensionPixelSize(info.minWidth, mDisplayMetrics);
412 info.minHeight =
413 TypedValue.complexToDimensionPixelSize(info.minHeight, mDisplayMetrics);
Adam Cohen324afba2011-07-22 11:51:45 -0700414 info.minResizeWidth =
415 TypedValue.complexToDimensionPixelSize(info.minResizeWidth, mDisplayMetrics);
416 info.minResizeHeight =
417 TypedValue.complexToDimensionPixelSize(info.minResizeHeight, mDisplayMetrics);
Mitsuru Oshima8f25c422009-07-01 00:10:43 -0700418 }
419 return info;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700420 }
421 catch (RemoteException e) {
422 throw new RuntimeException("system server dead?", e);
423 }
424 }
425
426 /**
427 * Set the component for a given appWidgetId.
428 *
429 * <p class="note">You need the APPWIDGET_LIST permission. This method is to be used by the
430 * AppWidget picker.
431 *
432 * @param appWidgetId The AppWidget instance for which to set the RemoteViews.
433 * @param provider The {@link android.content.BroadcastReceiver} that will be the AppWidget
434 * provider for this AppWidget.
435 */
436 public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
437 try {
438 sService.bindAppWidgetId(appWidgetId, provider);
439 }
440 catch (RemoteException e) {
441 throw new RuntimeException("system server dead?", e);
442 }
443 }
444
445 /**
Winson Chung81f39eb2011-01-11 18:05:01 -0800446 * Binds the RemoteViewsService for a given appWidgetId and intent.
447 *
448 * The appWidgetId specified must already be bound to the calling AppWidgetHost via
449 * {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
450 *
451 * @param appWidgetId The AppWidget instance for which to bind the RemoteViewsService.
452 * @param intent The intent of the service which will be providing the data to the
453 * RemoteViewsAdapter.
454 * @param connection The callback interface to be notified when a connection is made or lost.
455 * @hide
456 */
457 public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) {
458 try {
459 sService.bindRemoteViewsService(appWidgetId, intent, connection);
460 }
461 catch (RemoteException e) {
462 throw new RuntimeException("system server dead?", e);
463 }
464 }
465
466 /**
467 * Unbinds the RemoteViewsService for a given appWidgetId and intent.
468 *
469 * The appWidgetId specified muse already be bound to the calling AppWidgetHost via
470 * {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
471 *
472 * @param appWidgetId The AppWidget instance for which to bind the RemoteViewsService.
473 * @param intent The intent of the service which will be providing the data to the
474 * RemoteViewsAdapter.
475 * @hide
476 */
477 public void unbindRemoteViewsService(int appWidgetId, Intent intent) {
478 try {
479 sService.unbindRemoteViewsService(appWidgetId, intent);
480 }
481 catch (RemoteException e) {
482 throw new RuntimeException("system server dead?", e);
483 }
484 }
485
486 /**
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700487 * Get the list of appWidgetIds that have been bound to the given AppWidget
488 * provider.
Christian Mehlmauer10c543d2010-06-25 19:27:04 +0200489 *
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700490 * @param provider The {@link android.content.BroadcastReceiver} that is the
491 * AppWidget provider to find appWidgetIds for.
492 */
493 public int[] getAppWidgetIds(ComponentName provider) {
494 try {
495 return sService.getAppWidgetIds(provider);
496 }
497 catch (RemoteException e) {
498 throw new RuntimeException("system server dead?", e);
499 }
500 }
501}
502