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