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