ShortcutInfo.java revision 79cf718fcdf39d0e60743b32c6611fbb971ff38c
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.launcher3;
18
19import android.annotation.TargetApi;
20import android.content.ComponentName;
21import android.content.ContentValues;
22import android.content.Context;
23import android.content.Intent;
24import android.graphics.Bitmap;
25import android.graphics.drawable.Drawable;
26import android.os.Build;
27import android.text.TextUtils;
28
29import com.android.launcher3.LauncherSettings.Favorites;
30import com.android.launcher3.compat.LauncherActivityInfoCompat;
31import com.android.launcher3.compat.UserHandleCompat;
32import com.android.launcher3.compat.UserManagerCompat;
33import com.android.launcher3.folder.FolderIcon;
34import com.android.launcher3.shortcuts.ShortcutInfoCompat;
35
36/**
37 * Represents a launchable icon on the workspaces and in folders.
38 */
39public class ShortcutInfo extends ItemInfo {
40
41    public static final int DEFAULT = 0;
42
43    /**
44     * The shortcut was restored from a backup and it not ready to be used. This is automatically
45     * set during backup/restore
46     */
47    public static final int FLAG_RESTORED_ICON = 1;
48
49    /**
50     * The icon was added as an auto-install app, and is not ready to be used. This flag can't
51     * be present along with {@link #FLAG_RESTORED_ICON}, and is set during default layout
52     * parsing.
53     */
54    public static final int FLAG_AUTOINTALL_ICON = 2; //0B10;
55
56    /**
57     * The icon is being installed. If {@link #FLAG_RESTORED_ICON} or {@link #FLAG_AUTOINTALL_ICON}
58     * is set, then the icon is either being installed or is in a broken state.
59     */
60    public static final int FLAG_INSTALL_SESSION_ACTIVE = 4; // 0B100;
61
62    /**
63     * Indicates that the widget restore has started.
64     */
65    public static final int FLAG_RESTORE_STARTED = 8; //0B1000;
66
67    /**
68     * Indicates if it represents a common type mentioned in {@link CommonAppTypeParser}.
69     * Upto 15 different types supported.
70     */
71    public static final int FLAG_RESTORED_APP_TYPE = 0B0011110000;
72
73    /**
74     * The intent used to start the application.
75     */
76    public Intent intent;
77
78    /**
79     * Indicates whether we're using the default fallback icon instead of something from the
80     * app.
81     */
82    boolean usingFallbackIcon;
83
84    /**
85     * Indicates whether we're using a low res icon
86     */
87    boolean usingLowResIcon;
88
89    /**
90     * If isShortcut=true and customIcon=false, this contains a reference to the
91     * shortcut icon as an application's resource.
92     */
93    public Intent.ShortcutIconResource iconResource;
94
95    /**
96     * The application icon.
97     */
98    private Bitmap mIcon;
99
100    /**
101     * Indicates that the icon is disabled due to safe mode restrictions.
102     */
103    public static final int FLAG_DISABLED_SAFEMODE = 1;
104
105    /**
106     * Indicates that the icon is disabled as the app is not available.
107     */
108    public static final int FLAG_DISABLED_NOT_AVAILABLE = 2;
109
110    /**
111     * Indicates that the icon is disabled as the app is suspended
112     */
113    public static final int FLAG_DISABLED_SUSPENDED = 4;
114
115    /**
116     * Indicates that the icon is disabled as the user is in quiet mode.
117     */
118    public static final int FLAG_DISABLED_QUIET_USER = 8;
119
120    /**
121     * Could be disabled, if the the app is installed but unavailable (eg. in safe mode or when
122     * sd-card is not available).
123     */
124    int isDisabled = DEFAULT;
125
126    int status;
127
128    /**
129     * The installation progress [0-100] of the package that this shortcut represents.
130     */
131    private int mInstallProgress;
132
133    /**
134     * TODO move this to {@link #status}
135     */
136    int flags = 0;
137
138    /**
139     * If this shortcut is a placeholder, then intent will be a market intent for the package, and
140     * this will hold the original intent from the database.  Otherwise, null.
141     * Refer {@link #FLAG_RESTORED_ICON}, {@link #FLAG_AUTOINTALL_ICON}
142     */
143    Intent promisedIntent;
144
145    ShortcutInfo() {
146        itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
147    }
148
149    @Override
150    public Intent getIntent() {
151        return intent;
152    }
153
154    ShortcutInfo(Intent intent, CharSequence title, CharSequence contentDescription,
155            Bitmap icon, UserHandleCompat user) {
156        this();
157        this.intent = intent;
158        this.title = Utilities.trim(title);
159        this.contentDescription = contentDescription;
160        mIcon = icon;
161        this.user = user;
162    }
163
164    public ShortcutInfo(ShortcutInfo info) {
165        super(info);
166        title = info.title;
167        intent = new Intent(info.intent);
168        iconResource = info.iconResource;
169        mIcon = info.mIcon; // TODO: should make a copy here.  maybe we don't need this ctor at all
170        flags = info.flags;
171        status = info.status;
172        mInstallProgress = info.mInstallProgress;
173        isDisabled = info.isDisabled;
174        usingFallbackIcon = info.usingFallbackIcon;
175    }
176
177    /** TODO: Remove this.  It's only called by ApplicationInfo.makeShortcut. */
178    public ShortcutInfo(AppInfo info) {
179        super(info);
180        title = Utilities.trim(info.title);
181        intent = new Intent(info.intent);
182        flags = info.flags;
183        isDisabled = info.isDisabled;
184    }
185
186    public ShortcutInfo(LauncherActivityInfoCompat info, Context context) {
187        user = info.getUser();
188        title = Utilities.trim(info.getLabel());
189        contentDescription = UserManagerCompat.getInstance(context)
190                .getBadgedLabelForUser(info.getLabel(), info.getUser());
191        intent = AppInfo.makeLaunchIntent(context, info, info.getUser());
192        itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
193        flags = AppInfo.initFlags(info);
194    }
195
196    /**
197     * Creates a {@link ShortcutInfo} from a {@link ShortcutInfoCompat}.
198     */
199    @TargetApi(Build.VERSION_CODES.N)
200    public ShortcutInfo(ShortcutInfoCompat shortcutInfo, Context context) {
201        user = shortcutInfo.getUserHandle();
202        itemType = LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
203        intent = shortcutInfo.makeIntent(context);
204        flags = 0;
205        updateFromDeepShortcutInfo(shortcutInfo, context);
206    }
207
208    public void setIcon(Bitmap b) {
209        mIcon = b;
210    }
211
212    public Bitmap getIcon(IconCache iconCache) {
213        if (mIcon == null) {
214            updateIcon(iconCache);
215        }
216        return mIcon;
217    }
218
219    public void updateIcon(IconCache iconCache, boolean useLowRes) {
220        if (itemType == Favorites.ITEM_TYPE_APPLICATION) {
221            iconCache.getTitleAndIcon(this, promisedIntent != null ? promisedIntent : intent, user,
222                    useLowRes);
223        }
224    }
225
226    public void updateIcon(IconCache iconCache) {
227        updateIcon(iconCache, shouldUseLowResIcon());
228    }
229
230    @Override
231    void onAddToDatabase(Context context, ContentValues values) {
232        super.onAddToDatabase(context, values);
233
234        String titleStr = title != null ? title.toString() : null;
235        values.put(LauncherSettings.BaseLauncherColumns.TITLE, titleStr);
236
237        String uri = promisedIntent != null ? promisedIntent.toUri(0)
238                : (intent != null ? intent.toUri(0) : null);
239        values.put(LauncherSettings.BaseLauncherColumns.INTENT, uri);
240        values.put(LauncherSettings.Favorites.RESTORED, status);
241
242        if (!usingFallbackIcon && !usingLowResIcon) {
243            writeBitmap(values, mIcon);
244        }
245        if (iconResource != null) {
246            values.put(LauncherSettings.BaseLauncherColumns.ICON_PACKAGE,
247                    iconResource.packageName);
248            values.put(LauncherSettings.BaseLauncherColumns.ICON_RESOURCE,
249                    iconResource.resourceName);
250        }
251    }
252
253    @Override
254    public String toString() {
255        return "ShortcutInfo(title=" + title + "intent=" + intent + "id=" + this.id
256                + " type=" + this.itemType + " container=" + this.container + " screen=" + screenId
257                + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX + " spanY=" + spanY
258                + " user=" + user + ")";
259    }
260
261    public ComponentName getTargetComponent() {
262        return promisedIntent != null ? promisedIntent.getComponent() : intent.getComponent();
263    }
264
265    public boolean hasStatusFlag(int flag) {
266        return (status & flag) != 0;
267    }
268
269
270    public final boolean isPromise() {
271        return hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINTALL_ICON);
272    }
273
274    public int getInstallProgress() {
275        return mInstallProgress;
276    }
277
278    public void setInstallProgress(int progress) {
279        mInstallProgress = progress;
280        status |= FLAG_INSTALL_SESSION_ACTIVE;
281    }
282
283    public boolean shouldUseLowResIcon() {
284        return usingLowResIcon && container >= 0 && rank >= FolderIcon.NUM_ITEMS_IN_PREVIEW;
285    }
286
287    public void updateFromDeepShortcutInfo(ShortcutInfoCompat shortcutInfo, Context context) {
288        title = shortcutInfo.getShortLabel();
289
290        CharSequence label = shortcutInfo.getLongLabel();
291        if (TextUtils.isEmpty(label)) {
292            label = shortcutInfo.getShortLabel();
293        }
294        contentDescription = UserManagerCompat.getInstance(context)
295                .getBadgedLabelForUser(label, user);
296
297        // TODO: Use cache for this
298        LauncherAppState launcherAppState = LauncherAppState.getInstance();
299        Drawable unbadgedDrawable = launcherAppState.getShortcutManager()
300                .getShortcutIconDrawable(shortcutInfo,
301                        launcherAppState.getInvariantDeviceProfile().fillResIconDpi);
302
303        IconCache cache = launcherAppState.getIconCache();
304        Bitmap unbadgedBitmap = unbadgedDrawable == null
305                ? cache.getDefaultIcon(UserHandleCompat.myUserHandle())
306                : Utilities.createScaledBitmapWithoutShadow(unbadgedDrawable, context);
307        setIcon(getBadgedIcon(unbadgedBitmap, shortcutInfo, cache, context));
308    }
309
310    protected Bitmap getBadgedIcon(Bitmap unbadgedBitmap, ShortcutInfoCompat shortcutInfo,
311            IconCache cache, Context context) {
312        unbadgedBitmap = Utilities.addShadowToIcon(unbadgedBitmap);
313        // Get the app info for the source activity.
314        AppInfo appInfo = new AppInfo();
315        appInfo.user = user;
316        appInfo.componentName = shortcutInfo.getActivity();
317        try {
318            cache.getTitleAndIcon(appInfo, shortcutInfo.getActivityInfo(context), false);
319        } catch (NullPointerException e) {
320            // This may happen when we fail to load the activity info. Worst case ignore badging.
321            return Utilities.badgeIconForUser(unbadgedBitmap, user, context);
322        }
323        return Utilities.badgeWithBitmap(unbadgedBitmap, appInfo.iconBitmap, context);
324    }
325
326    /** Returns the ShortcutInfo id associated with the deep shortcut. */
327    public String getDeepShortcutId() {
328        return itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT ?
329                intent.getStringExtra(ShortcutInfoCompat.EXTRA_SHORTCUT_ID) : null;
330    }
331
332    @Override
333    public boolean isDisabled() {
334        return isDisabled != 0;
335    }
336}
337