From 866ff00eb39826b41515755703a0d0279d31c47f Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Fri, 9 Aug 2019 16:16:06 -0700 Subject: [PATCH] Add a "Dismiss" option for predicted apps in Launcher Test: LongPress on a pridicted app to see dismiss options. Bug:139020180 Change-Id: I877863c65def0d845c0ae2f0987fe7a4f6277565 --- protos/launcher_log.proto | 1 + .../appprediction/PredictionAppTracker.java | 34 ++++++++++++++---- .../appprediction/PredictionRowView.java | 5 ++- res/values/strings.xml | 3 ++ src/com/android/launcher3/AppInfo.java | 7 ++++ .../android/launcher3/ItemInfoWithIcon.java | 6 ++++ .../android/launcher3/LauncherSettings.java | 2 ++ .../android/launcher3/WorkspaceItemInfo.java | 5 +++ .../android/launcher3/config/BaseFlags.java | 4 +++ .../launcher3/model/AppLaunchTracker.java | 3 ++ .../launcher3/model/PackageItemInfo.java | 9 +++++ .../launcher3/popup/SystemShortcut.java | 35 ++++++++++++++++--- .../popup/SystemShortcutFactory.java | 5 ++- 13 files changed, 106 insertions(+), 13 deletions(-) diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto index 49fd43617e..055ade58eb 100644 --- a/protos/launcher_log.proto +++ b/protos/launcher_log.proto @@ -118,6 +118,7 @@ enum ControlType { APP_USAGE_SETTINGS = 18; BACK_GESTURE = 19; UNDO = 20; + DISMISS_PREDICTION = 21; } enum TipType { diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java index fe0d16017f..09cc4213ef 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java @@ -15,8 +15,6 @@ */ package com.android.launcher3.appprediction; -import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID; - import android.annotation.TargetApi; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppPredictionManager; @@ -34,13 +32,15 @@ import android.os.UserHandle; import android.util.Log; import androidx.annotation.Nullable; +import androidx.annotation.UiThread; +import androidx.annotation.WorkerThread; + import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.appprediction.PredictionUiStateManager.Client; import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.util.UiThreadHelper; -import androidx.annotation.UiThread; -import androidx.annotation.WorkerThread; +import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID; /** * Subclass of app tracker which publishes the data to the prediction engine and gets back results. @@ -174,6 +174,7 @@ public class PredictionAppTracker extends AppLaunchTracker { new AppTargetId("shortcut:" + shortcutId), packageName, user) .setClassName(shortcutId) .build(); + sendLaunch(target, container); } @@ -189,11 +190,32 @@ public class PredictionAppTracker extends AppLaunchTracker { } } + @Override @UiThread - private void sendLaunch(AppTarget target, String container) { - AppTargetEvent event = new AppTargetEvent.Builder(target, AppTargetEvent.ACTION_LAUNCH) + public void onDismissApp(ComponentName cn, UserHandle user, String container) { + if (cn == null) return; + AppTarget target = new AppTarget.Builder( + new AppTargetId("app: " + cn), cn.getPackageName(), user) + .setClassName(cn.getClassName()) + .build(); + sendDismiss(target, container); + } + + @UiThread + private void sendEvent(AppTarget target, String container, int eventId) { + AppTargetEvent event = new AppTargetEvent.Builder(target, eventId) .setLaunchLocation(container == null ? CONTAINER_DEFAULT : container) .build(); Message.obtain(mMessageHandler, MSG_LAUNCH, event).sendToTarget(); } + + @UiThread + private void sendLaunch(AppTarget target, String container) { + sendEvent(target, container, AppTargetEvent.ACTION_LAUNCH); + } + + @UiThread + private void sendDismiss(AppTarget target, String container) { + sendEvent(target, container, AppTargetEvent.ACTION_DISMISS); + } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java index 8e064aee83..95f63cea13 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java @@ -43,6 +43,7 @@ import com.android.launcher3.ItemInfo; import com.android.launcher3.ItemInfoWithIcon; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.allapps.AllAppsStore; @@ -290,7 +291,9 @@ public class PredictionRowView extends LinearLayout implements for (ComponentKeyMapper mapper : components) { ItemInfoWithIcon info = mapper.getApp(getAppsStore()); if (info != null) { - predictedApps.add(info); + ItemInfoWithIcon predictedApp = info.clone(); + predictedApp.container = LauncherSettings.Favorites.CONTAINER_PREDICTION; + predictedApps.add(predictedApp); } else { if (FeatureFlags.IS_DOGFOOD_BUILD) { Log.e(TAG, "Predicted app not found: " + mapper); diff --git a/res/values/strings.xml b/res/values/strings.xml index 13e096c95b..fa48f33dd9 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -105,6 +105,9 @@ Install + + Dismiss prediction + diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java index a132d04449..c8e7619c7b 100644 --- a/src/com/android/launcher3/AppInfo.java +++ b/src/com/android/launcher3/AppInfo.java @@ -85,6 +85,8 @@ public class AppInfo extends ItemInfoWithIcon { componentName = info.componentName; title = Utilities.trim(info.title); intent = new Intent(info.intent); + user = info.user; + runtimeStatusFlags = info.runtimeStatusFlags; } @Override @@ -127,4 +129,9 @@ public class AppInfo extends ItemInfoWithIcon { info.runtimeStatusFlags |= FLAG_ADAPTIVE_ICON; } } + + @Override + public AppInfo clone() { + return new AppInfo(this); + } } diff --git a/src/com/android/launcher3/ItemInfoWithIcon.java b/src/com/android/launcher3/ItemInfoWithIcon.java index e29f92713d..1550bb080d 100644 --- a/src/com/android/launcher3/ItemInfoWithIcon.java +++ b/src/com/android/launcher3/ItemInfoWithIcon.java @@ -27,6 +27,8 @@ import com.android.launcher3.icons.BitmapInfo; */ public abstract class ItemInfoWithIcon extends ItemInfo { + public static final String TAG = "ItemInfoDebug"; + /** * A bitmap version of the application icon. */ @@ -126,4 +128,8 @@ public abstract class ItemInfoWithIcon extends ItemInfo { iconColor = info.color; } + /** + * @return a copy of this + */ + public abstract ItemInfoWithIcon clone(); } diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index e248ba016d..242e099b23 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -122,11 +122,13 @@ public class LauncherSettings { */ public static final int CONTAINER_DESKTOP = -100; public static final int CONTAINER_HOTSEAT = -101; + public static final int CONTAINER_PREDICTION = -102; static final String containerToString(int container) { switch (container) { case CONTAINER_DESKTOP: return "desktop"; case CONTAINER_HOTSEAT: return "hotseat"; + case CONTAINER_PREDICTION: return "prediction"; default: return String.valueOf(container); } } diff --git a/src/com/android/launcher3/WorkspaceItemInfo.java b/src/com/android/launcher3/WorkspaceItemInfo.java index b72866c266..9a9aa976f0 100644 --- a/src/com/android/launcher3/WorkspaceItemInfo.java +++ b/src/com/android/launcher3/WorkspaceItemInfo.java @@ -219,4 +219,9 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { } return cn; } + + @Override + public ItemInfoWithIcon clone() { + return new WorkspaceItemInfo(this); + } } diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java index 31e8267f41..dcc8eff715 100644 --- a/src/com/android/launcher3/config/BaseFlags.java +++ b/src/com/android/launcher3/config/BaseFlags.java @@ -116,6 +116,10 @@ abstract class BaseFlags { "APP_SEARCH_IMPROVEMENTS", false, "Adds localized title and keyword search and ranking"); + public static final TogglableFlag ENABLE_PREDICTION_DISMISS = new TogglableFlag( + "ENABLE_PREDICTION_DISMISS", false, "Allow option to dimiss apps from predicted list"); + + public static void initialize(Context context) { // Avoid the disk read for user builds if (Utilities.IS_DEBUG_DEVICE) { diff --git a/src/com/android/launcher3/model/AppLaunchTracker.java b/src/com/android/launcher3/model/AppLaunchTracker.java index 29a46cfa5c..13ab033e4a 100644 --- a/src/com/android/launcher3/model/AppLaunchTracker.java +++ b/src/com/android/launcher3/model/AppLaunchTracker.java @@ -51,5 +51,8 @@ public class AppLaunchTracker implements ResourceBasedOverride { public void onStartApp(ComponentName componentName, UserHandle user, @Nullable String container) { } + public void onDismissApp(ComponentName componentName, UserHandle user, + @Nullable String container){} + public void onReturnedToHome() { } } diff --git a/src/com/android/launcher3/model/PackageItemInfo.java b/src/com/android/launcher3/model/PackageItemInfo.java index baeaa94923..741be66a03 100644 --- a/src/com/android/launcher3/model/PackageItemInfo.java +++ b/src/com/android/launcher3/model/PackageItemInfo.java @@ -32,8 +32,17 @@ public class PackageItemInfo extends ItemInfoWithIcon { this.packageName = packageName; } + public PackageItemInfo(PackageItemInfo copy) { + this.packageName = copy.packageName; + } + @Override protected String dumpProperties() { return super.dumpProperties() + " packageName=" + packageName; } + + @Override + public PackageItemInfo clone() { + return new PackageItemInfo(this); + } } diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java index 563f3b3c65..1f78a85fba 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -1,14 +1,11 @@ package com.android.launcher3.popup; -import static com.android.launcher3.userevent.nano.LauncherLogProto.Action; -import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; import android.app.ActivityOptions; import android.content.Context; import android.content.Intent; import android.graphics.Rect; import android.graphics.drawable.Icon; -import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.view.View; @@ -20,23 +17,30 @@ import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; import com.android.launcher3.WorkspaceItemInfo; +import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.model.AppLaunchTracker; import com.android.launcher3.model.WidgetItem; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; +import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.widget.WidgetsBottomSheet; import java.util.List; - /** * Represents a system shortcut for a given app. The shortcut should have a label and icon, and an * onClickListener that depends on the item that the shortcut services. * * Example system shortcuts, defined as inner classes, include Widgets and AppInfo. + * @param */ -public abstract class SystemShortcut extends ItemInfo { +public abstract class SystemShortcut + extends ItemInfo { private final int mIconResId; private final int mLabelResId; private final Icon mIcon; @@ -201,6 +205,27 @@ public abstract class SystemShortcut extends Ite } } + public static class DismissPrediction extends SystemShortcut { + public DismissPrediction() { + super(R.drawable.ic_remove_no_shadow, R.string.dismiss_prediction_label); + } + + @Override + public View.OnClickListener getOnClickListener(Launcher activity, ItemInfo itemInfo) { + if (!FeatureFlags.ENABLE_PREDICTION_DISMISS.get()) return null; + if (itemInfo.container != LauncherSettings.Favorites.CONTAINER_PREDICTION) return null; + return (view) -> { + PopupContainerWithArrow.closeAllOpenViews(activity); + activity.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, + ControlType.DISMISS_PREDICTION, ContainerType.DEEPSHORTCUTS); + AppLaunchTracker.INSTANCE.get(view.getContext()) + .onDismissApp(itemInfo.getTargetComponent(), + itemInfo.user, + AppLaunchTracker.CONTAINER_PREDICTIONS); + }; + } + } + protected static void dismissTaskMenuView(BaseDraggingActivity activity) { AbstractFloatingView.closeOpenViews(activity, true, AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE); diff --git a/src/com/android/launcher3/popup/SystemShortcutFactory.java b/src/com/android/launcher3/popup/SystemShortcutFactory.java index 37a209289e..dfcc2f8224 100644 --- a/src/com/android/launcher3/popup/SystemShortcutFactory.java +++ b/src/com/android/launcher3/popup/SystemShortcutFactory.java @@ -39,7 +39,9 @@ public class SystemShortcutFactory implements ResourceBasedOverride { @SuppressWarnings("unused") public SystemShortcutFactory() { this(new SystemShortcut.AppInfo(), - new SystemShortcut.Widgets(), new SystemShortcut.Install()); + new SystemShortcut.Widgets(), + new SystemShortcut.Install(), + new SystemShortcut.DismissPrediction()); } protected SystemShortcutFactory(SystemShortcut... shortcuts) { @@ -53,6 +55,7 @@ public class SystemShortcutFactory implements ResourceBasedOverride { systemShortcuts.add(systemShortcut); } } + return systemShortcuts; } }