Fix launcher activity leaking when desktop windowing enabled
When desktop windowing is enabled we initiate the
`SplitFromDesktopController` within the `SplitSelectStateController`
which registers a `SplitSelectListener` on the launcher instance.
However when we destroy the `SplitSelectStateController` the
`SplitFromDesktopController` is not destroyed an thus any listeners are
not unregisterd. Instead we should explicitly destroy the
`SplitFromDesktopController` by unregistering listener.
Flag: NONE
Fixes: 332667403
Bug: 331774319
Test: atest -c NexusLauncherTests:com.android.quickstep.TaplStartLauncherViaGestureTests
atest -c NexusLauncherTests:com.android.quickstep.util.SplitSelectStateControllerTest
Change-Id: I68ffcc4114644e75f751632eca8bc73e406139a8
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index d8cbbf9..4089498 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -70,6 +70,7 @@
import android.window.TransitionInfo;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.InstanceId;
import com.android.launcher3.Launcher;
@@ -132,6 +133,7 @@
private final StatsLogManager mStatsLogManager;
private final SystemUiProxy mSystemUiProxy;
private final StateManager mStateManager;
+ @Nullable
private SplitFromDesktopController mSplitFromDesktopController;
@Nullable
private DepthController mDepthController;
@@ -208,6 +210,9 @@
mActivityBackCallback = null;
mAppPairsController.onDestroy();
mSplitSelectDataHolder.onDestroy();
+ if (mSplitFromDesktopController != null) {
+ mSplitFromDesktopController.onDestroy();
+ }
}
/**
@@ -643,7 +648,12 @@
}
public void initSplitFromDesktopController(Launcher launcher) {
- mSplitFromDesktopController = new SplitFromDesktopController(launcher);
+ initSplitFromDesktopController(new SplitFromDesktopController(launcher));
+ }
+
+ @VisibleForTesting
+ void initSplitFromDesktopController(SplitFromDesktopController controller) {
+ mSplitFromDesktopController = controller;
}
private RemoteTransition getShellRemoteTransition(int firstTaskId, int secondTaskId,
@@ -977,6 +987,11 @@
SystemUiProxy.INSTANCE.get(mLauncher).registerSplitSelectListener(mSplitSelectListener);
}
+ void onDestroy() {
+ SystemUiProxy.INSTANCE.get(mLauncher).unregisterSplitSelectListener(
+ mSplitSelectListener);
+ }
+
/**
* Enter split select from desktop mode.
* @param taskInfo the desktop task to move to split stage
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
index 18b1ea0..a7ed8a7 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
@@ -36,6 +36,7 @@
import com.android.launcher3.util.SplitConfigurationOptions
import com.android.quickstep.RecentsModel
import com.android.quickstep.SystemUiProxy
+import com.android.quickstep.util.SplitSelectStateController.SplitFromDesktopController
import com.android.systemui.shared.recents.model.Task
import com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50
import java.util.function.Consumer
@@ -65,6 +66,7 @@
private val context: StatefulActivity<*> = mock()
private val recentsModel: RecentsModel = mock()
private val pendingIntent: PendingIntent = mock()
+ private val splitFromDesktopController: SplitFromDesktopController = mock()
private lateinit var splitSelectStateController: SplitSelectStateController
@@ -607,6 +609,18 @@
assertTrue(splitSelectStateController.isBothSplitAppsConfirmed)
}
+ @Test
+ fun splitSelectStateControllerDestroyed_SplitFromDesktopControllerAlsoDestroyed() {
+ // Initiate split from desktop controller
+ splitSelectStateController.initSplitFromDesktopController(splitFromDesktopController)
+
+ // Simulate default controller being destroyed
+ splitSelectStateController.onDestroy()
+
+ // Verify desktop controller is also destroyed
+ verify(splitFromDesktopController).onDestroy()
+ }
+
// Generate GroupTask with default userId.
private fun generateGroupTask(
task1ComponentName: ComponentName,