WidgetsModel.java 9.19 KB
Newer Older
Hyunyoung Song's avatar
Hyunyoung Song committed
1

2
package com.android.launcher3.model;
Hyunyoung Song's avatar
Hyunyoung Song committed
3

4
import android.content.ComponentName;
Hyunyoung Song's avatar
Hyunyoung Song committed
5
import android.content.Context;
6
import android.content.pm.PackageManager;
Hyunyoung Song's avatar
Hyunyoung Song committed
7 8 9
import android.content.pm.ResolveInfo;
import android.util.Log;

10
import com.android.launcher3.AppFilter;
Hyunyoung Song's avatar
Hyunyoung Song committed
11
import com.android.launcher3.IconCache;
12 13 14
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
Hyunyoung Song's avatar
Hyunyoung Song committed
15
import com.android.launcher3.LauncherAppWidgetProviderInfo;
16
import com.android.launcher3.Utilities;
17
import com.android.launcher3.compat.AlphabeticIndexCompat;
18
import com.android.launcher3.compat.AppWidgetManagerCompat;
Hyunyoung Song's avatar
Hyunyoung Song committed
19
import com.android.launcher3.compat.UserHandleCompat;
20
import com.android.launcher3.util.ComponentKey;
Hyunyoung Song's avatar
Hyunyoung Song committed
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

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.
 *
 * <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;

    /* List of packages that is tracked by this model. */
39
    private final ArrayList<PackageItemInfo> mPackageItemInfos;
Hyunyoung Song's avatar
Hyunyoung Song committed
40 41

    /* Map of widgets and shortcuts that are tracked per package. */
42
    private final HashMap<PackageItemInfo, ArrayList<Object>> mWidgetsList;
Hyunyoung Song's avatar
Hyunyoung Song committed
43

44 45 46
    /* Labels of widgets */
    private final HashMap<ComponentKey, CharSequence> mLabels;

47
    private final AppWidgetManagerCompat mAppWidgetMgr;
48
    private final PackageManager mPackageMgr;
49
    private final WidgetsAndShortcutNameComparator mWidgetAndShortcutNameComparator;
50
    private final Comparator<ItemInfo> mAppNameComparator;
51
    private final IconCache mIconCache;
52
    private final AppFilter mAppFilter;
53 54 55
    private final AlphabeticIndexCompat mIndexer;

    private ArrayList<Object> mRawList;
Hyunyoung Song's avatar
Hyunyoung Song committed
56

57
    public WidgetsModel(Context context,  IconCache iconCache, AppFilter appFilter) {
58
        mAppWidgetMgr = AppWidgetManagerCompat.getInstance(context);
59
        mPackageMgr = context.getPackageManager();
60 61
        mWidgetAndShortcutNameComparator = new WidgetsAndShortcutNameComparator(context);
        mAppNameComparator = (new AppNameComparator(context)).getAppInfoComparator();
62 63
        mIconCache = iconCache;
        mAppFilter = appFilter;
64
        mIndexer = new AlphabeticIndexCompat(context);
65 66 67
        mPackageItemInfos = new ArrayList<>();
        mWidgetsList = new HashMap<>();
        mRawList = new ArrayList<>();
68
        mLabels = new HashMap<>();
69 70
    }

71
    @SuppressWarnings("unchecked")
72
    private WidgetsModel(WidgetsModel model) {
73
        mAppWidgetMgr = model.mAppWidgetMgr;
74
        mPackageMgr = model.mPackageMgr;
75 76 77 78 79
        mPackageItemInfos = (ArrayList<PackageItemInfo>) model.mPackageItemInfos.clone();
        mWidgetsList = (HashMap<PackageItemInfo, ArrayList<Object>>) model.mWidgetsList.clone();
        mWidgetAndShortcutNameComparator = model.mWidgetAndShortcutNameComparator;
        mAppNameComparator = model.mAppNameComparator;
        mIconCache = model.mIconCache;
80
        mAppFilter = model.mAppFilter;
81 82
        mIndexer = model.mIndexer;
        mRawList = (ArrayList<Object>) model.mRawList.clone();
83
        mLabels = (HashMap<ComponentKey, CharSequence>) model.mLabels.clone();
Hyunyoung Song's avatar
Hyunyoung Song committed
84 85 86 87
    }

    // Access methods that may be deleted if the private fields are made package-private.
    public int getPackageSize() {
Hyunyoung Song's avatar
Hyunyoung Song committed
88
        return mPackageItemInfos.size();
Hyunyoung Song's avatar
Hyunyoung Song committed
89 90 91
    }

    // Access methods that may be deleted if the private fields are made package-private.
Hyunyoung Song's avatar
Hyunyoung Song committed
92
    public PackageItemInfo getPackageItemInfo(int pos) {
93 94 95
        if (pos >= mPackageItemInfos.size() || pos < 0) {
            return null;
        }
Hyunyoung Song's avatar
Hyunyoung Song committed
96
        return mPackageItemInfos.get(pos);
Hyunyoung Song's avatar
Hyunyoung Song committed
97 98
    }

99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
    public CharSequence getLabel(Object info) {
        ComponentKey key;
        if (info instanceof LauncherAppWidgetProviderInfo) {
            key = new ComponentKey(((LauncherAppWidgetProviderInfo) info).provider,
                    mAppWidgetMgr.getUser(((LauncherAppWidgetProviderInfo) info)));
            return mLabels.get(key);
        } else if (info instanceof ResolveInfo) {
            ResolveInfo ri = (ResolveInfo) info;
            ComponentName componentName = new ComponentName(ri.activityInfo.packageName,
                    ri.activityInfo.name);
            key = new ComponentKey(componentName, UserHandleCompat.myUserHandle());
            return mLabels.get(key);
        }
        return null;
    }

