1 2 package com.android.launcher3.model; 3 4 import android.content.ComponentName; 5 import android.content.Context; 6 import android.content.pm.ResolveInfo; 7 import android.util.Log; 8 9 import com.android.launcher3.AppFilter; 10 import com.android.launcher3.IconCache; 11 import com.android.launcher3.LauncherAppWidgetProviderInfo; 12 import com.android.launcher3.Utilities; 13 import com.android.launcher3.compat.AlphabeticIndexCompat; 14 import com.android.launcher3.compat.AppWidgetManagerCompat; 15 import com.android.launcher3.compat.UserHandleCompat; 16 17 import java.util.ArrayList; 18 import java.util.Collections; 19 import java.util.Comparator; 20 import java.util.HashMap; 21 import java.util.List; 22 23 /** 24 * Widgets data model that is used by the adapters of the widget views and controllers. 25 * 26 * <p> The widgets and shortcuts are organized using package name as its index. 27 */ 28 public class WidgetsModel { 29 30 private static final String TAG = "WidgetsModel"; 31 private static final boolean DEBUG = false; 32 33 /* List of packages that is tracked by this model. */ 34 private ArrayList<PackageItemInfo> mPackageItemInfos = new ArrayList<>(); 35 36 /* Map of widgets and shortcuts that are tracked per package. */ 37 private HashMap<PackageItemInfo, ArrayList<Object>> mWidgetsList = new HashMap<>(); 38 39 private ArrayList<Object> mRawList; 40 41 private final AppWidgetManagerCompat mAppWidgetMgr; 42 private final Comparator mWidgetAndShortcutNameComparator; 43 private final Comparator mAppNameComparator; 44 private final IconCache mIconCache; 45 private final AppFilter mAppFilter; 46 private AlphabeticIndexCompat mIndexer; 47 48 public WidgetsModel(Context context, IconCache iconCache, AppFilter appFilter) { 49 mAppWidgetMgr = AppWidgetManagerCompat.getInstance(context); 50 mWidgetAndShortcutNameComparator = new WidgetsAndShortcutNameComparator(context); 51 mAppNameComparator = (new AppNameComparator(context)).getAppInfoComparator(); 52 mIconCache = iconCache; 53 mAppFilter = appFilter; 54 mIndexer = new AlphabeticIndexCompat(context); 55 } 56 57 private WidgetsModel(WidgetsModel model) { 58 mAppWidgetMgr = model.mAppWidgetMgr; 59 mPackageItemInfos = (ArrayList<PackageItemInfo>) model.mPackageItemInfos.clone(); 60 mWidgetsList = (HashMap<PackageItemInfo, ArrayList<Object>>) model.mWidgetsList.clone(); 61 mRawList = (ArrayList<Object>) model.mRawList.clone(); 62 mWidgetAndShortcutNameComparator = model.mWidgetAndShortcutNameComparator; 63 mAppNameComparator = model.mAppNameComparator; 64 mIconCache = model.mIconCache; 65 mAppFilter = model.mAppFilter; 66 } 67 68 // Access methods that may be deleted if the private fields are made package-private. 69 public int getPackageSize() { 70 if (mPackageItemInfos == null) { 71 return 0; 72 } 73 return mPackageItemInfos.size(); 74 } 75 76 // Access methods that may be deleted if the private fields are made package-private. 77 public PackageItemInfo getPackageItemInfo(int pos) { 78 if (pos >= mPackageItemInfos.size() || pos < 0) { 79 return null; 80 } 81 return mPackageItemInfos.get(pos); 82 } 83 84 public List<Object> getSortedWidgets(int pos) { 85 return mWidgetsList.get(mPackageItemInfos.get(pos)); 86 } 87 88 public ArrayList<Object> getRawList() { 89 return mRawList; 90 } 91 92 public void setWidgetsAndShortcuts(ArrayList<Object> rawWidgetsShortcuts) { 93 Utilities.assertWorkerThread(); 94 mRawList = rawWidgetsShortcuts; 95 if (DEBUG) { 96 Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size()); 97 } 98 99 // Temporary list for {@link PackageItemInfos} to avoid having to go through 100 // {@link mPackageItemInfos} to locate the key to be used for {@link #mWidgetsList} 101 HashMap<String, PackageItemInfo> tmpPackageItemInfos = new HashMap<>(); 102 103 // clear the lists. 104 mWidgetsList.clear(); 105 mPackageItemInfos.clear(); 106 107 // add and update. 108 for (Object o: rawWidgetsShortcuts) { 109 String packageName = ""; 110 UserHandleCompat userHandle = null; 111 ComponentName componentName = null; 112 if (o instanceof LauncherAppWidgetProviderInfo) { 113 LauncherAppWidgetProviderInfo widgetInfo = (LauncherAppWidgetProviderInfo) o; 114 componentName = widgetInfo.provider; 115 packageName = widgetInfo.provider.getPackageName(); 116 userHandle = mAppWidgetMgr.getUser(widgetInfo); 117 } else if (o instanceof ResolveInfo) { 118 ResolveInfo resolveInfo = (ResolveInfo) o; 119 componentName = new ComponentName(resolveInfo.activityInfo.packageName, 120 resolveInfo.activityInfo.name); 121 packageName = resolveInfo.activityInfo.packageName; 122 userHandle = UserHandleCompat.myUserHandle(); 123 } 124 125 if (componentName == null || userHandle == null) { 126 Log.e(TAG, String.format("Widget cannot be set for %s.", o.getClass().toString())); 127 continue; 128 } 129 if (mAppFilter != null && !mAppFilter.shouldShowApp(componentName)) { 130 if (DEBUG) { 131 Log.d(TAG, String.format("%s is filtered and not added to the widget tray.", 132 packageName)); 133 } 134 continue; 135 } 136 137 PackageItemInfo pInfo = tmpPackageItemInfos.get(packageName); 138 ArrayList<Object> widgetsShortcutsList = mWidgetsList.get(pInfo); 139 if (widgetsShortcutsList != null) { 140 widgetsShortcutsList.add(o); 141 } else { 142 widgetsShortcutsList = new ArrayList<Object>(); 143 widgetsShortcutsList.add(o); 144 pInfo = new PackageItemInfo(packageName); 145 mIconCache.getTitleAndIconForApp(packageName, userHandle, 146 true /* userLowResIcon */, pInfo); 147 pInfo.titleSectionName = mIndexer.computeSectionName(pInfo.title); 148 mWidgetsList.put(pInfo, widgetsShortcutsList); 149 tmpPackageItemInfos.put(packageName, pInfo); 150 mPackageItemInfos.add(pInfo); 151 } 152 } 153 154 // sort. 155 Collections.sort(mPackageItemInfos, mAppNameComparator); 156 for (PackageItemInfo p: mPackageItemInfos) { 157 Collections.sort(mWidgetsList.get(p), mWidgetAndShortcutNameComparator); 158 } 159 } 160 161 /** 162 * Create a snapshot of the widgets model. 163 * <p> 164 * Usage case: view binding without being modified from package updates. 165 */ 166 @Override 167 public WidgetsModel clone(){ 168 return new WidgetsModel(this); 169 } 170 }