Merge "Import translations. DO NOT MERGE ANYWHERE" into main
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index 00a282a..a7e8118 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -17,6 +17,7 @@
 
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 
 import android.os.Debug;
 import android.os.SystemProperties;
@@ -106,13 +107,6 @@
     }
 
     /**
-     * Whether desktop mode is supported.
-     */
-    private boolean isDesktopModeSupported() {
-        return SystemProperties.getBoolean("persist.wm.debug.desktop_mode_2", false);
-    }
-
-    /**
      * Whether freeform windows are visible in desktop mode.
      */
     public boolean areFreeformTasksVisible() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
index dda8446..f58fd45 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.taskbar;
 
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
+
 import android.content.ComponentName;
 import android.content.pm.ActivityInfo;
 
@@ -28,7 +30,6 @@
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.util.DesktopTask;
 import com.android.quickstep.util.GroupTask;
-import com.android.quickstep.views.DesktopTaskView;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
@@ -109,7 +110,7 @@
         DesktopVisibilityController desktopController =
                 LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
         final boolean onDesktop =
-                DesktopTaskView.DESKTOP_MODE_SUPPORTED
+                isDesktopModeSupported()
                         && desktopController != null
                         && desktopController.areFreeformTasksVisible();
 
@@ -136,7 +137,7 @@
 
         // Hide all desktop tasks and show them on the hidden tile
         int hiddenDesktopTasks = 0;
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (isDesktopModeSupported()) {
             DesktopTask desktopTask = findDesktopTask(tasks);
             if (desktopTask != null) {
                 hiddenDesktopTasks = desktopTask.tasks.size();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index b500c3e..9bb7e67 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -21,6 +21,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 
+import static com.android.launcher3.BaseActivity.EVENT_DESTROYED;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate;
 import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
@@ -30,7 +31,6 @@
 import static com.android.quickstep.util.SystemActionConstants.SYSTEM_ACTION_ID_TASKBAR;
 
 import android.annotation.SuppressLint;
-import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.ComponentCallbacks;
 import android.content.Context;
@@ -61,7 +61,6 @@
 import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.SettingsCache;
 import com.android.launcher3.util.SimpleBroadcastReceiver;
@@ -145,27 +144,25 @@
     private final SimpleBroadcastReceiver mTaskbarBroadcastReceiver =
             new SimpleBroadcastReceiver(this::showTaskbarFromBroadcast);
 
-    private final ActivityLifecycleCallbacksAdapter mLifecycleCallbacks =
-            new ActivityLifecycleCallbacksAdapter() {
-                @Override
-                public void onActivityDestroyed(Activity activity) {
-                    if (mActivity != activity) return;
-                    if (mActivity != null) {
-                        mActivity.removeOnDeviceProfileChangeListener(
-                                mDebugActivityDeviceProfileChanged);
-                        Log.d(TASKBAR_NOT_DESTROYED_TAG,
-                                "unregistering activity lifecycle callbacks from "
-                                        + "onActivityDestroyed.");
-                        mActivity.unregisterActivityLifecycleCallbacks(this);
-                    }
-                    mActivity = null;
-                    debugWhyTaskbarNotDestroyed("clearActivity");
-                    if (mTaskbarActivityContext != null) {
-                        mTaskbarActivityContext.setUIController(TaskbarUIController.DEFAULT);
-                    }
-                    mUnfoldProgressProvider.setSourceProvider(null);
-                }
-            };
+    private final Runnable mActivityOnDestroyCallback = new Runnable() {
+        @Override
+        public void run() {
+            if (mActivity != null) {
+                mActivity.removeOnDeviceProfileChangeListener(
+                        mDebugActivityDeviceProfileChanged);
+                Log.d(TASKBAR_NOT_DESTROYED_TAG,
+                        "unregistering activity lifecycle callbacks from "
+                                + "onActivityDestroyed.");
+                mActivity.removeEventCallback(EVENT_DESTROYED, this);
+            }
+            mActivity = null;
+            debugWhyTaskbarNotDestroyed("clearActivity");
+            if (mTaskbarActivityContext != null) {
+                mTaskbarActivityContext.setUIController(TaskbarUIController.DEFAULT);
+            }
+            mUnfoldProgressProvider.setSourceProvider(null);
+        }
+    };
 
     UnfoldTransitionProgressProvider.TransitionProgressListener mUnfoldTransitionProgressListener =
             new UnfoldTransitionProgressProvider.TransitionProgressListener() {
@@ -371,7 +368,7 @@
         mActivity.addOnDeviceProfileChangeListener(mDebugActivityDeviceProfileChanged);
         Log.d(TASKBAR_NOT_DESTROYED_TAG,
                 "registering activity lifecycle callbacks from setActivity().");
-        mActivity.registerActivityLifecycleCallbacks(mLifecycleCallbacks);
+        mActivity.addEventCallback(EVENT_DESTROYED, mActivityOnDestroyCallback);
         UnfoldTransitionProgressProvider unfoldTransitionProgressProvider =
                 getUnfoldTransitionProgressProviderForActivity(activity);
         if (unfoldTransitionProgressProvider != null) {
@@ -547,7 +544,7 @@
             Log.d(TASKBAR_NOT_DESTROYED_TAG,
                     "unregistering activity lifecycle callbacks from "
                             + "removeActivityCallbackAndListeners().");
-            mActivity.unregisterActivityLifecycleCallbacks(mLifecycleCallbacks);
+            mActivity.removeEventCallback(EVENT_DESTROYED, mActivityOnDestroyCallback);
             UnfoldTransitionProgressProvider unfoldTransitionProgressProvider =
                     getUnfoldTransitionProgressProviderForActivity(mActivity);
             if (unfoldTransitionProgressProvider != null) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index 533785f..3f72e5d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -27,6 +27,7 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_IME_SWITCHER_BUTTON_TAP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_OVERVIEW_BUTTON_LONGPRESS;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_OVERVIEW_BUTTON_TAP;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
@@ -52,7 +53,6 @@
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.TouchInteractionService;
 import com.android.quickstep.util.AssistUtils;
-import com.android.quickstep.views.DesktopTaskView;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -274,7 +274,7 @@
     private void navigateHome() {
         TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY);
 
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (isDesktopModeSupported()) {
             DesktopVisibilityController desktopVisibilityController =
                     LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
             if (desktopVisibilityController != null) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
index 2d32407..4a26559 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.pm.LauncherActivityInfo;
 import android.content.pm.LauncherApps;
+import android.content.pm.LauncherUserInfo;
 import android.content.pm.ShortcutInfo;
 import android.graphics.drawable.ColorDrawable;
 import android.os.UserHandle;
@@ -28,6 +29,7 @@
 import android.util.ArrayMap;
 import android.window.RemoteTransition;
 
+import com.android.launcher3.Flags;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.util.UserIconInfo;
 import com.android.quickstep.util.FadeOutRemoteTransition;
@@ -69,17 +71,32 @@
         List<UserHandle> usersActual = um.getUserProfiles();
         if (usersActual != null) {
             for (UserHandle user : usersActual) {
-                long serial = um.getSerialNumberForUser(user);
+                if (android.os.Flags.allowPrivateProfile() && Flags.enablePrivateSpace()) {
+                    LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
+                    LauncherUserInfo launcherUserInfo = launcherApps.getLauncherUserInfo(user);
+                    // UserTypes not supported in Launcher are deemed to be the current
+                    // Foreground User.
+                    int userType = switch (launcherUserInfo.getUserType()) {
+                        case UserManager.USER_TYPE_PROFILE_MANAGED -> UserIconInfo.TYPE_WORK;
+                        case UserManager.USER_TYPE_PROFILE_CLONE -> UserIconInfo.TYPE_CLONED;
+                        case UserManager.USER_TYPE_PROFILE_PRIVATE -> UserIconInfo.TYPE_PRIVATE;
+                        default -> UserIconInfo.TYPE_MAIN;
+                    };
+                    long serial = launcherUserInfo.getUserSerialNumber();
+                    users.put(user, new UserIconInfo(user, userType, serial));
+                } else {
+                    long serial = um.getSerialNumberForUser(user);
 
-                // Simple check to check if the provided user is work profile
-                // TODO: Migrate to a better platform API
-                NoopDrawable d = new NoopDrawable();
-                boolean isWork = (d != context.getPackageManager().getUserBadgedIcon(d, user));
-                UserIconInfo info = new UserIconInfo(
-                        user,
-                        isWork ? UserIconInfo.TYPE_WORK : UserIconInfo.TYPE_MAIN,
-                        serial);
-                users.put(user, info);
+                    // Simple check to check if the provided user is work profile
+                    // TODO: Migrate to a better platform API
+                    NoopDrawable d = new NoopDrawable();
+                    boolean isWork = (d != context.getPackageManager().getUserBadgedIcon(d, user));
+                    UserIconInfo info = new UserIconInfo(
+                            user,
+                            isWork ? UserIconInfo.TYPE_WORK : UserIconInfo.TYPE_MAIN,
+                            serial);
+                    users.put(user, info);
+                }
             }
         }
         return users;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 8b9eeb1..22ab79d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -19,7 +19,6 @@
 import static android.os.Trace.TRACE_TAG_APP;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
 import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
-
 import static com.android.app.animation.Interpolators.EMPHASIZED;
 import static com.android.launcher3.LauncherSettings.Animation.DEFAULT_NO_ICON;
 import static com.android.launcher3.LauncherSettings.Animation.VIEW_BACKGROUND;
@@ -52,6 +51,7 @@
 import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
 
@@ -165,7 +165,6 @@
 import com.android.quickstep.util.SplitToWorkspaceController;
 import com.android.quickstep.util.SplitWithKeyboardShortcutController;
 import com.android.quickstep.util.TISBindHelper;
-import com.android.quickstep.views.DesktopTaskView;
 import com.android.quickstep.views.FloatingTaskView;
 import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.RecentsView;
@@ -247,7 +246,7 @@
                         getDepthController(), getStatsLogManager(),
                         systemUiProxy, RecentsModel.INSTANCE.get(this),
                         () -> onStateBack());
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (isDesktopModeSupported()) {
             mDesktopRecentsTransitionController = new DesktopRecentsTransitionController(
                     getStateManager(), systemUiProxy, getIApplicationThread(),
                     getDepthController());
@@ -273,7 +272,7 @@
         mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
         mDepthController = new DepthController(this);
         mDesktopVisibilityController = new DesktopVisibilityController(this);
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (isDesktopModeSupported()) {
             mDesktopVisibilityController.registerSystemUiListener();
             mSplitSelectStateController.initSplitFromDesktopController(this);
         }
@@ -890,7 +889,7 @@
 
     @Override
     public void setResumed() {
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (isDesktopModeSupported()) {
             DesktopVisibilityController controller = mDesktopVisibilityController;
             if (controller != null && controller.areFreeformTasksVisible()
                     && !controller.isRecentsGestureInProgress()) {
@@ -1184,11 +1183,6 @@
     }
 
     @Override
-    public void tryClearAccessibilityFocus(View view) {
-        view.clearAccessibilityFocus();
-    }
-
-    @Override
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
index 396f94f..36d62c6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
@@ -392,8 +392,8 @@
         int value = LauncherPrefs.get(getContext()).get(launcherPref);
         seekBarPref.setValue(value);
         // For some reason the initial value is not triggering the summary update, so call manually.
-        seekBarPref.getOnPreferenceChangeListener().onPreferenceChange(seekBarPref, value);
-
+        seekBarPref.setSummary(String.valueOf(scale == 1 ? value
+                : value / (float) scale));
         return seekBarPref;
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index e578720..d11a08b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -17,6 +17,7 @@
 
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
 import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 
 import android.content.Context;
 import android.graphics.Color;
@@ -26,7 +27,6 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.quickstep.util.LayoutUtils;
-import com.android.quickstep.views.DesktopTaskView;
 import com.android.quickstep.views.RecentsView;
 
 /**
@@ -90,7 +90,7 @@
 
     @Override
     protected float getDepthUnchecked(Context context) {
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (isDesktopModeSupported()) {
             if (Launcher.getLauncher(context).areFreeformTasksVisible()) {
                 // Don't blur the background while freeform tasks are visible
                 return 0;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
index 7392469..ba44d6a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.uioverrides.states;
 
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 
 import android.graphics.Color;
 
@@ -23,7 +24,6 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.util.Themes;
-import com.android.quickstep.views.DesktopTaskView;
 
 /**
  * State to indicate we are about to launch a recent task. Note that this state is only used when
@@ -46,7 +46,7 @@
 
     @Override
     public int getWorkspaceScrimColor(Launcher launcher) {
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (isDesktopModeSupported()) {
             if (launcher.areFreeformTasksVisible()) {
                 // No scrim while freeform tasks are visible
                 return Color.TRANSPARENT;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 6f421eb..968faf0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -16,7 +16,6 @@
 package com.android.launcher3.uioverrides.touchcontrollers;
 
 import static android.view.MotionEvent.ACTION_DOWN;
-
 import static com.android.app.animation.Interpolators.ACCELERATE_0_75;
 import static com.android.app.animation.Interpolators.DECELERATE_3;
 import static com.android.app.animation.Interpolators.LINEAR;
@@ -49,6 +48,7 @@
 import static com.android.launcher3.util.NavigationMode.THREE_BUTTONS;
 import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
 import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
 import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
@@ -83,7 +83,6 @@
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.util.MotionPauseDetector;
 import com.android.quickstep.util.WorkspaceRevealAnim;
-import com.android.quickstep.views.DesktopTaskView;
 import com.android.quickstep.views.LauncherRecentsView;
 import com.android.quickstep.views.RecentsView;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
@@ -177,7 +176,7 @@
         if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0) {
             return false;
         }
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (isDesktopModeSupported()) {
             // TODO(b/268075592): add support for quickswitch to/from desktop
             return false;
         }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index 9a35bb2..ff142fe 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -30,6 +30,7 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
 import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
 import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
@@ -48,7 +49,6 @@
 import com.android.launcher3.util.NavigationMode;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskUtils;
-import com.android.quickstep.views.DesktopTaskView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 
@@ -79,7 +79,7 @@
         if ((ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) == 0) {
             return false;
         }
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (isDesktopModeSupported()) {
             // TODO(b/268075592): add support for quickswitch to/from desktop
             return false;
         }
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 9ac5426..b06a978 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -20,10 +20,11 @@
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 import static android.widget.Toast.LENGTH_SHORT;
-
 import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
 import static com.android.app.animation.Interpolators.DECELERATE;
 import static com.android.app.animation.Interpolators.OVERSHOOT_1_2;
+import static com.android.launcher3.BaseActivity.EVENT_DESTROYED;
+import static com.android.launcher3.BaseActivity.EVENT_STARTED;
 import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
 import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
 import static com.android.launcher3.LauncherPrefs.ALL_APPS_OVERVIEW_THRESHOLD;
@@ -54,6 +55,7 @@
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.INVALID_VELOCITY_ON_SWIPE_UP;
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.LAUNCHER_DESTROYED;
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.ON_SETTLED_ON_END_TARGET;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
 
@@ -62,7 +64,6 @@
 import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
 import android.annotation.TargetApi;
-import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.TaskInfo;
 import android.app.WindowConfiguration;
@@ -110,7 +111,6 @@
 import com.android.launcher3.taskbar.TaskbarThresholdUtils;
 import com.android.launcher3.taskbar.TaskbarUIController;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.TraceHelper;
@@ -133,7 +133,6 @@
 import com.android.quickstep.util.SurfaceTransactionApplier;
 import com.android.quickstep.util.SwipePipToHomeAnimator;
 import com.android.quickstep.util.TaskViewSimulator;
-import com.android.quickstep.views.DesktopTaskView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
@@ -185,19 +184,13 @@
     protected MultiStateCallback mStateCallback;
     protected boolean mCanceled;
     private boolean mRecentsViewScrollLinked = false;
-    private final ActivityLifecycleCallbacksAdapter mLifecycleCallbacks =
-            new ActivityLifecycleCallbacksAdapter() {
-                @Override
-                public void onActivityDestroyed(Activity activity) {
-                    if (mActivity != activity) {
-                        return;
-                    }
-                    ActiveGestureLog.INSTANCE.addLog("Launcher destroyed", LAUNCHER_DESTROYED);
-                    mRecentsView = null;
-                    mActivity = null;
-                    mStateCallback.clearState(STATE_LAUNCHER_PRESENT);
-                }
-            };
+
+    private final Runnable mLauncherOnDestroyCallback = () -> {
+        ActiveGestureLog.INSTANCE.addLog("Launcher destroyed", LAUNCHER_DESTROYED);
+        mRecentsView = null;
+        mActivity = null;
+        mStateCallback.clearState(STATE_LAUNCHER_PRESENT);
+    };
 
     private static int FLAG_COUNT = 0;
     private static int getNextStateFlag(String name) {
@@ -318,6 +311,7 @@
     private final int mSplashMainWindowShiftLength;
 
     private final Runnable mOnDeferredActivityLaunch = this::onDeferredActivityLaunch;
+    private final Runnable mLauncherOnStartCallback = this::onLauncherStart;
 
     @Nullable private SwipePipToHomeAnimator mSwipePipToHomeAnimator;
     protected boolean mIsSwipingPipToHome;
@@ -491,6 +485,7 @@
                 mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED);
                 return true;
             }
+            resetLauncherListeners();
 
             // The launcher may have been recreated as a result of device rotation.
             int oldState = mStateCallback.getState() & ~LAUNCHER_UI_STATES;
@@ -514,7 +509,7 @@
         if (alreadyOnHome) {
             onLauncherStart();
         } else {
-            activity.runOnceOnStart(this::onLauncherStart);
+            activity.addEventCallback(EVENT_STARTED, mLauncherOnStartCallback);
         }
 
         // Set up a entire animation lifecycle callback to notify the current recents view when
@@ -539,9 +534,8 @@
 
         setupRecentsViewUi();
         mRecentsView.runOnPageScrollsInitialized(this::linkRecentsViewScroll);
-        activity.runOnBindToTouchInteractionService(this::onLauncherBindToService);
-
-        mActivity.registerActivityLifecycleCallbacks(mLifecycleCallbacks);
+        mActivity.runOnBindToTouchInteractionService(this::onLauncherBindToService);
+        mActivity.addEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback);
         return true;
     }
 
@@ -940,7 +934,7 @@
     public void onRecentsAnimationStart(RecentsAnimationController controller,
             RecentsAnimationTargets targets) {
         super.onRecentsAnimationStart(controller, targets);
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED && targets.hasDesktopTasks()) {
+        if (isDesktopModeSupported() && targets.hasDesktopTasks()) {
             mRemoteTargetHandles = mTargetGluer.assignTargetsForDesktop(targets);
         } else {
             int untrimmedAppCount = mRemoteTargetHandles.length;
@@ -1166,7 +1160,7 @@
                 mStateCallback.setState(STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT);
                 // Notify the SysUI to use fade-in animation when entering PiP
                 SystemUiProxy.INSTANCE.get(mContext).setPipAnimationTypeToAlpha();
-                if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+                if (isDesktopModeSupported()) {
                     // Notify the SysUI to stash desktop apps if they are visible
                     DesktopVisibilityController desktopVisibilityController =
                             mActivityInterface.getDesktopVisibilityController();
@@ -1251,7 +1245,7 @@
             return LAST_TASK;
         }
 
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED && endTarget == NEW_TASK) {
+        if (isDesktopModeSupported() && endTarget == NEW_TASK) {
             // TODO(b/268075592): add support for quickswitch to/from desktop
             return LAST_TASK;
         }
@@ -1868,7 +1862,6 @@
         if (mActivity != null) {
             // In the off chance that the gesture ends before Launcher is started, we should clear
             // the callback here so that it doesn't update with the wrong state
-            mActivity.clearRunOnceOnStartCallback();
             resetLauncherListeners();
         }
         if (mGestureState.isRecentsAnimationRunning() && mGestureState.getEndTarget() != null
@@ -1934,7 +1927,7 @@
     private void reset() {
         mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
         if (mActivity != null) {
-            mActivity.unregisterActivityLifecycleCallbacks(mLifecycleCallbacks);
+            mActivity.removeEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback);
         }
     }
 
@@ -2005,6 +1998,9 @@
      * continued quick switch gesture, which cancels the previous handler but doesn't invalidate it.
      */
     private void resetLauncherListeners() {
+        mActivity.removeEventCallback(EVENT_STARTED, mLauncherOnStartCallback);
+        mActivity.removeEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback);
+
         mActivity.getRootView().setOnApplyWindowInsetsListener(null);
 
         if (mRecentsView != null) {
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 88933f4..2dd6a29 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -25,6 +25,7 @@
 import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
 import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM;
 import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_X_ANIM;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
@@ -65,7 +66,6 @@
 import com.android.launcher3.views.ScrimView;
 import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
-import com.android.quickstep.views.DesktopTaskView;
 import com.android.quickstep.views.RecentsView;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
@@ -111,7 +111,7 @@
         if (endTarget != null) {
             // We were on our way to this state when we got canceled, end there instead.
             startState = stateFromGestureEndTarget(endTarget);
-            if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+            if (isDesktopModeSupported()) {
                 DesktopVisibilityController controller = getDesktopVisibilityController();
                 if (controller != null && controller.areFreeformTasksVisible()
                         && endTarget == LAST_TASK) {
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 3bc77ff..7c263b8 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -20,7 +20,7 @@
 
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.quickstep.util.SplitScreenUtils.convertShellSplitBoundsToLauncher;
-import static com.android.quickstep.views.DesktopTaskView.DESKTOP_MODE_SUPPORTED;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM;
 
 import android.annotation.TargetApi;
@@ -273,7 +273,7 @@
 
         int numVisibleTasks = 0;
         for (GroupedRecentTaskInfo rawTask : rawTasks) {
-            if (DESKTOP_MODE_SUPPORTED && rawTask.getType() == TYPE_FREEFORM) {
+            if (isDesktopModeSupported() && rawTask.getType() == TYPE_FREEFORM) {
                 GroupTask desktopTask = createDesktopTask(rawTask);
                 allTasks.add(desktopTask);
                 continue;
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 38e896e..961d8c0 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -18,7 +18,6 @@
 import static android.os.Trace.TRACE_TAG_APP;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
-
 import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
 import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSITION_DURATION;
 import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSITION_PRE_DELAY;
@@ -26,6 +25,7 @@
 import static com.android.quickstep.OverviewComponentObserver.startHomeIntentSafely;
 import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
 import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -81,7 +81,6 @@
 import com.android.quickstep.util.RecentsAtomicAnimationFactory;
 import com.android.quickstep.util.SplitSelectStateController;
 import com.android.quickstep.util.TISBindHelper;
-import com.android.quickstep.views.DesktopTaskView;
 import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
@@ -142,7 +141,7 @@
                         systemUiProxy, RecentsModel.INSTANCE.get(this),
                         null /*activityBackCallback*/);
         mDragLayer.recreateControllers();
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (isDesktopModeSupported()) {
             mDesktopRecentsTransitionController = new DesktopRecentsTransitionController(
                     getStateManager(), systemUiProxy, getIApplicationThread(),
                     null /* depthController */
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
index 67c56e3..556dd7e 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
@@ -17,14 +17,13 @@
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 
 import android.app.WindowConfiguration;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.view.RemoteAnimationTarget;
 
-import com.android.quickstep.views.DesktopTaskView;
-
 /**
  * Extension of {@link RemoteAnimationTargets} with additional information about swipe
  * up animation
@@ -53,7 +52,7 @@
      * @return {@code true} if at least one target app is a desktop task
      */
     public boolean hasDesktopTasks() {
-        if (!DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (!isDesktopModeSupported()) {
             return false;
         }
         for (RemoteAnimationTarget target : apps) {
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 3af5ab7..98d0ece 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -17,6 +17,7 @@
 package com.android.quickstep;
 
 import static com.android.quickstep.util.SplitScreenUtils.convertShellSplitBoundsToLauncher;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.wm.shell.util.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
 
 import android.content.Context;
@@ -30,7 +31,6 @@
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.TaskViewSimulator;
 import com.android.quickstep.util.TransformParams;
-import com.android.quickstep.views.DesktopTaskView;
 import com.android.wm.shell.util.SplitBounds;
 
 import java.util.ArrayList;
@@ -61,7 +61,7 @@
      * running tasks
      */
     public RemoteTargetGluer(Context context, BaseActivityInterface sizingStrategy) {
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (isDesktopModeSupported()) {
             // TODO(279931899): binder call, only for prototyping. Creating the gluer should be
             //  postponed so we can create it when we have the remote animation targets ready.
             int desktopTasks = SystemUiProxy.INSTANCE.get(context).getVisibleDesktopTaskCount(
diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java
index 164a366..f0f8aec 100644
--- a/quickstep/src/com/android/quickstep/TaskIconCache.java
+++ b/quickstep/src/com/android/quickstep/TaskIconCache.java
@@ -40,6 +40,7 @@
 import com.android.launcher3.icons.BaseIconFactory.IconOptions;
 import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.IconProvider;
+import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
 import com.android.launcher3.util.DisplayController.Info;
@@ -233,7 +234,9 @@
             } else {
                 try (BaseIconFactory li = getIconFactory()) {
                     BitmapInfo info = mDefaultIconBase.withFlags(
-                            li.getBitmapFlagOp(new IconOptions().setUser(UserHandle.of(userId))));
+                            li.getBitmapFlagOp(new IconOptions()
+                                    .setUser(UserCache.INSTANCE.get(mContext)
+                                            .getUserInfo(UserHandle.of(userId)))));
                     mDefaultIcons.put(userId, info);
                     return info.newIcon(mContext);
                 }
@@ -249,7 +252,9 @@
 
             // User version code O, so that the icon is always wrapped in an adaptive icon container
             return bif.createBadgedIconBitmap(drawable,
-                    new IconOptions().setUser(UserHandle.of(userId))
+                    new IconOptions()
+                            .setUser(UserCache.INSTANCE.get(mContext)
+                                    .getUserInfo(UserHandle.of(userId)))
                             .setInstantApp(isInstantApp)
                             .setExtractedColor(0));
         }
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index e8adcab..96e39c4 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -20,6 +20,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 
 import android.app.Activity;
 import android.app.ActivityOptions;
@@ -29,7 +30,6 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
-import android.os.SystemProperties;
 import android.provider.Settings;
 import android.util.Log;
 import android.view.View;
@@ -351,7 +351,7 @@
             return Settings.Global.getInt(
                         activity.getContentResolver(),
                         Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0
-                    && !SystemProperties.getBoolean("persist.wm.debug.desktop_mode_2", false);
+                    && !isDesktopModeSupported();
         }
     };
 
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 819f249..662a895 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -39,7 +39,7 @@
 import static com.android.launcher3.QuickstepTransitionManager.SPLIT_LAUNCH_DURATION;
 import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
 import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
-import static com.android.quickstep.views.DesktopTaskView.DESKTOP_MODE_SUPPORTED;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -185,7 +185,7 @@
             // Re-use existing handles
             remoteTargetHandles = recentsViewHandles;
         } else {
-            boolean forDesktop = DESKTOP_MODE_SUPPORTED && v instanceof DesktopTaskView;
+            boolean forDesktop = isDesktopModeSupported() && v instanceof DesktopTaskView;
             RemoteTargetGluer gluer = new RemoteTargetGluer(v.getContext(),
                     recentsView.getSizeStrategy(), targets, forDesktop);
             if (forDesktop) {
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index c873152..145707b 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -31,6 +31,7 @@
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_PENDINGINTENT;
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_SHORTCUT;
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_TASK;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
 
 import android.animation.Animator;
@@ -91,7 +92,6 @@
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskAnimationManager;
 import com.android.quickstep.TaskViewUtils;
-import com.android.quickstep.views.DesktopTaskView;
 import com.android.quickstep.views.FloatingTaskView;
 import com.android.quickstep.views.GroupedTaskView;
 import com.android.quickstep.views.RecentsView;
@@ -814,7 +814,7 @@
                 @Override
                 public boolean onRequestSplitSelect(ActivityManager.RunningTaskInfo taskInfo,
                         int splitPosition, Rect taskBounds) {
-                    if (!DesktopTaskView.DESKTOP_MODE_SUPPORTED) return false;
+                    if (!isDesktopModeSupported()) return false;
                     MAIN_EXECUTOR.execute(() -> enterSplitSelect(taskInfo, splitPosition,
                             taskBounds));
                     return true;
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index 1b80388..3748a24 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -18,6 +18,7 @@
 
 import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -44,7 +45,6 @@
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.model.data.PackageItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.quickstep.views.DesktopTaskView;
 import com.android.quickstep.views.FloatingTaskView;
 import com.android.quickstep.views.RecentsView;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
@@ -193,7 +193,7 @@
     private boolean shouldIgnoreSecondSplitLaunch() {
         return (!ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS.get()
                 && !FeatureFlags.enableSplitContextually()
-                && !DesktopTaskView.DESKTOP_MODE_SUPPORTED)
+                && !isDesktopModeSupported())
                 || !mController.isSplitSelectActive();
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java b/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
index d7b3431..cdadd71 100644
--- a/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
+++ b/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
@@ -18,11 +18,13 @@
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 
-import android.app.Activity;
+import static com.android.launcher3.BaseActivity.EVENT_DESTROYED;
+import static com.android.launcher3.BaseActivity.EVENT_RESUMED;
+import static com.android.launcher3.BaseActivity.EVENT_STOPPED;
 
 import androidx.annotation.NonNull;
 
-import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
+import com.android.launcher3.BaseActivity;
 import com.android.quickstep.RecentsModel;
 
 /**
@@ -34,19 +36,28 @@
  * If we hit either of those signals and the task is no longer valid, then the registered failure
  * callback will be notified.
  */
-public class TaskRemovedDuringLaunchListener implements ActivityLifecycleCallbacksAdapter {
+public class TaskRemovedDuringLaunchListener {
 
-    private Activity mActivity;
+    private BaseActivity mActivity;
     private int mLaunchedTaskId = INVALID_TASK_ID;
     private Runnable mTaskLaunchFailedCallback = null;
 
+    private final Runnable mUnregisterCallback = this::unregister;
+    private final Runnable mResumeCallback = this::checkTaskLaunchFailed;
+
     /**
      * Registers a failure listener callback if it detects a scenario in which an app launch
      * failed before the transition finished.
      */
-    public void register(Activity activity, int launchedTaskId,
+    public void register(BaseActivity activity, int launchedTaskId,
             @NonNull Runnable taskLaunchFailedCallback) {
-        activity.registerActivityLifecycleCallbacks(this);
+        // The normal task launch case, Launcher stops and updates its state correctly
+        activity.addEventCallback(EVENT_STOPPED, mUnregisterCallback);
+        // The transition hasn't finished but Launcher was resumed, check if the launch failed
+        activity.addEventCallback(EVENT_RESUMED, mResumeCallback);
+        // If we somehow don't get any of the above signals, then just unregister this listener
+        activity.addEventCallback(EVENT_DESTROYED, mUnregisterCallback);
+
         mActivity = activity;
         mLaunchedTaskId = launchedTaskId;
         mTaskLaunchFailedCallback = taskLaunchFailedCallback;
@@ -56,7 +67,10 @@
      * Unregisters the failure listener.
      */
     private void unregister() {
-        mActivity.unregisterActivityLifecycleCallbacks(this);
+        mActivity.removeEventCallback(EVENT_STOPPED, mUnregisterCallback);
+        mActivity.removeEventCallback(EVENT_RESUMED, mResumeCallback);
+        mActivity.removeEventCallback(EVENT_DESTROYED, mUnregisterCallback);
+
         mActivity = null;
         mLaunchedTaskId = INVALID_TASK_ID;
         mTaskLaunchFailedCallback = null;
@@ -70,24 +84,6 @@
         checkTaskLaunchFailed();
     }
 
-    @Override
-    public void onActivityStopped(Activity activity) {
-        // The normal task launch case, Launcher stops and updates its state correctly
-        unregister();
-    }
-
-    @Override
-    public void onActivityResumed(Activity activity) {
-        // The transition hasn't finished but Launcher was resumed, check if the launch failed
-        checkTaskLaunchFailed();
-    }
-
-    @Override
-    public void onActivityDestroyed(Activity activity) {
-        // If we somehow don't get any of the above signals, then just unregister this listener
-        unregister();
-    }
-
     private void checkTaskLaunchFailed() {
         if (mLaunchedTaskId != INVALID_TASK_ID) {
             final int launchedTaskId = mLaunchedTaskId;
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index 9ff990e..a10d2ed 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -17,7 +17,6 @@
 package com.android.quickstep.views;
 
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
 
 import android.content.Context;
@@ -52,6 +51,7 @@
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.QuickStepContract;
+import com.android.wm.shell.Flags;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -68,10 +68,11 @@
 // TODO(b/249371338): TaskView needs to be refactored to have better support for N tasks.
 public class DesktopTaskView extends TaskView {
 
-    /** Flag to indicate whether desktop windowing proto 2 is enabled */
-    public static final boolean DESKTOP_MODE_SUPPORTED = SystemProperties.getBoolean(
+    private static final boolean DESKTOP_MODE_SUPPORTED = SystemProperties.getBoolean(
             "persist.wm.debug.desktop_mode_2", false);
 
+    private static final boolean ENABLE_DESKTOP_WINDOWING = Flags.enableDesktopWindowing();
+
     private static final String TAG = DesktopTaskView.class.getSimpleName();
 
     private static final boolean DEBUG = false;
@@ -90,6 +91,17 @@
 
     private View mBackgroundView;
 
+    /** Check whether desktop windowing is enabled */
+    public static boolean isDesktopModeSupported() {
+        // Check for aconfig flag first
+        if (ENABLE_DESKTOP_WINDOWING) {
+            return true;
+        }
+        // Fall back to sysprop flag
+        // TODO(b/304778354): remove sysprop once desktop aconfig flag supports dynamic overriding
+        return DESKTOP_MODE_SUPPORTED;
+    }
+
     public DesktopTaskView(Context context) {
         this(context, null);
     }
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 7ff2de9..a265146 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -25,6 +25,7 @@
 import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
 import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
 import static com.android.launcher3.LauncherState.SPRING_LOADED;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 
 import android.annotation.TargetApi;
 import android.content.Context;
@@ -255,7 +256,7 @@
         DesktopVisibilityController desktopVisibilityController = null;
         boolean showDesktopApps = false;
         GestureState.GestureEndTarget endTarget = null;
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (isDesktopModeSupported()) {
             desktopVisibilityController = mActivity.getDesktopVisibilityController();
             endTarget = mCurrentGestureEndTarget;
             if (endTarget == GestureState.GestureEndTarget.LAST_TASK
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 2555ffa..7972999 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -56,7 +56,7 @@
 import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
 import static com.android.quickstep.util.LogUtils.splitFailureMessage;
 import static com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA;
-import static com.android.quickstep.views.DesktopTaskView.DESKTOP_MODE_SUPPORTED;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.quickstep.views.OverviewActionsView.FLAG_IS_NOT_TABLET;
 import static com.android.quickstep.views.OverviewActionsView.FLAG_SINGLE_TASK;
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_ACTIONS_IN_MENU;
@@ -1623,7 +1623,7 @@
         mMovingTaskView = null;
         runningTaskView.resetPersistentViewTransforms();
         int frontTaskIndex = 0;
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED && mDesktopTaskView != null
+        if (isDesktopModeSupported() && mDesktopTaskView != null
                 && !runningTaskView.isDesktopTask()) {
             // If desktop mode is enabled, desktop task view is pinned at first position if present.
             // Move running task to position 1.
@@ -1763,7 +1763,7 @@
 
         if (!taskGroups.isEmpty()) {
             addView(mClearAllButton);
-            if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+            if (isDesktopModeSupported()) {
                 // Check if we have apps on the desktop
                 if (desktopTask != null && !desktopTask.tasks.isEmpty()) {
                     // If we are actively choosing apps for split, skip the desktop tile
@@ -2068,7 +2068,7 @@
                 mLastComputedGridSize);
         mSizeStrategy.calculateGridTaskSize(mActivity, mActivity.getDeviceProfile(),
                 mLastComputedGridTaskSize, mOrientationHandler);
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (isDesktopModeSupported()) {
             mSizeStrategy.calculateDesktopTaskSize(mActivity, mActivity.getDeviceProfile(),
                     mLastComputedDesktopTaskSize);
         }
@@ -2759,7 +2759,7 @@
     }
 
     private boolean hasDesktopTask(Task[] runningTasks) {
-        if (!DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (!isDesktopModeSupported()) {
             return false;
         }
         for (Task task : runningTasks) {
@@ -3939,7 +3939,7 @@
         mActionsView.updateSplitButtonHiddenFlags(FLAG_IS_NOT_TABLET,
                 !mActivity.getDeviceProfile().isTablet);
         mActionsView.updateSplitButtonDisabledFlags(FLAG_SINGLE_TASK, /*enable=*/ false);
-        if (DESKTOP_MODE_SUPPORTED) {
+        if (isDesktopModeSupported()) {
             boolean isCurrentDesktop = getCurrentPageTaskView() instanceof DesktopTaskView;
             mActionsView.updateHiddenFlags(HIDDEN_DESKTOP, isCurrentDesktop);
         }
@@ -4613,7 +4613,7 @@
         mSplitSelectStateController.setAnimateCurrentTaskDismissal(
                 true /*animateCurrentTaskDismissal*/);
         mSplitHiddenTaskViewIndex = indexOfChild(taskView);
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (isDesktopModeSupported()) {
             updateDesktopTaskVisibility(false /* visible */);
         }
     }
@@ -4637,7 +4637,7 @@
         mSplitSelectStateController.setInitialTaskSelect(splitSelectSource.intent,
                 splitSelectSource.position.stagePosition, splitSelectSource.itemInfo,
                 splitSelectSource.splitEvent, splitSelectSource.alreadyRunningTaskId);
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (isDesktopModeSupported()) {
             updateDesktopTaskVisibility(false /* visible */);
         }
     }
@@ -4843,7 +4843,7 @@
             mSplitHiddenTaskView.setThumbnailVisibility(VISIBLE, INVALID_TASK_ID);
             mSplitHiddenTaskView = null;
         }
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+        if (isDesktopModeSupported()) {
             updateDesktopTaskVisibility(true /* visible */);
         }
     }
@@ -5218,7 +5218,7 @@
         }
 
         RemoteTargetGluer gluer;
-        if (DESKTOP_MODE_SUPPORTED && recentsAnimationTargets.hasDesktopTasks()) {
+        if (isDesktopModeSupported() && recentsAnimationTargets.hasDesktopTasks()) {
             gluer = new RemoteTargetGluer(getContext(), getSizeStrategy(), recentsAnimationTargets,
                     true /* forDesktop */);
             mRemoteTargetHandles = gluer.assignTargetsForDesktop(recentsAnimationTargets);
@@ -5391,7 +5391,7 @@
     }
 
     private int getFirstViewIndex() {
-        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED && mDesktopTaskView != null) {
+        if (isDesktopModeSupported() && mDesktopTaskView != null) {
             // Desktop task is at position 0, that is the first view
             return 0;
         }
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index b063c91..5093f22 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -36,6 +36,7 @@
 import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
 import static com.android.quickstep.TaskOverlayFactory.getEnabledShortcuts;
 import static com.android.quickstep.util.BorderAnimator.DEFAULT_BORDER_COLOR;
+import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -446,7 +447,7 @@
         mDigitalWellBeingToast = new DigitalWellBeingToast(mActivity, this);
 
         boolean keyboardFocusHighlightEnabled = FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get()
-                || DesktopTaskView.DESKTOP_MODE_SUPPORTED;
+                || isDesktopModeSupported();
         boolean cursorHoverStatesEnabled = enableCursorHoverStates();
 
         setWillNotDraw(!keyboardFocusHighlightEnabled && !cursorHoverStatesEnabled);
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 05a6452..1049314 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -29,7 +29,6 @@
 import android.content.res.Configuration;
 import android.os.Bundle;
 import android.util.Log;
-import android.view.View;
 import android.window.OnBackInvokedDispatcher;
 
 import androidx.annotation.IntDef;
@@ -38,6 +37,7 @@
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.ViewCache;
 import com.android.launcher3.views.ActivityContext;
@@ -153,6 +153,18 @@
 
     private final ViewCache mViewCache = new ViewCache();
 
+    @Retention(SOURCE)
+    @IntDef({EVENT_STARTED, EVENT_RESUMED, EVENT_STOPPED, EVENT_DESTROYED})
+    public @interface ActivityEvent { }
+    public static final int EVENT_STARTED = 0;
+    public static final int EVENT_RESUMED = 1;
+    public static final int EVENT_STOPPED = 2;
+    public static final int EVENT_DESTROYED = 3;
+
+    // Callback array that corresponds to events defined in @ActivityEvent
+    private final RunnableList[] mEventCallbacks =
+            {new RunnableList(), new RunnableList(), new RunnableList(), new RunnableList()};
+
     @Override
     public ViewCache getViewCache() {
         return mViewCache;
@@ -205,12 +217,14 @@
     protected void onStart() {
         addActivityFlags(ACTIVITY_STATE_STARTED);
         super.onStart();
+        mEventCallbacks[EVENT_STARTED].executeAllAndClear();
     }
 
     @Override
     protected void onResume() {
         setResumed();
         super.onResume();
+        mEventCallbacks[EVENT_RESUMED].executeAllAndClear();
     }
 
     @Override
@@ -232,6 +246,8 @@
         removeActivityFlags(ACTIVITY_STATE_STARTED | ACTIVITY_STATE_USER_ACTIVE);
         mForceInvisible = 0;
         super.onStop();
+        mEventCallbacks[EVENT_STOPPED].executeAllAndClear();
+
 
         // Reset the overridden sysui flags used for the task-swipe launch animation, this is a
         // catch all for if we do not get resumed (and therefore not paused below)
@@ -239,6 +255,12 @@
     }
 
     @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mEventCallbacks[EVENT_DESTROYED].executeAllAndClear();
+    }
+
+    @Override
     protected void onPause() {
         setPaused();
         super.onPause();
@@ -258,7 +280,6 @@
         } else {
             removeActivityFlags(ACTIVITY_STATE_WINDOW_FOCUSED);
         }
-
     }
 
     protected void registerBackDispatcher() {
@@ -364,9 +385,15 @@
     }
 
     /**
-     * Attempts to clear accessibility focus on {@param view}.
+     * Adds a callback for the provided activity event
      */
-    public void tryClearAccessibilityFocus(View view) {
+    public void addEventCallback(@ActivityEvent int event, Runnable callback) {
+        mEventCallbacks[event].add(callback);
+    }
+
+    /** Removes a previously added callback */
+    public void removeEventCallback(@ActivityEvent int event, Runnable callback) {
+        mEventCallbacks[event].remove(callback);
     }
 
     public interface MultiWindowModeChangedListener {
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 808cf70..f8ed4df 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -38,7 +38,6 @@
 import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
 import com.android.launcher3.util.DisplayController.Info;
 import com.android.launcher3.util.OnColorHintListener;
-import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.TraceHelper;
 import com.android.launcher3.util.WallpaperColorHints;
@@ -51,8 +50,6 @@
 public abstract class BaseDraggingActivity extends BaseActivity
         implements OnColorHintListener, DisplayInfoChangeListener {
 
-    private static final String TAG = "BaseDraggingActivity";
-
     // When starting an action mode, setting this tag will cause the action mode to be cancelled
     // automatically when user interacts with the launcher.
     public static final Object AUTO_CANCEL_ACTION_MODE = new Object();
@@ -60,8 +57,6 @@
     private ActionMode mCurrentActionMode;
     protected boolean mIsSafeModeEnabled;
 
-    private Runnable mOnStartCallback;
-    private final RunnableList mOnResumeCallbacks = new RunnableList();
     private int mThemeRes = R.style.AppTheme;
 
     @Override
@@ -81,16 +76,6 @@
         }
     }
 
-    @Override
-    protected void onResume() {
-        super.onResume();
-        mOnResumeCallbacks.executeAllAndClear();
-    }
-
-    public void addOnResumeCallback(Runnable callback) {
-        mOnResumeCallbacks.add(callback);
-    }
-
     @MainThread
     @Override
     public void onColorHintsChanged(int colorHints) {
@@ -146,42 +131,24 @@
     @NonNull
     public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) {
         ActivityOptionsWrapper wrapper = super.getActivityLaunchOptions(v, item);
-        addOnResumeCallback(wrapper.onEndCallback::executeAllAndDestroy);
+        addEventCallback(EVENT_RESUMED, wrapper.onEndCallback::executeAllAndDestroy);
         return wrapper;
     }
 
     @Override
     public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
         ActivityOptionsWrapper wrapper = super.makeDefaultActivityOptions(splashScreenStyle);
-        addOnResumeCallback(wrapper.onEndCallback::executeAllAndDestroy);
+        addEventCallback(EVENT_RESUMED, wrapper.onEndCallback::executeAllAndDestroy);
         return wrapper;
     }
 
     @Override
-    protected void onStart() {
-        super.onStart();
-
-        if (mOnStartCallback != null) {
-            mOnStartCallback.run();
-            mOnStartCallback = null;
-        }
-    }
-
-    @Override
     protected void onDestroy() {
         super.onDestroy();
         DisplayController.INSTANCE.get(this).removeChangeListener(this);
         WallpaperColorHints.get(this).unregisterOnColorsChangedListener(this);
     }
 
-    public void runOnceOnStart(Runnable action) {
-        mOnStartCallback = action;
-    }
-
-    public void clearRunOnceOnStartCallback() {
-        mOnStartCallback = null;
-    }
-
     protected void onDeviceProfileInitiated() {
         if (mDeviceProfile.isVerticalBarLayout()) {
             mDeviceProfile.updateIsSeascape(this);
diff --git a/src/com/android/launcher3/DropTargetHandler.kt b/src/com/android/launcher3/DropTargetHandler.kt
index 6560e16..78f2862 100644
--- a/src/com/android/launcher3/DropTargetHandler.kt
+++ b/src/com/android/launcher3/DropTargetHandler.kt
@@ -2,6 +2,7 @@
 
 import android.content.ComponentName
 import android.view.View
+import com.android.launcher3.BaseDraggingActivity.EVENT_RESUMED
 import com.android.launcher3.DropTarget.DragObject
 import com.android.launcher3.SecondaryDropTarget.DeferredOnComplete
 import com.android.launcher3.dragndrop.DragLayer
@@ -32,7 +33,7 @@
                 if (d.dragSource is SecondaryDropTarget.DeferredOnComplete) {
                     target?.let {
                         deferred.mPackageName = it.packageName
-                        mLauncher.addOnResumeCallback { deferred.onLauncherResume() }
+                        mLauncher.addEventCallback(EVENT_RESUMED) { deferred.onLauncherResume() }
                     }
                         ?: deferred.sendFailure()
                 }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 9255ff4..edff48b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -237,6 +237,7 @@
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.shared.LauncherOverlayManager;
 import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
+import com.android.wm.shell.Flags;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -330,6 +331,7 @@
     private static final FloatProperty<Hotseat> HOTSEAT_WIDGET_SCALE =
             HOTSEAT_SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_WIDGET_TRANSITION);
 
+    private static final boolean ENABLE_DESKTOP_WINDOWING = Flags.enableDesktopWindowing();
     private static final boolean DESKTOP_MODE_SUPPORTED =
             "1".equals(Utilities.getSystemProperty("persist.wm.debug.desktop_mode_2", "0"));
 
@@ -688,7 +690,7 @@
 
     private void switchOverlay(Supplier<LauncherOverlayManager> overlaySupplier) {
         if (mOverlayManager != null) {
-            mOverlayManager.onActivityDestroyed(this);
+            mOverlayManager.onActivityDestroyed();
         }
         mOverlayManager = overlaySupplier.get();
         if (getRootView().isAttachedToWindow()) {
@@ -1029,7 +1031,7 @@
         if (mDeferOverlayCallbacks) {
             checkIfOverlayStillDeferred();
         } else {
-            mOverlayManager.onActivityStopped(this);
+            mOverlayManager.onActivityStopped();
         }
         hideKeyboard();
         logStopAndResume(false /* isResume */);
@@ -1043,7 +1045,7 @@
         TraceHelper.INSTANCE.beginSection(ON_START_EVT);
         super.onStart();
         if (!mDeferOverlayCallbacks) {
-            mOverlayManager.onActivityStarted(this);
+            mOverlayManager.onActivityStarted();
         }
 
         mAppWidgetHolder.setActivityStarted(true);
@@ -1112,15 +1114,15 @@
 
         // Move the client to the correct state. Calling the same method twice is no-op.
         if (isStarted()) {
-            mOverlayManager.onActivityStarted(this);
+            mOverlayManager.onActivityStarted();
         }
         if (hasBeenResumed()) {
-            mOverlayManager.onActivityResumed(this);
+            mOverlayManager.onActivityResumed();
         } else {
-            mOverlayManager.onActivityPaused(this);
+            mOverlayManager.onActivityPaused();
         }
         if (!isStarted()) {
-            mOverlayManager.onActivityStopped(this);
+            mOverlayManager.onActivityStopped();
         }
     }
 
@@ -1220,7 +1222,7 @@
         if (mDeferOverlayCallbacks) {
             scheduleDeferredCheck();
         } else {
-            mOverlayManager.onActivityResumed(this);
+            mOverlayManager.onActivityResumed();
         }
 
         DragView.removeAllViews(this);
@@ -1238,7 +1240,7 @@
         mDropTargetBar.animateToVisibility(false);
 
         if (!mDeferOverlayCallbacks) {
-            mOverlayManager.onActivityPaused(this);
+            mOverlayManager.onActivityPaused();
         }
         mAppWidgetHolder.setActivityResumed(false);
     }
@@ -1683,7 +1685,6 @@
         }
 
         super.onSaveInstanceState(outState);
-        mOverlayManager.onActivitySaveInstanceState(this, outState);
     }
 
     @Override
@@ -1709,7 +1710,7 @@
         clearPendingBinds();
         LauncherAppState.getIDP(this).removeOnChangeListener(this);
 
-        mOverlayManager.onActivityDestroyed(this);
+        mOverlayManager.onActivityDestroyed();
     }
 
     public LauncherAccessibilityDelegate getAccessibilityDelegate() {
@@ -1742,7 +1743,7 @@
         try {
             super.startIntentSenderForResult(intent, requestCode,
                     fillInIntent, flagsMask, flagsValues, extraFlags, options);
-        } catch (IntentSender.SendIntentException e) {
+        } catch (Exception e) {
             throw new ActivityNotFoundException();
         }
     }
@@ -2004,7 +2005,7 @@
             // Workaround an issue where the WM launch animation is clobbered when finishing the
             // recents animation into launcher. Defer launching the activity until Launcher is
             // next resumed.
-            addOnResumeCallback(() -> {
+            addEventCallback(EVENT_RESUMED, () -> {
                 RunnableList actualResult = startActivitySafely(v, intent, item);
                 if (actualResult != null) {
                     actualResult.add(result::executeAllAndDestroy);
@@ -3044,7 +3045,8 @@
     }
 
     private void updateDisallowBack() {
-        if (DESKTOP_MODE_SUPPORTED) {
+        // TODO(b/304778354): remove sysprop once desktop aconfig flag supports dynamic overriding
+        if (ENABLE_DESKTOP_WINDOWING || DESKTOP_MODE_SUPPORTED) {
             // Do not disable back in launcher when prototype behavior is enabled
             return;
         }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index e797147..8ba6d2c 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -56,7 +56,6 @@
 import android.os.DeadObjectException;
 import android.os.Handler;
 import android.os.Message;
-import android.os.Process;
 import android.os.TransactionTooLargeException;
 import android.text.Spannable;
 import android.text.SpannableString;
@@ -80,12 +79,15 @@
 
 import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
 import com.android.launcher3.graphics.TintedDrawableSpan;
+import com.android.launcher3.icons.BaseIconFactory;
+import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.icons.ShortcutCachingLogic;
 import com.android.launcher3.icons.ThemedIconDrawable;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.pm.ShortcutConfigActivityInfo;
+import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.shortcuts.ShortcutRequest;
 import com.android.launcher3.testing.shared.ResourceUtils;
@@ -674,11 +676,15 @@
         }
 
         if (badge == null) {
-            badge = Process.myUserHandle().equals(info.user)
-                    ? new ColorDrawable(Color.TRANSPARENT)
-                    : context.getDrawable(useTheme
-                            ? R.drawable.ic_work_app_badge_themed
-                            : R.drawable.ic_work_app_badge);
+            try (LauncherIcons li = LauncherIcons.obtain(context)) {
+                badge = BitmapInfo.LOW_RES_INFO.withFlags(
+                                li.getBitmapFlagOp(new BaseIconFactory.IconOptions().setUser(
+                                        UserCache.INSTANCE.get(context).getUserInfo(info.user))))
+                        .getBadgeDrawable(context, useTheme);
+            }
+            if (badge == null) {
+                badge = new ColorDrawable(Color.TRANSPARENT);
+            }
         }
         return Pair.create(result, badge);
     }
diff --git a/src/com/android/launcher3/util/RunnableList.java b/src/com/android/launcher3/util/RunnableList.java
index 644537b..f6e0c57 100644
--- a/src/com/android/launcher3/util/RunnableList.java
+++ b/src/com/android/launcher3/util/RunnableList.java
@@ -25,9 +25,7 @@
     private ArrayList<Runnable> mList = null;
     private boolean mDestroyed = false;
 
-    /**
-     * Ads a runnable to this list
-     */
+    /** Adds a runnable to this list */
     public void add(Runnable runnable) {
         if (runnable == null) {
             return;
@@ -42,6 +40,13 @@
         mList.add(runnable);
     }
 
+    /** Removes a previously added runnable */
+    public void remove(Runnable runnable) {
+        if (mList != null) {
+            mList.remove(runnable);
+        }
+    }
+
     /**
      * Destroys the list, executing any pending callbacks. All new callbacks are
      * immediately executed
diff --git a/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java b/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
index 6b27503..54cc0bc 100644
--- a/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
+++ b/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
@@ -15,16 +15,12 @@
  */
 package com.android.systemui.plugins.shared;
 
-import android.app.Activity;
-import android.app.Application;
-import android.os.Bundle;
-
 import java.io.PrintWriter;
 
 /**
  * Interface to control the overlay on Launcher
  */
-public interface LauncherOverlayManager extends Application.ActivityLifecycleCallbacks {
+public interface LauncherOverlayManager {
 
     default void onDeviceProvideChanged() { }
 
@@ -41,26 +37,15 @@
 
     default void hideOverlay(int duration) { }
 
-    @Override
-    default void onActivityCreated(Activity activity, Bundle bundle) { }
+    default void onActivityStarted() { }
 
-    @Override
-    default void onActivityStarted(Activity activity) { }
+    default void onActivityResumed() { }
 
-    @Override
-    default void onActivityResumed(Activity activity) { }
+    default void onActivityPaused() { }
 
-    @Override
-    default void onActivityPaused(Activity activity) { }
+    default void onActivityStopped() { }
 
-    @Override
-    default void onActivityStopped(Activity activity) { }
-
-    @Override
-    default void onActivitySaveInstanceState(Activity activity, Bundle bundle) { }
-
-    @Override
-    default void onActivityDestroyed(Activity activity) { }
+    default void onActivityDestroyed() { }
 
     interface LauncherOverlay {
 
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 669aaab..ed846ed 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.ui;
 
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
 import static com.android.launcher3.testing.shared.TestProtocol.ICON_MISSING;
@@ -204,13 +206,7 @@
     public ScreenRecordRule mScreenRecordRule = new ScreenRecordRule();
 
     @Rule
-    public SetFlagsRule mSetFlagsRule = getFlagsRule();
-
-    private SetFlagsRule getFlagsRule() {
-        SetFlagsRule flagsRule = new SetFlagsRule();
-        flagsRule.initAllFlagsToReleaseConfigDefault();
-        return flagsRule;
-    }
+    public SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
 
     protected void clearPackageData(String pkg) throws IOException, InterruptedException {
         final CountDownLatch count = new CountDownLatch(2);
diff --git a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
index 0d15300..58af51c 100644
--- a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
+++ b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
@@ -63,7 +63,8 @@
  */
 public class BubbleTextViewTest {
 
-    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+    @Rule public final SetFlagsRule mSetFlagsRule =
+            new SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT);
     private static final StringMatcherUtility.StringMatcher
             MATCHER = StringMatcherUtility.StringMatcher.getInstance();
     private static final UserHandle WORK_HANDLE = new UserHandle(13);
@@ -99,7 +100,6 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mSetFlagsRule.initAllFlagsToReleaseConfigDefault();
         Utilities.enableRunningInTestHarnessForTests();
         mContext = new ActivityContextWrapper(getApplicationContext());
         mBubbleTextView = new BubbleTextView(mContext);
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index aa5c770..a85b6bd 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -366,8 +366,10 @@
         }
         int focusedTaskHeight = mLauncher.getFocusedTaskHeightForTablet();
         for (UiObject2 task : taskViews) {
-            if (task.getVisibleBounds().height() == focusedTaskHeight) {
-                return new OverviewTask(mLauncher, task, this);
+            OverviewTask overviewTask = new OverviewTask(mLauncher, task, this);
+
+            if (overviewTask.getVisibleHeight() == focusedTaskHeight) {
+                return overviewTask;
             }
         }
         return null;
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 95a4802..06fac48 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -36,6 +36,8 @@
  */
 public final class OverviewTask {
     private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
+    private static final String TASK_SNAPSHOT_1 = "snapshot";
+    private static final String TASK_SNAPSHOT_2 = "bottomright_snapshot";
 
     static final Pattern TASK_START_EVENT = Pattern.compile("startActivityFromRecentsAsync");
     static final Pattern SPLIT_SELECT_EVENT = Pattern.compile("enterSplitSelect");
@@ -55,14 +57,64 @@
         mOverview.verifyActiveContainer();
     }
 
+    /**
+     * Returns the height of the visible task, or the combined height of two tasks in split with a
+     * divider between.
+     */
     int getVisibleHeight() {
+        if (isTaskSplit()) {
+            return getCombinedSplitTaskHeight();
+        }
+
         return mTask.getVisibleBounds().height();
     }
 
+    /**
+     * Calculates the visible height for split tasks, containing 2 snapshot tiles and a divider.
+     */
+    private int getCombinedSplitTaskHeight() {
+        UiObject2 taskSnapshot1 =
+                mLauncher.findObjectInContainer(mTask.getParent(), TASK_SNAPSHOT_1);
+        UiObject2 taskSnapshot2 =
+                mLauncher.findObjectInContainer(mTask.getParent(), TASK_SNAPSHOT_2);
+
+        int top = Math.min(
+                taskSnapshot1.getVisibleBounds().top, taskSnapshot2.getVisibleBounds().top);
+        int bottom = Math.max(
+                taskSnapshot1.getVisibleBounds().bottom, taskSnapshot2.getVisibleBounds().bottom);
+
+        return bottom - top;
+    }
+
+    /**
+     * Returns the width of the visible task, or the combined width of two tasks in split with a
+     * divider between.
+     */
     int getVisibleWidth() {
+        if (isTaskSplit()) {
+            return getCombinedSplitTaskWidth();
+        }
+
         return mTask.getVisibleBounds().width();
     }
 
+    /**
+     * Calculates the visible width for split tasks, containing 2 snapshot tiles and a divider.
+     */
+    private int getCombinedSplitTaskWidth() {
+        UiObject2 taskSnapshot1 =
+                mLauncher.findObjectInContainer(mTask.getParent(), TASK_SNAPSHOT_1);
+        UiObject2 taskSnapshot2 =
+                mLauncher.findObjectInContainer(mTask.getParent(), TASK_SNAPSHOT_2);
+
+        int left = Math.min(
+                taskSnapshot1.getVisibleBounds().left, taskSnapshot2.getVisibleBounds().left);
+        int right = Math.max(
+                taskSnapshot1.getVisibleBounds().right, taskSnapshot2.getVisibleBounds().right);
+
+        return right - left;
+    }
+
     int getTaskCenterX() {
         return mTask.getVisibleCenter().x;
     }