Hyunyoung Song's avatar
Hyunyoung Song committed
115 116
    public List<Object> getSortedWidgets(int pos) {
        return mWidgetsList.get(mPackageItemInfos.get(pos));
Hyunyoung Song's avatar
Hyunyoung Song committed
117 118
    }

119 120 121 122
    public ArrayList<Object> getRawList() {
        return mRawList;
    }

123
    public void setWidgetsAndShortcuts(ArrayList<Object> rawWidgetsShortcuts) {
124 125
        Utilities.assertWorkerThread();
        mRawList = rawWidgetsShortcuts;
Hyunyoung Song's avatar
Hyunyoung Song committed
126
        if (DEBUG) {
127
            Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size());
Hyunyoung Song's avatar
Hyunyoung Song committed
128 129
        }

Hyunyoung Song's avatar
Hyunyoung Song committed
130 131 132
        // 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<>();
133

Hyunyoung Song's avatar
Hyunyoung Song committed
134 135
        // clear the lists.
        mWidgetsList.clear();
136
        mPackageItemInfos.clear();
137
        mLabels.clear();
138
        mWidgetAndShortcutNameComparator.reset();
Hyunyoung Song's avatar
Hyunyoung Song committed
139

140 141
        InvariantDeviceProfile idp = LauncherAppState.getInstance().getInvariantDeviceProfile();

Hyunyoung Song's avatar
Hyunyoung Song committed
142
        // add and update.
143
        for (Object o: rawWidgetsShortcuts) {
Hyunyoung Song's avatar
Hyunyoung Song committed
144
            String packageName = "";
145
            UserHandleCompat userHandle = null;
146
            ComponentName componentName = null;
147
            ComponentKey key = null;
Hyunyoung Song's avatar
Hyunyoung Song committed
148 149
            if (o instanceof LauncherAppWidgetProviderInfo) {
                LauncherAppWidgetProviderInfo widgetInfo = (LauncherAppWidgetProviderInfo) o;
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166

                // 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;
                }
167 168
                key = new ComponentKey(componentName, userHandle);
                mLabels.put(key, mAppWidgetMgr.loadLabel(widgetInfo));
Hyunyoung Song's avatar
Hyunyoung Song committed
169 170
            } else if (o instanceof ResolveInfo) {
                ResolveInfo resolveInfo = (ResolveInfo) o;
171 172
                componentName = new ComponentName(resolveInfo.activityInfo.packageName,
                        resolveInfo.activityInfo.name);
Hyunyoung Song's avatar
Hyunyoung Song committed
173
                packageName = resolveInfo.activityInfo.packageName;
174
                userHandle = UserHandleCompat.myUserHandle();
175 176
                key = new ComponentKey(componentName, userHandle);
                mLabels.put(key, resolveInfo.loadLabel(mPackageMgr));
177 178
            }

179 180
            if (componentName == null || userHandle == null) {
                Log.e(TAG, String.format("Widget cannot be set for %s.", o.getClass().toString()));
181 182 183
                continue;
            }
            if (mAppFilter != null && !mAppFilter.shouldShowApp(componentName)) {
184 185
                if (DEBUG) {
                    Log.d(TAG, String.format("%s is filtered and not added to the widget tray.",
186
                        packageName));
187
                }
188
                continue;
Hyunyoung Song's avatar
Hyunyoung Song committed
189 190
            }

Hyunyoung Song's avatar
Hyunyoung Song committed
191 192
            PackageItemInfo pInfo = tmpPackageItemInfos.get(packageName);
            ArrayList<Object> widgetsShortcutsList = mWidgetsList.get(pInfo);
Hyunyoung Song's avatar
Hyunyoung Song committed
193 194 195
            if (widgetsShortcutsList != null) {
                widgetsShortcutsList.add(o);
            } else {
196
                widgetsShortcutsList = new ArrayList<>();
Hyunyoung Song's avatar
Hyunyoung Song committed
197
                widgetsShortcutsList.add(o);
Hyunyoung Song's avatar
Hyunyoung Song committed
198
                pInfo = new PackageItemInfo(packageName);
199
                mIconCache.getTitleAndIconForApp(packageName, userHandle,
200
                        true /* userLowResIcon */, pInfo);
201
                pInfo.titleSectionName = mIndexer.computeSectionName(pInfo.title);
Hyunyoung Song's avatar
Hyunyoung Song committed
202 203 204
                mWidgetsList.put(pInfo, widgetsShortcutsList);
                tmpPackageItemInfos.put(packageName,  pInfo);
                mPackageItemInfos.add(pInfo);
Hyunyoung Song's avatar
Hyunyoung Song committed
205 206 207 208
            }
        }

        // sort.
209
        Collections.sort(mPackageItemInfos, mAppNameComparator);
Hyunyoung Song's avatar
Hyunyoung Song committed
210 211
        for (PackageItemInfo p: mPackageItemInfos) {
            Collections.sort(mWidgetsList.get(p), mWidgetAndShortcutNameComparator);
Hyunyoung Song's avatar
Hyunyoung Song committed
212 213
        }
    }
214 215 216 217 218 219 220 221 222 223

    /**
     * Create a snapshot of the widgets model.
     * <p>
     * Usage case: view binding without being modified from package updates.
     */
    @Override
    public WidgetsModel clone(){
        return new WidgetsModel(this);
    }
Hyunyoung Song's avatar
Hyunyoung Song committed
224
}