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.content.ComponentName;
20 import android.content.ContentValues;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.graphics.Bitmap;
24 import android.util.Log;
25 
26 import com.android.launcher3.LauncherSettings.Favorites;
27 import com.android.launcher3.compat.LauncherActivityInfoCompat;
28 import com.android.launcher3.compat.UserHandleCompat;
29 import com.android.launcher3.compat.UserManagerCompat;
30 
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 
34 /**
35  * Represents a launchable icon on the workspaces and in folders.
36  */
37 public class ShortcutInfo extends ItemInfo {
38 
39     public static final int DEFAULT = 0;
40 
41     /**
42      * The shortcut was restored from a backup and it not ready to be used. This is automatically
43      * set during backup/restore
44      */
45     public static final int FLAG_RESTORED_ICON = 1;
46 
47     /**
48      * The icon was added as an auto-install app, and is not ready to be used. This flag can't
49      * be present along with {@link #FLAG_RESTORED_ICON}, and is set during default layout
50      * parsing.
51      */
52     public static final int FLAG_AUTOINTALL_ICON = 2; //0B10;
53 
54     /**
55      * The icon is being installed. If {@link #FLAG_RESTORED_ICON} or {@link #FLAG_AUTOINTALL_ICON}
56      * is set, then the icon is either being installed or is in a broken state.
57      */
58     public static final int FLAG_INSTALL_SESSION_ACTIVE = 4; // 0B100;
59 
60     /**
61      * Indicates that the widget restore has started.
62      */
63     public static final int FLAG_RESTORE_STARTED = 8; //0B1000;
64 
65     /**
66      * Indicates if it represents a common type mentioned in {@link CommonAppTypeParser}.
67      * Upto 15 different types supported.
68      */
69     public static final int FLAG_RESTORED_APP_TYPE = 0B0011110000;
70 
71     /**
72      * The intent used to start the application.
73      */
74     Intent intent;
75 
76     /**
77      * Indicates whether the icon comes from an application's resource (if false)
78      * or from a custom Bitmap (if true.)
79      * TODO: remove this flag
80      */
81     public boolean customIcon;
82 
83     /**
84      * Indicates whether we're using the default fallback icon instead of something from the
85      * app.
86      */
87     boolean usingFallbackIcon;
88 
89     /**
90      * Indicates whether we're using a low res icon
91      */
92     boolean usingLowResIcon;
93 
94     /**
95      * If isShortcut=true and customIcon=false, this contains a reference to the
96      * shortcut icon as an application's resource.
97      */
98     public Intent.ShortcutIconResource iconResource;
99 
100     /**
101      * The application icon.
102      */
103     private Bitmap mIcon;
104 
105     /**
106      * Indicates that the icon is disabled due to safe mode restrictions.
107      */
108     public static final int FLAG_DISABLED_SAFEMODE = 1;
109 
110     /**
111      * Indicates that the icon is disabled as the app is not available.
112      */
113     public static final int FLAG_DISABLED_NOT_AVAILABLE = 2;
114 
115     /**
116      * Indicates that the icon is disabled as the app is suspended
117      */
118     public static final int FLAG_DISABLED_SUSPENDED = 4;
119 
120     /**
121      * Indicates that the icon is disabled as the user is in quiet mode.
122      */
123     public static final int FLAG_DISABLED_QUIET_USER = 8;
124 
125     /**
126      * Could be disabled, if the the app is installed but unavailable (eg. in safe mode or when
127      * sd-card is not available).
128      */
129     int isDisabled = DEFAULT;
130 
131     int status;
132 
133     /**
134      * The installation progress [0-100] of the package that this shortcut represents.
135      */
136     private int mInstallProgress;
137 
138     /**
139      * TODO move this to {@link #status}
140      */
141     int flags = 0;
142 
143     /**
144      * If this shortcut is a placeholder, then intent will be a market intent for the package, and
145      * this will hold the original intent from the database.  Otherwise, null.
146      * Refer {@link #FLAG_RESTORED_ICON}, {@link #FLAG_AUTOINTALL_ICON}
147      */
148     Intent promisedIntent;
149 
ShortcutInfo()150     ShortcutInfo() {
151         itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
152     }
153 
getIntent()154     public Intent getIntent() {
155         return intent;
156     }
157 
ShortcutInfo(Intent intent, CharSequence title, CharSequence contentDescription, Bitmap icon, UserHandleCompat user)158     ShortcutInfo(Intent intent, CharSequence title, CharSequence contentDescription,
159             Bitmap icon, UserHandleCompat user) {
160         this();
161         this.intent = intent;
162         this.title = Utilities.trim(title);
163         this.contentDescription = contentDescription;
164         mIcon = icon;
165         this.user = user;
166     }
167 
ShortcutInfo(Context context, ShortcutInfo info)168     public ShortcutInfo(Context context, ShortcutInfo info) {
169         super(info);
170         title = Utilities.trim(info.title);
171         intent = new Intent(info.intent);
172         if (info.iconResource != null) {
173             iconResource = new Intent.ShortcutIconResource();
174             iconResource.packageName = info.iconResource.packageName;
175             iconResource.resourceName = info.iconResource.resourceName;
176         }
177         mIcon = info.mIcon; // TODO: should make a copy here.  maybe we don't need this ctor at all
178         customIcon = info.customIcon;
179         flags = info.flags;
180         user = info.user;
181         status = info.status;
182     }
183 
184     /** TODO: Remove this.  It's only called by ApplicationInfo.makeShortcut. */
ShortcutInfo(AppInfo info)185     public ShortcutInfo(AppInfo info) {
186         super(info);
187         title = Utilities.trim(info.title);
188         intent = new Intent(info.intent);
189         customIcon = false;
190         flags = info.flags;
191         isDisabled = info.isDisabled;
192     }
193 
setIcon(Bitmap b)194     public void setIcon(Bitmap b) {
195         mIcon = b;
196     }
197 
getIcon(IconCache iconCache)198     public Bitmap getIcon(IconCache iconCache) {
199         if (mIcon == null) {
200             updateIcon(iconCache);
201         }
202         return mIcon;
203     }
204 
updateIcon(IconCache iconCache, boolean useLowRes)205     public void updateIcon(IconCache iconCache, boolean useLowRes) {
206         if (itemType == Favorites.ITEM_TYPE_APPLICATION) {
207             iconCache.getTitleAndIcon(this, promisedIntent != null ? promisedIntent : intent, user,
208                     useLowRes);
209         }
210     }
211 
updateIcon(IconCache iconCache)212     public void updateIcon(IconCache iconCache) {
213         updateIcon(iconCache, shouldUseLowResIcon());
214     }
215 
216     @Override
onAddToDatabase(Context context, ContentValues values)217     void onAddToDatabase(Context context, ContentValues values) {
218         super.onAddToDatabase(context, values);
219 
220         String titleStr = title != null ? title.toString() : null;
221         values.put(LauncherSettings.BaseLauncherColumns.TITLE, titleStr);
222 
223         String uri = promisedIntent != null ? promisedIntent.toUri(0)
224                 : (intent != null ? intent.toUri(0) : null);
225         values.put(LauncherSettings.BaseLauncherColumns.INTENT, uri);
226         values.put(LauncherSettings.Favorites.RESTORED, status);
227 
228         if (customIcon) {
229             values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE,
230                     LauncherSettings.BaseLauncherColumns.ICON_TYPE_BITMAP);
231             writeBitmap(values, mIcon);
232         } else {
233             if (!usingFallbackIcon) {
234                 writeBitmap(values, mIcon);
235             }
236             if (iconResource != null) {
237                 values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE,
238                         LauncherSettings.BaseLauncherColumns.ICON_TYPE_RESOURCE);
239                 values.put(LauncherSettings.BaseLauncherColumns.ICON_PACKAGE,
240                         iconResource.packageName);
241                 values.put(LauncherSettings.BaseLauncherColumns.ICON_RESOURCE,
242                         iconResource.resourceName);
243             }
244         }
245     }
246 
247     @Override
toString()248     public String toString() {
249         return "ShortcutInfo(title=" + title + "intent=" + intent + "id=" + this.id
250                 + " type=" + this.itemType + " container=" + this.container + " screen=" + screenId
251                 + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX + " spanY=" + spanY
252                 + " dropPos=" + Arrays.toString(dropPos) + " user=" + user + ")";
253     }
254 
dumpShortcutInfoList(String tag, String label, ArrayList<ShortcutInfo> list)255     public static void dumpShortcutInfoList(String tag, String label,
256             ArrayList<ShortcutInfo> list) {
257         Log.d(tag, label + " size=" + list.size());
258         for (ShortcutInfo info: list) {
259             Log.d(tag, "   title=\"" + info.title + " icon=" + info.mIcon
260                     + " customIcon=" + info.customIcon);
261         }
262     }
263 
getTargetComponent()264     public ComponentName getTargetComponent() {
265         return promisedIntent != null ? promisedIntent.getComponent() : intent.getComponent();
266     }
267 
hasStatusFlag(int flag)268     public boolean hasStatusFlag(int flag) {
269         return (status & flag) != 0;
270     }
271 
272 
isPromise()273     public final boolean isPromise() {
274         return hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINTALL_ICON);
275     }
276 
getInstallProgress()277     public int getInstallProgress() {
278         return mInstallProgress;
279     }
280 
setInstallProgress(int progress)281     public void setInstallProgress(int progress) {
282         mInstallProgress = progress;
283         status |= FLAG_INSTALL_SESSION_ACTIVE;
284     }
285 
shouldUseLowResIcon()286     public boolean shouldUseLowResIcon() {
287         return usingLowResIcon && container >= 0 && rank >= FolderIcon.NUM_ITEMS_IN_PREVIEW;
288     }
289 
fromActivityInfo(LauncherActivityInfoCompat info, Context context)290     public static ShortcutInfo fromActivityInfo(LauncherActivityInfoCompat info, Context context) {
291         final ShortcutInfo shortcut = new ShortcutInfo();
292         shortcut.user = info.getUser();
293         shortcut.title = Utilities.trim(info.getLabel());
294         shortcut.contentDescription = UserManagerCompat.getInstance(context)
295                 .getBadgedLabelForUser(info.getLabel(), info.getUser());
296         shortcut.customIcon = false;
297         shortcut.intent = AppInfo.makeLaunchIntent(context, info, info.getUser());
298         shortcut.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
299         shortcut.flags = AppInfo.initFlags(info);
300         return shortcut;
301     }
302 
303     @Override
isDisabled()304     public boolean isDisabled() {
305         return isDisabled != 0;
306     }
307 }
308 
309