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