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