content: 
  package com.android.launcher3.model;
  
  import static android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_HIDE_FROM_PICKER;
  
  import android.appwidget.AppWidgetProviderInfo;
  import android.content.Context;
  import android.content.pm.PackageManager;
  import android.os.Process;
  import android.os.UserHandle;
  import android.util.Log;
  
  import com.android.launcher3.AppFilter;
  import com.android.launcher3.icons.ComponentWithLabel;
  import com.android.launcher3.icons.IconCache;
  import com.android.launcher3.InvariantDeviceProfile;
  import com.android.launcher3.LauncherAppState;
  import com.android.launcher3.LauncherAppWidgetProviderInfo;
  import com.android.launcher3.Utilities;
  import com.android.launcher3.compat.AlphabeticIndexCompat;
  import com.android.launcher3.compat.AppWidgetManagerCompat;
  import com.android.launcher3.compat.LauncherAppsCompat;
  import com.android.launcher3.compat.ShortcutConfigActivityInfo;
  import com.android.launcher3.config.FeatureFlags;
  import com.android.launcher3.util.MultiHashMap;
  import com.android.launcher3.util.PackageUserKey;
  import com.android.launcher3.util.Preconditions;
  import com.android.launcher3.widget.WidgetItemComparator;
  import com.android.launcher3.widget.WidgetListRowEntry;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Map.Entry;
  import java.util.Set;
  
  import androidx.annotation.Nullable;
  
  /**
   * Widgets data model that is used by the adapters of the widget views and controllers.
   *
   * <p> The widgets and shortcuts are organized using package name as its index.
   */
  public class WidgetsModel {
  
      private static final String TAG = "WidgetsModel";
      private static final boolean DEBUG = false;
  
      /* Map of widgets and shortcuts that are tracked per package. */
      private final MultiHashMap<PackageItemInfo, WidgetItem> mWidgetsList = new MultiHashMap<>();
  
      private AppFilter mAppFilter;
  
      /**
       * Returns a list of {@link WidgetListRowEntry}. All {@link WidgetItem} in a single row
       * are sorted (based on label and user), but the overall list of {@link WidgetListRowEntry}s
       * is not sorted. This list is sorted at the UI when using
       * {@link com.android.launcher3.widget.WidgetsDiffReporter}
       *
       * @see com.android.launcher3.widget.WidgetsListAdapter#setWidgets(ArrayList)
       */
      public synchronized ArrayList<WidgetListRowEntry> getWidgetsList(Context context) {
          ArrayList<WidgetListRowEntry> result = new ArrayList<>();
          AlphabeticIndexCompat indexer = new AlphabeticIndexCompat(context);
  
          WidgetItemComparator widgetComparator = new WidgetItemComparator();
          for (Map.Entry<PackageItemInfo, ArrayList<WidgetItem>> entry : mWidgetsList.entrySet()) {
              WidgetListRowEntry row = new WidgetListRowEntry(entry.getKey(), entry.getValue());
              row.titleSectionName = (row.pkgItem.title == null) ? "" :
                      indexer.computeSectionName(row.pkgItem.title);
              Collections.sort(row.widgets, widgetComparator);
              result.add(row);
          }
          return result;
      }
  
      /**
       * @param packageUser If null, all widgets and shortcuts are updated and returned, otherwise
       *                    only widgets and shortcuts associated with the package/user are.
       */
      public List<ComponentWithLabel> update(LauncherAppState app, @Nullable PackageUserKey packageUser) {
          Preconditions.assertWorkerThread();
  
          Context context = app.getContext();
          final ArrayList<WidgetItem> widgetsAndShortcuts = new ArrayList<>();
          List<ComponentWithLabel> updatedItems = new ArrayList<>();
          try {
              InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
              PackageManager pm = app.getContext().getPackageManager();
  
              // Widgets
              AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(context);
              for (AppWidgetProviderInfo widgetInfo : widgetManager.getAllProviders(packageUser)) {
                  LauncherAppWidgetProviderInfo launcherWidgetInfo =
                          LauncherAppWidgetProviderInfo.fromProviderInfo(context, widgetInfo);
  
                  widgetsAndShortcuts.add(new WidgetItem(
                          launcherWidgetInfo, idp, app.getIconCache()));
                  updatedItems.add(launcherWidgetInfo);
              }
  
              // Shortcuts
              for (ShortcutConfigActivityInfo info : LauncherAppsCompat.getInstance(context)
                      .getCustomShortcutActivityList(packageUser)) {
                  widgetsAndShortcuts.add(new WidgetItem(info, app.getIconCache(), pm));
                  updatedItems.add(info);
              }
              setWidgetsAndShortcuts(widgetsAndShortcuts, app, packageUser);
          } catch (Exception e) {
              if (!FeatureFlags.IS_DOGFOOD_BUILD && Utilities.isBinderSizeError(e)) {
                  // the returned value may be incomplete and will not be refreshed until the next
                  // time Launcher starts.
                  // TODO: after figuring out a repro step, introduce a dirty bit to check when
                  // onResume is called to refresh the widget provider list.
              } else {
                  throw e;
              }
          }
  
          app.getWidgetCache().removeObsoletePreviews(widgetsAndShortcuts, packageUser);
          return updatedItems;
      }
  
      private synchronized void setWidgetsAndShortcuts(ArrayList<WidgetItem> rawWidgetsShortcuts,
              LauncherAppState app, @Nullable PackageUserKey packageUser) {
          if (DEBUG) {
              Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size());
          }
  
          // Temporary list for {@link PackageItemInfos} to avoid having to go through
          // {@link mPackageItemInfos} to locate the key to be used for {@link #mWidgetsList}
          HashMap<String, PackageItemInfo> tmpPackageItemInfos = new HashMap<>();
  
          // clear the lists.
          if (packageUser == null) {
              mWidgetsList.clear();
          } else {
              // Only clear the widgets for the given package/user.
              PackageItemInfo packageItem = null;
              for (PackageItemInfo item : mWidgetsList.keySet()) {
                  if (item.packageName.equals(packageUser.mPackageName)) {
                      packageItem = item;
                      break;
                  }
              }
              if (packageItem != null) {
                  // We want to preserve the user that was on the packageItem previously,
                  // so add it to tmpPackageItemInfos here to avoid creating a new entry.
                  tmpPackageItemInfos.put(packageItem.packageName, packageItem);
  
                  Iterator<WidgetItem> widgetItemIterator = mWidgetsList.get(packageItem).iterator();
                  while (widgetItemIterator.hasNext()) {
                      WidgetItem nextWidget = widgetItemIterator.next();
                      if (nextWidget.componentName.getPackageName().equals(packageUser.mPackageName)
                              && nextWidget.user.equals(packageUser.mUser)) {
                          widgetItemIterator.remove();
                      }
                  }
              }
          }
  
          InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
          UserHandle myUser = Process.myUserHandle();
  
          // add and update.
          for (WidgetItem item : rawWidgetsShortcuts) {
              if (item.widgetInfo != null) {
                  if ((item.widgetInfo.getWidgetFeatures() & WIDGET_FEATURE_HIDE_FROM_PICKER) != 0) {
                      // Widget is hidden from picker
                      continue;
                  }
  
                  // Ensure that all widgets we show can be added on a workspace of this size
                  int minSpanX = Math.min(item.widgetInfo.spanX, item.widgetInfo.minSpanX);
                  int minSpanY = Math.min(item.widgetInfo.spanY, item.widgetInfo.minSpanY);
                  if (minSpanX > idp.numColumns || minSpanY > idp.numRows) {
                      if (DEBUG) {
                          Log.d(TAG, String.format(
                                  "Widget %s : (%d X %d) can't fit on this device",
                                  item.componentName, minSpanX, minSpanY));
                      }
                      continue;
                  }
              }
  
              if (mAppFilter == null) {
                  mAppFilter = AppFilter.newInstance(app.getContext());
              }
              if (!mAppFilter.shouldShowApp(item.componentName, item.user)) {
                  if (DEBUG) {
                      Log.d(TAG, String.format("%s is filtered and not added to the widget tray.",
                              item.componentName));
                  }
                  continue;
              }
  
              String packageName = item.componentName.getPackageName();
              PackageItemInfo pInfo = tmpPackageItemInfos.get(packageName);
              if (pInfo == null) {
                  pInfo = new PackageItemInfo(packageName);
                  pInfo.user = item.user;
                  tmpPackageItemInfos.put(packageName,  pInfo);
              } else if (!myUser.equals(pInfo.user)) {
                  // Keep updating the user, until we get the primary user.
                  pInfo.user = item.user;
              }
              mWidgetsList.addToList(pInfo, item);
          }
  
          // Update each package entry
          IconCache iconCache = app.getIconCache();
          for (PackageItemInfo p : tmpPackageItemInfos.values()) {
              iconCache.getTitleAndIconForApp(p, true /* userLowResIcon */);
          }
      }
  
      public void onPackageIconsUpdated(Set<String> packageNames, UserHandle user,
              LauncherAppState app) {
          for (Entry<PackageItemInfo, ArrayList<WidgetItem>> entry : mWidgetsList.entrySet()) {
              if (packageNames.contains(entry.getKey().packageName)) {
                  ArrayList<WidgetItem> items = entry.getValue();
                  int count = items.size();
                  for (int i = 0; i < count; i++) {
                      WidgetItem item = items.get(i);
                      if (item.user.equals(user)) {
                          if (item.activityInfo != null) {
                              items.set(i, new WidgetItem(item.activityInfo, app.getIconCache(),
                                      app.getContext().getPackageManager()));
                          } else {
                              items.set(i, new WidgetItem(item.widgetInfo,
                                      app.getInvariantDeviceProfile(), app.getIconCache()));
                          }
                      }
                  }
              }
          }
      }
  }