diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index f6c58c4719..9da2b798b8 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -66,6 +66,7 @@ import com.android.launcher3.model.data.SearchActionItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.util.SafeCloseable; import com.android.launcher3.views.ActivityContext; +import com.android.launcher3.views.BubbleTextHolder; import com.android.launcher3.views.IconLabelDotView; import java.text.NumberFormat; @@ -297,7 +298,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, @UiThread public void applyFromWorkspaceItem(WorkspaceItemInfo info, boolean promiseStateChanged) { applyIconAndLabel(info); - setTag(info); + setItemInfo(info); applyLoadingState(promiseStateChanged); applyDotState(info, false /* animate */); setDownloadStateContentDescription(info, info.getProgressLevel()); @@ -308,7 +309,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, applyIconAndLabel(info); // We don't need to check the info since it's not a WorkspaceItemInfo - super.setTag(info); + setItemInfo(info); + // Verify high res immediately verifyHighRes(); @@ -327,7 +329,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, public void applyFromItemInfoWithIcon(ItemInfoWithIcon info) { applyIconAndLabel(info); // We don't need to check the info since it's not a WorkspaceItemInfo - super.setTag(info); + setItemInfo(info); // Verify high res immediately verifyHighRes(); @@ -335,13 +337,11 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, setDownloadStateContentDescription(info, info.getProgressLevel()); } - /** - * Apply label and tag using a {@link SearchActionItemInfo} - */ - @UiThread - public void applyFromSearchActionItemInfo(SearchActionItemInfo searchActionItemInfo) { - applyIconAndLabel(searchActionItemInfo); - setTag(searchActionItemInfo); + private void setItemInfo(ItemInfo itemInfo) { + setTag(itemInfo); + if (getParent() instanceof BubbleTextHolder) { + ((BubbleTextHolder) getParent()).onItemInfoChanged(itemInfo); + } } @UiThread @@ -799,7 +799,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, } else if (info instanceof PackageItemInfo) { applyFromItemInfoWithIcon((PackageItemInfo) info); } else if (info instanceof SearchActionItemInfo) { - applyFromSearchActionItemInfo((SearchActionItemInfo) info); + applyFromItemInfoWithIcon((SearchActionItemInfo) info); } mDisableRelayout = false; diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index 03e4ee767b..048aaaa3bf 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -94,6 +94,12 @@ public class LauncherSettings { */ public static final int ITEM_TYPE_DEEP_SHORTCUT = 6; + /** + * The favroite is a search action + */ + public static final int ITEM_TYPE_SEARCH_ACTION = 7; + + /** * Type of the item is recents task. * TODO(hyunyoungs): move constants not related to Favorites DB to a better location. diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 6ce2930532..d62e68e2d2 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -91,6 +91,7 @@ import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; +import com.android.launcher3.model.data.SearchActionItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pageindicators.WorkspacePageIndicator; import com.android.launcher3.popup.PopupContainerWithArrow; @@ -2735,11 +2736,17 @@ public class Workspace extends PagedView case ITEM_TYPE_APPLICATION: case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: + case LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION: if (info instanceof AppInfo) { // Came from all apps -- make a copy info = ((AppInfo) info).makeWorkspaceItem(); d.dragInfo = info; } + if (info instanceof SearchActionItemInfo) { + info = ((SearchActionItemInfo) info).createWorkspaceItem( + mLauncher.getModel()); + d.dragInfo = info; + } view = mLauncher.createShortcut(cellLayout, (WorkspaceItemInfo) info); break; case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 8a494ba539..e3c1ad3255 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -584,6 +584,7 @@ public class LoaderTask implements Runnable { && pmHelper.isAppSuspended(targetPkg, c.user)) { disabledState |= FLAG_DISABLED_SUSPENDED; } + info.options = c.getInt(optionsIndex); // App shortcuts that used to be automatically added to Launcher // didn't always have the correct intent flags set, so do that diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java index 4fdc412459..97398de3ff 100644 --- a/src/com/android/launcher3/model/data/ItemInfo.java +++ b/src/com/android/launcher3/model/data/ItemInfo.java @@ -164,6 +164,7 @@ public class ItemInfo { public void copyFrom(ItemInfo info) { id = info.id; + title = info.title; cellX = info.cellX; cellY = info.cellY; spanX = info.spanX; diff --git a/src/com/android/launcher3/model/data/SearchActionItemInfo.java b/src/com/android/launcher3/model/data/SearchActionItemInfo.java index b3057d5bd2..293c095f49 100644 --- a/src/com/android/launcher3/model/data/SearchActionItemInfo.java +++ b/src/com/android/launcher3/model/data/SearchActionItemInfo.java @@ -25,8 +25,15 @@ import android.os.UserHandle; import androidx.annotation.Nullable; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherModel; +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.logger.LauncherAtom.ItemInfo; import com.android.launcher3.logger.LauncherAtom.SearchActionItem; +import com.android.launcher3.model.AllAppsList; +import com.android.launcher3.model.BaseModelUpdateTask; +import com.android.launcher3.model.BgDataModel; /** * Represents a SearchAction with in launcher @@ -38,13 +45,14 @@ public class SearchActionItemInfo extends ItemInfoWithIcon { public static final int FLAG_BADGE_WITH_PACKAGE = 1 << 3; public static final int FLAG_PRIMARY_ICON_FROM_TITLE = 1 << 4; public static final int FLAG_BADGE_WITH_COMPONENT_NAME = 1 << 5; + public static final int FLAG_ALLOW_PINNING = 1 << 6; - private final String mFallbackPackageName; + private String mFallbackPackageName; private int mFlags = 0; - private final Icon mIcon; + private Icon mIcon; // If true title does not contain any personal info and eligible for logging. - private final boolean mIsPersonalTitle; + private boolean mIsPersonalTitle; private Intent mIntent; private PendingIntent mPendingIntent; @@ -52,6 +60,7 @@ public class SearchActionItemInfo extends ItemInfoWithIcon { public SearchActionItemInfo(Icon icon, String packageName, UserHandle user, CharSequence title, boolean isPersonalTitle) { mIsPersonalTitle = isPersonalTitle; + this.itemType = LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION; this.user = user == null ? Process.myUserHandle() : user; this.title = title; this.container = EXTENDED_CONTAINERS; @@ -59,14 +68,18 @@ public class SearchActionItemInfo extends ItemInfoWithIcon { mIcon = icon; } - public SearchActionItemInfo(SearchActionItemInfo info) { + private SearchActionItemInfo(SearchActionItemInfo info) { super(info); - mIcon = info.mIcon; - mFallbackPackageName = info.mFallbackPackageName; - mFlags = info.mFlags; - title = info.title; - this.container = EXTENDED_CONTAINERS; - this.mIsPersonalTitle = info.mIsPersonalTitle; + } + + @Override + public void copyFrom(com.android.launcher3.model.data.ItemInfo info) { + super.copyFrom(info); + SearchActionItemInfo itemInfo = (SearchActionItemInfo) info; + this.mFallbackPackageName = itemInfo.mFallbackPackageName; + this.mIcon = itemInfo.mIcon; + this.mFlags = itemInfo.mFlags; + this.mIsPersonalTitle = itemInfo.mIsPersonalTitle; } /** @@ -77,7 +90,7 @@ public class SearchActionItemInfo extends ItemInfoWithIcon { } public void setFlags(int flags) { - mFlags |= flags ; + mFlags |= flags; } @Override @@ -134,4 +147,50 @@ public class SearchActionItemInfo extends ItemInfoWithIcon { .setContainerInfo(getContainerInfo()) .build(); } + + /** + * Returns true if result supports drag/drop to home screen + */ + public boolean supportsPinning() { + return hasFlags(FLAG_ALLOW_PINNING) && getIntentPackageName() != null; + } + + /** + * Creates a {@link WorkspaceItemInfo} coorsponding to search action to be stored in launcher db + */ + public WorkspaceItemInfo createWorkspaceItem(LauncherModel model) { + WorkspaceItemInfo info = new WorkspaceItemInfo(); + info.title = title; + info.bitmap = bitmap; + info.intent = mIntent; + + if (hasFlags(FLAG_SHOULD_START_FOR_RESULT)) { + info.options |= WorkspaceItemInfo.FLAG_START_FOR_RESULT; + } + + model.enqueueModelUpdateTask(new BaseModelUpdateTask() { + @Override + public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) { + + model.updateAndBindWorkspaceItem(() -> { + PackageItemInfo pkgInfo = new PackageItemInfo(getIntentPackageName(), user); + app.getIconCache().getTitleAndIconForApp(pkgInfo, false); + try (LauncherIcons li = LauncherIcons.obtain(app.getContext())) { + info.bitmap = li.badgeBitmap(info.bitmap.icon, pkgInfo.bitmap); + } + return info; + }); + } + }); + return info; + } + + @Nullable + private String getIntentPackageName() { + if (mIntent != null) { + if (mIntent.getPackage() != null) return mIntent.getPackage(); + return mFallbackPackageName; + } + return null; + } } diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java index a395709bbb..a195979148 100644 --- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java +++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java @@ -67,6 +67,11 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { */ public static final int FLAG_SUPPORTS_WEB_UI = 1 << 3; + /** + * + */ + public static final int FLAG_START_FOR_RESULT = 1 << 4; + /** * The intent used to start the application. */ @@ -92,6 +97,8 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { */ @NonNull private String[] personKeys = Utilities.EMPTY_STRING_ARRAY; + public int options; + public WorkspaceItemInfo() { itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; @@ -127,6 +134,7 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { super.onAddToDatabase(writer); writer.put(Favorites.TITLE, title) .put(Favorites.INTENT, getIntent()) + .put(Favorites.OPTIONS, options) .put(Favorites.RESTORED, status); if (!usingLowResIcon()) { diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java index b53f96eea3..5e907a4da9 100644 --- a/src/com/android/launcher3/touch/ItemClickHandler.java +++ b/src/com/android/launcher3/touch/ItemClickHandler.java @@ -46,6 +46,8 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; +import com.android.launcher3.logging.InstanceId; +import com.android.launcher3.logging.InstanceIdSequence; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.FolderInfo; @@ -314,6 +316,12 @@ public class ItemClickHandler { intent = new Intent(intent); intent.setPackage(null); } + if ((si.options & WorkspaceItemInfo.FLAG_START_FOR_RESULT) != 0) { + launcher.startActivityForResult(item.getIntent(), 0); + InstanceId instanceId = new InstanceIdSequence().newInstanceId(); + launcher.logAppLaunch(launcher.getStatsLogManager(), item, instanceId); + return; + } } if (v != null && launcher.supportsAdaptiveIconAnimation(v)) { // Preload the icon to reduce latency b/w swapping the floating view with the original. diff --git a/src/com/android/launcher3/views/BubbleTextHolder.java b/src/com/android/launcher3/views/BubbleTextHolder.java index 47d356374e..78aac06b72 100644 --- a/src/com/android/launcher3/views/BubbleTextHolder.java +++ b/src/com/android/launcher3/views/BubbleTextHolder.java @@ -16,10 +16,19 @@ package com.android.launcher3.views; import com.android.launcher3.BubbleTextView; +import com.android.launcher3.model.data.ItemInfo; /** * Views that contain {@link BubbleTextView} should implement this interface. */ public interface BubbleTextHolder { BubbleTextView getBubbleText(); + + /** + * Called when new {@link ItemInfo} is set to {@link BubbleTextView} + * + * @param itemInfo the new itemInfo + */ + default void onItemInfoChanged(ItemInfo itemInfo) { + } }