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