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