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.BroadcastBehavior;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.RequiresFeature;
23 import android.annotation.SdkConstant;
24 import android.annotation.SdkConstant.SdkConstantType;
25 import android.annotation.SystemService;
26 import android.annotation.TestApi;
27 import android.annotation.UiThread;
28 import android.annotation.UserIdInt;
29 import android.app.IServiceConnection;
30 import android.app.PendingIntent;
31 import android.compat.annotation.UnsupportedAppUsage;
32 import android.content.ComponentName;
33 import android.content.Context;
34 import android.content.Intent;
35 import android.content.IntentSender;
36 import android.content.ServiceConnection;
37 import android.content.pm.PackageManager;
38 import android.content.pm.ParceledListSlice;
39 import android.content.pm.ShortcutInfo;
40 import android.os.Build;
41 import android.os.Bundle;
42 import android.os.Handler;
43 import android.os.HandlerExecutor;
44 import android.os.HandlerThread;
45 import android.os.Looper;
46 import android.os.Process;
47 import android.os.RemoteException;
48 import android.os.UserHandle;
49 import android.util.DisplayMetrics;
50 import android.util.Log;
51 import android.widget.RemoteViews;
52 
53 import com.android.internal.appwidget.IAppWidgetService;
54 import com.android.internal.os.BackgroundThread;
55 
56 import java.util.ArrayList;
57 import java.util.Collections;
58 import java.util.List;
59 import java.util.Objects;
60 import java.util.concurrent.CompletableFuture;
61 import java.util.concurrent.Executor;
62 
63 /**
64  * Updates AppWidget state; gets information about installed AppWidget providers and other
65  * AppWidget related state.
66  *
67  * <div class="special reference">
68  * <h3>Developer Guides</h3>
69  * <p>For more information about creating app widgets, read the
70  * <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widgets</a> developer guide.</p>
71  * </div>
72  */
73 @SystemService(Context.APPWIDGET_SERVICE)
74 @RequiresFeature(PackageManager.FEATURE_APP_WIDGETS)
75 public class AppWidgetManager {
76 
77 
78     /**
79      * Activity action to launch from your {@link AppWidgetHost} activity when you want to
80      * pick an AppWidget to display.  The AppWidget picker activity will be launched.
81      * <p>
82      * You must supply the following extras:
83      * <table>
84      *   <tr>
85      *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
86      *     <td>A newly allocated appWidgetId, which will be bound to the AppWidget provider
87      *         once the user has selected one.</td>
88      *  </tr>
89      * </table>
90      *
91      * <p>
92      * The system will respond with an onActivityResult call with the following extras in
93      * the intent:
94      * <table>
95      *   <tr>
96      *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
97      *     <td>The appWidgetId that you supplied in the original intent.</td>
98      *  </tr>
99      * </table>
100      * <p>
101      * When you receive the result from the AppWidget pick activity, if the resultCode is
102      * {@link android.app.Activity#RESULT_OK}, an AppWidget has been selected.  You should then
103      * check the AppWidgetProviderInfo for the returned AppWidget, and if it has one, launch its
104      * configuration activity.  If {@link android.app.Activity#RESULT_CANCELED} is returned, you
105      * should delete the appWidgetId.
106      *
107      * @see #ACTION_APPWIDGET_CONFIGURE
108      */
109     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
110     public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK";
111 
112     /**
113      * Similar to ACTION_APPWIDGET_PICK, but used from keyguard
114      * @hide
115      */
116     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
117     public static final String
118             ACTION_KEYGUARD_APPWIDGET_PICK = "android.appwidget.action.KEYGUARD_APPWIDGET_PICK";
119 
120     /**
121      * Activity action to launch from your {@link AppWidgetHost} activity when you want to bind
122      * an AppWidget to display and bindAppWidgetIdIfAllowed returns false.
123      * <p>
124      * You must supply the following extras:
125      * <table>
126      *   <tr>
127      *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
128      *     <td>A newly allocated appWidgetId, which will be bound to the AppWidget provider
129      *         you provide.</td>
130      *  </tr>
131      *  <tr>
132      *     <td>{@link #EXTRA_APPWIDGET_PROVIDER}</td>
133      *     <td>The BroadcastReceiver that will be the AppWidget provider for this AppWidget.
134      *     </td>
135      *  </tr>
136      *  <tr>
137      *     <td>{@link #EXTRA_APPWIDGET_PROVIDER_PROFILE}</td>
138      *     <td>An optional handle to a user profile under which runs the provider
139      *     for this AppWidget.
140      *     </td>
141      *  </tr>
142      * </table>
143      *
144      * <p>
145      * The system will respond with an onActivityResult call with the following extras in
146      * the intent:
147      * <table>
148      *   <tr>
149      *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
150      *     <td>The appWidgetId that you supplied in the original intent.</td>
151      *  </tr>
152      * </table>
153      * <p>
154      * When you receive the result from the AppWidget bind activity, if the resultCode is
155      * {@link android.app.Activity#RESULT_OK}, the AppWidget has been bound.  You should then
156      * check the AppWidgetProviderInfo for the returned AppWidget, and if it has one, launch its
157      * configuration activity.  If {@link android.app.Activity#RESULT_CANCELED} is returned, you
158      * should delete the appWidgetId.
159      *
160      * @see #ACTION_APPWIDGET_CONFIGURE
161      *
162      */
163     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
164     public static final String ACTION_APPWIDGET_BIND = "android.appwidget.action.APPWIDGET_BIND";
165 
166     /**
167      * Sent when it is time to configure your AppWidget while it is being added to a host.
168      * This action is not sent as a broadcast to the AppWidget provider, but as a startActivity
169      * to the activity specified in the {@link AppWidgetProviderInfo AppWidgetProviderInfo
170      * meta-data}.
171      *
172      * <p>
173      * The intent will contain the following extras:
174      * <table>
175      *   <tr>
176      *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
177      *     <td>The appWidgetId to configure.</td>
178      *  </tr>
179      * </table>
180      *
181      * <p>If you return {@link android.app.Activity#RESULT_OK} using
182      * {@link android.app.Activity#setResult Activity.setResult()}, the AppWidget will be added,
183      * and you will receive an {@link #ACTION_APPWIDGET_UPDATE} broadcast for this AppWidget.
184      * If you return {@link android.app.Activity#RESULT_CANCELED}, the host will cancel the add
185      * and not display this AppWidget, and you will receive a {@link #ACTION_APPWIDGET_DELETED}
186      * broadcast.
187      */
188     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
189     public static final String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE";
190 
191     /**
192      * An intent extra (int) that contains one appWidgetId.
193      * <p>
194      * The value will be an int that can be retrieved like this:
195      * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetHostActivity.java getExtra_EXTRA_APPWIDGET_ID}
196      */
197     public static final String EXTRA_APPWIDGET_ID = "appWidgetId";
198 
199     /**
200      * A bundle extra (boolean) that contains whether or not an app has finished restoring a widget.
201      * <p> After restore, the app should set OPTION_APPWIDGET_RESTORE_COMPLETED to true on its
202      * widgets followed by calling {@link #updateAppWidget} to update the views.
203      *
204      * @see #updateAppWidgetOptions(int, Bundle)
205      */
206     public static final String OPTION_APPWIDGET_RESTORE_COMPLETED = "appWidgetRestoreCompleted";
207 
208 
209     /**
210      * A bundle extra (int) that contains the lower bound on the current width, in dips, of a
211      * widget instance.
212      */
213     public static final String OPTION_APPWIDGET_MIN_WIDTH = "appWidgetMinWidth";
214 
215     /**
216      * A bundle extra (int) that contains the lower bound on the current height, in dips, of a
217      * widget instance.
218      */
219     public static final String OPTION_APPWIDGET_MIN_HEIGHT = "appWidgetMinHeight";
220 
221     /**
222      * A bundle extra (int) that contains the upper bound on the current width, in dips, of a
223      * widget instance.
224      */
225     public static final String OPTION_APPWIDGET_MAX_WIDTH = "appWidgetMaxWidth";
226 
227     /**
228      * A bundle extra (int) that contains the upper bound on the current width, in dips, of a
229      * widget instance.
230      */
231     public static final String OPTION_APPWIDGET_MAX_HEIGHT = "appWidgetMaxHeight";
232 
233     /**
234      * A bundle extra ({@code List<SizeF>}) that contains the list of possible sizes, in dips, a
235      * widget instance can take.
236      */
237     public static final String OPTION_APPWIDGET_SIZES = "appWidgetSizes";
238 
239     /**
240      * A bundle extra that hints to the AppWidgetProvider the category of host that owns this
241      * this widget. Can have the value {@link
242      * AppWidgetProviderInfo#WIDGET_CATEGORY_HOME_SCREEN} or {@link
243      * AppWidgetProviderInfo#WIDGET_CATEGORY_KEYGUARD} or {@link
244      * AppWidgetProviderInfo#WIDGET_CATEGORY_SEARCHBOX}.
245      */
246     public static final String OPTION_APPWIDGET_HOST_CATEGORY = "appWidgetCategory";
247 
248     /**
249      * An intent extra which points to a bundle of extra information for a particular widget id.
250      * In particular this bundle can contain {@link #OPTION_APPWIDGET_MIN_WIDTH},
251      * {@link #OPTION_APPWIDGET_MIN_HEIGHT}, {@link #OPTION_APPWIDGET_MAX_WIDTH},
252      * {@link #OPTION_APPWIDGET_MAX_HEIGHT}.
253      */
254     public static final String EXTRA_APPWIDGET_OPTIONS = "appWidgetOptions";
255 
256     /**
257      * An intent extra that contains multiple appWidgetIds.
258      * <p>
259      * The value will be an int array that can be retrieved like this:
260      * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetProvider.java getExtra_EXTRA_APPWIDGET_IDS}
261      */
262     public static final String EXTRA_APPWIDGET_IDS = "appWidgetIds";
263 
264     /**
265      * An intent extra that contains the component name of a AppWidget provider.
266      * <p>
267      * The value will be an {@link android.content.ComponentName}.
268      */
269     public static final String EXTRA_APPWIDGET_PROVIDER = "appWidgetProvider";
270 
271     /**
272      * An intent extra that contains the user handle of the profile under
273      * which an AppWidget provider is registered.
274      * <p>
275      * The value will be a {@link android.os.UserHandle}.
276      */
277     public static final String EXTRA_APPWIDGET_PROVIDER_PROFILE = "appWidgetProviderProfile";
278 
279     /**
280      * An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of
281      * {@link AppWidgetProviderInfo} objects to mix in to the list of AppWidgets that are
282      * installed.  (This is how the launcher shows the search widget).
283      */
284     public static final String EXTRA_CUSTOM_INFO = "customInfo";
285 
286     /**
287      * An intent extra attached to the {@link #ACTION_APPWIDGET_HOST_RESTORED} broadcast,
288      * indicating the integer ID of the host whose widgets have just been restored.
289      */
290     public static final String EXTRA_HOST_ID = "hostId";
291 
292     /**
293      * An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of
294      * {@link android.os.Bundle} objects to mix in to the list of AppWidgets that are
295      * installed.  It will be added to the extras object on the {@link android.content.Intent}
296      * that is returned from the picker activity.
297      *
298      * {@more}
299      */
300     public static final String EXTRA_CUSTOM_EXTRAS = "customExtras";
301 
302     /**
303      * An intent extra to pass to the AppWidget picker which allows the picker to filter
304      * the list based on the {@link AppWidgetProviderInfo#widgetCategory}.
305      *
306      * @hide
307      */
308     public static final String EXTRA_CATEGORY_FILTER = "categoryFilter";
309 
310     /**
311      * An intent extra to pass to the AppWidget picker to specify whether or not to sort
312      * the list of caller-specified extra AppWidgets along with the rest of the AppWidgets
313      * @hide
314      */
315     public static final String EXTRA_CUSTOM_SORT = "customSort";
316 
317     /**
318      * A sentinel value that the AppWidget manager will never return as a appWidgetId.
319      */
320     public static final int INVALID_APPWIDGET_ID = 0;
321 
322     /**
323      * Sent when it is time to update your AppWidget.
324      *
325      * <p>This may be sent in response to a new instance for this AppWidget provider having
326      * been instantiated, the requested {@link AppWidgetProviderInfo#updatePeriodMillis update interval}
327      * having lapsed, or the system booting.
328      *
329      * <p>
330      * The intent will contain the following extras:
331      * <table>
332      *   <tr>
333      *     <td>{@link #EXTRA_APPWIDGET_IDS}</td>
334      *     <td>The appWidgetIds to update.  This may be all of the AppWidgets created for this
335      *     provider, or just a subset.  The system tries to send updates for as few AppWidget
336      *     instances as possible.</td>
337      *  </tr>
338      * </table>
339      *
340      * @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
341      */
342     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
343     @BroadcastBehavior(explicitOnly = true)
344     public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
345 
346     /**
347      * A combination broadcast of APPWIDGET_ENABLED and APPWIDGET_UPDATE.
348      * Sent during boot time and when the host is binding the widget for the very first time
349      *
350      * @hide
351      */
352     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
353     @BroadcastBehavior(explicitOnly = true)
354     public static final String ACTION_APPWIDGET_ENABLE_AND_UPDATE = "android.appwidget.action"
355             + ".APPWIDGET_ENABLE_AND_UPDATE";
356 
357     /**
358      * Sent when the custom extras for an AppWidget change.
359      *
360      * <p class="note">This is a protected intent that can only be sent
361      * by the system.
362      *
363      * @see AppWidgetProvider#onAppWidgetOptionsChanged
364      *      AppWidgetProvider.onAppWidgetOptionsChanged(Context context,
365      *      AppWidgetManager appWidgetManager, int appWidgetId, Bundle newExtras)
366      */
367     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
368     @BroadcastBehavior(explicitOnly = true)
369     public static final String ACTION_APPWIDGET_OPTIONS_CHANGED = "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS";
370 
371     /**
372      * Sent when an instance of an AppWidget is deleted from its host.
373      *
374      * <p class="note">This is a protected intent that can only be sent
375      * by the system.
376      *
377      * @see AppWidgetProvider#onDeleted AppWidgetProvider.onDeleted(Context context, int[] appWidgetIds)
378      */
379     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
380     @BroadcastBehavior(explicitOnly = true)
381     public static final String ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED";
382 
383     /**
384      * Sent when the last AppWidget of this provider is removed from the last host.
385      *
386      * <p class="note">This is a protected intent that can only be sent
387      * by the system.
388      *
389      * @see AppWidgetProvider#onEnabled AppWidgetProvider.onDisabled(Context context)
390      */
391     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
392     @BroadcastBehavior(explicitOnly = true)
393     public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
394 
395     /**
396      * Sent when an instance of an AppWidget is added to a host for the first time.
397      * This broadcast is sent at boot time if there is a AppWidgetHost installed with
398      * an instance for this provider.
399      *
400      * <p class="note">This is a protected intent that can only be sent
401      * by the system.
402      *
403      * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
404      */
405     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
406     @BroadcastBehavior(explicitOnly = true)
407     public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
408 
409     /**
410      * Sent to an {@link AppWidgetProvider} after AppWidget state related to that provider has
411      * been restored from backup. The intent contains information about how to translate AppWidget
412      * ids from the restored data to their new equivalents.
413      *
414      * <p>The intent will contain the following extras:
415      *
416      * <table>
417      *   <tr>
418      *     <td>{@link #EXTRA_APPWIDGET_OLD_IDS}</td>
419      *     <td>The set of appWidgetIds represented in a restored backup that have been successfully
420      *     incorporated into the current environment.  This may be all of the AppWidgets known
421      *     to this application, or just a subset.  Each entry in this array of appWidgetIds has
422      *     a corresponding entry in the {@link #EXTRA_APPWIDGET_IDS} extra.</td>
423      *  </tr>
424      *   <tr>
425      *     <td>{@link #EXTRA_APPWIDGET_IDS}</td>
426      *     <td>The set of appWidgetIds now valid for this application.  The app should look at
427      *     its restored widget configuration and translate each appWidgetId in the
428      *     {@link #EXTRA_APPWIDGET_OLD_IDS} array to its new value found at the corresponding
429      *     index within this array.</td>
430      *  </tr>
431      * </table>
432      *
433      * <p class="note">This is a protected intent that can only be sent
434      * by the system.
435      *
436      * @see #ACTION_APPWIDGET_HOST_RESTORED
437      */
438     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
439     @BroadcastBehavior(explicitOnly = true)
440     public static final String ACTION_APPWIDGET_RESTORED
441             = "android.appwidget.action.APPWIDGET_RESTORED";
442 
443     /**
444      * Sent to widget hosts after AppWidget state related to the host has been restored from
445      * backup. The intent contains information about how to translate AppWidget ids from the
446      * restored data to their new equivalents.  If an application maintains multiple separate
447      * widget host instances, it will receive this broadcast separately for each one.
448      *
449      * <p>The intent will contain the following extras:
450      *
451      * <table>
452      *   <tr>
453      *     <td>{@link #EXTRA_APPWIDGET_OLD_IDS}</td>
454      *     <td>The set of appWidgetIds represented in a restored backup that have been successfully
455      *     incorporated into the current environment.  This may be all of the AppWidgets known
456      *     to this application, or just a subset.  Each entry in this array of appWidgetIds has
457      *     a corresponding entry in the {@link #EXTRA_APPWIDGET_IDS} extra.</td>
458      *  </tr>
459      *   <tr>
460      *     <td>{@link #EXTRA_APPWIDGET_IDS}</td>
461      *     <td>The set of appWidgetIds now valid for this application.  The app should look at
462      *     its restored widget configuration and translate each appWidgetId in the
463      *     {@link #EXTRA_APPWIDGET_OLD_IDS} array to its new value found at the corresponding
464      *     index within this array.</td>
465      *  </tr>
466      *  <tr>
467      *     <td>{@link #EXTRA_HOST_ID}</td>
468      *     <td>The integer ID of the widget host instance whose state has just been restored.</td>
469      *  </tr>
470      * </table>
471      *
472      * <p class="note">This is a protected intent that can only be sent
473      * by the system.
474      *
475      * @see #ACTION_APPWIDGET_RESTORED
476      */
477     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
478     @BroadcastBehavior(explicitOnly = true)
479     public static final String ACTION_APPWIDGET_HOST_RESTORED
480             = "android.appwidget.action.APPWIDGET_HOST_RESTORED";
481 
482     private static final String TAG = "AppWidgetManager";
483 
484     private static Executor sUpdateExecutor;
485 
486     /**
487      * An intent extra that contains multiple appWidgetIds.  These are id values as
488      * they were provided to the application during a recent restore from backup.  It is
489      * attached to the {@link #ACTION_APPWIDGET_RESTORED} broadcast intent.
490      *
491      * <p>
492      * The value will be an int array that can be retrieved like this:
493      * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetProvider.java getExtra_EXTRA_APPWIDGET_IDS}
494      */
495     public static final String EXTRA_APPWIDGET_OLD_IDS = "appWidgetOldIds";
496 
497     /**
498      * An extra that can be passed to
499      * {@link #requestPinAppWidget(ComponentName, Bundle, PendingIntent)}. This would allow the
500      * launcher app to present a custom preview to the user.
501      *
502      * <p>
503      * The value should be a {@link RemoteViews} similar to what is used with
504      * {@link #updateAppWidget} calls.
505      */
506     public static final String EXTRA_APPWIDGET_PREVIEW = "appWidgetPreview";
507 
508     /**
509      * Field for the manifest meta-data tag.
510      *
511      * @see AppWidgetProviderInfo
512      */
513     public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";
514 
515     private final Context mContext;
516     private final String mPackageName;
517     @UnsupportedAppUsage
518     private final IAppWidgetService mService;
519     private final DisplayMetrics mDisplayMetrics;
520 
521     private boolean mHasPostedLegacyLists = false;
522 
523     /**
524      * Get the AppWidgetManager instance to use for the supplied {@link android.content.Context
525      * Context} object.
526      */
getInstance(Context context)527     public static AppWidgetManager getInstance(Context context) {
528         return (AppWidgetManager) context.getSystemService(Context.APPWIDGET_SERVICE);
529     }
530 
531     /**
532      * Creates a new instance.
533      *
534      * @param context The current context in which to operate.
535      * @param service The backing system service.
536      * @hide
537      */
AppWidgetManager(Context context, IAppWidgetService service)538     public AppWidgetManager(Context context, IAppWidgetService service) {
539         mContext = context;
540         mPackageName = context.getOpPackageName();
541         mService = service;
542         mDisplayMetrics = context.getResources().getDisplayMetrics();
543         if (mService == null) {
544             return;
545         }
546         BackgroundThread.getExecutor().execute(() -> {
547             try {
548                 mService.notifyProviderInheritance(getInstalledProvidersForPackage(mPackageName,
549                         null)
550                         .stream().filter(Objects::nonNull)
551                         .map(info -> info.provider).filter(p -> {
552                             try {
553                                 Class clazz = Class.forName(p.getClassName());
554                                 return AppWidgetProvider.class.isAssignableFrom(clazz);
555                             } catch (Exception e) {
556                                 return false;
557                             }
558                         }).toArray(ComponentName[]::new));
559             } catch (Exception e) {
560                 Log.e(TAG, "Nofity service of inheritance info", e);
561             }
562         });
563     }
564 
isPostingTaskToBackground(@ullable RemoteViews views)565     private boolean isPostingTaskToBackground(@Nullable RemoteViews views) {
566         return Looper.myLooper() == Looper.getMainLooper()
567                 && RemoteViews.isAdapterConversionEnabled()
568                 && (mHasPostedLegacyLists = mHasPostedLegacyLists
569                         || (views != null && views.hasLegacyLists()));
570     }
571 
572     /**
573      * Set the RemoteViews to use for the specified appWidgetIds.
574      * <p>
575      * Note that the RemoteViews parameter will be cached by the AppWidgetService, and hence should
576      * contain a complete representation of the widget. For performing partial widget updates, see
577      * {@link #partiallyUpdateAppWidget(int[], RemoteViews)}.
578      *
579      * <p>
580      * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
581      * and outside of the handler.
582      * This method will only work when called from the uid that owns the AppWidget provider.
583      *
584      * <p>
585      * The total Bitmap memory used by the RemoteViews object cannot exceed that required to
586      * fill the screen 1.5 times, ie. (screen width x screen height x 4 x 1.5) bytes.
587      *
588      * @param appWidgetIds The AppWidget instances for which to set the RemoteViews.
589      * @param views The RemoteViews object to show.
590      */
updateAppWidget(int[] appWidgetIds, RemoteViews views)591     public void updateAppWidget(int[] appWidgetIds, RemoteViews views) {
592         if (mService == null) {
593             return;
594         }
595 
596         if (isPostingTaskToBackground(views)) {
597             createUpdateExecutorIfNull().execute(() -> {
598                 try {
599                     mService.updateAppWidgetIds(mPackageName, appWidgetIds, views);
600                 } catch (RemoteException e) {
601                     Log.e(TAG, "Error updating app widget views in background", e);
602                 }
603             });
604 
605             return;
606         }
607 
608         try {
609             mService.updateAppWidgetIds(mPackageName, appWidgetIds, views);
610         } catch (RemoteException e) {
611             throw e.rethrowFromSystemServer();
612         }
613     }
614 
615     /**
616      * Update the extras for a given widget instance.
617      * <p>
618      * The extras can be used to embed additional information about this widget to be accessed
619      * by the associated widget's AppWidgetProvider.
620      *
621      * <p>
622      * The new options are merged into existing options using {@link Bundle#putAll} semantics.
623      *
624      * @see #getAppWidgetOptions(int)
625      *
626      * @param appWidgetId The AppWidget instances for which to set the RemoteViews.
627      * @param options The options to associate with this widget
628      */
updateAppWidgetOptions(int appWidgetId, Bundle options)629     public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
630         if (mService == null) {
631             return;
632         }
633         try {
634             mService.updateAppWidgetOptions(mPackageName, appWidgetId, options);
635         } catch (RemoteException e) {
636             throw e.rethrowFromSystemServer();
637         }
638     }
639 
640     /**
641      * Get the extras associated with a given widget instance.
642      * <p>
643      * The extras can be used to embed additional information about this widget to be accessed
644      * by the associated widget's AppWidgetProvider.
645      *
646      * @see #updateAppWidgetOptions(int, Bundle)
647      *
648      * @param appWidgetId The AppWidget instances for which to set the RemoteViews.
649      * @return The options associated with the given widget instance.
650      */
getAppWidgetOptions(int appWidgetId)651     public Bundle getAppWidgetOptions(int appWidgetId) {
652         if (mService == null) {
653             return Bundle.EMPTY;
654         }
655         try {
656             return mService.getAppWidgetOptions(mPackageName, appWidgetId);
657         } catch (RemoteException e) {
658             throw e.rethrowFromSystemServer();
659         }
660     }
661 
662     /**
663      * Set the RemoteViews to use for the specified appWidgetId.
664      * <p>
665      * Note that the RemoteViews parameter will be cached by the AppWidgetService, and hence should
666      * contain a complete representation of the widget. For performing partial widget updates, see
667      * {@link #partiallyUpdateAppWidget(int, RemoteViews)}.
668      *
669      * <p>
670      * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
671      * and outside of the handler.
672      * This method will only work when called from the uid that owns the AppWidget provider.
673      *
674      * <p>
675      * The total Bitmap memory used by the RemoteViews object cannot exceed that required to
676      * fill the screen 1.5 times, ie. (screen width x screen height x 4 x 1.5) bytes.
677      *
678      * @param appWidgetId      The AppWidget instance for which to set the RemoteViews.
679      * @param views         The RemoteViews object to show.
680      */
updateAppWidget(int appWidgetId, RemoteViews views)681     public void updateAppWidget(int appWidgetId, RemoteViews views) {
682         if (mService == null) {
683             return;
684         }
685         updateAppWidget(new int[] { appWidgetId }, views);
686     }
687 
688     /**
689      * Perform an incremental update or command on the widget(s) specified by appWidgetIds.
690      * <p>
691      * This update  differs from {@link #updateAppWidget(int[], RemoteViews)} in that the
692      * RemoteViews object which is passed is understood to be an incomplete representation of the
693      * widget, and hence does not replace the cached representation of the widget. As of API
694      * level 17, the new properties set within the views objects will be appended to the cached
695      * representation of the widget, and hence will persist.
696      *
697      * Use with {@link RemoteViews#showNext(int)}, {@link RemoteViews#showPrevious(int)},
698      * {@link RemoteViews#setScrollPosition(int, int)} and similar commands.
699      *
700      * <p>
701      * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
702      * and outside of the handler.
703      * This method will only work when called from the uid that owns the AppWidget provider.
704      *
705      * <p>
706      * This method will be ignored if a widget has not received a full update via
707      * {@link #updateAppWidget(int[], RemoteViews)}.
708      *
709      * @param appWidgetIds     The AppWidget instances for which to set the RemoteViews.
710      * @param views            The RemoteViews object containing the incremental update / command.
711      */
partiallyUpdateAppWidget(int[] appWidgetIds, RemoteViews views)712     public void partiallyUpdateAppWidget(int[] appWidgetIds, RemoteViews views) {
713         if (mService == null) {
714             return;
715         }
716 
717         if (isPostingTaskToBackground(views)) {
718             createUpdateExecutorIfNull().execute(() -> {
719                 try {
720                     mService.partiallyUpdateAppWidgetIds(mPackageName, appWidgetIds, views);
721                 } catch (RemoteException e) {
722                     Log.e(TAG, "Error partially updating app widget views in background", e);
723                 }
724             });
725 
726             return;
727         }
728 
729         try {
730             mService.partiallyUpdateAppWidgetIds(mPackageName, appWidgetIds, views);
731         } catch (RemoteException e) {
732             throw e.rethrowFromSystemServer();
733         }
734     }
735 
736     /**
737      * Perform an incremental update or command on the widget specified by appWidgetId.
738      * <p>
739      * This update  differs from {@link #updateAppWidget(int, RemoteViews)} in that the RemoteViews
740      * object which is passed is understood to be an incomplete representation of the widget, and
741      * hence is not cached by the AppWidgetService. Note that because these updates are not cached,
742      * any state that they modify that is not restored by restoreInstanceState will not persist in
743      * the case that the widgets are restored using the cached version in AppWidgetService.
744      *
745      * Use with {@link RemoteViews#showNext(int)}, {@link RemoteViews#showPrevious(int)},
746      * {@link RemoteViews#setScrollPosition(int, int)} and similar commands.
747      *
748      * <p>
749      * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
750      * and outside of the handler.
751      * This method will only work when called from the uid that owns the AppWidget provider.
752      *
753      * <p>
754      * This method will be ignored if a widget has not received a full update via
755      * {@link #updateAppWidget(int[], RemoteViews)}.
756      *
757      * @param appWidgetId      The AppWidget instance for which to set the RemoteViews.
758      * @param views            The RemoteViews object containing the incremental update / command.
759      */
partiallyUpdateAppWidget(int appWidgetId, RemoteViews views)760     public void partiallyUpdateAppWidget(int appWidgetId, RemoteViews views) {
761         if (mService == null) {
762             return;
763         }
764         partiallyUpdateAppWidget(new int[] { appWidgetId }, views);
765     }
766 
767     /**
768      * Set the RemoteViews to use for all AppWidget instances for the supplied AppWidget provider.
769      *
770      * <p>
771      * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
772      * and outside of the handler.
773      * This method will only work when called from the uid that owns the AppWidget provider.
774      *
775      * @param provider      The {@link ComponentName} for the {@link
776      * android.content.BroadcastReceiver BroadcastReceiver} provider
777      *                      for your AppWidget.
778      * @param views         The RemoteViews object to show.
779      */
updateAppWidget(ComponentName provider, RemoteViews views)780     public void updateAppWidget(ComponentName provider, RemoteViews views) {
781         if (mService == null) {
782             return;
783         }
784 
785         if (isPostingTaskToBackground(views)) {
786             createUpdateExecutorIfNull().execute(() -> {
787                 try {
788                     mService.updateAppWidgetProvider(provider, views);
789                 } catch (RemoteException e) {
790                     Log.e(TAG, "Error updating app widget view using provider in background", e);
791                 }
792             });
793 
794             return;
795         }
796 
797         try {
798             mService.updateAppWidgetProvider(provider, views);
799         } catch (RemoteException e) {
800             throw e.rethrowFromSystemServer();
801         }
802     }
803 
804     /**
805      * Updates the info for the supplied AppWidget provider. Apps can use this to change the default
806      * behavior of the widget based on the state of the app (for e.g., if the user is logged in
807      * or not). Calling this API completely replaces the previous definition.
808      *
809      * <p>
810      * The manifest entry of the provider should contain an additional meta-data tag similar to
811      * {@link #META_DATA_APPWIDGET_PROVIDER} which should point to any alternative definitions for
812      * the provider.
813      *
814      * <p>
815      * This is persisted across device reboots and app updates. If this meta-data key is not
816      * present in the manifest entry, the info reverts to default.
817      *
818      * @param provider {@link ComponentName} for the {@link
819      *    android.content.BroadcastReceiver BroadcastReceiver} provider for your AppWidget.
820      * @param metaDataKey key for the meta-data tag pointing to the new provider info. Use null
821      *    to reset any previously set info.
822      */
updateAppWidgetProviderInfo(ComponentName provider, @Nullable String metaDataKey)823     public void updateAppWidgetProviderInfo(ComponentName provider, @Nullable String metaDataKey) {
824         if (mService == null) {
825             return;
826         }
827         try {
828             mService.updateAppWidgetProviderInfo(provider, metaDataKey);
829         } catch (RemoteException e) {
830             throw e.rethrowFromSystemServer();
831         }
832     }
833 
834     /**
835      * Notifies the specified collection view in all the specified AppWidget instances
836      * to invalidate their data.
837      *
838      * @param appWidgetIds  The AppWidget instances to notify of view data changes.
839      * @param viewId        The collection view id.
840      */
notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId)841     public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) {
842         if (mService == null) {
843             return;
844         }
845 
846         if (!RemoteViews.isAdapterConversionEnabled()) {
847             try {
848                 mService.notifyAppWidgetViewDataChanged(mPackageName, appWidgetIds, viewId);
849             } catch (RemoteException re) {
850                 throw re.rethrowFromSystemServer();
851             }
852 
853             return;
854         }
855 
856         if (Looper.myLooper() == Looper.getMainLooper()) {
857             mHasPostedLegacyLists = true;
858             createUpdateExecutorIfNull().execute(() -> notifyCollectionWidgetChange(appWidgetIds,
859                     viewId));
860         } else {
861             notifyCollectionWidgetChange(appWidgetIds, viewId);
862         }
863     }
864 
notifyCollectionWidgetChange(int[] appWidgetIds, int viewId)865     private void notifyCollectionWidgetChange(int[] appWidgetIds, int viewId) {
866         try {
867             List<CompletableFuture<Void>> updateFutures = new ArrayList<>();
868             for (int i = 0; i < appWidgetIds.length; i++) {
869                 final int widgetId = appWidgetIds[i];
870                 updateFutures.add(CompletableFuture.runAsync(() -> {
871                     try {
872                         RemoteViews views = mService.getAppWidgetViews(mPackageName, widgetId);
873                         if (views.replaceRemoteCollections(viewId)) {
874                             updateAppWidget(widgetId, views);
875                         }
876                     } catch (Exception e) {
877                         Log.e(TAG, "Error notifying changes in RemoteViews", e);
878                     }
879                 }));
880             }
881             CompletableFuture.allOf(updateFutures.toArray(CompletableFuture[]::new)).join();
882         } catch (Exception e) {
883             Log.e(TAG, "Error notifying changes for all widgets", e);
884         }
885     }
886 
887     /**
888      * Notifies the specified collection view in the specified AppWidget instance
889      * to invalidate its data.
890      *
891      * @param appWidgetId  The AppWidget instance to notify of view data changes.
892      * @param viewId       The collection view id.
893      */
notifyAppWidgetViewDataChanged(int appWidgetId, int viewId)894     public void notifyAppWidgetViewDataChanged(int appWidgetId, int viewId) {
895         if (mService == null) {
896             return;
897         }
898         notifyAppWidgetViewDataChanged(new int[] { appWidgetId }, viewId);
899     }
900 
901     /**
902      * Gets the AppWidget providers for the given user profile. User profile can only
903      * be the current user or a profile of the current user. For example, the current
904      * user may have a corporate profile. In this case the parent user profile has a
905      * child profile, the corporate one.
906      *
907      * @param profile The profile for which to get providers. Passing null is equivalent
908      *        to querying for only the calling user.
909      * @return The installed providers, or an empty list if none are found for the given user.
910      *
911      * @see android.os.Process#myUserHandle()
912      * @see android.os.UserManager#getUserProfiles()
913      */
getInstalledProvidersForProfile( @ullable UserHandle profile)914     public @NonNull List<AppWidgetProviderInfo> getInstalledProvidersForProfile(
915             @Nullable UserHandle profile) {
916         if (mService == null) {
917             return Collections.emptyList();
918         }
919         return getInstalledProvidersForProfile(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,
920                 profile, null);
921     }
922 
923     /**
924      * Gets the AppWidget providers for the given package and user profile. User
925      * profile can only be the current user or a profile of the current user. For
926      * example, the current user may have a corporate profile. In this case the
927      * parent user profile has a child profile, the corporate one.
928      *
929      * @param packageName The package for which to get providers. If null, this method is
930      *        equivalent to {@link #getInstalledProvidersForProfile(UserHandle)}.
931      * @param profile The profile for which to get providers. Passing null is equivalent
932      *        to querying for only the calling user.
933      * @return The installed providers, or an empty list if none are found for the given
934      *         package and user.
935      * @throws NullPointerException if the provided package name is null
936      *
937      * @see android.os.Process#myUserHandle()
938      * @see android.os.UserManager#getUserProfiles()
939      */
getInstalledProvidersForPackage( @onNull String packageName, @Nullable UserHandle profile)940     public @NonNull List<AppWidgetProviderInfo> getInstalledProvidersForPackage(
941             @NonNull String packageName, @Nullable UserHandle profile) {
942         if (packageName == null) {
943             throw new NullPointerException("A non-null package must be passed to this method. " +
944                     "If you want all widgets regardless of package, see " +
945                     "getInstalledProvidersForProfile(UserHandle)");
946         }
947         if (mService == null) {
948             return Collections.emptyList();
949         }
950         return getInstalledProvidersForProfile(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,
951                 profile, packageName);
952     }
953 
954     /**
955      * Return a list of the AppWidget providers that are currently installed.
956      */
getInstalledProviders()957     public List<AppWidgetProviderInfo> getInstalledProviders() {
958         if (mService == null) {
959             return Collections.emptyList();
960         }
961         return getInstalledProvidersForProfile(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,
962                 null, null);
963     }
964 
965     /**
966      * Gets the AppWidget providers for the current user.
967      *
968      * @param categoryFilter Will only return providers which register as any of the specified
969      *        specified categories. See {@link AppWidgetProviderInfo#widgetCategory}.
970      * @return The intalled providers.
971      *
972      * @see android.os.Process#myUserHandle()
973      * @see android.os.UserManager#getUserProfiles()
974      *
975      * @hide
976      */
977     @UnsupportedAppUsage
getInstalledProviders(int categoryFilter)978     public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) {
979         if (mService == null) {
980             return Collections.emptyList();
981         }
982         return getInstalledProvidersForProfile(categoryFilter, null, null);
983     }
984 
985     /**
986      * Gets the AppWidget providers for the given user profile. User profile can only
987      * be the current user or a profile of the current user. For example, the current
988      * user may have a corporate profile. In this case the parent user profile has a
989      * child profile, the corporate one.
990      *
991      * @param categoryFilter Will only return providers which register as any of the specified
992      *        specified categories. See {@link AppWidgetProviderInfo#widgetCategory}.
993      * @param profile A profile of the current user which to be queried. The user
994      *        is itself also a profile. If null, the providers only for the current user
995      *        are returned.
996      * @param packageName If specified, will only return providers from the given package.
997      * @return The intalled providers.
998      *
999      * @see android.os.Process#myUserHandle()
1000      * @see android.os.UserManager#getUserProfiles()
1001      *
1002      * @hide
1003      */
1004     @UnsupportedAppUsage
getInstalledProvidersForProfile(int categoryFilter, @Nullable UserHandle profile, @Nullable String packageName)1005     public List<AppWidgetProviderInfo> getInstalledProvidersForProfile(int categoryFilter,
1006             @Nullable UserHandle profile, @Nullable String packageName) {
1007         if (mService == null) {
1008             return Collections.emptyList();
1009         }
1010 
1011         if (profile == null) {
1012             profile = mContext.getUser();
1013         }
1014 
1015         try {
1016             ParceledListSlice<AppWidgetProviderInfo> providers = mService.getInstalledProvidersForProfile(
1017                     categoryFilter, profile.getIdentifier(), packageName);
1018             if (providers == null) {
1019                 return Collections.emptyList();
1020             }
1021             for (AppWidgetProviderInfo info : providers.getList()) {
1022                 // Converting complex to dp.
1023                 info.updateDimensions(mDisplayMetrics);
1024             }
1025             return providers.getList();
1026         } catch (RemoteException e) {
1027             throw e.rethrowFromSystemServer();
1028         }
1029     }
1030 
1031     /**
1032      * Get the available info about the AppWidget.
1033      *
1034      * @return A appWidgetId.  If the appWidgetId has not been bound to a provider yet, or
1035      * you don't have access to that appWidgetId, null is returned.
1036      */
getAppWidgetInfo(int appWidgetId)1037     public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
1038         if (mService == null) {
1039             return null;
1040         }
1041         try {
1042             AppWidgetProviderInfo info = mService.getAppWidgetInfo(mPackageName, appWidgetId);
1043             if (info != null) {
1044                 // Converting complex to dp.
1045                 info.updateDimensions(mDisplayMetrics);
1046             }
1047             return info;
1048         } catch (RemoteException e) {
1049             throw e.rethrowFromSystemServer();
1050         }
1051     }
1052 
1053     /**
1054      * Set the component for a given appWidgetId.
1055      *
1056      * <p class="note">You need the BIND_APPWIDGET permission or the user must have enabled binding
1057      *         widgets always for your component. This method is used by the AppWidget picker and
1058      *         should not be used by other apps.
1059      *
1060      * @param appWidgetId     The AppWidget instance for which to set the RemoteViews.
1061      * @param provider      The {@link android.content.BroadcastReceiver} that will be the AppWidget
1062      *                      provider for this AppWidget.
1063      * @hide
1064      */
1065     @UnsupportedAppUsage
bindAppWidgetId(int appWidgetId, ComponentName provider)1066     public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
1067         if (mService == null) {
1068             return;
1069         }
1070         bindAppWidgetId(appWidgetId, provider, null);
1071     }
1072 
1073     /**
1074      * Set the component for a given appWidgetId.
1075      *
1076      * <p class="note">You need the BIND_APPWIDGET permission or the user must have enabled binding
1077      *         widgets always for your component. This method is used by the AppWidget picker and
1078      *         should not be used by other apps.
1079      *
1080      * @param appWidgetId     The AppWidget instance for which to set the RemoteViews.
1081      * @param provider      The {@link android.content.BroadcastReceiver} that will be the AppWidget
1082      *                      provider for this AppWidget.
1083      * @param options       Bundle containing options for the AppWidget. See also
1084      *                      {@link #updateAppWidgetOptions(int, Bundle)}
1085      *
1086      * @hide
1087      */
1088     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options)1089     public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) {
1090         if (mService == null) {
1091             return;
1092         }
1093         bindAppWidgetIdIfAllowed(appWidgetId, mContext.getUser(), provider, options);
1094     }
1095 
1096     /**
1097      * Set the component for a given appWidgetId.
1098      *
1099      * If successful, the app widget provider will receive a {@link #ACTION_APPWIDGET_UPDATE}
1100      * broadcast.
1101      *
1102      * <p class="note">You need the BIND_APPWIDGET permission or the user must have enabled binding
1103      *         widgets always for your component. Should be used by apps that host widgets; if this
1104      *         method returns false, call {@link #ACTION_APPWIDGET_BIND} to request permission to
1105      *         bind
1106      *
1107      * @param appWidgetId   The AppWidget id under which to bind the provider.
1108      * @param provider      The {@link android.content.BroadcastReceiver} that will be the AppWidget
1109      *                      provider for this AppWidget.
1110      * @return true if this component has permission to bind the AppWidget
1111      */
bindAppWidgetIdIfAllowed(int appWidgetId, ComponentName provider)1112     public boolean bindAppWidgetIdIfAllowed(int appWidgetId, ComponentName provider) {
1113         if (mService == null) {
1114             return false;
1115         }
1116         return bindAppWidgetIdIfAllowed(appWidgetId, mContext.getUserId(), provider, null);
1117     }
1118 
1119     /**
1120      * Set the component for a given appWidgetId.
1121      *
1122      * If successful, the app widget provider will receive a {@link #ACTION_APPWIDGET_UPDATE}
1123      * broadcast.
1124      *
1125      * <p class="note">You need the BIND_APPWIDGET permission or the user must have enabled binding
1126      *         widgets always for your component. Should be used by apps that host widgets; if this
1127      *         method returns false, call {@link #ACTION_APPWIDGET_BIND} to request permission to
1128      *         bind
1129      *
1130      * @param appWidgetId The AppWidget id under which to bind the provider.
1131      * @param provider      The {@link android.content.BroadcastReceiver} that will be the AppWidget
1132      *                      provider for this AppWidget.
1133      * @param options       Bundle containing options for the AppWidget. See also
1134      *                      {@link #updateAppWidgetOptions(int, Bundle)}
1135      *
1136      * @return true if this component has permission to bind the AppWidget
1137      */
bindAppWidgetIdIfAllowed(int appWidgetId, ComponentName provider, Bundle options)1138     public boolean bindAppWidgetIdIfAllowed(int appWidgetId, ComponentName provider,
1139             Bundle options) {
1140         if (mService == null) {
1141             return false;
1142         }
1143         return bindAppWidgetIdIfAllowed(appWidgetId, mContext.getUserId(), provider, options);
1144     }
1145 
1146     /**
1147      * Set the provider for a given appWidgetId if the caller has a permission.
1148      *
1149      * If successful, the app widget provider will receive a {@link #ACTION_APPWIDGET_UPDATE}
1150      * broadcast.
1151      *
1152      * <p>
1153      * <strong>Note:</strong> You need the {@link android.Manifest.permission#BIND_APPWIDGET}
1154      * permission or the user must have enabled binding widgets always for your component.
1155      * Should be used by apps that host widgets. If this method returns false, call {@link
1156      * #ACTION_APPWIDGET_BIND} to request permission to bind.
1157      * </p>
1158      *
1159      * @param appWidgetId The AppWidget id under which to bind the provider.
1160      * @param user The user id in which the provider resides.
1161      * @param provider The component name of the provider.
1162      * @param options An optional Bundle containing options for the AppWidget.
1163      *
1164      * @return true if this component has permission to bind the AppWidget
1165      */
bindAppWidgetIdIfAllowed(int appWidgetId, UserHandle user, ComponentName provider, Bundle options)1166     public boolean bindAppWidgetIdIfAllowed(int appWidgetId, UserHandle user,
1167             ComponentName provider, Bundle options) {
1168         if (mService == null) {
1169             return false;
1170         }
1171         return bindAppWidgetIdIfAllowed(appWidgetId, user.getIdentifier(), provider, options);
1172     }
1173 
1174     /**
1175      * Query if a given package was granted permission by the user to bind app widgets
1176      *
1177      * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
1178      *
1179      * @param packageName The package for which the permission is being queried
1180      * @param userId The user id of the user under which the package runs.
1181      * @return true if the package was granted permission by the user to bind app widgets
1182      * @hide
1183      */
hasBindAppWidgetPermission(String packageName, int userId)1184     public boolean hasBindAppWidgetPermission(String packageName, int userId) {
1185         if (mService == null) {
1186             return false;
1187         }
1188         try {
1189             return mService.hasBindAppWidgetPermission(packageName, userId);
1190         } catch (RemoteException e) {
1191             throw e.rethrowFromSystemServer();
1192         }
1193     }
1194 
1195     /**
1196      * Query if a given package was granted permission by the user to bind app widgets
1197      *
1198      * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
1199      *
1200      * @param packageName        The package for which the permission is being queried
1201      * @return true if the package was granted permission by the user to bind app widgets
1202      * @hide
1203      */
hasBindAppWidgetPermission(String packageName)1204     public boolean hasBindAppWidgetPermission(String packageName) {
1205         if (mService == null) {
1206             return false;
1207         }
1208         try {
1209             return mService.hasBindAppWidgetPermission(packageName, mContext.getUserId());
1210         } catch (RemoteException e) {
1211             throw e.rethrowFromSystemServer();
1212         }
1213     }
1214 
1215     /**
1216      * Changes any user-granted permission for the given package to bind app widgets
1217      *
1218      * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
1219      *
1220      * @param packageName The package whose permission is being changed
1221      * @param permission Whether to give the package permission to bind widgets
1222      *
1223      * @hide
1224      */
setBindAppWidgetPermission(String packageName, boolean permission)1225     public void setBindAppWidgetPermission(String packageName, boolean permission) {
1226         if (mService == null) {
1227             return;
1228         }
1229         setBindAppWidgetPermission(packageName, mContext.getUserId(), permission);
1230     }
1231 
1232     /**
1233      * Changes any user-granted permission for the given package to bind app widgets
1234      *
1235      * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
1236      *
1237      * @param packageName The package whose permission is being changed
1238      * @param userId The user under which the package is running.
1239      * @param permission Whether to give the package permission to bind widgets
1240      *
1241      * @hide
1242      */
1243     @TestApi
setBindAppWidgetPermission( @onNull String packageName, @UserIdInt int userId, boolean permission)1244     public void setBindAppWidgetPermission(
1245             @NonNull String packageName, @UserIdInt int userId, boolean permission) {
1246         if (mService == null) {
1247             return;
1248         }
1249         try {
1250             mService.setBindAppWidgetPermission(packageName, userId, permission);
1251         } catch (RemoteException e) {
1252             throw e.rethrowFromSystemServer();
1253         }
1254     }
1255 
1256     /**
1257      * Binds the RemoteViewsService for a given appWidgetId and intent.
1258      *
1259      * The appWidgetId specified must already be bound to the calling AppWidgetHost via
1260      * {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
1261      *
1262      * @param appWidgetId   The AppWidget instance for which to bind the RemoteViewsService.
1263      * @param intent        The intent of the service which will be providing the data to the
1264      *                      RemoteViewsAdapter.
1265      * @param connection    The callback interface to be notified when a connection is made or lost.
1266      * @param flags         Flags used for binding to the service. Currently only
1267      *                     {@link Context#BIND_AUTO_CREATE} and
1268      *                     {@link Context#BIND_FOREGROUND_SERVICE_WHILE_AWAKE} are supported.
1269      *
1270      * @see Context#getServiceDispatcher(ServiceConnection, Handler, long)
1271      * @hide
1272      */
1273     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
bindRemoteViewsService(Context context, int appWidgetId, Intent intent, IServiceConnection connection, @Context.BindServiceFlagsBits int flags)1274     public boolean bindRemoteViewsService(Context context, int appWidgetId, Intent intent,
1275             IServiceConnection connection, @Context.BindServiceFlagsBits int flags) {
1276         if (mService == null) {
1277             return false;
1278         }
1279         try {
1280             return mService.bindRemoteViewsService(context.getOpPackageName(), appWidgetId, intent,
1281                     context.getIApplicationThread(), context.getActivityToken(), connection,
1282                     Integer.toUnsignedLong(flags));
1283         } catch (RemoteException e) {
1284             throw e.rethrowFromSystemServer();
1285         }
1286     }
1287 
1288     /**
1289      * Get the list of appWidgetIds that have been bound to the given AppWidget
1290      * provider.
1291      *
1292      * @param provider The {@link android.content.BroadcastReceiver} that is the
1293      *            AppWidget provider to find appWidgetIds for.
1294      */
getAppWidgetIds(ComponentName provider)1295     public int[] getAppWidgetIds(ComponentName provider) {
1296         if (mService == null) {
1297             return new int[0];
1298         }
1299         try {
1300             return mService.getAppWidgetIds(provider);
1301         } catch (RemoteException e) {
1302             throw e.rethrowFromSystemServer();
1303         }
1304     }
1305 
1306     /**
1307      * @hide
1308      */
isBoundWidgetPackage(String packageName, int userId)1309     public boolean isBoundWidgetPackage(String packageName, int userId) {
1310         if (mService == null) {
1311             return false;
1312         }
1313         try {
1314             return mService.isBoundWidgetPackage(packageName, userId);
1315         } catch (RemoteException e) {
1316             throw e.rethrowFromSystemServer();
1317         }
1318     }
1319 
1320     @UnsupportedAppUsage
bindAppWidgetIdIfAllowed(int appWidgetId, int profileId, ComponentName provider, Bundle options)1321     private boolean bindAppWidgetIdIfAllowed(int appWidgetId, int profileId,
1322             ComponentName provider, Bundle options) {
1323         if (mService == null) {
1324             return false;
1325         }
1326         try {
1327             return mService.bindAppWidgetId(mPackageName, appWidgetId,
1328                     profileId, provider, options);
1329         } catch (RemoteException e) {
1330             throw e.rethrowFromSystemServer();
1331         }
1332     }
1333 
1334     /**
1335      * Return {@code TRUE} if the default launcher supports
1336      * {@link #requestPinAppWidget(ComponentName, Bundle, PendingIntent)}
1337      */
isRequestPinAppWidgetSupported()1338     public boolean isRequestPinAppWidgetSupported() {
1339         try {
1340             return mService.isRequestPinAppWidgetSupported();
1341         } catch (RemoteException e) {
1342             throw e.rethrowFromSystemServer();
1343         }
1344     }
1345 
1346     /**
1347      * Only used during development. Can be deleted before release.
1348      * @hide
1349      */
requestPinAppWidget(@onNull ComponentName provider, @Nullable PendingIntent successCallback)1350     public boolean requestPinAppWidget(@NonNull ComponentName provider,
1351             @Nullable PendingIntent successCallback) {
1352         return requestPinAppWidget(provider, null, successCallback);
1353     }
1354 
1355     /**
1356      * Request to pin an app widget on the current launcher. It's up to the launcher to accept this
1357      * request (optionally showing a user confirmation). If the request is accepted, the caller will
1358      * get a confirmation with extra {@link #EXTRA_APPWIDGET_ID}.
1359      *
1360      * <p>When a request is denied by the user, the caller app will not get any response.
1361      *
1362      * <p>Only apps with a foreground activity or a foreground service can call it.  Otherwise
1363      * it'll throw {@link IllegalStateException}.
1364      *
1365      * <p>It's up to the launcher how to handle previous pending requests when the same package
1366      * calls this API multiple times in a row.  It may ignore the previous requests,
1367      * for example.
1368      *
1369      * <p>Launcher will not show the configuration activity associated with the provider in this
1370      * case. The app could either show the configuration activity as a response to the callback,
1371      * or show if before calling the API (various configurations can be encapsulated in
1372      * {@code successCallback} to avoid persisting them before the widgetId is known).
1373      *
1374      * @param provider The {@link ComponentName} for the {@link
1375      *    android.content.BroadcastReceiver BroadcastReceiver} provider for your AppWidget.
1376      * @param extras In not null, this is passed to the launcher app. For eg {@link
1377      *    #EXTRA_APPWIDGET_PREVIEW} can be used for a custom preview.
1378      * @param successCallback If not null, this intent will be sent when the widget is created.
1379      *
1380      * @return {@code TRUE} if the launcher supports this feature. Note the API will return without
1381      *    waiting for the user to respond, so getting {@code TRUE} from this API does *not* mean
1382      *    the shortcut is pinned. {@code FALSE} if the launcher doesn't support this feature.
1383      *
1384      * @see android.content.pm.ShortcutManager#isRequestPinShortcutSupported()
1385      * @see android.content.pm.ShortcutManager#requestPinShortcut(ShortcutInfo, IntentSender)
1386      * @see #isRequestPinAppWidgetSupported()
1387      *
1388      * @throws IllegalStateException The caller doesn't have a foreground activity or a foreground
1389      * service or when the user is locked.
1390      */
requestPinAppWidget(@onNull ComponentName provider, @Nullable Bundle extras, @Nullable PendingIntent successCallback)1391     public boolean requestPinAppWidget(@NonNull ComponentName provider,
1392             @Nullable Bundle extras, @Nullable PendingIntent successCallback) {
1393         try {
1394             return mService.requestPinAppWidget(mPackageName, provider, extras,
1395                     successCallback == null ? null : successCallback.getIntentSender());
1396         } catch (RemoteException e) {
1397             throw e.rethrowFromSystemServer();
1398         }
1399     }
1400 
1401     /**
1402      * Note an app widget is tapped on.
1403      *
1404      * @param appWidgetId App widget id.
1405      * @hide
1406      */
noteAppWidgetTapped(int appWidgetId)1407     public void noteAppWidgetTapped(int appWidgetId) {
1408         try {
1409             mService.noteAppWidgetTapped(mPackageName, appWidgetId);
1410         } catch (RemoteException e) {
1411             throw e.rethrowFromSystemServer();
1412         }
1413     }
1414 
1415     @UiThread
createUpdateExecutorIfNull()1416     private static @NonNull Executor createUpdateExecutorIfNull() {
1417         if (sUpdateExecutor == null) {
1418             sUpdateExecutor = new HandlerExecutor(createAndStartNewHandler(
1419                     "widget_manager_update_helper_thread", Process.THREAD_PRIORITY_FOREGROUND));
1420         }
1421 
1422         return sUpdateExecutor;
1423     }
1424 
createAndStartNewHandler(@onNull String name, int priority)1425     private static @NonNull Handler createAndStartNewHandler(@NonNull String name, int priority) {
1426         HandlerThread thread = new HandlerThread(name, priority);
1427         thread.start();
1428         return thread.getThreadHandler();
1429     }
1430 }
1431