2015-04-08 19:01:34 -07:00
|
|
|
|
2015-05-21 13:04:53 -07:00
|
|
|
package com.android.launcher3.model;
|
2015-04-08 19:01:34 -07:00
|
|
|
|
2016-03-03 16:58:55 -08:00
|
|
|
import android.appwidget.AppWidgetProviderInfo;
|
2015-04-08 19:01:34 -07:00
|
|
|
import android.content.Context;
|
2016-03-10 12:02:29 -08:00
|
|
|
import android.content.pm.PackageManager;
|
2016-12-15 15:53:17 -08:00
|
|
|
import android.os.Process;
|
|
|
|
|
import android.os.UserHandle;
|
2017-03-29 15:30:43 -07:00
|
|
|
import android.support.annotation.Nullable;
|
2015-04-08 19:01:34 -07:00
|
|
|
import android.util.Log;
|
|
|
|
|
|
2015-06-17 21:12:44 -07:00
|
|
|
import com.android.launcher3.AppFilter;
|
2015-04-08 19:01:34 -07:00
|
|
|
import com.android.launcher3.IconCache;
|
2015-08-03 13:05:01 -07:00
|
|
|
import com.android.launcher3.InvariantDeviceProfile;
|
|
|
|
|
import com.android.launcher3.LauncherAppState;
|
2015-04-08 19:01:34 -07:00
|
|
|
import com.android.launcher3.LauncherAppWidgetProviderInfo;
|
2016-11-04 10:19:58 -07:00
|
|
|
import com.android.launcher3.Utilities;
|
2017-10-10 15:21:15 -07:00
|
|
|
import com.android.launcher3.compat.AlphabeticIndexCompat;
|
2015-07-16 17:24:30 -07:00
|
|
|
import com.android.launcher3.compat.AppWidgetManagerCompat;
|
2017-01-19 10:27:54 -08:00
|
|
|
import com.android.launcher3.compat.LauncherAppsCompat;
|
|
|
|
|
import com.android.launcher3.compat.ShortcutConfigActivityInfo;
|
2017-03-06 16:56:39 -08:00
|
|
|
import com.android.launcher3.config.FeatureFlags;
|
2016-10-12 20:49:31 -07:00
|
|
|
import com.android.launcher3.util.MultiHashMap;
|
2017-03-29 15:30:43 -07:00
|
|
|
import com.android.launcher3.util.PackageUserKey;
|
2016-04-15 18:03:27 -07:00
|
|
|
import com.android.launcher3.util.Preconditions;
|
2017-10-10 15:21:15 -07:00
|
|
|
import com.android.launcher3.widget.WidgetItemComparator;
|
|
|
|
|
import com.android.launcher3.widget.WidgetListRowEntry;
|
2015-04-08 19:01:34 -07:00
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
2017-10-10 15:21:15 -07:00
|
|
|
import java.util.Collections;
|
2015-04-08 19:01:34 -07:00
|
|
|
import java.util.HashMap;
|
2017-03-29 15:30:43 -07:00
|
|
|
import java.util.Iterator;
|
2017-10-10 15:21:15 -07:00
|
|
|
import java.util.Map;
|
2015-04-08 19:01:34 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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. */
|
2017-06-02 13:46:55 -07:00
|
|
|
private final MultiHashMap<PackageItemInfo, WidgetItem> mWidgetsList = new MultiHashMap<>();
|
2015-04-08 19:01:34 -07:00
|
|
|
|
2017-06-02 13:46:55 -07:00
|
|
|
private AppFilter mAppFilter;
|
2015-04-08 19:01:34 -07:00
|
|
|
|
2017-10-10 15:21:15 -07:00
|
|
|
/**
|
|
|
|
|
* 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 = indexer.computeSectionName(row.pkgItem.title);
|
|
|
|
|
Collections.sort(row.widgets, widgetComparator);
|
|
|
|
|
result.add(row);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
2016-03-03 16:58:55 -08:00
|
|
|
}
|
|
|
|
|
|
2017-03-29 15:30:43 -07:00
|
|
|
/**
|
|
|
|
|
* @param packageUser If null, all widgets and shortcuts are updated and returned, otherwise
|
|
|
|
|
* only widgets and shortcuts associated with the package/user are.
|
|
|
|
|
*/
|
2017-06-02 13:46:55 -07:00
|
|
|
public void update(LauncherAppState app, @Nullable PackageUserKey packageUser) {
|
2016-04-15 18:03:27 -07:00
|
|
|
Preconditions.assertWorkerThread();
|
2016-03-03 16:58:55 -08:00
|
|
|
|
2017-06-02 13:46:55 -07:00
|
|
|
Context context = app.getContext();
|
2016-10-12 20:49:31 -07:00
|
|
|
final ArrayList<WidgetItem> widgetsAndShortcuts = new ArrayList<>();
|
2016-03-03 16:58:55 -08:00
|
|
|
try {
|
2016-12-16 15:04:51 -08:00
|
|
|
PackageManager pm = context.getPackageManager();
|
2017-06-02 13:46:55 -07:00
|
|
|
InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
|
2016-12-16 15:04:51 -08:00
|
|
|
|
2016-03-03 16:58:55 -08:00
|
|
|
// Widgets
|
2017-03-29 15:30:43 -07:00
|
|
|
AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(context);
|
|
|
|
|
for (AppWidgetProviderInfo widgetInfo : widgetManager.getAllProviders(packageUser)) {
|
2017-01-11 10:48:34 -08:00
|
|
|
widgetsAndShortcuts.add(new WidgetItem(LauncherAppWidgetProviderInfo
|
|
|
|
|
.fromProviderInfo(context, widgetInfo), pm, idp));
|
2016-03-03 16:58:55 -08:00
|
|
|
}
|
2016-03-10 12:02:29 -08:00
|
|
|
|
2016-03-03 16:58:55 -08:00
|
|
|
// Shortcuts
|
2017-01-19 10:27:54 -08:00
|
|
|
for (ShortcutConfigActivityInfo info : LauncherAppsCompat.getInstance(context)
|
2017-03-29 15:30:43 -07:00
|
|
|
.getCustomShortcutActivityList(packageUser)) {
|
2017-01-19 10:27:54 -08:00
|
|
|
widgetsAndShortcuts.add(new WidgetItem(info));
|
2016-03-10 12:02:29 -08:00
|
|
|
}
|
2017-06-02 13:46:55 -07:00
|
|
|
setWidgetsAndShortcuts(widgetsAndShortcuts, app, packageUser);
|
2016-03-03 16:58:55 -08:00
|
|
|
} catch (Exception e) {
|
2017-03-06 16:56:39 -08:00
|
|
|
if (!FeatureFlags.IS_DOGFOOD_BUILD && Utilities.isBinderSizeError(e)) {
|
2016-03-03 16:58:55 -08:00
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-02 13:46:55 -07:00
|
|
|
|
|
|
|
|
app.getWidgetCache().removeObsoletePreviews(widgetsAndShortcuts, packageUser);
|
2016-03-03 16:58:55 -08:00
|
|
|
}
|
|
|
|
|
|
2017-06-02 13:46:55 -07:00
|
|
|
private synchronized void setWidgetsAndShortcuts(ArrayList<WidgetItem> rawWidgetsShortcuts,
|
|
|
|
|
LauncherAppState app, @Nullable PackageUserKey packageUser) {
|
2015-04-08 19:01:34 -07:00
|
|
|
if (DEBUG) {
|
2015-05-21 13:04:53 -07:00
|
|
|
Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size());
|
2015-04-08 19:01:34 -07:00
|
|
|
}
|
|
|
|
|
|
2015-04-11 15:44:32 -07:00
|
|
|
// 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<>();
|
2015-04-14 11:50:44 -07:00
|
|
|
|
2015-04-08 19:01:34 -07:00
|
|
|
// clear the lists.
|
2017-03-29 15:30:43 -07:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-04-08 19:01:34 -07:00
|
|
|
|
2017-06-02 13:46:55 -07:00
|
|
|
InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
|
2016-12-15 15:53:17 -08:00
|
|
|
UserHandle myUser = Process.myUserHandle();
|
2015-08-03 13:05:01 -07:00
|
|
|
|
2015-04-08 19:01:34 -07:00
|
|
|
// add and update.
|
2017-03-29 15:30:43 -07:00
|
|
|
for (WidgetItem item : rawWidgetsShortcuts) {
|
2016-03-10 12:02:29 -08:00
|
|
|
if (item.widgetInfo != null) {
|
2015-08-03 13:05:01 -07:00
|
|
|
// Ensure that all widgets we show can be added on a workspace of this size
|
2016-03-10 12:02:29 -08:00
|
|
|
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) {
|
2015-08-03 13:05:01 -07:00
|
|
|
if (DEBUG) {
|
|
|
|
|
Log.d(TAG, String.format(
|
|
|
|
|
"Widget %s : (%d X %d) can't fit on this device",
|
2016-03-10 12:02:29 -08:00
|
|
|
item.componentName, minSpanX, minSpanY));
|
2015-08-03 13:05:01 -07:00
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-06-17 21:12:44 -07:00
|
|
|
}
|
|
|
|
|
|
2017-06-02 13:46:55 -07:00
|
|
|
if (mAppFilter == null) {
|
|
|
|
|
mAppFilter = AppFilter.newInstance(app.getContext());
|
|
|
|
|
}
|
2016-12-02 19:29:43 +05:30
|
|
|
if (!mAppFilter.shouldShowApp(item.componentName)) {
|
2015-07-13 10:26:22 -07:00
|
|
|
if (DEBUG) {
|
|
|
|
|
Log.d(TAG, String.format("%s is filtered and not added to the widget tray.",
|
2016-03-10 12:02:29 -08:00
|
|
|
item.componentName));
|
2015-07-13 10:26:22 -07:00
|
|
|
}
|
2015-06-17 21:12:44 -07:00
|
|
|
continue;
|
2015-04-08 19:01:34 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-10 12:02:29 -08:00
|
|
|
String packageName = item.componentName.getPackageName();
|
2015-04-11 15:44:32 -07:00
|
|
|
PackageItemInfo pInfo = tmpPackageItemInfos.get(packageName);
|
2016-10-12 20:49:31 -07:00
|
|
|
if (pInfo == null) {
|
2015-04-11 15:44:32 -07:00
|
|
|
pInfo = new PackageItemInfo(packageName);
|
2016-10-12 20:49:31 -07:00
|
|
|
pInfo.user = item.user;
|
2015-04-11 15:44:32 -07:00
|
|
|
tmpPackageItemInfos.put(packageName, pInfo);
|
2016-10-12 20:49:31 -07:00
|
|
|
} else if (!myUser.equals(pInfo.user)) {
|
|
|
|
|
// Keep updating the user, until we get the primary user.
|
|
|
|
|
pInfo.user = item.user;
|
2015-04-08 19:01:34 -07:00
|
|
|
}
|
2016-10-12 20:49:31 -07:00
|
|
|
mWidgetsList.addToList(pInfo, item);
|
2015-04-08 19:01:34 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-10 12:02:29 -08:00
|
|
|
// Update each package entry
|
2017-06-02 13:46:55 -07:00
|
|
|
IconCache iconCache = app.getIconCache();
|
2016-10-12 20:49:31 -07:00
|
|
|
for (PackageItemInfo p : tmpPackageItemInfos.values()) {
|
2017-06-02 13:46:55 -07:00
|
|
|
iconCache.getTitleAndIconForApp(p, true /* userLowResIcon */);
|
2015-04-08 19:01:34 -07:00
|
|
|
}
|
2015-05-22 14:49:23 -07:00
|
|
|
}
|
2015-04-11 15:44:32 -07:00
|
|
|
}
|