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 
17 package android.appwidget;
18 
19 import android.annotation.Nullable;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.os.Bundle;
24 import android.os.IBinder;
25 import android.os.Process;
26 import android.os.RemoteException;
27 import android.os.UserHandle;
28 import android.util.DisplayMetrics;
29 import android.util.TypedValue;
30 import android.widget.RemoteViews;
31 
32 import com.android.internal.appwidget.IAppWidgetService;
33 
34 import java.util.Collections;
35 import java.util.List;
36 
37 /**
38  * Updates AppWidget state; gets information about installed AppWidget providers and other
39  * AppWidget related state.
40  *
41  * <div class="special reference">
42  * <h3>Developer Guides</h3>
43  * <p>For more information about creating app widgets, read the
44  * <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widgets</a> developer guide.</p>
45  * </div>
46  */
47 public class AppWidgetManager {
48 
49     /**
50      * Activity action to launch from your {@link AppWidgetHost} activity when you want to
51      * pick an AppWidget to display.  The AppWidget picker activity will be launched.
52      * <p>
53      * You must supply the following extras:
54      * <table>
55      *   <tr>
56      *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
57      *     <td>A newly allocated appWidgetId, which will be bound to the AppWidget provider
58      *         once the user has selected one.</td>
59      *  </tr>
60      * </table>
61      *
62      * <p>
63      * The system will respond with an onActivityResult call with the following extras in
64      * the intent:
65      * <table>
66      *   <tr>
67      *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
68      *     <td>The appWidgetId that you supplied in the original intent.</td>
69      *  </tr>
70      * </table>
71      * <p>
72      * When you receive the result from the AppWidget pick activity, if the resultCode is
73      * {@link android.app.Activity#RESULT_OK}, an AppWidget has been selected.  You should then
74      * check the AppWidgetProviderInfo for the returned AppWidget, and if it has one, launch its
75      * configuration activity.  If {@link android.app.Activity#RESULT_CANCELED} is returned, you
76      * should delete the appWidgetId.
77      *
78      * @see #ACTION_APPWIDGET_CONFIGURE
79      */
80     public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK";
81 
82     /**
83      * Similar to ACTION_APPWIDGET_PICK, but used from keyguard
84      * @hide
85      */
86     public static final String
87             ACTION_KEYGUARD_APPWIDGET_PICK = "android.appwidget.action.KEYGUARD_APPWIDGET_PICK";
88 
89     /**
90      * Activity action to launch from your {@link AppWidgetHost} activity when you want to bind
91      * an AppWidget to display and bindAppWidgetIdIfAllowed returns false.
92      * <p>
93      * You must supply the following extras:
94      * <table>
95      *   <tr>
96      *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
97      *     <td>A newly allocated appWidgetId, which will be bound to the AppWidget provider
98      *         you provide.</td>
99      *  </tr>
100      *  <tr>
101      *     <td>{@link #EXTRA_APPWIDGET_PROVIDER}</td>
102      *     <td>The BroadcastReceiver that will be the AppWidget provider for this AppWidget.
103      *     </td>
104      *  </tr>
105      *  <tr>
106      *     <td>{@link #EXTRA_APPWIDGET_PROVIDER_PROFILE}</td>
107      *     <td>An optional handle to a user profile under which runs the provider
108      *     for this AppWidget.
109      *     </td>
110      *  </tr>
111      * </table>
112      *
113      * <p>
114      * The system will respond with an onActivityResult call with the following extras in
115      * the intent:
116      * <table>
117      *   <tr>
118      *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
119      *     <td>The appWidgetId that you supplied in the original intent.</td>
120      *  </tr>
121      * </table>
122      * <p>
123      * When you receive the result from the AppWidget bind activity, if the resultCode is
124      * {@link android.app.Activity#RESULT_OK}, the AppWidget has been bound.  You should then
125      * check the AppWidgetProviderInfo for the returned AppWidget, and if it has one, launch its
126      * configuration activity.  If {@link android.app.Activity#RESULT_CANCELED} is returned, you
127      * should delete the appWidgetId.
128      *
129      * @see #ACTION_APPWIDGET_CONFIGURE
130      *
131      */
132     public static final String ACTION_APPWIDGET_BIND = "android.appwidget.action.APPWIDGET_BIND";
133 
134     /**
135      * Sent when it is time to configure your AppWidget while it is being added to a host.
136      * This action is not sent as a broadcast to the AppWidget provider, but as a startActivity
137      * to the activity specified in the {@link AppWidgetProviderInfo AppWidgetProviderInfo
138      * meta-data}.
139      *
140      * <p>
141      * The intent will contain the following extras:
142      * <table>
143      *   <tr>
144      *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
145      *     <td>The appWidgetId to configure.</td>
146      *  </tr>
147      * </table>
148      *
149      * <p>If you return {@link android.app.Activity#RESULT_OK} using
150      * {@link android.app.Activity#setResult Activity.setResult()}, the AppWidget will be added,
151      * and you will receive an {@link #ACTION_APPWIDGET_UPDATE} broadcast for this AppWidget.
152      * If you return {@link android.app.Activity#RESULT_CANCELED}, the host will cancel the add
153      * and not display this AppWidget, and you will receive a {@link #ACTION_APPWIDGET_DELETED}
154      * broadcast.
155      */
156     public static final String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE";
157 
158     /**
159      * An intent extra that contains one appWidgetId.
160      * <p>
161      * The value will be an int that can be retrieved like this:
162      * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetHostActivity.java getExtra_EXTRA_APPWIDGET_ID}
163      */
164     public static final String EXTRA_APPWIDGET_ID = "appWidgetId";
165 
166     /**
167      * A bundle extra that contains the lower bound on the current width, in dips, of a widget instance.
168      */
169     public static final String OPTION_APPWIDGET_MIN_WIDTH = "appWidgetMinWidth";
170 
171     /**
172      * A bundle extra that contains the lower bound on the current height, in dips, of a widget instance.
173      */
174     public static final String OPTION_APPWIDGET_MIN_HEIGHT = "appWidgetMinHeight";
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_WIDTH = "appWidgetMaxWidth";
180 
181     /**
182      * A bundle extra that contains the upper bound on the current width, in dips, of a widget instance.
183      */
184     public static final String OPTION_APPWIDGET_MAX_HEIGHT = "appWidgetMaxHeight";
185 
186     /**
187      * A bundle extra that hints to the AppWidgetProvider the category of host that owns this
188      * this widget. Can have the value {@link
189      * AppWidgetProviderInfo#WIDGET_CATEGORY_HOME_SCREEN} or {@link
190      * AppWidgetProviderInfo#WIDGET_CATEGORY_KEYGUARD} or {@link
191      * AppWidgetProviderInfo#WIDGET_CATEGORY_SEARCHBOX}.
192      */
193     public static final String OPTION_APPWIDGET_HOST_CATEGORY = "appWidgetCategory";
194 
195     /**
196      * An intent extra which points to a bundle of extra information for a particular widget id.
197      * In particular this bundle can contain {@link #OPTION_APPWIDGET_MIN_WIDTH},
198      * {@link #OPTION_APPWIDGET_MIN_HEIGHT}, {@link #OPTION_APPWIDGET_MAX_WIDTH},
199      * {@link #OPTION_APPWIDGET_MAX_HEIGHT}.
200      */
201     public static final String EXTRA_APPWIDGET_OPTIONS = "appWidgetOptions";
202 
203     /**
204      * An intent extra that contains multiple appWidgetIds.
205      * <p>
206      * The value will be an int array that can be retrieved like this:
207      * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetProvider.java getExtra_EXTRA_APPWIDGET_IDS}
208      */
209     public static final String EXTRA_APPWIDGET_IDS = "appWidgetIds";
210 
211     /**
212      * An intent extra that contains the component name of a AppWidget provider.
213      * <p>
214      * The value will be an {@link android.content.ComponentName}.
215      */
216     public static final String EXTRA_APPWIDGET_PROVIDER = "appWidgetProvider";
217 
218     /**
219      * An intent extra that contains the user handle of the profile under
220      * which an AppWidget provider is registered.
221      * <p>
222      * The value will be a {@link android.os.UserHandle}.
223      */
224     public static final String EXTRA_APPWIDGET_PROVIDER_PROFILE = "appWidgetProviderProfile";
225 
226     /**
227      * An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of
228      * {@link AppWidgetProviderInfo} objects to mix in to the list of AppWidgets that are
229      * installed.  (This is how the launcher shows the search widget).
230      */
231     public static final String EXTRA_CUSTOM_INFO = "customInfo";
232 
233     /**
234      * An intent extra attached to the {@link #ACTION_APPWIDGET_HOST_RESTORED} broadcast,
235      * indicating the integer ID of the host whose widgets have just been restored.
236      */
237     public static final String EXTRA_HOST_ID = "hostId";
238 
239     /**
240      * An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of
241      * {@link android.os.Bundle} objects to mix in to the list of AppWidgets that are
242      * installed.  It will be added to the extras object on the {@link android.content.Intent}
243      * that is returned from the picker activity.
244      *
245      * {@more}
246      */
247     public static final String EXTRA_CUSTOM_EXTRAS = "customExtras";
248 
249     /**
250      * An intent extra to pass to the AppWidget picker which allows the picker to filter
251      * the list based on the {@link AppWidgetProviderInfo#widgetCategory}.
252      *
253      * @hide
254      */
255     public static final String EXTRA_CATEGORY_FILTER = "categoryFilter";
256 
257     /**
258      * An intent extra to pass to the AppWidget picker to specify whether or not to sort
259      * the list of caller-specified extra AppWidgets along with the rest of the AppWidgets
260      * @hide
261      */
262     public static final String EXTRA_CUSTOM_SORT = "customSort";
263 
264     /**
265      * A sentinel value that the AppWidget manager will never return as a appWidgetId.
266      */
267     public static final int INVALID_APPWIDGET_ID = 0;
268 
269     /**
270      * Sent when it is time to update your AppWidget.
271      *
272      * <p>This may be sent in response to a new instance for this AppWidget provider having
273      * been instantiated, the requested {@link AppWidgetProviderInfo#updatePeriodMillis update interval}
274      * having lapsed, or the system booting.
275      *
276      * <p>
277      * The intent will contain the following extras:
278      * <table>
279      *   <tr>
280      *     <td>{@link #EXTRA_APPWIDGET_IDS}</td>
281      *     <td>The appWidgetIds to update.  This may be all of the AppWidgets created for this
282      *     provider, or just a subset.  The system tries to send updates for as few AppWidget
283      *     instances as possible.</td>
284      *  </tr>
285      * </table>
286      *
287      * @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
288      */
289     public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
290 
291     /**
292      * Sent when the custom extras for an AppWidget change.
293      *
294      * <p class="note">This is a protected intent that can only be sent
295      * by the system.
296      *
297      * @see AppWidgetProvider#onAppWidgetOptionsChanged
298      *      AppWidgetProvider.onAppWidgetOptionsChanged(Context context,
299      *      AppWidgetManager appWidgetManager, int appWidgetId, Bundle newExtras)
300      */
301     public static final String ACTION_APPWIDGET_OPTIONS_CHANGED = "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS";
302 
303     /**
304      * Sent when an instance of an AppWidget is deleted from its host.
305      *
306      * <p class="note">This is a protected intent that can only be sent
307      * by the system.
308      *
309      * @see AppWidgetProvider#onDeleted AppWidgetProvider.onDeleted(Context context, int[] appWidgetIds)
310      */
311     public static final String ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED";
312 
313     /**
314      * Sent when the last AppWidget of this provider is removed from the last host.
315      *
316      * <p class="note">This is a protected intent that can only be sent
317      * by the system.
318      *
319      * @see AppWidgetProvider#onEnabled AppWidgetProvider.onDisabled(Context context)
320      */
321     public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
322 
323     /**
324      * Sent when an instance of an AppWidget is added to a host for the first time.
325      * This broadcast is sent at boot time if there is a AppWidgetHost installed with
326      * an instance for this provider.
327      *
328      * <p class="note">This is a protected intent that can only be sent
329      * by the system.
330      *
331      * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
332      */
333     public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
334 
335     /**
336      * Sent to an {@link AppWidgetProvider} after AppWidget state related to that provider has
337      * been restored from backup. The intent contains information about how to translate AppWidget
338      * ids from the restored data to their new equivalents.
339      *
340      * <p>The intent will contain the following extras:
341      *
342      * <table>
343      *   <tr>
344      *     <td>{@link #EXTRA_APPWIDGET_OLD_IDS}</td>
345      *     <td>The set of appWidgetIds represented in a restored backup that have been successfully
346      *     incorporated into the current environment.  This may be all of the AppWidgets known
347      *     to this application, or just a subset.  Each entry in this array of appWidgetIds has
348      *     a corresponding entry in the {@link #EXTRA_APPWIDGET_IDS} extra.</td>
349      *  </tr>
350      *   <tr>
351      *     <td>{@link #EXTRA_APPWIDGET_IDS}</td>
352      *     <td>The set of appWidgetIds now valid for this application.  The app should look at
353      *     its restored widget configuration and translate each appWidgetId in the
354      *     {@link #EXTRA_APPWIDGET_OLD_IDS} array to its new value found at the corresponding
355      *     index within this array.</td>
356      *  </tr>
357      * </table>
358      *
359      * <p class="note">This is a protected intent that can only be sent
360      * by the system.
361      *
362      * @see #ACTION_APPWIDGET_HOST_RESTORED
363      */
364     public static final String ACTION_APPWIDGET_RESTORED
365             = "android.appwidget.action.APPWIDGET_RESTORED";
366 
367     /**
368      * Sent to widget hosts after AppWidget state related to the host has been restored from
369      * backup. The intent contains information about how to translate AppWidget ids from the
370      * restored data to their new equivalents.  If an application maintains multiple separate
371      * widget host instances, it will receive this broadcast separately for each one.
372      *
373      * <p>The intent will contain the following extras:
374      *
375      * <table>
376      *   <tr>
377      *     <td>{@link #EXTRA_APPWIDGET_OLD_IDS}</td>
378      *     <td>The set of appWidgetIds represented in a restored backup that have been successfully
379      *     incorporated into the current environment.  This may be all of the AppWidgets known
380      *     to this application, or just a subset.  Each entry in this array of appWidgetIds has
381      *     a corresponding entry in the {@link #EXTRA_APPWIDGET_IDS} extra.</td>
382      *  </tr>
383      *   <tr>
384      *     <td>{@link #EXTRA_APPWIDGET_IDS}</td>
385      *     <td>The set of appWidgetIds now valid for this application.  The app should look at
386      *     its restored widget configuration and translate each appWidgetId in the
387      *     {@link #EXTRA_APPWIDGET_OLD_IDS} array to its new value found at the corresponding
388      *     index within this array.</td>
389      *  </tr>
390      *  <tr>
391      *     <td>{@link #EXTRA_HOST_ID}</td>
392      *     <td>The integer ID of the widget host instance whose state has just been restored.</td>
393      *  </tr>
394      * </table>
395      *
396      * <p class="note">This is a protected intent that can only be sent
397      * by the system.
398      *
399      * @see #ACTION_APPWIDGET_RESTORED
400      */
401     public static final String ACTION_APPWIDGET_HOST_RESTORED
402             = "android.appwidget.action.APPWIDGET_HOST_RESTORED";
403 
404     /**
405      * An intent extra that contains multiple appWidgetIds.  These are id values as
406      * they were provided to the application during a recent restore from backup.  It is
407      * attached to the {@link #ACTION_APPWIDGET_RESTORED} broadcast intent.
408      *
409      * <p>
410      * The value will be an int array that can be retrieved like this:
411      * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetProvider.java getExtra_EXTRA_APPWIDGET_IDS}
412      */
413     public static final String EXTRA_APPWIDGET_OLD_IDS = "appWidgetOldIds";
414 
415     /**
416      * Field for the manifest meta-data tag.
417      *
418      * @see AppWidgetProviderInfo
419      */
420     public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";
421 
422     private final String mPackageName;
423 
424     private final IAppWidgetService mService;
425 
426     private final DisplayMetrics mDisplayMetrics;
427 
428     /**
429      * Get the AppWidgetManager instance to use for the supplied {@link android.content.Context
430      * Context} object.
431      */
getInstance(Context context)432     public static AppWidgetManager getInstance(Context context) {
433         return (AppWidgetManager) context.getSystemService(Context.APPWIDGET_SERVICE);
434     }
435 
436     /**
437      * Creates a new instance.
438      *
439      * @param context The current context in which to operate.
440      * @param service The backing system service.
441      * @hide
442      */
AppWidgetManager(Context context, IAppWidgetService service)443     public AppWidgetManager(Context context, IAppWidgetService service) {
444         mPackageName = context.getOpPackageName();
445         mService = service;
446         mDisplayMetrics = context.getResources().getDisplayMetrics();
447     }
448 
449     /**
450      * Set the RemoteViews to use for the specified appWidgetIds.
451      * <p>
452      * Note that the RemoteViews parameter will be cached by the AppWidgetService, and hence should
453      * contain a complete representation of the widget. For performing partial widget updates, see
454      * {@link #partiallyUpdateAppWidget(int[], RemoteViews)}.
455      *
456      * <p>
457      * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
458      * and outside of the handler.
459      * This method will only work when called from the uid that owns the AppWidget provider.
460      *
461      * <p>
462      * The total Bitmap memory used by the RemoteViews object cannot exceed that required to
463      * fill the screen 1.5 times, ie. (screen width x screen height x 4 x 1.5) bytes.
464      *
465      * @param appWidgetIds The AppWidget instances for which to set the RemoteViews.
466      * @param views The RemoteViews object to show.
467      */
updateAppWidget(int[] appWidgetIds, RemoteViews views)468     public void updateAppWidget(int[] appWidgetIds, RemoteViews views) {
469         if (mService == null) {
470             return;
471         }
472         try {
473             mService.updateAppWidgetIds(mPackageName, appWidgetIds, views);
474         }
475         catch (RemoteException e) {
476             throw new RuntimeException("system server dead?", e);
477         }
478     }
479 
480     /**
481      * Update the extras for a given widget instance.
482      * <p>
483      * The extras can be used to embed additional information about this widget to be accessed
484      * by the associated widget's AppWidgetProvider.
485      *
486      * @see #getAppWidgetOptions(int)
487      *
488      * @param appWidgetId The AppWidget instances for which to set the RemoteViews.
489      * @param options The options to associate with this widget
490      */
updateAppWidgetOptions(int appWidgetId, Bundle options)491     public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
492         if (mService == null) {
493             return;
494         }
495         try {
496             mService.updateAppWidgetOptions(mPackageName, appWidgetId, options);
497         }
498         catch (RemoteException e) {
499             throw new RuntimeException("system server dead?", e);
500         }
501     }
502 
503     /**
504      * Get the extras associated with a given widget instance.
505      * <p>
506      * The extras can be used to embed additional information about this widget to be accessed
507      * by the associated widget's AppWidgetProvider.
508      *
509      * @see #updateAppWidgetOptions(int, Bundle)
510      *
511      * @param appWidgetId The AppWidget instances for which to set the RemoteViews.
512      * @return The options associated with the given widget instance.
513      */
getAppWidgetOptions(int appWidgetId)514     public Bundle getAppWidgetOptions(int appWidgetId) {
515         if (mService == null) {
516             return Bundle.EMPTY;
517         }
518         try {
519             return mService.getAppWidgetOptions(mPackageName, appWidgetId);
520         }
521         catch (RemoteException e) {
522             throw new RuntimeException("system server dead?", e);
523         }
524     }
525 
526     /**
527      * Set the RemoteViews to use for the specified appWidgetId.
528      * <p>
529      * Note that the RemoteViews parameter will be cached by the AppWidgetService, and hence should
530      * contain a complete representation of the widget. For performing partial widget updates, see
531      * {@link #partiallyUpdateAppWidget(int, RemoteViews)}.
532      *
533      * <p>
534      * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
535      * and outside of the handler.
536      * This method will only work when called from the uid that owns the AppWidget provider.
537      *
538      * <p>
539      * The total Bitmap memory used by the RemoteViews object cannot exceed that required to
540      * fill the screen 1.5 times, ie. (screen width x screen height x 4 x 1.5) bytes.
541      *
542      * @param appWidgetId      The AppWidget instance for which to set the RemoteViews.
543      * @param views         The RemoteViews object to show.
544      */
updateAppWidget(int appWidgetId, RemoteViews views)545     public void updateAppWidget(int appWidgetId, RemoteViews views) {
546         if (mService == null) {
547             return;
548         }
549         updateAppWidget(new int[] { appWidgetId }, views);
550     }
551 
552     /**
553      * Perform an incremental update or command on the widget(s) specified by appWidgetIds.
554      * <p>
555      * This update  differs from {@link #updateAppWidget(int[], RemoteViews)} in that the
556      * RemoteViews object which is passed is understood to be an incomplete representation of the
557      * widget, and hence does not replace the cached representation of the widget. As of API
558      * level 17, the new properties set within the views objects will be appended to the cached
559      * representation of the widget, and hence will persist.
560      *
561      * Use with {@link RemoteViews#showNext(int)}, {@link RemoteViews#showPrevious(int)},
562      * {@link RemoteViews#setScrollPosition(int, int)} and similar commands.
563      *
564      * <p>
565      * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
566      * and outside of the handler.
567      * This method will only work when called from the uid that owns the AppWidget provider.
568      *
569      * <p>
570      * This method will be ignored if a widget has not received a full update via
571      * {@link #updateAppWidget(int[], RemoteViews)}.
572      *
573      * @param appWidgetIds     The AppWidget instances for which to set the RemoteViews.
574      * @param views            The RemoteViews object containing the incremental update / command.
575      */
partiallyUpdateAppWidget(int[] appWidgetIds, RemoteViews views)576     public void partiallyUpdateAppWidget(int[] appWidgetIds, RemoteViews views) {
577         if (mService == null) {
578             return;
579         }
580         try {
581             mService.partiallyUpdateAppWidgetIds(mPackageName, appWidgetIds, views);
582         } catch (RemoteException e) {
583             throw new RuntimeException("system server dead?", e);
584         }
585     }
586 
587     /**
588      * Perform an incremental update or command on the widget specified by appWidgetId.
589      * <p>
590      * This update  differs from {@link #updateAppWidget(int, RemoteViews)} in that the RemoteViews
591      * object which is passed is understood to be an incomplete representation of the widget, and
592      * hence is not cached by the AppWidgetService. Note that because these updates are not cached,
593      * any state that they modify that is not restored by restoreInstanceState will not persist in
594      * the case that the widgets are restored using the cached version in AppWidgetService.
595      *
596      * Use with {@link RemoteViews#showNext(int)}, {@link RemoteViews#showPrevious(int)},
597      * {@link RemoteViews#setScrollPosition(int, int)} and similar commands.
598      *
599      * <p>
600      * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
601      * and outside of the handler.
602      * This method will only work when called from the uid that owns the AppWidget provider.
603      *
604      * <p>
605      * This method will be ignored if a widget has not received a full update via
606      * {@link #updateAppWidget(int[], RemoteViews)}.
607      *
608      * @param appWidgetId      The AppWidget instance for which to set the RemoteViews.
609      * @param views            The RemoteViews object containing the incremental update / command.
610      */
partiallyUpdateAppWidget(int appWidgetId, RemoteViews views)611     public void partiallyUpdateAppWidget(int appWidgetId, RemoteViews views) {
612         if (mService == null) {
613             return;
614         }
615         partiallyUpdateAppWidget(new int[] { appWidgetId }, views);
616     }
617 
618     /**
619      * Set the RemoteViews to use for all AppWidget instances for the supplied AppWidget provider.
620      *
621      * <p>
622      * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
623      * and outside of the handler.
624      * This method will only work when called from the uid that owns the AppWidget provider.
625      *
626      * @param provider      The {@link ComponentName} for the {@link
627      * android.content.BroadcastReceiver BroadcastReceiver} provider
628      *                      for your AppWidget.
629      * @param views         The RemoteViews object to show.
630      */
updateAppWidget(ComponentName provider, RemoteViews views)631     public void updateAppWidget(ComponentName provider, RemoteViews views) {
632         if (mService == null) {
633             return;
634         }
635         try {
636             mService.updateAppWidgetProvider(provider, views);
637         }
638         catch (RemoteException e) {
639             throw new RuntimeException("system server dead?", e);
640         }
641     }
642 
643     /**
644      * Notifies the specified collection view in all the specified AppWidget instances
645      * to invalidate their data.
646      *
647      * @param appWidgetIds  The AppWidget instances to notify of view data changes.
648      * @param viewId        The collection view id.
649      */
notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)650     public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) {
651         if (mService == null) {
652             return;
653         }
654         try {
655             mService.notifyAppWidgetViewDataChanged(mPackageName, appWidgetIds, viewId);
656         }
657         catch (RemoteException e) {
658             throw new RuntimeException("system server dead?", e);
659         }
660     }
661 
662     /**
663      * Notifies the specified collection view in the specified AppWidget instance
664      * to invalidate its data.
665      *
666      * @param appWidgetId  The AppWidget instance to notify of view data changes.
667      * @param viewId       The collection view id.
668      */
notifyAppWidgetViewDataChanged(int appWidgetId, int viewId)669     public void notifyAppWidgetViewDataChanged(int appWidgetId, int viewId) {
670         if (mService == null) {
671             return;
672         }
673         notifyAppWidgetViewDataChanged(new int[] { appWidgetId }, viewId);
674     }
675 
676     /**
677      * Gets the AppWidget providers for the given user profile. User profile can only
678      * be the current user or a profile of the current user. For example, the current
679      * user may have a corporate profile. In this case the parent user profile has a
680      * child profile, the corporate one.
681      *
682      * @param profile The profile for which to get providers. Passing null is equivaled
683      *         to passing only the current user handle.
684      * @return The intalled providers.
685      *
686      * @see android.os.Process#myUserHandle()
687      * @see android.os.UserManager#getUserProfiles()
688      */
getInstalledProvidersForProfile(@ullable UserHandle profile)689     public List<AppWidgetProviderInfo> getInstalledProvidersForProfile(@Nullable UserHandle profile) {
690         if (mService == null) {
691             return Collections.emptyList();
692         }
693         return getInstalledProvidersForProfile(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,
694                 profile);
695     }
696 
697     /**
698      * Return a list of the AppWidget providers that are currently installed.
699      */
getInstalledProviders()700     public List<AppWidgetProviderInfo> getInstalledProviders() {
701         if (mService == null) {
702             return Collections.emptyList();
703         }
704         return getInstalledProvidersForProfile(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,
705                 null);
706     }
707 
708     /**
709      * Gets the AppWidget providers for the current user.
710      *
711      * @param categoryFilter Will only return providers which register as any of the specified
712      *        specified categories. See {@link AppWidgetProviderInfo#widgetCategory}.
713      * @return The intalled providers.
714      *
715      * @see android.os.Process#myUserHandle()
716      * @see android.os.UserManager#getUserProfiles()
717      *
718      * @hide
719      */
getInstalledProviders(int categoryFilter)720     public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) {
721         if (mService == null) {
722             return Collections.emptyList();
723         }
724         return getInstalledProvidersForProfile(categoryFilter, null);
725     }
726 
727     /**
728      * Gets the AppWidget providers for the given user profile. User profile can only
729      * be the current user or a profile of the current user. For example, the current
730      * user may have a corporate profile. In this case the parent user profile has a
731      * child profile, the corporate one.
732      *
733      * @param categoryFilter Will only return providers which register as any of the specified
734      *        specified categories. See {@link AppWidgetProviderInfo#widgetCategory}.
735      * @param profile A profile of the current user which to be queried. The user
736      *        is itself also a profile. If null, the providers only for the current user
737      *        are returned.
738      * @return The intalled providers.
739      *
740      * @see android.os.Process#myUserHandle()
741      * @see android.os.UserManager#getUserProfiles()
742      *
743      * @hide
744      */
getInstalledProvidersForProfile(int categoryFilter, UserHandle profile)745     public List<AppWidgetProviderInfo> getInstalledProvidersForProfile(int categoryFilter,
746             UserHandle profile) {
747         if (mService == null) {
748             return Collections.emptyList();
749         }
750 
751         if (profile == null) {
752             profile = Process.myUserHandle();
753         }
754 
755         try {
756             List<AppWidgetProviderInfo> providers = mService.getInstalledProvidersForProfile(
757                     categoryFilter, profile.getIdentifier());
758             if (providers == null) {
759                 return Collections.emptyList();
760             }
761             for (AppWidgetProviderInfo info : providers) {
762                 // Converting complex to dp.
763                 convertSizesToPixels(info);
764             }
765             return providers;
766         }
767         catch (RemoteException e) {
768             throw new RuntimeException("system server dead?", e);
769         }
770     }
771 
772     /**
773      * Get the available info about the AppWidget.
774      *
775      * @return A appWidgetId.  If the appWidgetId has not been bound to a provider yet, or
776      * you don't have access to that appWidgetId, null is returned.
777      */
getAppWidgetInfo(int appWidgetId)778     public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
779         if (mService == null) {
780             return null;
781         }
782         try {
783             AppWidgetProviderInfo info = mService.getAppWidgetInfo(mPackageName, appWidgetId);
784             if (info != null) {
785                 // Converting complex to dp.
786                 convertSizesToPixels(info);
787             }
788             return info;
789         }
790         catch (RemoteException e) {
791             throw new RuntimeException("system server dead?", e);
792         }
793     }
794 
795     /**
796      * Set the component for a given appWidgetId.
797      *
798      * <p class="note">You need the BIND_APPWIDGET permission or the user must have enabled binding
799      *         widgets always for your component. This method is used by the AppWidget picker and
800      *         should not be used by other apps.
801      *
802      * @param appWidgetId     The AppWidget instance for which to set the RemoteViews.
803      * @param provider      The {@link android.content.BroadcastReceiver} that will be the AppWidget
804      *                      provider for this AppWidget.
805      * @hide
806      */
bindAppWidgetId(int appWidgetId, ComponentName provider)807     public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
808         if (mService == null) {
809             return;
810         }
811         bindAppWidgetId(appWidgetId, provider, null);
812     }
813 
814     /**
815      * Set the component for a given appWidgetId.
816      *
817      * <p class="note">You need the BIND_APPWIDGET permission or the user must have enabled binding
818      *         widgets always for your component. This method is used by the AppWidget picker and
819      *         should not be used by other apps.
820      *
821      * @param appWidgetId     The AppWidget instance for which to set the RemoteViews.
822      * @param provider      The {@link android.content.BroadcastReceiver} that will be the AppWidget
823      *                      provider for this AppWidget.
824      * @param options       Bundle containing options for the AppWidget. See also
825      *                      {@link #updateAppWidgetOptions(int, Bundle)}
826      *
827      * @hide
828      */
bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options)829     public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) {
830         if (mService == null) {
831             return;
832         }
833         bindAppWidgetIdIfAllowed(appWidgetId, Process.myUserHandle(), provider, options);
834     }
835 
836     /**
837      * Set the component for a given appWidgetId.
838      *
839      * <p class="note">You need the BIND_APPWIDGET permission or the user must have enabled binding
840      *         widgets always for your component. Should be used by apps that host widgets; if this
841      *         method returns false, call {@link #ACTION_APPWIDGET_BIND} to request permission to
842      *         bind
843      *
844      * @param appWidgetId   The AppWidget id under which to bind the provider.
845      * @param provider      The {@link android.content.BroadcastReceiver} that will be the AppWidget
846      *                      provider for this AppWidget.
847      * @return true if this component has permission to bind the AppWidget
848      */
bindAppWidgetIdIfAllowed(int appWidgetId, ComponentName provider)849     public boolean bindAppWidgetIdIfAllowed(int appWidgetId, ComponentName provider) {
850         if (mService == null) {
851             return false;
852         }
853         return bindAppWidgetIdIfAllowed(appWidgetId, UserHandle.myUserId(), provider, null);
854     }
855 
856     /**
857      * Set the component for a given appWidgetId.
858      *
859      * <p class="note">You need the BIND_APPWIDGET permission or the user must have enabled binding
860      *         widgets always for your component. Should be used by apps that host widgets; if this
861      *         method returns false, call {@link #ACTION_APPWIDGET_BIND} to request permission to
862      *         bind
863      *
864      * @param appWidgetId The AppWidget id under which to bind the provider.
865      * @param provider      The {@link android.content.BroadcastReceiver} that will be the AppWidget
866      *                      provider for this AppWidget.
867      * @param options       Bundle containing options for the AppWidget. See also
868      *                      {@link #updateAppWidgetOptions(int, Bundle)}
869      *
870      * @return true if this component has permission to bind the AppWidget
871      */
bindAppWidgetIdIfAllowed(int appWidgetId, ComponentName provider, Bundle options)872     public boolean bindAppWidgetIdIfAllowed(int appWidgetId, ComponentName provider,
873             Bundle options) {
874         if (mService == null) {
875             return false;
876         }
877         return bindAppWidgetIdIfAllowed(appWidgetId, UserHandle.myUserId(), provider, options);
878     }
879 
880     /**
881      * Set the provider for a given appWidgetId if the caller has a permission.
882      * <p>
883      * <strong>Note:</strong> You need the {@link android.Manifest.permission#BIND_APPWIDGET}
884      * permission or the user must have enabled binding widgets always for your component.
885      * Should be used by apps that host widgets. If this method returns false, call {@link
886      * #ACTION_APPWIDGET_BIND} to request permission to bind.
887      * </p>
888      *
889      * @param appWidgetId The AppWidget id under which to bind the provider.
890      * @param user The user id in which the provider resides.
891      * @param provider The component name of the provider.
892      * @param options An optional Bundle containing options for the AppWidget.
893      *
894      * @return true if this component has permission to bind the AppWidget
895      */
bindAppWidgetIdIfAllowed(int appWidgetId, UserHandle user, ComponentName provider, Bundle options)896     public boolean bindAppWidgetIdIfAllowed(int appWidgetId, UserHandle user,
897             ComponentName provider, Bundle options) {
898         if (mService == null) {
899             return false;
900         }
901         return bindAppWidgetIdIfAllowed(appWidgetId, user.getIdentifier(), provider, options);
902     }
903 
904     /**
905      * Query if a given package was granted permission by the user to bind app widgets
906      *
907      * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
908      *
909      * @param packageName The package for which the permission is being queried
910      * @param userId The user id of the user under which the package runs.
911      * @return true if the package was granted permission by the user to bind app widgets
912      * @hide
913      */
hasBindAppWidgetPermission(String packageName, int userId)914     public boolean hasBindAppWidgetPermission(String packageName, int userId) {
915         if (mService == null) {
916             return false;
917         }
918         try {
919             return mService.hasBindAppWidgetPermission(packageName, userId);
920         }
921         catch (RemoteException e) {
922             throw new RuntimeException("system server dead?", e);
923         }
924     }
925 
926     /**
927      * Query if a given package was granted permission by the user to bind app widgets
928      *
929      * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
930      *
931      * @param packageName        The package for which the permission is being queried
932      * @return true if the package was granted permission by the user to bind app widgets
933      * @hide
934      */
hasBindAppWidgetPermission(String packageName)935     public boolean hasBindAppWidgetPermission(String packageName) {
936         if (mService == null) {
937             return false;
938         }
939         try {
940             return mService.hasBindAppWidgetPermission(packageName, UserHandle.myUserId());
941         }
942         catch (RemoteException e) {
943             throw new RuntimeException("system server dead?", e);
944         }
945     }
946 
947     /**
948      * Changes any user-granted permission for the given package to bind app widgets
949      *
950      * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
951      *
952      * @param packageName The package whose permission is being changed
953      * @param permission Whether to give the package permission to bind widgets
954      *
955      * @hide
956      */
setBindAppWidgetPermission(String packageName, boolean permission)957     public void setBindAppWidgetPermission(String packageName, boolean permission) {
958         if (mService == null) {
959             return;
960         }
961         setBindAppWidgetPermission(packageName, UserHandle.myUserId(), permission);
962     }
963 
964     /**
965      * Changes any user-granted permission for the given package to bind app widgets
966      *
967      * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
968      *
969      * @param packageName The package whose permission is being changed
970      * @param userId The user under which the package is running.
971      * @param permission Whether to give the package permission to bind widgets
972      *
973      * @hide
974      */
setBindAppWidgetPermission(String packageName, int userId, boolean permission)975     public void setBindAppWidgetPermission(String packageName, int userId, boolean permission) {
976         if (mService == null) {
977             return;
978         }
979         try {
980             mService.setBindAppWidgetPermission(packageName, userId, permission);
981         }
982         catch (RemoteException e) {
983             throw new RuntimeException("system server dead?", e);
984         }
985     }
986 
987     /**
988      * Binds the RemoteViewsService for a given appWidgetId and intent.
989      *
990      * The appWidgetId specified must already be bound to the calling AppWidgetHost via
991      * {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
992      *
993      * @param packageName   The package from which the binding is requested.
994      * @param appWidgetId   The AppWidget instance for which to bind the RemoteViewsService.
995      * @param intent        The intent of the service which will be providing the data to the
996      *                      RemoteViewsAdapter.
997      * @param connection    The callback interface to be notified when a connection is made or lost.
998      * @hide
999      */
bindRemoteViewsService(String packageName, int appWidgetId, Intent intent, IBinder connection)1000     public void bindRemoteViewsService(String packageName, int appWidgetId, Intent intent,
1001             IBinder connection) {
1002         if (mService == null) {
1003             return;
1004         }
1005         try {
1006             mService.bindRemoteViewsService(packageName, appWidgetId, intent, connection);
1007         }
1008         catch (RemoteException e) {
1009             throw new RuntimeException("system server dead?", e);
1010         }
1011     }
1012 
1013     /**
1014      * Unbinds the RemoteViewsService for a given appWidgetId and intent.
1015      *
1016      * The appWidgetId specified muse already be bound to the calling AppWidgetHost via
1017      * {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
1018      *
1019      * @param packageName   The package from which the binding is requested.
1020      * @param appWidgetId   The AppWidget instance for which to bind the RemoteViewsService.
1021      * @param intent        The intent of the service which will be providing the data to the
1022      *                      RemoteViewsAdapter.
1023      * @hide
1024      */
unbindRemoteViewsService(String packageName, int appWidgetId, Intent intent)1025     public void unbindRemoteViewsService(String packageName, int appWidgetId, Intent intent) {
1026         if (mService == null) {
1027             return;
1028         }
1029         try {
1030             mService.unbindRemoteViewsService(packageName, appWidgetId, intent);
1031         }
1032         catch (RemoteException e) {
1033             throw new RuntimeException("system server dead?", e);
1034         }
1035     }
1036 
1037     /**
1038      * Get the list of appWidgetIds that have been bound to the given AppWidget
1039      * provider.
1040      *
1041      * @param provider The {@link android.content.BroadcastReceiver} that is the
1042      *            AppWidget provider to find appWidgetIds for.
1043      */
getAppWidgetIds(ComponentName provider)1044     public int[] getAppWidgetIds(ComponentName provider) {
1045         if (mService == null) {
1046             return new int[0];
1047         }
1048         try {
1049             return mService.getAppWidgetIds(provider);
1050         }
1051         catch (RemoteException e) {
1052             throw new RuntimeException("system server dead?", e);
1053         }
1054     }
1055 
bindAppWidgetIdIfAllowed(int appWidgetId, int profileId, ComponentName provider, Bundle options)1056     private boolean bindAppWidgetIdIfAllowed(int appWidgetId, int profileId,
1057             ComponentName provider, Bundle options) {
1058         if (mService == null) {
1059             return false;
1060         }
1061         try {
1062             return mService.bindAppWidgetId(mPackageName, appWidgetId,
1063                     profileId, provider, options);
1064         }
1065         catch (RemoteException e) {
1066             throw new RuntimeException("system server dead?", e);
1067         }
1068     }
1069 
convertSizesToPixels(AppWidgetProviderInfo info)1070     private void convertSizesToPixels(AppWidgetProviderInfo info) {
1071         // Converting complex to dp.
1072         info.minWidth = TypedValue.complexToDimensionPixelSize(info.minWidth,
1073                 mDisplayMetrics);
1074         info.minHeight = TypedValue.complexToDimensionPixelSize(info.minHeight,
1075                 mDisplayMetrics);
1076         info.minResizeWidth = TypedValue.complexToDimensionPixelSize(info.minResizeWidth,
1077                 mDisplayMetrics);
1078         info.minResizeHeight = TypedValue.complexToDimensionPixelSize(info.minResizeHeight,
1079                 mDisplayMetrics);
1080     }
1081 }
1082