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