• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.launcher3;
18 
19 import android.annotation.TargetApi;
20 import android.content.ComponentName;
21 import android.content.ContentValues;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.graphics.Bitmap;
25 import android.graphics.drawable.Drawable;
26 import android.os.Build;
27 import android.text.TextUtils;
28 
29 import com.android.launcher3.LauncherSettings.Favorites;
30 import com.android.launcher3.compat.LauncherActivityInfoCompat;
31 import com.android.launcher3.compat.UserHandleCompat;
32 import com.android.launcher3.compat.UserManagerCompat;
33 import com.android.launcher3.folder.FolderIcon;
34 import com.android.launcher3.shortcuts.ShortcutInfoCompat;
35 
36 /**
37  * Represents a launchable icon on the workspaces and in folders.
38  */
39 public 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 << 0;
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 = 1 << 1;
109 
110     /**
111      * Indicates that the icon is disabled as the app is suspended
112      */
113     public static final int FLAG_DISABLED_SUSPENDED = 1 << 2;
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 = 1 << 3;
119 
120     /**
121      * Indicates that the icon is disabled as the publisher has disabled the actual shortcut.
122      */
123     public static final int FLAG_DISABLED_BY_PUBLISHER = 1 << 4;
124 
125     /**
126      * Indicates that the icon is disabled as the user partition is currently locked.
127      */
128     public static final int FLAG_DISABLED_LOCKED_USER = 1 << 5;
129 
130     /**
131      * Could be disabled, if the the app is installed but unavailable (eg. in safe mode or when
132      * sd-card is not available).
133      */
134     int isDisabled = DEFAULT;
135 
136     /**
137      * A message to display when the user tries to start a disabled shortcut.
138      * This is currently only used for deep shortcuts.
139      */
140     CharSequence disabledMessage;
141 
142     int status;
143 
144     /**
145      * The installation progress [0-100] of the package that this shortcut represents.
146      */
147     private int mInstallProgress;
148 
149     /**
150      * TODO move this to {@link #status}
151      */
152     int flags = 0;
153 
154     /**
155      * If this shortcut is a placeholder, then intent will be a market intent for the package, and
156      * this will hold the original intent from the database.  Otherwise, null.
157      * Refer {@link #FLAG_RESTORED_ICON}, {@link #FLAG_AUTOINTALL_ICON}
158      */
159     Intent promisedIntent;
160 
ShortcutInfo()161     public ShortcutInfo() {
162         itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
163     }
164 
165     @Override
getIntent()166     public Intent getIntent() {
167         return intent;
168     }
169 
170     /** Returns {@link #promisedIntent}, or {@link #intent} if promisedIntent is null. */
getPromisedIntent()171     public Intent getPromisedIntent() {
172         return promisedIntent != null ? promisedIntent : intent;
173     }
174 
ShortcutInfo(Intent intent, CharSequence title, CharSequence contentDescription, Bitmap icon, UserHandleCompat user)175     ShortcutInfo(Intent intent, CharSequence title, CharSequence contentDescription,
176             Bitmap icon, UserHandleCompat user) {
177         this();
178         this.intent = intent;
179         this.title = Utilities.trim(title);
180         this.contentDescription = contentDescription;
181         mIcon = icon;
182         this.user = user;
183     }
184 
ShortcutInfo(ShortcutInfo info)185     public ShortcutInfo(ShortcutInfo info) {
186         super(info);
187         title = info.title;
188         intent = new Intent(info.intent);
189         iconResource = info.iconResource;
190         mIcon = info.mIcon; // TODO: should make a copy here.  maybe we don't need this ctor at all
191         flags = info.flags;
192         status = info.status;
193         mInstallProgress = info.mInstallProgress;
194         isDisabled = info.isDisabled;
195         usingFallbackIcon = info.usingFallbackIcon;
196     }
197 
198     /** TODO: Remove this.  It's only called by ApplicationInfo.makeShortcut. */
ShortcutInfo(AppInfo info)199     public ShortcutInfo(AppInfo info) {
200         super(info);
201         title = Utilities.trim(info.title);
202         intent = new Intent(info.intent);
203         flags = info.flags;
204         isDisabled = info.isDisabled;
205     }
206 
ShortcutInfo(LauncherActivityInfoCompat info, Context context)207     public ShortcutInfo(LauncherActivityInfoCompat info, Context context) {
208         user = info.getUser();
209         title = Utilities.trim(info.getLabel());
210         contentDescription = UserManagerCompat.getInstance(context)
211                 .getBadgedLabelForUser(info.getLabel(), info.getUser());
212         intent = AppInfo.makeLaunchIntent(context, info, info.getUser());
213         itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
214         flags = AppInfo.initFlags(info);
215     }
216 
217     /**
218      * Creates a {@link ShortcutInfo} from a {@link ShortcutInfoCompat}.
219      */
220     @TargetApi(Build.VERSION_CODES.N)
ShortcutInfo(ShortcutInfoCompat shortcutInfo, Context context)221     public ShortcutInfo(ShortcutInfoCompat shortcutInfo, Context context) {
222         user = shortcutInfo.getUserHandle();
223         itemType = LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
224         flags = 0;
225         updateFromDeepShortcutInfo(shortcutInfo, context);
226     }
227 
setIcon(Bitmap b)228     public void setIcon(Bitmap b) {
229         mIcon = b;
230     }
231 
getIcon(IconCache iconCache)232     public Bitmap getIcon(IconCache iconCache) {
233         if (mIcon == null) {
234             updateIcon(iconCache);
235         }
236         return mIcon;
237     }
238 
updateIcon(IconCache iconCache, boolean useLowRes)239     public void updateIcon(IconCache iconCache, boolean useLowRes) {
240         if (itemType == Favorites.ITEM_TYPE_APPLICATION) {
241             iconCache.getTitleAndIcon(this, promisedIntent != null ? promisedIntent : intent, user,
242                     useLowRes);
243         }
244     }
245 
updateIcon(IconCache iconCache)246     public void updateIcon(IconCache iconCache) {
247         updateIcon(iconCache, shouldUseLowResIcon());
248     }
249 
250     @Override
onAddToDatabase(Context context, ContentValues values)251     void onAddToDatabase(Context context, ContentValues values) {
252         super.onAddToDatabase(context, values);
253 
254         String titleStr = title != null ? title.toString() : null;
255         values.put(LauncherSettings.BaseLauncherColumns.TITLE, titleStr);
256 
257         String uri = promisedIntent != null ? promisedIntent.toUri(0)
258                 : (intent != null ? intent.toUri(0) : null);
259         values.put(LauncherSettings.BaseLauncherColumns.INTENT, uri);
260         values.put(LauncherSettings.Favorites.RESTORED, status);
261 
262         if (!usingFallbackIcon && !usingLowResIcon) {
263             writeBitmap(values, mIcon);
264         }
265         if (iconResource != null) {
266             values.put(LauncherSettings.BaseLauncherColumns.ICON_PACKAGE,
267                     iconResource.packageName);
268             values.put(LauncherSettings.BaseLauncherColumns.ICON_RESOURCE,
269                     iconResource.resourceName);
270         }
271     }
272 
getTargetComponent()273     public ComponentName getTargetComponent() {
274         return promisedIntent != null ? promisedIntent.getComponent() : intent.getComponent();
275     }
276 
hasStatusFlag(int flag)277     public boolean hasStatusFlag(int flag) {
278         return (status & flag) != 0;
279     }
280 
281 
isPromise()282     public final boolean isPromise() {
283         return hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINTALL_ICON);
284     }
285 
getInstallProgress()286     public int getInstallProgress() {
287         return mInstallProgress;
288     }
289 
setInstallProgress(int progress)290     public void setInstallProgress(int progress) {
291         mInstallProgress = progress;
292         status |= FLAG_INSTALL_SESSION_ACTIVE;
293     }
294 
shouldUseLowResIcon()295     public boolean shouldUseLowResIcon() {
296         return usingLowResIcon && container >= 0 && rank >= FolderIcon.NUM_ITEMS_IN_PREVIEW;
297     }
298 
updateFromDeepShortcutInfo(ShortcutInfoCompat shortcutInfo, Context context)299     public void updateFromDeepShortcutInfo(ShortcutInfoCompat shortcutInfo, Context context) {
300         // {@link ShortcutInfoCompat#getActivity} can change during an update. Recreate the intent
301         intent = shortcutInfo.makeIntent(context);
302         title = shortcutInfo.getShortLabel();
303 
304         CharSequence label = shortcutInfo.getLongLabel();
305         if (TextUtils.isEmpty(label)) {
306             label = shortcutInfo.getShortLabel();
307         }
308         contentDescription = UserManagerCompat.getInstance(context)
309                 .getBadgedLabelForUser(label, user);
310         if (shortcutInfo.isEnabled()) {
311             isDisabled &= ~FLAG_DISABLED_BY_PUBLISHER;
312         } else {
313             isDisabled |= FLAG_DISABLED_BY_PUBLISHER;
314         }
315         disabledMessage = shortcutInfo.getDisabledMessage();
316 
317         // TODO: Use cache for this
318         LauncherAppState launcherAppState = LauncherAppState.getInstance();
319         Drawable unbadgedDrawable = launcherAppState.getShortcutManager()
320                 .getShortcutIconDrawable(shortcutInfo,
321                         launcherAppState.getInvariantDeviceProfile().fillResIconDpi);
322 
323         IconCache cache = launcherAppState.getIconCache();
324         Bitmap unbadgedBitmap = unbadgedDrawable == null
325                 ? cache.getDefaultIcon(UserHandleCompat.myUserHandle())
326                 : Utilities.createScaledBitmapWithoutShadow(unbadgedDrawable, context);
327         setIcon(getBadgedIcon(unbadgedBitmap, shortcutInfo, cache, context));
328     }
329 
getBadgedIcon(Bitmap unbadgedBitmap, ShortcutInfoCompat shortcutInfo, IconCache cache, Context context)330     protected Bitmap getBadgedIcon(Bitmap unbadgedBitmap, ShortcutInfoCompat shortcutInfo,
331             IconCache cache, Context context) {
332         unbadgedBitmap = Utilities.addShadowToIcon(unbadgedBitmap);
333         // Get the app info for the source activity.
334         AppInfo appInfo = new AppInfo();
335         appInfo.user = user;
336         appInfo.componentName = shortcutInfo.getActivity();
337         try {
338             cache.getTitleAndIcon(appInfo, shortcutInfo.getActivityInfo(context), false);
339         } catch (NullPointerException e) {
340             // This may happen when we fail to load the activity info. Worst case ignore badging.
341             return Utilities.badgeIconForUser(unbadgedBitmap, user, context);
342         }
343         return Utilities.badgeWithBitmap(unbadgedBitmap, appInfo.iconBitmap, context);
344     }
345 
346     /** Returns the ShortcutInfo id associated with the deep shortcut. */
getDeepShortcutId()347     public String getDeepShortcutId() {
348         return itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT ?
349                 getPromisedIntent().getStringExtra(ShortcutInfoCompat.EXTRA_SHORTCUT_ID) : null;
350     }
351 
352     @Override
isDisabled()353     public boolean isDisabled() {
354         return isDisabled != 0;
355     }
356 }
357