content: /*
   * Copyright (C) 2006 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.appwidget;
  
  import android.annotation.BroadcastBehavior;
  import android.annotation.NonNull;
  import android.annotation.Nullable;
  import android.annotation.RequiresFeature;
  import android.annotation.SdkConstant;
  import android.annotation.SdkConstant.SdkConstantType;
  import android.annotation.SystemService;
  import android.annotation.UnsupportedAppUsage;
  import android.app.IServiceConnection;
  import android.app.PendingIntent;
  import android.content.ComponentName;
  import android.content.Context;
  import android.content.Intent;
  import android.content.IntentSender;
  import android.content.ServiceConnection;
  import android.content.pm.PackageManager;
  import android.content.pm.ParceledListSlice;
  import android.content.pm.ShortcutInfo;
  import android.os.Bundle;
  import android.os.Handler;
  import android.os.RemoteException;
  import android.os.UserHandle;
  import android.util.DisplayMetrics;
  import android.widget.RemoteViews;
  
  import com.android.internal.appwidget.IAppWidgetService;
  
  import java.util.Collections;
  import java.util.List;
  
  /**
   * Updates AppWidget state; gets information about installed AppWidget providers and other
   * AppWidget related state.
   *
   * <div class="special reference">
   * <h3>Developer Guides</h3>
   * <p>For more information about creating app widgets, read the
   * <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widgets</a> developer guide.</p>
   * </div>
   */
  @SystemService(Context.APPWIDGET_SERVICE)
  @RequiresFeature(PackageManager.FEATURE_APP_WIDGETS)
  public class AppWidgetManager {
  
      /**
       * Activity action to launch from your {@link AppWidgetHost} activity when you want to
       * pick an AppWidget to display.  The AppWidget picker activity will be launched.
       * <p>
       * You must supply the following extras:
       * <table>
       *   <tr>
       *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
       *     <td>A newly allocated appWidgetId, which will be bound to the AppWidget provider
       *         once the user has selected one.</td>
       *  </tr>
       * </table>
       *
       * <p>
       * The system will respond with an onActivityResult call with the following extras in
       * the intent:
       * <table>
       *   <tr>
       *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
       *     <td>The appWidgetId that you supplied in the original intent.</td>
       *  </tr>
       * </table>
       * <p>
       * When you receive the result from the AppWidget pick activity, if the resultCode is
       * {@link android.app.Activity#RESULT_OK}, an AppWidget has been selected.  You should then
       * check the AppWidgetProviderInfo for the returned AppWidget, and if it has one, launch its
       * configuration activity.  If {@link android.app.Activity#RESULT_CANCELED} is returned, you
       * should delete the appWidgetId.
       *
       * @see #ACTION_APPWIDGET_CONFIGURE
       */
      @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
      public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK";
  
      /**
       * Similar to ACTION_APPWIDGET_PICK, but used from keyguard
       * @hide
       */
      @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
      public static final String
              ACTION_KEYGUARD_APPWIDGET_PICK = "android.appwidget.action.KEYGUARD_APPWIDGET_PICK";
  
      /**
       * Activity action to launch from your {@link AppWidgetHost} activity when you want to bind
       * an AppWidget to display and bindAppWidgetIdIfAllowed returns false.
       * <p>
       * You must supply the following extras:
       * <table>
       *   <tr>
       *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
       *     <td>A newly allocated appWidgetId, which will be bound to the AppWidget provider
       *         you provide.</td>
       *  </tr>
       *  <tr>
       *     <td>{@link #EXTRA_APPWIDGET_PROVIDER}</td>
       *     <td>The BroadcastReceiver that will be the AppWidget provider for this AppWidget.
       *     </td>
       *  </tr>
       *  <tr>
       *     <td>{@link #EXTRA_APPWIDGET_PROVIDER_PROFILE}</td>
       *     <td>An optional handle to a user profile under which runs the provider
       *     for this AppWidget.
       *     </td>
       *  </tr>
       * </table>
       *
       * <p>
       * The system will respond with an onActivityResult call with the following extras in
       * the intent:
       * <table>
       *   <tr>
       *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
       *     <td>The appWidgetId that you supplied in the original intent.</td>
       *  </tr>
       * </table>
       * <p>
       * When you receive the result from the AppWidget bind activity, if the resultCode is
       * {@link android.app.Activity#RESULT_OK}, the AppWidget has been bound.  You should then
       * check the AppWidgetProviderInfo for the returned AppWidget, and if it has one, launch its
       * configuration activity.  If {@link android.app.Activity#RESULT_CANCELED} is returned, you
       * should delete the appWidgetId.
       *
       * @see #ACTION_APPWIDGET_CONFIGURE
       *
       */
      @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
      public static final String ACTION_APPWIDGET_BIND = "android.appwidget.action.APPWIDGET_BIND";
  
      /**
       * Sent when it is time to configure your AppWidget while it is being added to a host.
       * This action is not sent as a broadcast to the AppWidget provider, but as a startActivity
       * to the activity specified in the {@link AppWidgetProviderInfo AppWidgetProviderInfo
       * meta-data}.
       *
       * <p>
       * The intent will contain the following extras:
       * <table>
       *   <tr>
       *     <td>{@link #EXTRA_APPWIDGET_ID}</td>
       *     <td>The appWidgetId to configure.</td>
       *  </tr>
       * </table>
       *
       * <p>If you return {@link android.app.Activity#RESULT_OK} using
       * {@link android.app.Activity#setResult Activity.setResult()}, the AppWidget will be added,
       * and you will receive an {@link #ACTION_APPWIDGET_UPDATE} broadcast for this AppWidget.
       * If you return {@link android.app.Activity#RESULT_CANCELED}, the host will cancel the add
       * and not display this AppWidget, and you will receive a {@link #ACTION_APPWIDGET_DELETED}
       * broadcast.
       */
      @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
      public static final String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE";
  
      /**
       * An intent extra that contains one appWidgetId.
       * <p>
       * The value will be an int that can be retrieved like this:
       * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetHostActivity.java getExtra_EXTRA_APPWIDGET_ID}
       */
      public static final String EXTRA_APPWIDGET_ID = "appWidgetId";
  
      /**
       * A bundle extra that contains the lower bound on the current width, in dips, of a widget instance.
       */
      public static final String OPTION_APPWIDGET_MIN_WIDTH = "appWidgetMinWidth";
  
      /**
       * A bundle extra that contains the lower bound on the current height, in dips, of a widget instance.
       */
      public static final String OPTION_APPWIDGET_MIN_HEIGHT = "appWidgetMinHeight";
  
      /**
       * A bundle extra that contains the upper bound on the current width, in dips, of a widget instance.
       */
      public static final String OPTION_APPWIDGET_MAX_WIDTH = "appWidgetMaxWidth";
  
      /**
       * A bundle extra that contains the upper bound on the current width, in dips, of a widget instance.
       */
      public static final String OPTION_APPWIDGET_MAX_HEIGHT = "appWidgetMaxHeight";
  
      /**
       * A bundle extra that hints to the AppWidgetProvider the category of host that owns this
       * this widget. Can have the value {@link
       * AppWidgetProviderInfo#WIDGET_CATEGORY_HOME_SCREEN} or {@link
       * AppWidgetProviderInfo#WIDGET_CATEGORY_KEYGUARD} or {@link
       * AppWidgetProviderInfo#WIDGET_CATEGORY_SEARCHBOX}.
       */
      public static final String OPTION_APPWIDGET_HOST_CATEGORY = "appWidgetCategory";
  
      /**
       * An intent extra which points to a bundle of extra information for a particular widget id.
       * In particular this bundle can contain {@link #OPTION_APPWIDGET_MIN_WIDTH},
       * {@link #OPTION_APPWIDGET_MIN_HEIGHT}, {@link #OPTION_APPWIDGET_MAX_WIDTH},
       * {@link #OPTION_APPWIDGET_MAX_HEIGHT}.
       */
      public static final String EXTRA_APPWIDGET_OPTIONS = "appWidgetOptions";
  
      /**
       * An intent extra that contains multiple appWidgetIds.
       * <p>
       * The value will be an int array that can be retrieved like this:
       * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetProvider.java getExtra_EXTRA_APPWIDGET_IDS}
       */
      public static final String EXTRA_APPWIDGET_IDS = "appWidgetIds";
  
      /**
       * An intent extra that contains the component name of a AppWidget provider.
       * <p>
       * The value will be an {@link android.content.ComponentName}.
       */
      public static final String EXTRA_APPWIDGET_PROVIDER = "appWidgetProvider";
  
      /**
       * An intent extra that contains the user handle of the profile under
       * which an AppWidget provider is registered.
       * <p>
       * The value will be a {@link android.os.UserHandle}.
       */
      public static final String EXTRA_APPWIDGET_PROVIDER_PROFILE = "appWidgetProviderProfile";
  
      /**
       * An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of
       * {@link AppWidgetProviderInfo} objects to mix in to the list of AppWidgets that are
       * installed.  (This is how the launcher shows the search widget).
       */
      public static final String EXTRA_CUSTOM_INFO = "customInfo";
  
      /**
       * An intent extra attached to the {@link #ACTION_APPWIDGET_HOST_RESTORED} broadcast,
       * indicating the integer ID of the host whose widgets have just been restored.
       */
      public static final String EXTRA_HOST_ID = "hostId";
  
      /**
       * An intent extra to pass to the AppWidget picker containing a {@link java.util.List} of
       * {@link android.os.Bundle} objects to mix in to the list of AppWidgets that are
       * installed.  It will be added to the extras object on the {@link android.content.Intent}
       * that is returned from the picker activity.
       *
       * {@more}
       */
      public static final String EXTRA_CUSTOM_EXTRAS = "customExtras";
  
      /**
       * An intent extra to pass to the AppWidget picker which allows the picker to filter
       * the list based on the {@link AppWidgetProviderInfo#widgetCategory}.
       *
       * @hide
       */
      public static final String EXTRA_CATEGORY_FILTER = "categoryFilter";
  
      /**
       * An intent extra to pass to the AppWidget picker to specify whether or not to sort
       * the list of caller-specified extra AppWidgets along with the rest of the AppWidgets
       * @hide
       */
      public static final String EXTRA_CUSTOM_SORT = "customSort";
  
      /**
       * A sentinel value that the AppWidget manager will never return as a appWidgetId.
       */
      public static final int INVALID_APPWIDGET_ID = 0;
  
      /**
       * Sent when it is time to update your AppWidget.
       *
       * <p>This may be sent in response to a new instance for this AppWidget provider having
       * been instantiated, the requested {@link AppWidgetProviderInfo#updatePeriodMillis update interval}
       * having lapsed, or the system booting.
       *
       * <p>
       * The intent will contain the following extras:
       * <table>
       *   <tr>
       *     <td>{@link #EXTRA_APPWIDGET_IDS}</td>
       *     <td>The appWidgetIds to update.  This may be all of the AppWidgets created for this
       *     provider, or just a subset.  The system tries to send updates for as few AppWidget
       *     instances as possible.</td>
       *  </tr>
       * </table>
       *
       * @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
       */
      @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
      @BroadcastBehavior(explicitOnly = true)
      public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";
  
      /**
       * Sent when the custom extras for an AppWidget change.
       *
       * <p class="note">This is a protected intent that can only be sent
       * by the system.
       *
       * @see AppWidgetProvider#onAppWidgetOptionsChanged
       *      AppWidgetProvider.onAppWidgetOptionsChanged(Context context,
       *      AppWidgetManager appWidgetManager, int appWidgetId, Bundle newExtras)
       */
      @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
      @BroadcastBehavior(explicitOnly = true)
      public static final String ACTION_APPWIDGET_OPTIONS_CHANGED = "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS";
  
      /**
       * Sent when an instance of an AppWidget is deleted from its host.
       *
       * <p class="note">This is a protected intent that can only be sent
       * by the system.
       *
       * @see AppWidgetProvider#onDeleted AppWidgetProvider.onDeleted(Context context, int[] appWidgetIds)
       */
      @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
      @BroadcastBehavior(explicitOnly = true)
      public static final String ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED";
  
      /**
       * Sent when the last AppWidget of this provider is removed from the last host.
       *
       * <p class="note">This is a protected intent that can only be sent
       * by the system.
       *
       * @see AppWidgetProvider#onEnabled AppWidgetProvider.onDisabled(Context context)
       */
      @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
      @BroadcastBehavior(explicitOnly = true)
      public static final String ACTION_APPWIDGET_DISABLED = "android.appwidget.action.APPWIDGET_DISABLED";
  
      /**
       * Sent when an instance of an AppWidget is added to a host for the first time.
       * This broadcast is sent at boot time if there is a AppWidgetHost installed with
       * an instance for this provider.
       *
       * <p class="note">This is a protected intent that can only be sent
       * by the system.
       *
       * @see AppWidgetProvider#onEnabled AppWidgetProvider.onEnabled(Context context)
       */
      @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
      @BroadcastBehavior(explicitOnly = true)
      public static final String ACTION_APPWIDGET_ENABLED = "android.appwidget.action.APPWIDGET_ENABLED";
  
      /**
       * Sent to an {@link AppWidgetProvider} after AppWidget state related to that provider has
       * been restored from backup. The intent contains information about how to translate AppWidget
       * ids from the restored data to their new equivalents.
       *
       * <p>The intent will contain the following extras:
       *
       * <table>
       *   <tr>
       *     <td>{@link #EXTRA_APPWIDGET_OLD_IDS}</td>
       *     <td>The set of appWidgetIds represented in a restored backup that have been successfully
       *     incorporated into the current environment.  This may be all of the AppWidgets known
       *     to this application, or just a subset.  Each entry in this array of appWidgetIds has
       *     a corresponding entry in the {@link #EXTRA_APPWIDGET_IDS} extra.</td>
       *  </tr>
       *   <tr>
       *     <td>{@link #EXTRA_APPWIDGET_IDS}</td>
       *     <td>The set of appWidgetIds now valid for this application.  The app should look at
       *     its restored widget configuration and translate each appWidgetId in the
       *     {@link #EXTRA_APPWIDGET_OLD_IDS} array to its new value found at the corresponding
       *     index within this array.</td>
       *  </tr>
       * </table>
       *
       * <p class="note">This is a protected intent that can only be sent
       * by the system.
       *
       * @see #ACTION_APPWIDGET_HOST_RESTORED
       */
      @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
      @BroadcastBehavior(explicitOnly = true)
      public static final String ACTION_APPWIDGET_RESTORED
              = "android.appwidget.action.APPWIDGET_RESTORED";
  
      /**
       * Sent to widget hosts after AppWidget state related to the host has been restored from
       * backup. The intent contains information about how to translate AppWidget ids from the
       * restored data to their new equivalents.  If an application maintains multiple separate
       * widget host instances, it will receive this broadcast separately for each one.
       *
       * <p>The intent will contain the following extras:
       *
       * <table>
       *   <tr>
       *     <td>{@link #EXTRA_APPWIDGET_OLD_IDS}</td>
       *     <td>The set of appWidgetIds represented in a restored backup that have been successfully
       *     incorporated into the current environment.  This may be all of the AppWidgets known
       *     to this application, or just a subset.  Each entry in this array of appWidgetIds has
       *     a corresponding entry in the {@link #EXTRA_APPWIDGET_IDS} extra.</td>
       *  </tr>
       *   <tr>
       *     <td>{@link #EXTRA_APPWIDGET_IDS}</td>
       *     <td>The set of appWidgetIds now valid for this application.  The app should look at
       *     its restored widget configuration and translate each appWidgetId in the
       *     {@link #EXTRA_APPWIDGET_OLD_IDS} array to its new value found at the corresponding
       *     index within this array.</td>
       *  </tr>
       *  <tr>
       *     <td>{@link #EXTRA_HOST_ID}</td>
       *     <td>The integer ID of the widget host instance whose state has just been restored.</td>
       *  </tr>
       * </table>
       *
       * <p class="note">This is a protected intent that can only be sent
       * by the system.
       *
       * @see #ACTION_APPWIDGET_RESTORED
       */
      @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
      @BroadcastBehavior(explicitOnly = true)
      public static final String ACTION_APPWIDGET_HOST_RESTORED
              = "android.appwidget.action.APPWIDGET_HOST_RESTORED";
  
      /**
       * An intent extra that contains multiple appWidgetIds.  These are id values as
       * they were provided to the application during a recent restore from backup.  It is
       * attached to the {@link #ACTION_APPWIDGET_RESTORED} broadcast intent.
       *
       * <p>
       * The value will be an int array that can be retrieved like this:
       * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/TestAppWidgetProvider.java getExtra_EXTRA_APPWIDGET_IDS}
       */
      public static final String EXTRA_APPWIDGET_OLD_IDS = "appWidgetOldIds";
  
      /**
       * An extra that can be passed to
       * {@link #requestPinAppWidget(ComponentName, Bundle, PendingIntent)}. This would allow the
       * launcher app to present a custom preview to the user.
       *
       * <p>
       * The value should be a {@link RemoteViews} similar to what is used with
       * {@link #updateAppWidget} calls.
       */
      public static final String EXTRA_APPWIDGET_PREVIEW = "appWidgetPreview";
  
      /**
       * Field for the manifest meta-data tag.
       *
       * @see AppWidgetProviderInfo
       */
      public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";
  
      private final Context mContext;
      private final String mPackageName;
      @UnsupportedAppUsage
      private final IAppWidgetService mService;
      private final DisplayMetrics mDisplayMetrics;
  
      /**
       * Get the AppWidgetManager instance to use for the supplied {@link android.content.Context
       * Context} object.
       */
      public static AppWidgetManager getInstance(Context context) {
          return (AppWidgetManager) context.getSystemService(Context.APPWIDGET_SERVICE);
      }
  
      /**
       * Creates a new instance.
       *
       * @param context The current context in which to operate.
       * @param service The backing system service.
       * @hide
       */
      public AppWidgetManager(Context context, IAppWidgetService service) {
          mContext = context;
          mPackageName = context.getOpPackageName();
          mService = service;
          mDisplayMetrics = context.getResources().getDisplayMetrics();
      }
  
      /**
       * Set the RemoteViews to use for the specified appWidgetIds.
       * <p>
       * Note that the RemoteViews parameter will be cached by the AppWidgetService, and hence should
       * contain a complete representation of the widget. For performing partial widget updates, see
       * {@link #partiallyUpdateAppWidget(int[], RemoteViews)}.
       *
       * <p>
       * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
       * and outside of the handler.
       * This method will only work when called from the uid that owns the AppWidget provider.
       *
       * <p>
       * The total Bitmap memory used by the RemoteViews object cannot exceed that required to
       * fill the screen 1.5 times, ie. (screen width x screen height x 4 x 1.5) bytes.
       *
       * @param appWidgetIds The AppWidget instances for which to set the RemoteViews.
       * @param views The RemoteViews object to show.
       */
      public void updateAppWidget(int[] appWidgetIds, RemoteViews views) {
          if (mService == null) {
              return;
          }
          try {
              mService.updateAppWidgetIds(mPackageName, appWidgetIds, views);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Update the extras for a given widget instance.
       * <p>
       * The extras can be used to embed additional information about this widget to be accessed
       * by the associated widget's AppWidgetProvider.
       *
       * @see #getAppWidgetOptions(int)
       *
       * @param appWidgetId The AppWidget instances for which to set the RemoteViews.
       * @param options The options to associate with this widget
       */
      public void updateAppWidgetOptions(int appWidgetId, Bundle options) {
          if (mService == null) {
              return;
          }
          try {
              mService.updateAppWidgetOptions(mPackageName, appWidgetId, options);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Get the extras associated with a given widget instance.
       * <p>
       * The extras can be used to embed additional information about this widget to be accessed
       * by the associated widget's AppWidgetProvider.
       *
       * @see #updateAppWidgetOptions(int, Bundle)
       *
       * @param appWidgetId The AppWidget instances for which to set the RemoteViews.
       * @return The options associated with the given widget instance.
       */
      public Bundle getAppWidgetOptions(int appWidgetId) {
          if (mService == null) {
              return Bundle.EMPTY;
          }
          try {
              return mService.getAppWidgetOptions(mPackageName, appWidgetId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Set the RemoteViews to use for the specified appWidgetId.
       * <p>
       * Note that the RemoteViews parameter will be cached by the AppWidgetService, and hence should
       * contain a complete representation of the widget. For performing partial widget updates, see
       * {@link #partiallyUpdateAppWidget(int, RemoteViews)}.
       *
       * <p>
       * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
       * and outside of the handler.
       * This method will only work when called from the uid that owns the AppWidget provider.
       *
       * <p>
       * The total Bitmap memory used by the RemoteViews object cannot exceed that required to
       * fill the screen 1.5 times, ie. (screen width x screen height x 4 x 1.5) bytes.
       *
       * @param appWidgetId      The AppWidget instance for which to set the RemoteViews.
       * @param views         The RemoteViews object to show.
       */
      public void updateAppWidget(int appWidgetId, RemoteViews views) {
          if (mService == null) {
              return;
          }
          updateAppWidget(new int[] { appWidgetId }, views);
      }
  
      /**
       * Perform an incremental update or command on the widget(s) specified by appWidgetIds.
       * <p>
       * This update  differs from {@link #updateAppWidget(int[], RemoteViews)} in that the
       * RemoteViews object which is passed is understood to be an incomplete representation of the
       * widget, and hence does not replace the cached representation of the widget. As of API
       * level 17, the new properties set within the views objects will be appended to the cached
       * representation of the widget, and hence will persist.
       *
       * Use with {@link RemoteViews#showNext(int)}, {@link RemoteViews#showPrevious(int)},
       * {@link RemoteViews#setScrollPosition(int, int)} and similar commands.
       *
       * <p>
       * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
       * and outside of the handler.
       * This method will only work when called from the uid that owns the AppWidget provider.
       *
       * <p>
       * This method will be ignored if a widget has not received a full update via
       * {@link #updateAppWidget(int[], RemoteViews)}.
       *
       * @param appWidgetIds     The AppWidget instances for which to set the RemoteViews.
       * @param views            The RemoteViews object containing the incremental update / command.
       */
      public void partiallyUpdateAppWidget(int[] appWidgetIds, RemoteViews views) {
          if (mService == null) {
              return;
          }
          try {
              mService.partiallyUpdateAppWidgetIds(mPackageName, appWidgetIds, views);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Perform an incremental update or command on the widget specified by appWidgetId.
       * <p>
       * This update  differs from {@link #updateAppWidget(int, RemoteViews)} in that the RemoteViews
       * object which is passed is understood to be an incomplete representation of the widget, and
       * hence is not cached by the AppWidgetService. Note that because these updates are not cached,
       * any state that they modify that is not restored by restoreInstanceState will not persist in
       * the case that the widgets are restored using the cached version in AppWidgetService.
       *
       * Use with {@link RemoteViews#showNext(int)}, {@link RemoteViews#showPrevious(int)},
       * {@link RemoteViews#setScrollPosition(int, int)} and similar commands.
       *
       * <p>
       * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
       * and outside of the handler.
       * This method will only work when called from the uid that owns the AppWidget provider.
       *
       * <p>
       * This method will be ignored if a widget has not received a full update via
       * {@link #updateAppWidget(int[], RemoteViews)}.
       *
       * @param appWidgetId      The AppWidget instance for which to set the RemoteViews.
       * @param views            The RemoteViews object containing the incremental update / command.
       */
      public void partiallyUpdateAppWidget(int appWidgetId, RemoteViews views) {
          if (mService == null) {
              return;
          }
          partiallyUpdateAppWidget(new int[] { appWidgetId }, views);
      }
  
      /**
       * Set the RemoteViews to use for all AppWidget instances for the supplied AppWidget provider.
       *
       * <p>
       * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
       * and outside of the handler.
       * This method will only work when called from the uid that owns the AppWidget provider.
       *
       * @param provider      The {@link ComponentName} for the {@link
       * android.content.BroadcastReceiver BroadcastReceiver} provider
       *                      for your AppWidget.
       * @param views         The RemoteViews object to show.
       */
      public void updateAppWidget(ComponentName provider, RemoteViews views) {
          if (mService == null) {
              return;
          }
          try {
              mService.updateAppWidgetProvider(provider, views);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Updates the info for the supplied AppWidget provider. Apps can use this to change the default
       * behavior of the widget based on the state of the app (for e.g., if the user is logged in
       * or not). Calling this API completely replaces the previous definition.
       *
       * <p>
       * The manifest entry of the provider should contain an additional meta-data tag similar to
       * {@link #META_DATA_APPWIDGET_PROVIDER} which should point to any alternative definitions for
       * the provider.
       *
       * <p>
       * This is persisted across device reboots and app updates. If this meta-data key is not
       * present in the manifest entry, the info reverts to default.
       *
       * @param provider {@link ComponentName} for the {@link
       *    android.content.BroadcastReceiver BroadcastReceiver} provider for your AppWidget.
       * @param metaDataKey key for the meta-data tag pointing to the new provider info. Use null
       *    to reset any previously set info.
       */
      public void updateAppWidgetProviderInfo(ComponentName provider, @Nullable String metaDataKey) {
          if (mService == null) {
              return;
          }
          try {
              mService.updateAppWidgetProviderInfo(provider, metaDataKey);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Notifies the specified collection view in all the specified AppWidget instances
       * to invalidate their data.
       *
       * @param appWidgetIds  The AppWidget instances to notify of view data changes.
       * @param viewId        The collection view id.
       */
      public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) {
          if (mService == null) {
              return;
          }
          try {
              mService.notifyAppWidgetViewDataChanged(mPackageName, appWidgetIds, viewId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Notifies the specified collection view in the specified AppWidget instance
       * to invalidate its data.
       *
       * @param appWidgetId  The AppWidget instance to notify of view data changes.
       * @param viewId       The collection view id.
       */
      public void notifyAppWidgetViewDataChanged(int appWidgetId, int viewId) {
          if (mService == null) {
              return;
          }
          notifyAppWidgetViewDataChanged(new int[] { appWidgetId }, viewId);
      }
  
      /**
       * Gets the AppWidget providers for the given user profile. User profile can only
       * be the current user or a profile of the current user. For example, the current
       * user may have a corporate profile. In this case the parent user profile has a
       * child profile, the corporate one.
       *
       * @param profile The profile for which to get providers. Passing null is equivalent
       *        to querying for only the calling user.
       * @return The installed providers, or an empty list if none are found for the given user.
       *
       * @see android.os.Process#myUserHandle()
       * @see android.os.UserManager#getUserProfiles()
       */
      public @NonNull List<AppWidgetProviderInfo> getInstalledProvidersForProfile(
              @Nullable UserHandle profile) {
          if (mService == null) {
              return Collections.emptyList();
          }
          return getInstalledProvidersForProfile(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,
                  profile, null);
      }
  
      /**
       * Gets the AppWidget providers for the given package and user profile. User
       * profile can only be the current user or a profile of the current user. For
       * example, the current user may have a corporate profile. In this case the
       * parent user profile has a child profile, the corporate one.
       *
       * @param packageName The package for which to get providers. If null, this method is
       *        equivalent to {@link #getInstalledProvidersForProfile(UserHandle)}.
       * @param profile The profile for which to get providers. Passing null is equivalent
       *        to querying for only the calling user.
       * @return The installed providers, or an empty list if none are found for the given
       *         package and user.
       * @throws NullPointerException if the provided package name is null
       *
       * @see android.os.Process#myUserHandle()
       * @see android.os.UserManager#getUserProfiles()
       */
      public @NonNull List<AppWidgetProviderInfo> getInstalledProvidersForPackage(
              @NonNull String packageName, @Nullable UserHandle profile) {
          if (packageName == null) {
              throw new NullPointerException("A non-null package must be passed to this method. " +
                      "If you want all widgets regardless of package, see " +
                      "getInstalledProvidersForProfile(UserHandle)");
          }
          if (mService == null) {
              return Collections.emptyList();
          }
          return getInstalledProvidersForProfile(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,
                  profile, packageName);
      }
  
      /**
       * Return a list of the AppWidget providers that are currently installed.
       */
      public List<AppWidgetProviderInfo> getInstalledProviders() {
          if (mService == null) {
              return Collections.emptyList();
          }
          return getInstalledProvidersForProfile(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,
                  null, null);
      }
  
      /**
       * Gets the AppWidget providers for the current user.
       *
       * @param categoryFilter Will only return providers which register as any of the specified
       *        specified categories. See {@link AppWidgetProviderInfo#widgetCategory}.
       * @return The intalled providers.
       *
       * @see android.os.Process#myUserHandle()
       * @see android.os.UserManager#getUserProfiles()
       *
       * @hide
       */
      @UnsupportedAppUsage
      public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) {
          if (mService == null) {
              return Collections.emptyList();
          }
          return getInstalledProvidersForProfile(categoryFilter, null, null);
      }
  
      /**
       * Gets the AppWidget providers for the given user profile. User profile can only
       * be the current user or a profile of the current user. For example, the current
       * user may have a corporate profile. In this case the parent user profile has a
       * child profile, the corporate one.
       *
       * @param categoryFilter Will only return providers which register as any of the specified
       *        specified categories. See {@link AppWidgetProviderInfo#widgetCategory}.
       * @param profile A profile of the current user which to be queried. The user
       *        is itself also a profile. If null, the providers only for the current user
       *        are returned.
       * @param packageName If specified, will only return providers from the given package.
       * @return The intalled providers.
       *
       * @see android.os.Process#myUserHandle()
       * @see android.os.UserManager#getUserProfiles()
       *
       * @hide
       */
      @UnsupportedAppUsage
      public List<AppWidgetProviderInfo> getInstalledProvidersForProfile(int categoryFilter,
              @Nullable UserHandle profile, @Nullable String packageName) {
          if (mService == null) {
              return Collections.emptyList();
          }
  
          if (profile == null) {
              profile = mContext.getUser();
          }
  
          try {
              ParceledListSlice<AppWidgetProviderInfo> providers = mService.getInstalledProvidersForProfile(
                      categoryFilter, profile.getIdentifier(), packageName);
              if (providers == null) {
                  return Collections.emptyList();
              }
              for (AppWidgetProviderInfo info : providers.getList()) {
                  // Converting complex to dp.
                  info.updateDimensions(mDisplayMetrics);
              }
              return providers.getList();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Get the available info about the AppWidget.
       *
       * @return A appWidgetId.  If the appWidgetId has not been bound to a provider yet, or
       * you don't have access to that appWidgetId, null is returned.
       */
      public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
          if (mService == null) {
              return null;
          }
          try {
              AppWidgetProviderInfo info = mService.getAppWidgetInfo(mPackageName, appWidgetId);
              if (info != null) {
                  // Converting complex to dp.
                  info.updateDimensions(mDisplayMetrics);
              }
              return info;
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Set the component for a given appWidgetId.
       *
       * <p class="note">You need the BIND_APPWIDGET permission or the user must have enabled binding
       *         widgets always for your component. This method is used by the AppWidget picker and
       *         should not be used by other apps.
       *
       * @param appWidgetId     The AppWidget instance for which to set the RemoteViews.
       * @param provider      The {@link android.content.BroadcastReceiver} that will be the AppWidget
       *                      provider for this AppWidget.
       * @hide
       */
      @UnsupportedAppUsage
      public void bindAppWidgetId(int appWidgetId, ComponentName provider) {
          if (mService == null) {
              return;
          }
          bindAppWidgetId(appWidgetId, provider, null);
      }
  
      /**
       * Set the component for a given appWidgetId.
       *
       * <p class="note">You need the BIND_APPWIDGET permission or the user must have enabled binding
       *         widgets always for your component. This method is used by the AppWidget picker and
       *         should not be used by other apps.
       *
       * @param appWidgetId     The AppWidget instance for which to set the RemoteViews.
       * @param provider      The {@link android.content.BroadcastReceiver} that will be the AppWidget
       *                      provider for this AppWidget.
       * @param options       Bundle containing options for the AppWidget. See also
       *                      {@link #updateAppWidgetOptions(int, Bundle)}
       *
       * @hide
       */
      @UnsupportedAppUsage
      public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) {
          if (mService == null) {
              return;
          }
          bindAppWidgetIdIfAllowed(appWidgetId, mContext.getUser(), provider, options);
      }
  
      /**
       * Set the component for a given appWidgetId.
       *
       * <p class="note">You need the BIND_APPWIDGET permission or the user must have enabled binding
       *         widgets always for your component. Should be used by apps that host widgets; if this
       *         method returns false, call {@link #ACTION_APPWIDGET_BIND} to request permission to
       *         bind
       *
       * @param appWidgetId   The AppWidget id under which to bind the provider.
       * @param provider      The {@link android.content.BroadcastReceiver} that will be the AppWidget
       *                      provider for this AppWidget.
       * @return true if this component has permission to bind the AppWidget
       */
      public boolean bindAppWidgetIdIfAllowed(int appWidgetId, ComponentName provider) {
          if (mService == null) {
              return false;
          }
          return bindAppWidgetIdIfAllowed(appWidgetId, mContext.getUserId(), provider, null);
      }
  
      /**
       * Set the component for a given appWidgetId.
       *
       * <p class="note">You need the BIND_APPWIDGET permission or the user must have enabled binding
       *         widgets always for your component. Should be used by apps that host widgets; if this
       *         method returns false, call {@link #ACTION_APPWIDGET_BIND} to request permission to
       *         bind
       *
       * @param appWidgetId The AppWidget id under which to bind the provider.
       * @param provider      The {@link android.content.BroadcastReceiver} that will be the AppWidget
       *                      provider for this AppWidget.
       * @param options       Bundle containing options for the AppWidget. See also
       *                      {@link #updateAppWidgetOptions(int, Bundle)}
       *
       * @return true if this component has permission to bind the AppWidget
       */
      public boolean bindAppWidgetIdIfAllowed(int appWidgetId, ComponentName provider,
              Bundle options) {
          if (mService == null) {
              return false;
          }
          return bindAppWidgetIdIfAllowed(appWidgetId, mContext.getUserId(), provider, options);
      }
  
      /**
       * Set the provider for a given appWidgetId if the caller has a permission.
       * <p>
       * <strong>Note:</strong> You need the {@link android.Manifest.permission#BIND_APPWIDGET}
       * permission or the user must have enabled binding widgets always for your component.
       * Should be used by apps that host widgets. If this method returns false, call {@link
       * #ACTION_APPWIDGET_BIND} to request permission to bind.
       * </p>
       *
       * @param appWidgetId The AppWidget id under which to bind the provider.
       * @param user The user id in which the provider resides.
       * @param provider The component name of the provider.
       * @param options An optional Bundle containing options for the AppWidget.
       *
       * @return true if this component has permission to bind the AppWidget
       */
      public boolean bindAppWidgetIdIfAllowed(int appWidgetId, UserHandle user,
              ComponentName provider, Bundle options) {
          if (mService == null) {
              return false;
          }
          return bindAppWidgetIdIfAllowed(appWidgetId, user.getIdentifier(), provider, options);
      }
  
      /**
       * Query if a given package was granted permission by the user to bind app widgets
       *
       * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
       *
       * @param packageName The package for which the permission is being queried
       * @param userId The user id of the user under which the package runs.
       * @return true if the package was granted permission by the user to bind app widgets
       * @hide
       */
      public boolean hasBindAppWidgetPermission(String packageName, int userId) {
          if (mService == null) {
              return false;
          }
          try {
              return mService.hasBindAppWidgetPermission(packageName, userId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Query if a given package was granted permission by the user to bind app widgets
       *
       * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
       *
       * @param packageName        The package for which the permission is being queried
       * @return true if the package was granted permission by the user to bind app widgets
       * @hide
       */
      public boolean hasBindAppWidgetPermission(String packageName) {
          if (mService == null) {
              return false;
          }
          try {
              return mService.hasBindAppWidgetPermission(packageName, mContext.getUserId());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Changes any user-granted permission for the given package to bind app widgets
       *
       * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
       *
       * @param packageName The package whose permission is being changed
       * @param permission Whether to give the package permission to bind widgets
       *
       * @hide
       */
      public void setBindAppWidgetPermission(String packageName, boolean permission) {
          if (mService == null) {
              return;
          }
          setBindAppWidgetPermission(packageName, mContext.getUserId(), permission);
      }
  
      /**
       * Changes any user-granted permission for the given package to bind app widgets
       *
       * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
       *
       * @param packageName The package whose permission is being changed
       * @param userId The user under which the package is running.
       * @param permission Whether to give the package permission to bind widgets
       *
       * @hide
       */
      public void setBindAppWidgetPermission(String packageName, int userId, boolean permission) {
          if (mService == null) {
              return;
          }
          try {
              mService.setBindAppWidgetPermission(packageName, userId, permission);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Binds the RemoteViewsService for a given appWidgetId and intent.
       *
       * The appWidgetId specified must already be bound to the calling AppWidgetHost via
       * {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
       *
       * @param appWidgetId   The AppWidget instance for which to bind the RemoteViewsService.
       * @param intent        The intent of the service which will be providing the data to the
       *                      RemoteViewsAdapter.
       * @param connection    The callback interface to be notified when a connection is made or lost.
       * @param flags         Flags used for binding to the service
       *
       * @see Context#getServiceDispatcher(ServiceConnection, Handler, int)
       * @hide
       */
      @UnsupportedAppUsage
      public boolean bindRemoteViewsService(Context context, int appWidgetId, Intent intent,
              IServiceConnection connection, @Context.BindServiceFlags int flags) {
          if (mService == null) {
              return false;
          }
          try {
              return mService.bindRemoteViewsService(context.getOpPackageName(), appWidgetId, intent,
                      context.getIApplicationThread(), context.getActivityToken(), connection, flags);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Get the list of appWidgetIds that have been bound to the given AppWidget
       * provider.
       *
       * @param provider The {@link android.content.BroadcastReceiver} that is the
       *            AppWidget provider to find appWidgetIds for.
       */
      public int[] getAppWidgetIds(ComponentName provider) {
          if (mService == null) {
              return new int[0];
          }
          try {
              return mService.getAppWidgetIds(provider);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * @hide
       */
      public boolean isBoundWidgetPackage(String packageName, int userId) {
          if (mService == null) {
              return false;
          }
          try {
              return mService.isBoundWidgetPackage(packageName, userId);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      @UnsupportedAppUsage
      private boolean bindAppWidgetIdIfAllowed(int appWidgetId, int profileId,
              ComponentName provider, Bundle options) {
          if (mService == null) {
              return false;
          }
          try {
              return mService.bindAppWidgetId(mPackageName, appWidgetId,
                      profileId, provider, options);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Return {@code TRUE} if the default launcher supports
       * {@link #requestPinAppWidget(ComponentName, Bundle, PendingIntent)}
       */
      public boolean isRequestPinAppWidgetSupported() {
          try {
              return mService.isRequestPinAppWidgetSupported();
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Only used during development. Can be deleted before release.
       * @hide
       */
      public boolean requestPinAppWidget(@NonNull ComponentName provider,
              @Nullable PendingIntent successCallback) {
          return requestPinAppWidget(provider, null, successCallback);
      }
  
      /**
       * Request to pin an app widget on the current launcher. It's up to the launcher to accept this
       * request (optionally showing a user confirmation). If the request is accepted, the caller will
       * get a confirmation with extra {@link #EXTRA_APPWIDGET_ID}.
       *
       * <p>When a request is denied by the user, the caller app will not get any response.
       *
       * <p>Only apps with a foreground activity or a foreground service can call it.  Otherwise
       * it'll throw {@link IllegalStateException}.
       *
       * <p>It's up to the launcher how to handle previous pending requests when the same package
       * calls this API multiple times in a row.  It may ignore the previous requests,
       * for example.
       *
       * <p>Launcher will not show the configuration activity associated with the provider in this
       * case. The app could either show the configuration activity as a response to the callback,
       * or show if before calling the API (various configurations can be encapsulated in
       * {@code successCallback} to avoid persisting them before the widgetId is known).
       *
       * @param provider The {@link ComponentName} for the {@link
       *    android.content.BroadcastReceiver BroadcastReceiver} provider for your AppWidget.
       * @param extras In not null, this is passed to the launcher app. For eg {@link
       *    #EXTRA_APPWIDGET_PREVIEW} can be used for a custom preview.
       * @param successCallback If not null, this intent will be sent when the widget is created.
       *
       * @return {@code TRUE} if the launcher supports this feature. Note the API will return without
       *    waiting for the user to respond, so getting {@code TRUE} from this API does *not* mean
       *    the shortcut is pinned. {@code FALSE} if the launcher doesn't support this feature.
       *
       * @see android.content.pm.ShortcutManager#isRequestPinShortcutSupported()
       * @see android.content.pm.ShortcutManager#requestPinShortcut(ShortcutInfo, IntentSender)
       * @see #isRequestPinAppWidgetSupported()
       *
       * @throws IllegalStateException The caller doesn't have a foreground activity or a foreground
       * service or when the user is locked.
       */
      public boolean requestPinAppWidget(@NonNull ComponentName provider,
              @Nullable Bundle extras, @Nullable PendingIntent successCallback) {
          try {
              return mService.requestPinAppWidget(mPackageName, provider, extras,
                      successCallback == null ? null : successCallback.getIntentSender());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  }
  