• 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.model.data;
18 
19 import android.app.Person;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.pm.ShortcutInfo;
24 import android.text.TextUtils;
25 
26 import androidx.annotation.NonNull;
27 
28 import com.android.launcher3.LauncherSettings;
29 import com.android.launcher3.LauncherSettings.Favorites;
30 import com.android.launcher3.Utilities;
31 import com.android.launcher3.icons.IconCache;
32 import com.android.launcher3.shortcuts.ShortcutKey;
33 import com.android.launcher3.uioverrides.ApiWrapper;
34 import com.android.launcher3.util.ContentWriter;
35 
36 import java.util.Arrays;
37 
38 /**
39  * Represents a launchable icon on the workspaces and in folders.
40  */
41 public class WorkspaceItemInfo extends ItemInfoWithIcon {
42 
43     public static final int DEFAULT = 0;
44 
45     /**
46      * The shortcut was restored from a backup and it not ready to be used. This is automatically
47      * set during backup/restore
48      */
49     public static final int FLAG_RESTORED_ICON = 1;
50 
51     /**
52      * The icon was added as an auto-install app, and is not ready to be used. This flag can't
53      * be present along with {@link #FLAG_RESTORED_ICON}, and is set during default layout
54      * parsing.
55      *
56      * OR this icon was added due to it being an active install session created by the user.
57      */
58     public static final int FLAG_AUTOINSTALL_ICON = 1 << 1;
59 
60     /**
61      * Indicates that the widget restore has started.
62      */
63     public static final int FLAG_RESTORE_STARTED = 1 << 2;
64 
65     /**
66      * Web UI supported.
67      */
68     public static final int FLAG_SUPPORTS_WEB_UI = 1 << 3;
69 
70     /**
71      *
72      */
73     public static final int FLAG_START_FOR_RESULT = 1 << 4;
74 
75     /**
76      * The intent used to start the application.
77      */
78     @NonNull
79     public Intent intent;
80 
81     /**
82      * A message to display when the user tries to start a disabled shortcut.
83      * This is currently only used for deep shortcuts.
84      */
85     public CharSequence disabledMessage;
86 
87     public int status;
88 
89     /**
90      * A set of person's Id associated with the WorkspaceItemInfo, this is only used if the item
91      * represents a deep shortcut.
92      */
93     @NonNull private String[] personKeys = Utilities.EMPTY_STRING_ARRAY;
94 
95     public int options;
96 
97 
WorkspaceItemInfo()98     public WorkspaceItemInfo() {
99         itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
100     }
101 
WorkspaceItemInfo(WorkspaceItemInfo info)102     public WorkspaceItemInfo(WorkspaceItemInfo info) {
103         super(info);
104         title = info.title;
105         intent = new Intent(info.intent);
106         status = info.status;
107         personKeys = info.personKeys.clone();
108     }
109 
110     /** TODO: Remove this.  It's only called by ApplicationInfo.makeWorkspaceItem. */
WorkspaceItemInfo(AppInfo info)111     public WorkspaceItemInfo(AppInfo info) {
112         super(info);
113         title = Utilities.trim(info.title);
114         intent = new Intent(info.getIntent());
115     }
116 
117     /**
118      * Creates a {@link WorkspaceItemInfo} from a {@link ShortcutInfo}.
119      */
WorkspaceItemInfo(ShortcutInfo shortcutInfo, Context context)120     public WorkspaceItemInfo(ShortcutInfo shortcutInfo, Context context) {
121         user = shortcutInfo.getUserHandle();
122         itemType = Favorites.ITEM_TYPE_DEEP_SHORTCUT;
123         updateFromDeepShortcutInfo(shortcutInfo, context);
124     }
125 
126     @Override
onAddToDatabase(@onNull ContentWriter writer)127     public void onAddToDatabase(@NonNull ContentWriter writer) {
128         super.onAddToDatabase(writer);
129         writer.put(Favorites.TITLE, title)
130                 .put(Favorites.INTENT, getIntent())
131                 .put(Favorites.OPTIONS, options)
132                 .put(Favorites.RESTORED, status);
133 
134         if (!usingLowResIcon()) {
135             writer.putIcon(bitmap, user);
136         }
137     }
138 
139     @Override
140     @NonNull
getIntent()141     public Intent getIntent() {
142         return intent;
143     }
144 
hasStatusFlag(int flag)145     public boolean hasStatusFlag(int flag) {
146         return (status & flag) != 0;
147     }
148 
149 
isPromise()150     public final boolean isPromise() {
151         return hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON);
152     }
153 
hasPromiseIconUi()154     public boolean hasPromiseIconUi() {
155         return isPromise() && !hasStatusFlag(FLAG_SUPPORTS_WEB_UI);
156     }
157 
updateFromDeepShortcutInfo(@onNull final ShortcutInfo shortcutInfo, @NonNull final Context context)158     public void updateFromDeepShortcutInfo(@NonNull final ShortcutInfo shortcutInfo,
159             @NonNull final Context context) {
160         // {@link ShortcutInfo#getActivity} can change during an update. Recreate the intent
161         intent = ShortcutKey.makeIntent(shortcutInfo);
162         title = shortcutInfo.getShortLabel();
163 
164         CharSequence label = shortcutInfo.getLongLabel();
165         if (TextUtils.isEmpty(label)) {
166             label = shortcutInfo.getShortLabel();
167         }
168         contentDescription = context.getPackageManager().getUserBadgedLabel(label, user);
169         if (shortcutInfo.isEnabled()) {
170             runtimeStatusFlags &= ~FLAG_DISABLED_BY_PUBLISHER;
171         } else {
172             runtimeStatusFlags |= FLAG_DISABLED_BY_PUBLISHER;
173         }
174         disabledMessage = shortcutInfo.getDisabledMessage();
175         if (Utilities.ATLEAST_P
176                 && shortcutInfo.getDisabledReason() == ShortcutInfo.DISABLED_REASON_VERSION_LOWER) {
177             runtimeStatusFlags |= FLAG_DISABLED_VERSION_LOWER;
178         } else {
179             runtimeStatusFlags &= ~FLAG_DISABLED_VERSION_LOWER;
180         }
181 
182         Person[] persons = ApiWrapper.getPersons(shortcutInfo);
183         personKeys = persons.length == 0 ? Utilities.EMPTY_STRING_ARRAY
184             : Arrays.stream(persons).map(Person::getKey).sorted().toArray(String[]::new);
185     }
186 
187     /**
188      * {@code true} if the shortcut is disabled due to its app being a lower version.
189      */
isDisabledVersionLower()190     public boolean isDisabledVersionLower() {
191         return (runtimeStatusFlags & FLAG_DISABLED_VERSION_LOWER) != 0;
192     }
193 
194     /** Returns the WorkspaceItemInfo id associated with the deep shortcut. */
getDeepShortcutId()195     public String getDeepShortcutId() {
196         return itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
197                 ? getIntent().getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID) : null;
198     }
199 
200     @NonNull
getPersonKeys()201     public String[] getPersonKeys() {
202         return personKeys;
203     }
204 
205     @Override
getTargetComponent()206     public ComponentName getTargetComponent() {
207         ComponentName cn = super.getTargetComponent();
208         if (cn == null && hasStatusFlag(
209                 FLAG_SUPPORTS_WEB_UI | FLAG_AUTOINSTALL_ICON | FLAG_RESTORED_ICON)) {
210             // Legacy shortcuts and promise icons with web UI may not have a componentName but just
211             // a packageName. In that case create a empty componentName instead of adding additional
212             // check everywhere.
213             String pkg = intent.getPackage();
214             return pkg == null ? null : new ComponentName(pkg, IconCache.EMPTY_CLASS_NAME);
215         }
216         return cn;
217     }
218 
219     @Override
clone()220     public WorkspaceItemInfo clone() {
221         return new WorkspaceItemInfo(this);
222     }
223 }
224