diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java index 78cc2dcde8..7f8f0a0576 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduController.java @@ -48,6 +48,7 @@ import com.android.launcher3.views.Snackbar; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; +import java.util.stream.IntStream; /** * Controller class for managing user onboaridng flow for hybrid hotseat @@ -110,7 +111,8 @@ public class HotseatEduController { ItemInfo info = (ItemInfo) view.getTag(); if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { folders.add((FolderInfo) info); - } else if (info instanceof WorkspaceItemInfo) { + } else if (info instanceof WorkspaceItemInfo && info.container == LauncherSettings + .Favorites.CONTAINER_HOTSEAT) { putIntoFolder.add((WorkspaceItemInfo) info); } } @@ -206,6 +208,7 @@ public class HotseatEduController { View child = mHotseat.getChildAt(i, 0); if (child == null || child.getTag() == null) continue; ItemInfo tag = (ItemInfo) child.getTag(); + if (tag.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) continue; mLauncher.getModelWriter().moveItemInDatabase(tag, LauncherSettings.Favorites.CONTAINER_DESKTOP, pageId, i, toRow); mNewItems.add(tag); @@ -300,13 +303,23 @@ public class HotseatEduController { } void showEdu() { + int childCount = mHotseat.getShortcutsAndWidgets().getChildCount(); + CellLayout cellLayout = mLauncher.getWorkspace().getScreenWithId(Workspace.FIRST_SCREEN_ID); // hotseat is already empty and does not require migration. show edu tip - if (mHotseat.getShortcutsAndWidgets().getChildCount() == 0) { - new ArrowTipView(mLauncher).show(mLauncher.getString(R.string.hotseat_auto_enrolled), + boolean requiresMigration = IntStream.range(0, childCount).anyMatch(i -> { + View v = mHotseat.getShortcutsAndWidgets().getChildAt(i); + return v != null && v.getTag() != null && ((ItemInfo) v.getTag()).container + != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; + }); + boolean canMigrateToFirstPage = cellLayout.makeSpaceForHotseatMigration(false); + if (requiresMigration && canMigrateToFirstPage) { + showDialog(); + } else { + new ArrowTipView(mLauncher).show(mLauncher.getString( + requiresMigration ? R.string.hotseat_tip_no_empty_slots + : R.string.hotseat_auto_enrolled), mHotseat.getTop()); finishOnboarding(); - } else { - showDialog(); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java index 1aff8e9799..cb8d1c4bba 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java @@ -16,9 +16,6 @@ package com.android.launcher3.hybridhotseat; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; -import static com.android.launcher3.logging.LoggerUtils.newAction; -import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; -import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent; import android.animation.Animator; import android.animation.AnimatorSet; @@ -32,7 +29,6 @@ import android.app.prediction.AppTargetId; import android.content.ComponentName; import android.os.Bundle; import android.os.Process; -import android.provider.DeviceConfig; import android.util.Log; import android.view.View; import android.view.ViewGroup; @@ -60,7 +56,6 @@ import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.icons.IconCache; import com.android.launcher3.logging.FileLog; -import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; @@ -70,12 +65,12 @@ import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.touch.ItemLongClickListener; -import com.android.launcher3.uioverrides.DeviceFlag; import com.android.launcher3.uioverrides.PredictedAppIcon; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.util.ComponentKey; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -155,9 +150,9 @@ public class HotseatPredictionController implements DragController.DragListener, } /** - * Returns whether or not the prediction controller is ready to show predictions + * Returns whether or not user has seen hybrid hotseat education */ - public boolean isReady() { + public boolean isEduSeen() { return mLauncher.getSharedPrefs().getBoolean(HotseatEduController.KEY_HOTSEAT_EDU_SEEN, false); } @@ -186,7 +181,7 @@ public class HotseatPredictionController implements DragController.DragListener, } private void fillGapsWithPrediction(boolean animate, Runnable callback) { - if (!isReady() || mUIUpdatePaused || mDragObject != null) { + if (mUIUpdatePaused || mDragObject != null) { return; } List predictedApps = mapToWorkspaceItemInfo(mComponentKeyMappers); @@ -262,6 +257,10 @@ public class HotseatPredictionController implements DragController.DragListener, if (mAppPredictor != null) { mAppPredictor.destroy(); } + if (mHotseatEduController != null) { + mHotseatEduController.destroy(); + mHotseatEduController = null; + } } /** @@ -291,11 +290,16 @@ public class HotseatPredictionController implements DragController.DragListener, .setPredictedTargetCount(mHotSeatItemsCount) .setExtras(getAppPredictionContextExtra()) .build()); - mAppPredictor.registerPredictionUpdates(mLauncher.getMainExecutor(), - this::setPredictedApps); + WeakReference controllerRef = new WeakReference<>(this); + mAppPredictor.registerPredictionUpdates(mLauncher.getApplicationContext().getMainExecutor(), + list -> { + if (controllerRef.get() != null) { + controllerRef.get().setPredictedApps(list); + } + }); + setPauseUIUpdate(false); - performBetaCheck(); - if (!isReady()) { + if (!isEduSeen()) { mHotseatEduController = new HotseatEduController(mLauncher, this::createPredictor); } mAppPredictor.requestPredictionUpdate(); @@ -386,9 +390,8 @@ public class HotseatPredictionController implements DragController.DragListener, predictionLog.append("]"); if (Utilities.IS_DEBUG_DEVICE) FileLog.d(TAG, predictionLog.toString()); updateDependencies(); - if (isReady()) { fillGapsWithPrediction(); - } else if (mHotseatEduController != null) { + if (!isEduSeen() && mHotseatEduController != null) { mHotseatEduController.setPredictedApps(mapToWorkspaceItemInfo(mComponentKeyMappers)); } // should invalidate cache if AiAi sends empty list of AppTargets @@ -682,42 +685,6 @@ public class HotseatPredictionController implements DragController.DragListener, } } - private void performBetaCheck() { - if (isReady()) return; - int hotseatItemsCount = mHotseat.getShortcutsAndWidgets().getChildCount(); - - int maxItems = DeviceConfig.getInt( - DeviceFlag.NAMESPACE_LAUNCHER, "max_homepage_items_for_migration", 5); - - // -1 to exclude smart space - int workspaceItemCount = mLauncher.getWorkspace().getScreenWithId( - Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets().getChildCount() - 1; - - // opt user into the feature without onboarding tip or migration if they don't have any - // open spots in their hotseat and have more than maxItems in their hotseat + workspace - - if (hotseatItemsCount == mHotSeatItemsCount && workspaceItemCount + hotseatItemsCount - > maxItems) { - mLauncher.getSharedPrefs().edit().putBoolean(HotseatEduController.KEY_HOTSEAT_EDU_SEEN, - true).apply(); - - LauncherLogProto.Action action = newAction(LauncherLogProto.Action.Type.TOUCH); - LauncherLogProto.Target target = newContainerTarget(LauncherLogProto.ContainerType.TIP); - action.touch = LauncherLogProto.Action.Touch.TAP; - target.tipType = LauncherLogProto.TipType.HYBRID_HOTSEAT; - target.controlType = LauncherLogProto.ControlType.HYBRID_HOTSEAT_CANCELED; - - // temporarily encode details in log target (go/hotseat_migration) - target.rank = 2; - target.cardinality = (workspaceItemCount * 1000) + hotseatItemsCount; - target.pageIndex = maxItems; - LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target); - UserEventDispatcher.newInstance(mLauncher).dispatchUserEvent(event, null); - - - } - } - /** * Fill in predicted_rank field based on app prediction. * Only applicable when {@link ItemInfo#itemType} is PREDICTED_HOTSEAT diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 1110df7179..f4dfe60100 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -170,6 +170,7 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { super.onDestroy(); if (mHotseatPredictionController != null) { mHotseatPredictionController.destroy(); + mHotseatPredictionController = null; } } diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index df30f7bc77..ffe106f4fe 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -117,8 +117,8 @@ public final class FeatureFlags { "ASSISTANT_GIVES_LAUNCHER_FOCUS", false, "Allow Launcher to handle nav bar gestures while Assistant is running over it"); - public static final BooleanFlag ENABLE_HYBRID_HOTSEAT = new DeviceFlag( - "ENABLE_HYBRID_HOTSEAT", false, "Fill gaps in hotseat with predicted apps"); + public static final BooleanFlag ENABLE_HYBRID_HOTSEAT = getDebugFlag( + "ENABLE_HYBRID_HOTSEAT", true, "Fill gaps in hotseat with predicted apps"); public static final BooleanFlag HOTSEAT_MIGRATE_TO_FOLDER = new DeviceFlag( "HOTSEAT_MIGRATE_TO_FOLDER", false, "Should move hotseat items into a folder");