1/*
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.app.ActivityManagerNative;
20import android.content.ComponentName;
21import android.content.Context;
22import android.content.Intent;
23import android.os.Bundle;
24import android.os.IBinder;
25import android.os.RemoteException;
26import android.os.ServiceManager;
27import android.os.UserHandle;
28import android.util.DisplayMetrics;
29import android.util.TypedValue;
30import android.widget.RemoteViews;
31
32import com.android.internal.appwidget.IAppWidgetService;
33
34import java.lang.ref.WeakReference;
35import java.util.List;
36import java.util.WeakHashMap;
37
38/**
39 * Updates AppWidget state; gets information about installed AppWidget providers and other
40 * AppWidget related state.
41 *
42 * <div class="special reference">
43 * <h3>Developer Guides</h3>
44 * <p>For more information about creating app widgets, read the
45 * <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widgets</a> developer guide.</p>
46 * </div>
47 */
48public class AppWidgetManager {
49    static final String TAG = "AppWidgetManager";
50
51    /**
52     * Activity action to launch from your {@link AppWidgetHost} activity when you want to
53     * pick an AppWidget to display.  The AppWidget picker activity will be launched.
54     * <p>
55     * You must supply the following extras:
56     * <table>
57     *   <tr>
58     *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
59     *     <td>A newly allocated appWidgetId, which will be bound to the AppWidget provider
60     *         once the user has selected one.</td>
61     *  </tr>
62     * </table>
63     *
64     * <p>
65     * The system will respond with an onActivityResult call with the following extras in
66     * the intent:
67     * <table>
68     *   <tr>
69     *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
70     *     <td>The appWidgetId that you supplied in the original intent.</td>
71     *  </tr>
72     * </table>
73     * <p>
74     * When you receive the result from the AppWidget pick activity, if the resultCode is
75     * {@link android.app.Activity#RESULT_OK}, an AppWidget has been selected.  You should then
76     * check the AppWidgetProviderInfo for the returned AppWidget, and if it has one, launch its configuration
77     * activity.  If {@link android.app.Activity#RESULT_CANCELED} is returned, you should delete
78     * the appWidgetId.
79     *
80     * @see #ACTION_APPWIDGET_CONFIGURE
81     */
82    public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK";
83
84    /**
85     * Similar to ACTION_APPWIDGET_PICK, but used from keyguard
86     * @hide
87     */
88    public static final String
89            ACTION_KEYGUARD_APPWIDGET_PICK = "android.appwidget.action.KEYGUARD_APPWIDGET_PICK";
90
91    /**
92     * Activity action to launch from your {@link AppWidgetHost} activity when you want to bind
93     * an AppWidget to display and bindAppWidgetIdIfAllowed returns false.
94     * <p>
95     * You must supply the following extras:
96     * <table>
97     *   <tr>
98     *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
99     *     <td>A newly allocated appWidgetId, which will be bound to the AppWidget provider
100     *         you provide.</td>
101     *  </tr>
102     *  <tr>
103     *     <td>{@link #EXTRA_APPWIDGET_PROVIDER}</td>
104     *     <td>The BroadcastReceiver that will be the AppWidget provider for this AppWidget.
105     *     </td>
106     *  </tr>
107     * </table>
108     *
109     * <p>
110     * The system will respond with an onActivityResult call with the following extras in
111     * the intent:
112     * <table>
113     *   <tr>
114     *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
115     *     <td>The appWidgetId that you supplied in the original intent.</td>
116     *  </tr>
117     * </table>
118     * <p>
119     * When you receive the result from the AppWidget bind activity, if the resultCode is
120     * {@link android.app.Activity#RESULT_OK}, the AppWidget has been bound.  You should then
121     * check the AppWidgetProviderInfo for the returned AppWidget, and if it has one, launch its
122     * configuration activity.  If {@link android.app.Activity#RESULT_CANCELED} is returned, you
123     * should delete
124     * the appWidgetId.
125     *
126     * @see #ACTION_APPWIDGET_CONFIGURE
127     *
128     */
129    public static final String ACTION_APPWIDGET_BIND = "android.appwidget.action.APPWIDGET_BIND";
130
131    /**
132     * Sent when it is time to configure your AppWidget while it is being added to a host.
133     * This action is not sent as a broadcast to the AppWidget provider, but as a startActivity
134     * to the activity specified in the {@link AppWidgetProviderInfo AppWidgetProviderInfo meta-data}.
135     *
136     * <p>
137     * The intent will contain the following extras:
138     * <table>
139     *   <tr>
140     *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
141     *     <td>The appWidgetId to configure.</td>
142     *  </tr>
143     * </table>
144     *
145     * <p>If you return {@link android.app.Activity#RESULT_OK} using
146     * {@link android.app.Activity#setResult Activity.setResult()}, the AppWidget will be added,
147     * and you will receive an {@link #ACTION_APPWIDGET_UPDATE} broadcast for this AppWidget.
148     * If you return {@link android.app.Activity#RESULT_CANCELED}, the host will cancel the add
149     * and not display this AppWidget, and you will receive a {@link #ACTION_APPWIDGET_DELETED} broadcast.
150     */
151    public static final String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE";
152
153    /**
154     * An intent extra that contains one appWidgetId.
155     * <p>
156     * The value will be an int that can be retrieved like this:
157     * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetHostActivity.java getExtra_EXTRA_APPWIDGET_ID}
158     */
159    public static final String EXTRA_APPWIDGET_ID = "appWidgetId";
160
161    /**
162     * A bundle extra that contains the lower bound on the current width, in dips, of a widget instance.
163     */
164    public static final String OPTION_APPWIDGET_MIN_WIDTH = "appWidgetMinWidth";
165
166    /**
167     * A bundle extra that contains the lower bound on the current height, in dips, of a widget instance.
168     */
169    public static final String OPTION_APPWIDGET_MIN_HEIGHT = "appWidgetMinHeight";
170
171    /**
172     * A bundle extra that contains the upper bound on the current width, in dips, of a widget instance.
173     */
174    public static final String OPTION_APPWIDGET_MAX_WIDTH = "appWidgetMaxWidth";
175
176    /**
177     * A bundle extra that contains the upper bound on the current width, in dips, of a widget instance.
178     */
179    public static final String OPTION_APPWIDGET_MAX_HEIGHT = "appWidgetMaxHeight";
180
181    /**
182     * A bundle extra that hints to the AppWidgetProvider the category of host that owns this
183     * this widget. Can have the value {@link
184     * AppWidgetProviderInfo#WIDGET_CATEGORY_HOME_SCREEN} or {@link
185     * AppWidgetProviderInfo#WIDGET_CATEGORY_KEYGUARD}.
186     */
187    public static final String OPTION_APPWIDGET_HOST_CATEGORY = "appWidgetCategory";
188
189    /**
190     * An intent extra which points to a bundle of extra information for a particular widget id.
191     * In particular this bundle can contain EXTRA_APPWIDGET_WIDTH and EXTRA_APPWIDGET_HEIGHT.
192     */
193    public static final String EXTRA_APPWIDGET_OPTIONS = "appWidgetOptions";
194
195    /**
196     * An intent extra that contains multiple appWidgetIds.
197     * <p>
198     * The value will be an int array that can be retrieved like this:
199     * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetProvider.java getExtra_EXTRA_APPWIDGET_IDS}
200     */
201    public static final String EXTRA_APPWIDGET_IDS = "appWidgetIds";
202
203    /**
204     * An intent extra that contains the component name of a AppWidget provider.
205     * <p>
206     * The value will be an ComponentName.
207     */
208    public static final String EXTRA_APPWIDGET_PROVIDER = "appWidgetProvider";
209
210    /**
211     * An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of
212     * {@link AppWidgetProviderInfo} objects to mix in to the list of AppWidgets that are
213     * installed.  (This is how the launcher shows the search widget).
214     */
215    public static final String EXTRA_CUSTOM_INFO = "customInfo";
216
217    /**
218     * An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of
219     * {@link android.os.Bundle} objects to mix in to the list of AppWidgets that are
220     * installed.  It will be added to the extras object on the {@link android.content.Intent}
221     * that is returned from the picker activity.
222     *
223     * {@more}
224     */
225    public static final String EXTRA_CUSTOM_EXTRAS = "customExtras";
226
227    /**
228     * An intent extra to pass to the AppWidget picker which allows the picker to filter
229     * the list based on the {@link AppWidgetProviderInfo#widgetCategory}.
230     *
231     * @hide
232     */
233    public static final String EXTRA_CATEGORY_FILTER = "categoryFilter";
234
235    /**
236     * An intent extra to pass to the AppWidget picker to specify whether or not to sort
237     * the list of caller-specified extra AppWidgets along with the rest of the AppWidgets
238     * @hide
239     */
240    public static final String EXTRA_CUSTOM_SORT = "customSort";
241
242    /**
243     * A sentinel value that the AppWidget manager will never return as a appWidgetId.
244     */
245    public static final int INVALID_APPWIDGET_ID = 0;
246
247    /**
248     * Sent when it is time to update your AppWidget.
249     *
250     * <p>This may be sent in response to a new instance for this AppWidget provider having
251     * been instantiated, the requested {@link AppWidgetProviderInfo#updatePeriodMillis update interval}
252     * having lapsed, or the system booting.
253     *
254     * <p>
255     * The intent will contain the following extras:
256     * <table>
257     *   <tr>
258     *     <td>{@link #EXTRA_APPWIDGET_IDS}</td>
259     *     <td>The appWidgetIds to update.  This may be all of the AppWidgets created for this
260     *     provider, or just a subset.  The system tries to send updates for as few AppWidget
261     *     instances as possible.</td>
262     *  </tr>
263     * </table>
264     *
265     * @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
266     */
267    public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
268
269    /**
270     * Sent when the custom extras for an AppWidget change.
271     *
272     * <p class="note">This is a protected intent that can only be sent
273     * by the system.
274     *
275     * @see AppWidgetProvider#onAppWidgetOptionsChanged
276     *      AppWidgetProvider.onAppWidgetOptionsChanged(Context context,
277     *      AppWidgetManager appWidgetManager, int appWidgetId, Bundle newExtras)
278     */
279    public static final String ACTION_APPWIDGET_OPTIONS_CHANGED = "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS";
280
281    /**
282     * Sent when an instance of an AppWidget is deleted from its host.
283     *
284     * <p class="note">This is a protected intent that can only be sent
285     * by the system.
286     *
287     * @see AppWidgetProvider#onDeleted AppWidgetProvider.onDeleted(Context context, int[] appWidgetIds)
288     */
289    public static final String ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED";
290
291    /**
292     * Sent when an instance of an AppWidget is removed from the last host.
293     *
294     * <p class="note">This is a protected intent that can only be sent
295     * by the system.
296     *
297     * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
298     */
299    public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
300
301    /**
302     * Sent when an instance of an AppWidget is added to a host for the first time.
303     * This broadcast is sent at boot time if there is a AppWidgetHost installed with
304     * an instance for this provider.
305     *
306     * <p class="note">This is a protected intent that can only be sent
307     * by the system.
308     *
309     * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
310     */
311    public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
312
313    /**
314     * Field for the manifest meta-data tag.
315     *
316     * @see AppWidgetProviderInfo
317     */
318    public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";
319
320    static WeakHashMap<Context, WeakReference<AppWidgetManager>> sManagerCache =
321        new WeakHashMap<Context, WeakReference<AppWidgetManager>>();
322    static IAppWidgetService sService;
323
324    Context mContext;
325
326    private DisplayMetrics mDisplayMetrics;
327
328    /**
329     * Get the AppWidgetManager instance to use for the supplied {@link android.content.Context
330     * Context} object.
331     */
332    public static AppWidgetManager getInstance(Context context) {
333        synchronized (sManagerCache) {
334            if (sService == null) {
335                IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
336                sService = IAppWidgetService.Stub.asInterface(b);
337            }
338
339            WeakReference<AppWidgetManager> ref = sManagerCache.get(context);
340            AppWidgetManager result = null;
341            if (ref != null) {
342                result = ref.get();
343            }
344            if (result == null) {
345                result = new AppWidgetManager(context);
346                sManagerCache.put(context, new WeakReference<AppWidgetManager>(result));
347            }
348            return result;
349        }
350    }
351
352    private AppWidgetManager(Context context) {
353        mContext = context;
354        mDisplayMetrics = context.getResources().getDisplayMetrics();
355    }
356
357    /**
358     * Set the RemoteViews to use for the specified appWidgetIds.
359     *
360     * Note that the RemoteViews parameter will be cached by the AppWidgetService, and hence should
361     * contain a complete representation of the widget. For performing partial widget updates, see
362     * {@link #partiallyUpdateAppWidget(int[], RemoteViews)}.
363     *
364     * <p>
365     * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
366     * and outside of the handler.
367     * This method will only work when called from the uid that owns the AppWidget provider.
368     *
369     * <p>
370     * The total Bitmap memory used by the RemoteViews object cannot exceed that required to
371     * fill the screen 1.5 times, ie. (screen width x screen height x 4 x 1.5) bytes.
372     *
373     * @param appWidgetIds     The AppWidget instances for which to set the RemoteViews.
374     * @param views         The RemoteViews object to show.
375     */
376    public void updateAppWidget(int[] appWidgetIds, RemoteViews views) {
377        try {
378            sService.updateAppWidgetIds(appWidgetIds, views, mContext.getUserId());
379        }
380        catch (RemoteException e) {
381            throw new RuntimeException("system server dead?", e);
382        }
383    }
384
385    /**
386     * Update the extras for a given widget instance.
387     *
388     * The extras can be used to embed additional information about this widget to be accessed
389     * by the associated widget's AppWidgetProvider.
390     *
391     * @see #getAppWidgetOptions(int)
392     *
393     * @param appWidgetId    The AppWidget instances for which to set the RemoteViews.
394     * @param options         The options to associate with this widget
395     */
396    public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
397        try {
398            sService.updateAppWidgetOptions(appWidgetId, options, mContext.getUserId());
399        }
400        catch (RemoteException e) {
401            throw new RuntimeException("system server dead?", e);
402        }
403    }
404
405    /**
406     * Get the extras associated with a given widget instance.
407     *
408     * The extras can be used to embed additional information about this widget to be accessed
409     * by the associated widget's AppWidgetProvider.
410     *
411     * @see #updateAppWidgetOptions(int, Bundle)
412     *
413     * @param appWidgetId     The AppWidget instances for which to set the RemoteViews.
414     * @return                The options associated with the given widget instance.
415     */
416    public Bundle getAppWidgetOptions(int appWidgetId) {
417        try {
418            return sService.getAppWidgetOptions(appWidgetId, mContext.getUserId());
419        }
420        catch (RemoteException e) {
421            throw new RuntimeException("system server dead?", e);
422        }
423    }
424
425    /**
426     * Set the RemoteViews to use for the specified appWidgetId.
427     *
428     * Note that the RemoteViews parameter will be cached by the AppWidgetService, and hence should
429     * contain a complete representation of the widget. For performing partial widget updates, see
430     * {@link #partiallyUpdateAppWidget(int, RemoteViews)}.
431     *
432     * <p>
433     * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
434     * and outside of the handler.
435     * This method will only work when called from the uid that owns the AppWidget provider.
436     *
437     * <p>
438     * The total Bitmap memory used by the RemoteViews object cannot exceed that required to
439     * fill the screen 1.5 times, ie. (screen width x screen height x 4 x 1.5) bytes.
440     *
441     * @param appWidgetId      The AppWidget instance for which to set the RemoteViews.
442     * @param views         The RemoteViews object to show.
443     */
444    public void updateAppWidget(int appWidgetId, RemoteViews views) {
445        updateAppWidget(new int[] { appWidgetId }, views);
446    }
447
448    /**
449     * Perform an incremental update or command on the widget(s) specified by appWidgetIds.
450     *
451     * This update  differs from {@link #updateAppWidget(int[], RemoteViews)} in that the
452     * RemoteViews object which is passed is understood to be an incomplete representation of the
453     * widget, and hence does not replace the cached representation of the widget. As of API
454     * level 17, the new properties set within the views objects will be appended to the cached
455     * representation of the widget, and hence will persist.
456     *
457     * Use with {@link RemoteViews#showNext(int)}, {@link RemoteViews#showPrevious(int)},
458     * {@link RemoteViews#setScrollPosition(int, int)} and similar commands.
459     *
460     * <p>
461     * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
462     * and outside of the handler.
463     * This method will only work when called from the uid that owns the AppWidget provider.
464     *
465     * <p>
466     * This method will be ignored if a widget has not received a full update via
467     * {@link #updateAppWidget(int[], RemoteViews)}.
468     *
469     * @param appWidgetIds     The AppWidget instances for which to set the RemoteViews.
470     * @param views            The RemoteViews object containing the incremental update / command.
471     */
472    public void partiallyUpdateAppWidget(int[] appWidgetIds, RemoteViews views) {
473        try {
474            sService.partiallyUpdateAppWidgetIds(appWidgetIds, views, mContext.getUserId());
475        } catch (RemoteException e) {
476            throw new RuntimeException("system server dead?", e);
477        }
478    }
479
480    /**
481     * Perform an incremental update or command on the widget specified by appWidgetId.
482     *
483     * This update  differs from {@link #updateAppWidget(int, RemoteViews)} in that the RemoteViews
484     * object which is passed is understood to be an incomplete representation of the widget, and
485     * hence is not cached by the AppWidgetService. Note that because these updates are not cached,
486     * any state that they modify that is not restored by restoreInstanceState will not persist in
487     * the case that the widgets are restored using the cached version in AppWidgetService.
488     *
489     * Use with {@link RemoteViews#showNext(int)}, {@link RemoteViews#showPrevious(int)},
490     * {@link RemoteViews#setScrollPosition(int, int)} and similar commands.
491     *
492     * <p>
493     * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
494     * and outside of the handler.
495     * This method will only work when called from the uid that owns the AppWidget provider.
496     *
497     * <p>
498     * This method will be ignored if a widget has not received a full update via
499     * {@link #updateAppWidget(int[], RemoteViews)}.
500     *
501     * @param appWidgetId      The AppWidget instance for which to set the RemoteViews.
502     * @param views            The RemoteViews object containing the incremental update / command.
503     */
504    public void partiallyUpdateAppWidget(int appWidgetId, RemoteViews views) {
505        partiallyUpdateAppWidget(new int[] { appWidgetId }, views);
506    }
507
508    /**
509     * Set the RemoteViews to use for all AppWidget instances for the supplied AppWidget provider.
510     *
511     * <p>
512     * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
513     * and outside of the handler.
514     * This method will only work when called from the uid that owns the AppWidget provider.
515     *
516     * @param provider      The {@link ComponentName} for the {@link
517     * android.content.BroadcastReceiver BroadcastReceiver} provider
518     *                      for your AppWidget.
519     * @param views         The RemoteViews object to show.
520     */
521    public void updateAppWidget(ComponentName provider, RemoteViews views) {
522        try {
523            sService.updateAppWidgetProvider(provider, views, mContext.getUserId());
524        }
525        catch (RemoteException e) {
526            throw new RuntimeException("system server dead?", e);
527        }
528    }
529
530    /**
531     * Notifies the specified collection view in all the specified AppWidget instances
532     * to invalidate their data.
533     *
534     * @param appWidgetIds  The AppWidget instances to notify of view data changes.
535     * @param viewId        The collection view id.
536     */
537    public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) {
538        try {
539            sService.notifyAppWidgetViewDataChanged(appWidgetIds, viewId, mContext.getUserId());
540        }
541        catch (RemoteException e) {
542            throw new RuntimeException("system server dead?", e);
543        }
544    }
545
546    /**
547     * Notifies the specified collection view in the specified AppWidget instance
548     * to invalidate its data.
549     *
550     * @param appWidgetId  The AppWidget instance to notify of view data changes.
551     * @param viewId       The collection view id.
552     */
553    public void notifyAppWidgetViewDataChanged(int appWidgetId, int viewId) {
554        notifyAppWidgetViewDataChanged(new int[] { appWidgetId }, viewId);
555    }
556
557    /**
558     * Return a list of the AppWidget providers that are currently installed.
559     */
560    public List<AppWidgetProviderInfo> getInstalledProviders() {
561        return getInstalledProviders(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN);
562    }
563
564    /**
565     * Return a list of the AppWidget providers that are currently installed.
566     *
567     * @param categoryFilter Will only return providers which register as any of the specified
568     *        specified categories. See {@link AppWidgetProviderInfo#widgetCategory}.
569     * @hide
570     */
571    public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) {
572        try {
573            List<AppWidgetProviderInfo> providers = sService.getInstalledProviders(categoryFilter,
574                    mContext.getUserId());
575            for (AppWidgetProviderInfo info : providers) {
576                // Converting complex to dp.
577                info.minWidth =
578                        TypedValue.complexToDimensionPixelSize(info.minWidth, mDisplayMetrics);
579                info.minHeight =
580                        TypedValue.complexToDimensionPixelSize(info.minHeight, mDisplayMetrics);
581                info.minResizeWidth =
582                    TypedValue.complexToDimensionPixelSize(info.minResizeWidth, mDisplayMetrics);
583                info.minResizeHeight =
584                    TypedValue.complexToDimensionPixelSize(info.minResizeHeight, mDisplayMetrics);
585            }
586            return providers;
587        }
588        catch (RemoteException e) {
589            throw new RuntimeException("system server dead?", e);
590        }
591    }
592
593    /**
594     * Get the available info about the AppWidget.
595     *
596     * @return A appWidgetId.  If the appWidgetId has not been bound to a provider yet, or
597     * you don't have access to that appWidgetId, null is returned.
598     */
599    public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
600        try {
601            AppWidgetProviderInfo info = sService.getAppWidgetInfo(appWidgetId,
602                    mContext.getUserId());
603            if (info != null) {
604                // Converting complex to dp.
605                info.minWidth =
606                        TypedValue.complexToDimensionPixelSize(info.minWidth, mDisplayMetrics);
607                info.minHeight =
608                        TypedValue.complexToDimensionPixelSize(info.minHeight, mDisplayMetrics);
609                info.minResizeWidth =
610                    TypedValue.complexToDimensionPixelSize(info.minResizeWidth, mDisplayMetrics);
611                info.minResizeHeight =
612                    TypedValue.complexToDimensionPixelSize(info.minResizeHeight, mDisplayMetrics);
613            }
614            return info;
615        }
616        catch (RemoteException e) {
617            throw new RuntimeException("system server dead?", e);
618        }
619    }
620
621    /**
622     * Set the component for a given appWidgetId.
623     *
624     * <p class="note">You need the BIND_APPWIDGET permission or the user must have enabled binding
625     *         widgets always for your component. This method is used by the AppWidget picker and
626     *         should not be used by other apps.
627     *
628     * @param appWidgetId     The AppWidget instance for which to set the RemoteViews.
629     * @param provider      The {@link android.content.BroadcastReceiver} that will be the AppWidget
630     *                      provider for this AppWidget.
631     * @hide
632     */
633    public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
634        try {
635            sService.bindAppWidgetId(appWidgetId, provider, null, mContext.getUserId());
636        }
637        catch (RemoteException e) {
638            throw new RuntimeException("system server dead?", e);
639        }
640    }
641
642    /**
643     * Set the component for a given appWidgetId.
644     *
645     * <p class="note">You need the BIND_APPWIDGET permission or the user must have enabled binding
646     *         widgets always for your component. This method is used by the AppWidget picker and
647     *         should not be used by other apps.
648     *
649     * @param appWidgetId     The AppWidget instance for which to set the RemoteViews.
650     * @param provider      The {@link android.content.BroadcastReceiver} that will be the AppWidget
651     *                      provider for this AppWidget.
652     * @param options       Bundle containing options for the AppWidget. See also
653     *                      {@link #updateAppWidgetOptions(int, Bundle)}
654     *
655     * @hide
656     */
657    public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) {
658        try {
659            sService.bindAppWidgetId(appWidgetId, provider, options, mContext.getUserId());
660        }
661        catch (RemoteException e) {
662            throw new RuntimeException("system server dead?", e);
663        }
664    }
665
666    /**
667     * Set the component for a given appWidgetId.
668     *
669     * <p class="note">You need the BIND_APPWIDGET permission or the user must have enabled binding
670     *         widgets always for your component. Should be used by apps that host widgets; if this
671     *         method returns false, call {@link #ACTION_APPWIDGET_BIND} to request permission to
672     *         bind
673     *
674     * @param appWidgetId     The AppWidget instance for which to set the RemoteViews.
675     * @param provider      The {@link android.content.BroadcastReceiver} that will be the AppWidget
676     *                      provider for this AppWidget.
677     * @return true if this component has permission to bind the AppWidget
678     */
679    public boolean bindAppWidgetIdIfAllowed(int appWidgetId, ComponentName provider) {
680        if (mContext == null) {
681            return false;
682        }
683        try {
684            return sService.bindAppWidgetIdIfAllowed(
685                    mContext.getPackageName(), appWidgetId, provider, null, mContext.getUserId());
686        }
687        catch (RemoteException e) {
688            throw new RuntimeException("system server dead?", e);
689        }
690    }
691
692    /**
693     * Set the component for a given appWidgetId.
694     *
695     * <p class="note">You need the BIND_APPWIDGET permission or the user must have enabled binding
696     *         widgets always for your component. Should be used by apps that host widgets; if this
697     *         method returns false, call {@link #ACTION_APPWIDGET_BIND} to request permission to
698     *         bind
699     *
700     * @param appWidgetId     The AppWidget instance for which to set the RemoteViews.
701     * @param provider      The {@link android.content.BroadcastReceiver} that will be the AppWidget
702     *                      provider for this AppWidget.
703     * @param options       Bundle containing options for the AppWidget. See also
704     *                      {@link #updateAppWidgetOptions(int, Bundle)}
705     *
706     * @return true if this component has permission to bind the AppWidget
707     */
708    public boolean bindAppWidgetIdIfAllowed(int appWidgetId, ComponentName provider,
709            Bundle options) {
710        if (mContext == null) {
711            return false;
712        }
713        try {
714            return sService.bindAppWidgetIdIfAllowed(mContext.getPackageName(), appWidgetId,
715                    provider, options, mContext.getUserId());
716        }
717        catch (RemoteException e) {
718            throw new RuntimeException("system server dead?", e);
719        }
720    }
721
722    /**
723     * Query if a given package was granted permission by the user to bind app widgets
724     *
725     * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
726     *
727     * @param packageName        The package for which the permission is being queried
728     * @return true if the package was granted permission by the user to bind app widgets
729     * @hide
730     */
731    public boolean hasBindAppWidgetPermission(String packageName) {
732        try {
733            return sService.hasBindAppWidgetPermission(packageName, mContext.getUserId());
734        }
735        catch (RemoteException e) {
736            throw new RuntimeException("system server dead?", e);
737        }
738    }
739
740    /**
741     * Changes any user-granted permission for the given package to bind app widgets
742     *
743     * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
744     *
745     * @param provider        The package whose permission is being changed
746     * @param permission      Whether to give the package permission to bind widgets
747     * @hide
748     */
749    public void setBindAppWidgetPermission(String packageName, boolean permission) {
750        try {
751            sService.setBindAppWidgetPermission(packageName, permission, mContext.getUserId());
752        }
753        catch (RemoteException e) {
754            throw new RuntimeException("system server dead?", e);
755        }
756    }
757
758    /**
759     * Binds the RemoteViewsService for a given appWidgetId and intent.
760     *
761     * The appWidgetId specified must already be bound to the calling AppWidgetHost via
762     * {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
763     *
764     * @param appWidgetId   The AppWidget instance for which to bind the RemoteViewsService.
765     * @param intent        The intent of the service which will be providing the data to the
766     *                      RemoteViewsAdapter.
767     * @param connection    The callback interface to be notified when a connection is made or lost.
768     * @param userHandle    The user to bind to.
769     * @hide
770     */
771    public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection,
772            UserHandle userHandle) {
773        try {
774            sService.bindRemoteViewsService(appWidgetId, intent, connection,
775                    userHandle.getIdentifier());
776        }
777        catch (RemoteException e) {
778            throw new RuntimeException("system server dead?", e);
779        }
780    }
781
782    /**
783     * Unbinds the RemoteViewsService for a given appWidgetId and intent.
784     *
785     * The appWidgetId specified muse already be bound to the calling AppWidgetHost via
786     * {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
787     *
788     * @param appWidgetId   The AppWidget instance for which to bind the RemoteViewsService.
789     * @param intent        The intent of the service which will be providing the data to the
790     *                      RemoteViewsAdapter.
791     * @param userHandle    The user to unbind from.
792     * @hide
793     */
794    public void unbindRemoteViewsService(int appWidgetId, Intent intent, UserHandle userHandle) {
795        try {
796            sService.unbindRemoteViewsService(appWidgetId, intent, userHandle.getIdentifier());
797        }
798        catch (RemoteException e) {
799            throw new RuntimeException("system server dead?", e);
800        }
801    }
802
803    /**
804     * Get the list of appWidgetIds that have been bound to the given AppWidget
805     * provider.
806     *
807     * @param provider The {@link android.content.BroadcastReceiver} that is the
808     *            AppWidget provider to find appWidgetIds for.
809     */
810    public int[] getAppWidgetIds(ComponentName provider) {
811        try {
812            return sService.getAppWidgetIds(provider, mContext.getUserId());
813        }
814        catch (RemoteException e) {
815            throw new RuntimeException("system server dead?", e);
816        }
817    }
818}
819
820