• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.model.data;
18 
19 import static com.android.launcher3.icons.BitmapInfo.FLAG_THEMED;
20 
21 import android.content.Context;
22 import android.content.Intent;
23 import android.os.Process;
24 
25 import androidx.annotation.NonNull;
26 import androidx.annotation.Nullable;
27 
28 import com.android.launcher3.Flags;
29 import com.android.launcher3.Utilities;
30 import com.android.launcher3.graphics.ThemeManager;
31 import com.android.launcher3.icons.BitmapInfo;
32 import com.android.launcher3.icons.BitmapInfo.DrawableCreationFlags;
33 import com.android.launcher3.icons.FastBitmapDrawable;
34 import com.android.launcher3.icons.cache.CacheLookupFlag;
35 import com.android.launcher3.logging.FileLog;
36 import com.android.launcher3.pm.PackageInstallInfo;
37 import com.android.launcher3.util.ApiWrapper;
38 
39 /**
40  * Represents an ItemInfo which also holds an icon.
41  */
42 public abstract class ItemInfoWithIcon extends ItemInfo {
43 
44     public static final String TAG = "ItemInfoDebug";
45 
46     /**
47      * The bitmap for the application icon
48      */
49     @NonNull
50     public BitmapInfo bitmap = BitmapInfo.LOW_RES_INFO;
51 
52     /**
53      * Indicates that the icon is disabled due to safe mode restrictions.
54      */
55     public static final int FLAG_DISABLED_SAFEMODE = 1 << 0;
56 
57     /**
58      * Indicates that the icon is disabled as the app is not available.
59      */
60     public static final int FLAG_DISABLED_NOT_AVAILABLE = 1 << 1;
61 
62     /**
63      * Indicates that the icon is disabled as the app is suspended
64      */
65     public static final int FLAG_DISABLED_SUSPENDED = 1 << 2;
66 
67     /**
68      * Indicates that the icon is disabled as the user is in quiet mode.
69      */
70     public static final int FLAG_DISABLED_QUIET_USER = 1 << 3;
71 
72     /**
73      * Indicates that the icon is disabled as the publisher has disabled the actual shortcut.
74      */
75     public static final int FLAG_DISABLED_BY_PUBLISHER = 1 << 4;
76 
77     /**
78      * Indicates that the icon is disabled as the user partition is currently locked.
79      */
80     public static final int FLAG_DISABLED_LOCKED_USER = 1 << 5;
81 
82     /**
83      * The item points to a system app.
84      */
85     public static final int FLAG_SYSTEM_YES = 1 << 6;
86 
87     /**
88      * The item points to a non system app.
89      */
90     public static final int FLAG_SYSTEM_NO = 1 << 7;
91 
92     public static final int FLAG_SYSTEM_MASK = FLAG_SYSTEM_YES | FLAG_SYSTEM_NO;
93 
94     /**
95      * The icon is being installed. If {@link WorkspaceItemInfo#FLAG_RESTORED_ICON} or
96      * {@link WorkspaceItemInfo#FLAG_AUTOINSTALL_ICON} is set, then the icon is either being
97      * installed or is in a broken state.
98      */
99     public static final int FLAG_INSTALL_SESSION_ACTIVE = 1 << 10;
100 
101     /**
102      * This icon is still being downloaded.
103      */
104     public static final int FLAG_INCREMENTAL_DOWNLOAD_ACTIVE = 1 << 11;
105 
106     public static final int FLAG_SHOW_DOWNLOAD_PROGRESS_MASK = FLAG_INSTALL_SESSION_ACTIVE
107             | FLAG_INCREMENTAL_DOWNLOAD_ACTIVE;
108 
109     /**
110      * Indicates that the icon is a disabled shortcut and application updates are required.
111      */
112     public static final int FLAG_DISABLED_VERSION_LOWER = 1 << 12;
113 
114     public static final int FLAG_DISABLED_MASK = FLAG_DISABLED_SAFEMODE
115             | FLAG_DISABLED_NOT_AVAILABLE | FLAG_DISABLED_SUSPENDED
116             | FLAG_DISABLED_QUIET_USER | FLAG_DISABLED_BY_PUBLISHER | FLAG_DISABLED_LOCKED_USER
117             | FLAG_DISABLED_VERSION_LOWER;
118 
119     /**
120      * Flag indicating this item can't be pinned to home screen.
121      */
122     public static final int FLAG_NOT_PINNABLE = 1 << 13;
123 
124     /**
125      * Flag indicating whether the package related to the item & user corresponds to that of
126      * archived app.
127      */
128     public static final int FLAG_ARCHIVED = 1 << 14;
129 
130     /**
131      * Flag indicating whether the package related to the item & user does not support resizing.
132      */
133     public static final int FLAG_NOT_RESIZEABLE = 1 << 15;
134 
135     /**
136      * Flag indicating whether the package related to the item & user supports multiple instances.
137      */
138     public static final int FLAG_SUPPORTS_MULTI_INSTANCE = 1 << 16;
139 
140     /**
141      * Status associated with the system state of the underlying item. This is calculated every
142      * time a new info is created and not persisted on the disk.
143      */
144     public int runtimeStatusFlags = 0;
145 
146     /**
147      * The download progress of the package that this shortcut represents. For legacy apps, this
148      * will always be the installation progress. For apps that support incremental downloads, this
149      * will only match be the installation progress until the app is installed, then this will the
150      * total download progress.
151      */
152     private int mProgressLevel = 100;
153 
ItemInfoWithIcon()154     protected ItemInfoWithIcon() {
155     }
156 
ItemInfoWithIcon(ItemInfoWithIcon info)157     protected ItemInfoWithIcon(ItemInfoWithIcon info) {
158         super(info);
159         bitmap = info.bitmap;
160         mProgressLevel = info.mProgressLevel;
161         runtimeStatusFlags = info.runtimeStatusFlags;
162         user = info.user;
163     }
164 
165     @Override
isDisabled()166     public boolean isDisabled() {
167         return (runtimeStatusFlags & FLAG_DISABLED_MASK) != 0;
168     }
169 
170     /**
171      * @return {@code true} if the app is pending download (0 progress) or if the app is archived
172      * and its install session is active
173      */
isPendingDownload()174     public boolean isPendingDownload() {
175         return getProgressLevel() == 0;
176     }
177 
178     /**
179      * Returns true if the app corresponding to the item is archived.
180      */
isArchived()181     public boolean isArchived() {
182         if (!Flags.enableSupportForArchiving()) {
183             return false;
184         }
185         return (runtimeStatusFlags & FLAG_ARCHIVED) != 0;
186     }
187 
188     /** Returns true if the app is archived and doesn't have an active install session. */
isInactiveArchive()189     public boolean isInactiveArchive() {
190         return isArchived() && (runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) == 0;
191     }
192 
193     /**
194      * Returns the lookup flag to match this current state of this info
195      */
getMatchingLookupFlag()196     public CacheLookupFlag getMatchingLookupFlag() {
197         return bitmap.getMatchingLookupFlag();
198     }
199 
200     /**
201      * Returns whether the app this shortcut represents is able to be started. For legacy apps,
202      * this returns whether it is fully installed. For apps that support incremental downloads,
203      * this returns whether the app is either fully downloaded or has installed and is downloading
204      * incrementally.
205      */
isAppStartable()206     public boolean isAppStartable() {
207         return ((runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) == 0)
208                 && (((runtimeStatusFlags & FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) != 0)
209                 || mProgressLevel == 100 || isArchived());
210     }
211 
212     /**
213      * Returns the download progress for the app this shortcut represents. If this app is not yet
214      * installed or does not support incremental downloads, this will return the installation
215      * progress.
216      */
getProgressLevel()217     public int getProgressLevel() {
218         if (((runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0)
219                 // This condition for archived apps is so that in case unarchival/update of
220                 // archived app is cancelled, the state transitions back to 0% installed state.
221                 || isArchived()) {
222             return mProgressLevel;
223         }
224         return 100;
225     }
226 
227     /**
228      * Sets the download progress for the app this shortcut represents. If this app is not yet
229      * installed or does not support incremental downloads, this will set
230      * {@code FLAG_INSTALL_SESSION_ACTIVE}. If this app is downloading incrementally, this will
231      * set {@code FLAG_INCREMENTAL_DOWNLOAD_ACTIVE}. Otherwise, this will remove both flags.
232      */
setProgressLevel(PackageInstallInfo installInfo)233     public void setProgressLevel(PackageInstallInfo installInfo) {
234         setProgressLevel(installInfo.progress, installInfo.state);
235 
236         if (installInfo.state == PackageInstallInfo.STATUS_FAILED) {
237             FileLog.d(TAG,
238                     "Icon info: " + this + " marked broken with install info: " + installInfo,
239                     new Exception());
240         }
241     }
242 
243     /**
244      * Sets the download progress for the app this shortcut represents.
245      */
setProgressLevel(int progress, int status)246     public void setProgressLevel(int progress, int status) {
247         if (status == PackageInstallInfo.STATUS_INSTALLING) {
248             mProgressLevel = progress;
249             runtimeStatusFlags = progress < 100
250                     ? runtimeStatusFlags | FLAG_INSTALL_SESSION_ACTIVE
251                     : runtimeStatusFlags & ~FLAG_INSTALL_SESSION_ACTIVE;
252         } else if (status == PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING) {
253             mProgressLevel = progress;
254             runtimeStatusFlags = runtimeStatusFlags & ~FLAG_INSTALL_SESSION_ACTIVE;
255             runtimeStatusFlags = progress < 100
256                     ? runtimeStatusFlags | FLAG_INCREMENTAL_DOWNLOAD_ACTIVE
257                     : runtimeStatusFlags & ~FLAG_INCREMENTAL_DOWNLOAD_ACTIVE;
258         } else {
259             mProgressLevel = status == PackageInstallInfo.STATUS_INSTALLED ? 100 : 0;
260             runtimeStatusFlags &= ~FLAG_INSTALL_SESSION_ACTIVE;
261             runtimeStatusFlags &= ~FLAG_INCREMENTAL_DOWNLOAD_ACTIVE;
262         }
263     }
264 
265     /**
266      * Sets whether this app info supports multi-instance.
267      */
268     protected void setSupportsMultiInstance(boolean supportsMultiInstance) {
269         if (supportsMultiInstance) {
270             runtimeStatusFlags |= FLAG_SUPPORTS_MULTI_INSTANCE;
271         } else {
272             runtimeStatusFlags &= ~FLAG_SUPPORTS_MULTI_INSTANCE;
273         }
274     }
275 
276     /**
277      * Returns whether this app info supports multi-instance.
278      */
279     public boolean supportsMultiInstance() {
280         return (runtimeStatusFlags & FLAG_SUPPORTS_MULTI_INSTANCE) != 0;
281     }
282 
283     /**
284      * Sets whether this app info is non-resizeable.
285      */
286     public void setNonResizeable(boolean nonResizeable) {
287         if (nonResizeable) {
288             runtimeStatusFlags |= FLAG_NOT_RESIZEABLE;
289         } else {
290             runtimeStatusFlags &= ~FLAG_NOT_RESIZEABLE;
291         }
292     }
293 
294     /**
295      * Returns whether this app info is resizeable.
296      */
297     public boolean isNonResizeable() {
298         return (runtimeStatusFlags & FLAG_NOT_RESIZEABLE) != 0;
299     }
300 
301     /** Creates an intent to that launches the app store at this app's page. */
302     @Nullable
303     public Intent getMarketIntent(Context context) {
304         String targetPackage = getTargetPackage();
305 
306         return targetPackage != null
307                 ? ApiWrapper.INSTANCE.get(context).getAppMarketActivityIntent(
308                         targetPackage, Process.myUserHandle())
309                 : null;
310     }
311 
312     /**
313      * @return a copy of this
314      */
315     public abstract ItemInfoWithIcon clone();
316 
317 
318     /**
319      * Returns a FastBitmapDrawable with the icon.
320      */
321     public FastBitmapDrawable newIcon(Context context) {
322         return newIcon(context, 0);
323     }
324 
325     /**
326      * Returns a FastBitmapDrawable with the icon and context theme applied
327      */
328     public FastBitmapDrawable newIcon(Context context, @DrawableCreationFlags int creationFlags) {
329         ThemeManager themeManager = ThemeManager.INSTANCE.get(context);
330         if (!themeManager.isIconThemeEnabled()) {
331             creationFlags &= ~FLAG_THEMED;
332         }
333         FastBitmapDrawable drawable = bitmap.newIcon(
334                 context, creationFlags, Utilities.getIconShapeOrNull(context));
335         drawable.setIsDisabled(isDisabled());
336         return drawable;
337     }
338 
339     @Override
340     protected String dumpProperties() {
341         return super.dumpProperties()
342                 + " supportsMultiInstance=" + supportsMultiInstance()
343                 + " nonResizeable=" + isNonResizeable();
344     }
345 }
346