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 f1ce72e708..49f3eb8fde 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 @@ -47,12 +47,12 @@ public class HotseatEduController { public static final String KEY_HOTSEAT_EDU_SEEN = "hotseat_edu_seen"; public static final String HOTSEAT_EDU_ACTION = "com.android.launcher3.action.SHOW_HYBRID_HOTSEAT_EDU"; - private static final String SETTINGS_ACTION = + public static final String SETTINGS_ACTION = "android.settings.ACTION_CONTENT_SUGGESTIONS_SETTINGS"; private final Launcher mLauncher; private final Hotseat mHotseat; - private final HotseatRestoreHelper mRestoreHelper; + private HotseatRestoreHelper mRestoreHelper; private List mPredictedApps; private HotseatEduDialog mActiveDialog; @@ -71,14 +71,17 @@ public class HotseatEduController { * Checks what type of migration should be used and migrates hotseat */ void migrate() { - mRestoreHelper.createBackup(); + if (mRestoreHelper != null) { + mRestoreHelper.createBackup(); + } if (FeatureFlags.HOTSEAT_MIGRATE_TO_FOLDER.get()) { migrateToFolder(); } else { migrateHotseatWhole(); } - Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_enabled, R.string.hotseat_turn_off, - null, () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION))); + Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_enabled, + R.string.hotseat_prediction_settings, null, + () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION))); } /** @@ -223,15 +226,15 @@ public class HotseatEduController { void finishOnboarding() { mOnOnboardingComplete.run(); - destroy(); mLauncher.getSharedPrefs().edit().putBoolean(KEY_HOTSEAT_EDU_SEEN, true).apply(); } void showDimissTip() { if (mHotseat.getShortcutsAndWidgets().getChildCount() < mLauncher.getDeviceProfile().inv.numHotseatIcons) { - Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled, R.string.hotseat_turn_off, - null, () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION))); + Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled, + R.string.hotseat_prediction_settings, null, + () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION))); } else { new ArrowTipView(mLauncher).show( mLauncher.getString(R.string.hotseat_tip_no_empty_slots), mHotseat.getTop()); @@ -242,12 +245,6 @@ public class HotseatEduController { mPredictedApps = predictedApps; } - void destroy() { - if (mActiveDialog != null) { - mActiveDialog.setHotseatEduController(null); - } - } - void showEdu() { int childCount = mHotseat.getShortcutsAndWidgets().getChildCount(); CellLayout cellLayout = mLauncher.getWorkspace().getScreenWithId(Workspace.FIRST_SCREEN_ID); diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java index 99cb3b351b..bbc128f5ce 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java @@ -29,6 +29,7 @@ import android.view.View; import android.widget.Button; import android.widget.TextView; +import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.CellLayout; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; @@ -245,6 +246,7 @@ public class HotseatEduDialog extends AbstractSlideInView implements Insettable || mHotseatEduController == null) { return; } + AbstractFloatingView.closeAllOpenViews(mLauncher); attachToContainer(); logOnBoardingSeen(); animateOpen(); 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 bd4d7139e9..27423a5968 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 @@ -17,6 +17,7 @@ package com.android.launcher3.hybridhotseat; import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; +import static com.android.launcher3.hybridhotseat.HotseatEduController.SETTINGS_ACTION; import android.animation.Animator; import android.animation.AnimatorSet; @@ -27,6 +28,7 @@ import android.app.prediction.AppPredictor; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; import android.content.ComponentName; +import android.content.Intent; import android.util.Log; import android.view.View; import android.view.ViewGroup; @@ -64,6 +66,8 @@ import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.IntArray; +import com.android.launcher3.views.ArrowTipView; +import com.android.launcher3.views.Snackbar; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -107,8 +111,6 @@ public class HotseatPredictionController implements DragController.DragListener, private boolean mIsCacheEmpty; private boolean mIsDestroyed = false; - private HotseatEduController mHotseatEduController; - private List mOutlineDrawings = new ArrayList<>(); @@ -146,11 +148,48 @@ public class HotseatPredictionController implements DragController.DragListener, } /** - * Transitions to NORMAL workspace mode and shows edu + * Shows appropriate hotseat education based on prediction enabled and migration states. */ public void showEdu() { - if (mHotseatEduController == null) return; - mHotseatEduController.showEdu(); + if (mComponentKeyMappers.isEmpty()) { + // launcher has empty predictions set + Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_disabled, + R.string.hotseat_prediction_settings, null, + () -> mLauncher.startActivity( + new Intent(SETTINGS_ACTION))); + } else if (isEduSeen()) { + // user has already went through education + new ArrowTipView(mLauncher).show( + mLauncher.getString(R.string.hotsaet_tip_prediction_enabled), + mHotseat.getTop()); + } else { + HotseatEduController eduController = new HotseatEduController(mLauncher, mRestoreHelper, + this::createPredictor); + eduController.setPredictedApps(mapToWorkspaceItemInfo(mComponentKeyMappers)); + eduController.showEdu(); + } + } + + /** + * Shows educational tip for hotseat if user does not go through Tips app. + */ + public void showDiscoveryTip() { + if (getPredictedIcons().size() == mHotSeatItemsCount) { + new ArrowTipView(mLauncher).show( + mLauncher.getString(R.string.hotseat_tip_no_empty_slots), mHotseat.getTop()); + } else { + Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled, + R.string.hotseat_prediction_settings, null, + () -> mLauncher.startActivity(new Intent(SETTINGS_ACTION))); + } + } + + /** + * Returns if hotseat client has predictions + * @return + */ + public boolean hasPredictions() { + return !mComponentKeyMappers.isEmpty(); } @Override @@ -250,10 +289,6 @@ public class HotseatPredictionController implements DragController.DragListener, if (mAppPredictor != null) { mAppPredictor.destroy(); } - if (mHotseatEduController != null) { - mHotseatEduController.destroy(); - mHotseatEduController = null; - } } /** @@ -299,10 +334,6 @@ public class HotseatPredictionController implements DragController.DragListener, mAppPredictor.requestPredictionUpdate(); }); setPauseUIUpdate(false); - if (!isEduSeen()) { - mHotseatEduController = new HotseatEduController(mLauncher, mRestoreHelper, - this::createPredictor); - } } /** @@ -350,9 +381,6 @@ public class HotseatPredictionController implements DragController.DragListener, if (Utilities.IS_DEBUG_DEVICE) FileLog.d(TAG, predictionLog.toString()); updateDependencies(); fillGapsWithPrediction(); - if (!isEduSeen() && mHotseatEduController != null) { - mHotseatEduController.setPredictedApps(mapToWorkspaceItemInfo(mComponentKeyMappers)); - } cachePredictionComponentKeysIfNecessary(componentKeys); } 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 494a98dcf5..f7d0cd508c 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 @@ -88,7 +88,6 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { */ public static final AsyncCommand SET_SHELF_HEIGHT = (context, arg1, arg2) -> SystemUiProxy.INSTANCE.get(context).setShelfHeight(arg1 != 0, arg2); - private HotseatPredictionController mHotseatPredictionController; @Override protected void onCreate(Bundle savedInstanceState) { @@ -168,13 +167,6 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { } } - /** - * Returns Prediction controller for hybrid hotseat - */ - public HotseatPredictionController getHotseatPredictionController() { - return mHotseatPredictionController; - } - /** * Recents logic that triggers when launcher state changes or launcher activity stops/resumes. */ @@ -195,7 +187,8 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { @Override public void bindPredictedItems(List appInfos, IntArray ranks) { super.bindPredictedItems(appInfos, ranks); - if (mHotseatPredictionController != null) { + if (mHotseatPredictionController != null + && !mHotseatPredictionController.hasPredictions()) { mHotseatPredictionController.showCachedItems(appInfos, ranks); } } diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml index a27c127317..1b828268ce 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -76,8 +76,8 @@ No thanks - - Settings + + Settings Most-used apps appear here, and change based on routines @@ -86,7 +86,9 @@ App suggestions added to empty space - App suggestions Enabled + App suggestions enabled + + App suggestions are disabled Predicted app: %1$s diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index 48743070d8..d2e0339325 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -31,6 +31,7 @@ import android.os.Bundle; import android.os.CancellationSignal; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.model.WellbeingModel; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.proxy.ProxyActivityStarter; @@ -75,6 +76,7 @@ public abstract class BaseQuickstepLauncher extends Launcher private final ShelfPeekAnim mShelfPeekAnim = new ShelfPeekAnim(this); private OverviewActionsView mActionsView; + protected HotseatPredictionController mHotseatPredictionController; @Override protected void onCreate(Bundle savedInstanceState) { @@ -305,6 +307,13 @@ public abstract class BaseQuickstepLauncher extends Launcher return mShelfPeekAnim; } + /** + * Returns Prediction controller for hybrid hotseat + */ + public HotseatPredictionController getHotseatPredictionController() { + return mHotseatPredictionController; + } + public void setHintUserWillBeActive() { addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE); } diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java index 7e8222c228..1abe903d3d 100644 --- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java +++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java @@ -31,6 +31,7 @@ import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.LauncherState; import com.android.launcher3.Workspace; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.hybridhotseat.HotseatPredictionController; import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.statemanager.StateManager.StateListener; import com.android.launcher3.util.OnboardingPrefs; @@ -100,6 +101,28 @@ public class QuickstepOnboardingPrefs extends OnboardingPrefs() { + boolean mFromAllApps = false; + + @Override + public void onStateTransitionStart(LauncherState toState) { + mFromAllApps = mLauncher.getStateManager().getCurrentStableState() == ALL_APPS; + } + + @Override + public void onStateTransitionComplete(LauncherState finalState) { + HotseatPredictionController client = mLauncher.getHotseatPredictionController(); + if (mFromAllApps && finalState == NORMAL && client.hasPredictions()) { + if (incrementEventCount(HOTSEAT_DISCOVERY_TIP_COUNT)) { + client.showDiscoveryTip(); + stateManager.removeStateListener(this); + } + } + } + }); + } + if (SysUINavigationMode.getMode(launcher) == NO_BUTTON && FeatureFlags.ENABLE_ALL_APPS_EDU.get()) { stateManager.addStateListener(new StateListener() { diff --git a/res/layout/arrow_toast.xml b/res/layout/arrow_toast.xml index 087e45a4dd..2c97e8954b 100644 --- a/res/layout/arrow_toast.xml +++ b/res/layout/arrow_toast.xml @@ -34,6 +34,8 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" + android:paddingTop="5dp" + android:paddingBottom="5dp" android:gravity="center" android:layout_gravity="center_vertical" android:textColor="@android:color/white" diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java index 162028991d..90a1c82661 100644 --- a/src/com/android/launcher3/util/OnboardingPrefs.java +++ b/src/com/android/launcher3/util/OnboardingPrefs.java @@ -37,13 +37,14 @@ public class OnboardingPrefs { public static final String HOME_BOUNCE_COUNT = "launcher.home_bounce_count"; public static final String SHELF_BOUNCE_COUNT = "launcher.shelf_bounce_count"; public static final String ALL_APPS_COUNT = "launcher.all_apps_count"; + public static final String HOTSEAT_DISCOVERY_TIP_COUNT = "launcher.hotseat_discovery_tip_count"; /** * Events that either have happened or have not (booleans). */ @StringDef(value = { HOME_BOUNCE_SEEN, - SHELF_BOUNCE_SEEN, + SHELF_BOUNCE_SEEN }) @Retention(RetentionPolicy.SOURCE) public @interface EventBoolKey {} @@ -55,6 +56,7 @@ public class OnboardingPrefs { HOME_BOUNCE_COUNT, SHELF_BOUNCE_COUNT, ALL_APPS_COUNT, + HOTSEAT_DISCOVERY_TIP_COUNT }) @Retention(RetentionPolicy.SOURCE) public @interface EventCountKey {} @@ -65,6 +67,7 @@ public class OnboardingPrefs { maxCounts.put(HOME_BOUNCE_COUNT, 3); maxCounts.put(SHELF_BOUNCE_COUNT, 3); maxCounts.put(ALL_APPS_COUNT, 5); + maxCounts.put(HOTSEAT_DISCOVERY_TIP_COUNT, 5); MAX_COUNTS = Collections.unmodifiableMap(maxCounts); }