package com.android.launcher3.model; import android.content.ComponentName; import android.content.Context; import android.content.pm.ResolveInfo; import android.util.Log; import com.android.launcher3.AppFilter; import com.android.launcher3.AppInfo; import com.android.launcher3.IconCache; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.ProtectedComponentsHelper; import com.android.launcher3.Utilities; import com.android.launcher3.compat.AlphabeticIndexCompat; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.UserHandleCompat; import cyanogenmod.providers.CMSettings; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; /** * Widgets data model that is used by the adapters of the widget views and controllers. * *

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; /* List of packages that is tracked by this model. */ private ArrayList mPackageItemInfos = new ArrayList<>(); /* Map of widgets and shortcuts that are tracked per package. */ private HashMap> mWidgetsList = new HashMap<>(); private ArrayList mRawList; private Context mContext; private final AppWidgetManagerCompat mAppWidgetMgr; private final WidgetsAndShortcutNameComparator mWidgetAndShortcutNameComparator; private final Comparator mAppNameComparator; private final IconCache mIconCache; private final AppFilter mAppFilter; private AlphabeticIndexCompat mIndexer; public WidgetsModel(Context context, IconCache iconCache, AppFilter appFilter) { mContext = context; mAppWidgetMgr = AppWidgetManagerCompat.getInstance(context); mWidgetAndShortcutNameComparator = new WidgetsAndShortcutNameComparator(context); mAppNameComparator = (new AppNameComparator(context)).getAppInfoComparator(); mIconCache = iconCache; mAppFilter = appFilter; mIndexer = new AlphabeticIndexCompat(context); } @SuppressWarnings("unchecked") private WidgetsModel(WidgetsModel model) { mAppWidgetMgr = model.mAppWidgetMgr; mPackageItemInfos = (ArrayList) model.mPackageItemInfos.clone(); mWidgetsList = (HashMap>) model.mWidgetsList.clone(); mRawList = (ArrayList) model.mRawList.clone(); mWidgetAndShortcutNameComparator = model.mWidgetAndShortcutNameComparator; mAppNameComparator = model.mAppNameComparator; mIconCache = model.mIconCache; mAppFilter = model.mAppFilter; } // Access methods that may be deleted if the private fields are made package-private. public int getPackageSize() { if (mPackageItemInfos == null) { return 0; } return mPackageItemInfos.size(); } // Access methods that may be deleted if the private fields are made package-private. public PackageItemInfo getPackageItemInfo(int pos) { if (pos >= mPackageItemInfos.size() || pos < 0) { return null; } return mPackageItemInfos.get(pos); } public List getSortedWidgets(int pos) { return mWidgetsList.get(mPackageItemInfos.get(pos)); } public ArrayList getRawList() { return mRawList; } public void setWidgetsAndShortcuts(ArrayList rawWidgetsShortcuts) { Utilities.assertWorkerThread(); mRawList = rawWidgetsShortcuts; 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 tmpPackageItemInfos = new HashMap<>(); // clear the lists. mWidgetsList.clear(); mPackageItemInfos.clear(); mWidgetAndShortcutNameComparator.reset(); InvariantDeviceProfile idp = LauncherAppState.getInstance().getInvariantDeviceProfile(); ProtectedComponentsHelper.updateProtectedComponentsLists(mContext); // add and update. for (Object o: rawWidgetsShortcuts) { String packageName = ""; UserHandleCompat userHandle = null; ComponentName componentName = null; if (o instanceof LauncherAppWidgetProviderInfo) { LauncherAppWidgetProviderInfo widgetInfo = (LauncherAppWidgetProviderInfo) o; // Ensure that all widgets we show can be added on a workspace of this size int minSpanX = Math.min(widgetInfo.spanX, widgetInfo.minSpanX); int minSpanY = Math.min(widgetInfo.spanY, widgetInfo.minSpanY); if (minSpanX <= (int) idp.numColumns && minSpanY <= (int) idp.numRows) { componentName = widgetInfo.provider; packageName = widgetInfo.provider.getPackageName(); userHandle = mAppWidgetMgr.getUser(widgetInfo); } else { if (DEBUG) { Log.d(TAG, String.format( "Widget %s : (%d X %d) can't fit on this device", widgetInfo.provider, minSpanX, minSpanY)); } continue; } } else if (o instanceof ResolveInfo) { ResolveInfo resolveInfo = (ResolveInfo) o; componentName = new ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name); packageName = resolveInfo.activityInfo.packageName; userHandle = UserHandleCompat.myUserHandle(); } if (componentName == null || userHandle == null) { Log.e(TAG, String.format("Widget cannot be set for %s.", o.getClass().toString())); continue; } if (mAppFilter != null && !mAppFilter.shouldShowApp(componentName)) { if (DEBUG) { Log.d(TAG, String.format("%s is filtered and not added to the widget tray.", packageName)); } continue; } PackageItemInfo pInfo = tmpPackageItemInfos.get(packageName); ArrayList widgetsShortcutsList = mWidgetsList.get(pInfo); if (widgetsShortcutsList != null) { if (pInfo != null && ProtectedComponentsHelper.isProtectedPackage(pInfo.flags, packageName)) { continue; } widgetsShortcutsList.add(o); } else { pInfo = new PackageItemInfo(packageName); if (ProtectedComponentsHelper.isProtectedPackage(pInfo.flags, packageName)) { continue; } widgetsShortcutsList = new ArrayList<>(); widgetsShortcutsList.add(o); mIconCache.getTitleAndIconForApp(packageName, userHandle, true /* userLowResIcon */, pInfo); pInfo.titleSectionName = mIndexer.computeSectionName(pInfo.title); mWidgetsList.put(pInfo, widgetsShortcutsList); tmpPackageItemInfos.put(packageName, pInfo); mPackageItemInfos.add(pInfo); } } // sort. Collections.sort(mPackageItemInfos, mAppNameComparator); for (PackageItemInfo p: mPackageItemInfos) { Collections.sort(mWidgetsList.get(p), mWidgetAndShortcutNameComparator); } } /** * Create a snapshot of the widgets model. *

* Usage case: view binding without being modified from package updates. */ @Override public WidgetsModel clone(){ return new WidgetsModel(this); } }