Loading libs/WindowManager/Shell/multivalentTests/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,8 @@ android_robolectric_test { "mockito-robolectric-prebuilt", "mockito-kotlin2", "truth", "flag-junit-base", "flag-junit", ], auto_gen_config: true, } Loading libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt +29 −2 Original line number Diff line number Diff line Loading @@ -18,14 +18,19 @@ package com.android.wm.shell.bubbles import android.content.ComponentName import android.content.Context import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.SetFlagsRule import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.wm.shell.Flags import com.android.wm.shell.taskview.TaskView import com.google.common.truth.Truth.assertThat import com.google.common.util.concurrent.MoreExecutors.directExecutor import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.mock Loading @@ -36,6 +41,9 @@ import org.mockito.kotlin.verify @RunWith(AndroidJUnit4::class) class BubbleTaskViewTest { @get:Rule val setFlagsRule = SetFlagsRule() private lateinit var bubbleTaskView: BubbleTaskView private val context = ApplicationProvider.getApplicationContext<Context>() private lateinit var taskView: TaskView Loading Loading @@ -75,14 +83,33 @@ class BubbleTaskViewTest { assertThat(actualComponentName).isEqualTo(componentName) } @DisableFlags(Flags.FLAG_ENABLE_TASK_VIEW_CONTROLLER_CLEANUP) @Test fun cleanup_invalidTaskId_doesNotRemoveTask() { fun cleanup_flagOff_invalidTaskId_doesNotRemoveTask() { bubbleTaskView.cleanup() verify(taskView, never()).removeTask() } @EnableFlags(Flags.FLAG_ENABLE_TASK_VIEW_CONTROLLER_CLEANUP) @Test fun cleanup_flagOn_invalidTaskId_removesTask() { bubbleTaskView.cleanup() verify(taskView).removeTask() } @DisableFlags(Flags.FLAG_ENABLE_TASK_VIEW_CONTROLLER_CLEANUP) @Test fun cleanup_flagOff_validTaskId_removesTask() { val componentName = ComponentName(context, "TestClass") bubbleTaskView.listener.onTaskCreated(123, componentName) bubbleTaskView.cleanup() verify(taskView).removeTask() } @EnableFlags(Flags.FLAG_ENABLE_TASK_VIEW_CONTROLLER_CLEANUP) @Test fun cleanup_validTaskId_removesTask() { fun cleanup_flagOn_validTaskId_removesTask() { val componentName = ComponentName(context, "TestClass") bubbleTaskView.listener.onTaskCreated(123, componentName) Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskView.kt +3 −19 Original line number Diff line number Diff line Loading @@ -16,14 +16,11 @@ package com.android.wm.shell.bubbles import android.app.ActivityTaskManager import android.app.ActivityTaskManager.INVALID_TASK_ID import android.content.ComponentName import android.os.RemoteException import android.util.Log import androidx.annotation.VisibleForTesting import com.android.wm.shell.Flags import com.android.wm.shell.taskview.TaskView import com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS import java.util.concurrent.Executor /** Loading Loading @@ -89,21 +86,8 @@ class BubbleTaskView(val taskView: TaskView, executor: Executor) { * This should be called after all other cleanup animations have finished. */ fun cleanup() { if (taskId != INVALID_TASK_ID) { // Ensure the task is removed from WM if (ENABLE_SHELL_TRANSITIONS) { if (Flags.enableTaskViewControllerCleanup() || taskId != INVALID_TASK_ID) { taskView.removeTask() } else { try { ActivityTaskManager.getService().removeTask(taskId) } catch (e: RemoteException) { Log.w(TAG, e.message ?: "") } } } } private companion object { const val TAG = "BubbleTaskView" } } libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java +8 −2 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.view.WindowInsets; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import com.android.wm.shell.Flags; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.SyncTransactionQueue; Loading Loading @@ -525,8 +526,13 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { */ void removeTask() { if (mTaskToken == null) { if (Flags.enableTaskViewControllerCleanup()) { // We don't have a task yet. Only clean up the controller mTaskViewTransitions.removeTaskView(this); } else { // Call to remove task before we have one, do nothing Slog.w(TAG, "Trying to remove a task that was never added? (no taskToken)"); } return; } mShellExecutor.execute(() -> { Loading libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java +32 −6 Original line number Diff line number Diff line Loading @@ -37,11 +37,14 @@ import android.window.WindowContainerTransaction; import androidx.annotation.VisibleForTesting; import com.android.wm.shell.Flags; import com.android.wm.shell.shared.TransitionUtil; import com.android.wm.shell.transition.Transitions; import java.util.ArrayList; import java.util.Map; import java.util.Objects; import java.util.WeakHashMap; /** * Handles Shell Transitions that involve TaskView tasks. Loading @@ -49,8 +52,15 @@ import java.util.Objects; public class TaskViewTransitions implements Transitions.TransitionHandler { static final String TAG = "TaskViewTransitions"; private final ArrayMap<TaskViewTaskController, TaskViewRequestedState> mTaskViews = new ArrayMap<>(); /** * Map of {@link TaskViewTaskController} to {@link TaskViewRequestedState}. * <p> * {@link TaskView} keeps a reference to the {@link TaskViewTaskController} instance and * manages its lifecycle. * Only keep a weak reference to the controller instance here to allow for it to be cleaned * up when its TaskView is no longer used. */ private final Map<TaskViewTaskController, TaskViewRequestedState> mTaskViews; private final ArrayList<PendingTransition> mPending = new ArrayList<>(); private final Transitions mTransitions; private final boolean[] mRegistered = new boolean[]{false}; Loading Loading @@ -95,6 +105,11 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { public TaskViewTransitions(Transitions transitions) { mTransitions = transitions; if (Flags.enableTaskViewControllerCleanup()) { mTaskViews = new WeakHashMap<>(); } else { mTaskViews = new ArrayMap<>(); } // Defer registration until the first TaskView because we want this to be the "first" in // priority when handling requests. // TODO(210041388): register here once we have an explicit ordering mechanism. Loading Loading @@ -208,10 +223,21 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { } private TaskViewTaskController findTaskView(ActivityManager.RunningTaskInfo taskInfo) { for (int i = 0; i < mTaskViews.size(); ++i) { if (mTaskViews.keyAt(i).getTaskInfo() == null) continue; if (taskInfo.token.equals(mTaskViews.keyAt(i).getTaskInfo().token)) { return mTaskViews.keyAt(i); if (Flags.enableTaskViewControllerCleanup()) { for (TaskViewTaskController controller : mTaskViews.keySet()) { if (controller.getTaskInfo() == null) continue; if (taskInfo.token.equals(controller.getTaskInfo().token)) { return controller; } } } else { ArrayMap<TaskViewTaskController, TaskViewRequestedState> taskViews = (ArrayMap<TaskViewTaskController, TaskViewRequestedState>) mTaskViews; for (int i = 0; i < taskViews.size(); ++i) { if (taskViews.keyAt(i).getTaskInfo() == null) continue; if (taskInfo.token.equals(taskViews.keyAt(i).getTaskInfo().token)) { return taskViews.keyAt(i); } } } return null; Loading Loading
libs/WindowManager/Shell/multivalentTests/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,8 @@ android_robolectric_test { "mockito-robolectric-prebuilt", "mockito-kotlin2", "truth", "flag-junit-base", "flag-junit", ], auto_gen_config: true, } Loading
libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskViewTest.kt +29 −2 Original line number Diff line number Diff line Loading @@ -18,14 +18,19 @@ package com.android.wm.shell.bubbles import android.content.ComponentName import android.content.Context import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.SetFlagsRule import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.wm.shell.Flags import com.android.wm.shell.taskview.TaskView import com.google.common.truth.Truth.assertThat import com.google.common.util.concurrent.MoreExecutors.directExecutor import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.mock Loading @@ -36,6 +41,9 @@ import org.mockito.kotlin.verify @RunWith(AndroidJUnit4::class) class BubbleTaskViewTest { @get:Rule val setFlagsRule = SetFlagsRule() private lateinit var bubbleTaskView: BubbleTaskView private val context = ApplicationProvider.getApplicationContext<Context>() private lateinit var taskView: TaskView Loading Loading @@ -75,14 +83,33 @@ class BubbleTaskViewTest { assertThat(actualComponentName).isEqualTo(componentName) } @DisableFlags(Flags.FLAG_ENABLE_TASK_VIEW_CONTROLLER_CLEANUP) @Test fun cleanup_invalidTaskId_doesNotRemoveTask() { fun cleanup_flagOff_invalidTaskId_doesNotRemoveTask() { bubbleTaskView.cleanup() verify(taskView, never()).removeTask() } @EnableFlags(Flags.FLAG_ENABLE_TASK_VIEW_CONTROLLER_CLEANUP) @Test fun cleanup_flagOn_invalidTaskId_removesTask() { bubbleTaskView.cleanup() verify(taskView).removeTask() } @DisableFlags(Flags.FLAG_ENABLE_TASK_VIEW_CONTROLLER_CLEANUP) @Test fun cleanup_flagOff_validTaskId_removesTask() { val componentName = ComponentName(context, "TestClass") bubbleTaskView.listener.onTaskCreated(123, componentName) bubbleTaskView.cleanup() verify(taskView).removeTask() } @EnableFlags(Flags.FLAG_ENABLE_TASK_VIEW_CONTROLLER_CLEANUP) @Test fun cleanup_validTaskId_removesTask() { fun cleanup_flagOn_validTaskId_removesTask() { val componentName = ComponentName(context, "TestClass") bubbleTaskView.listener.onTaskCreated(123, componentName) Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskView.kt +3 −19 Original line number Diff line number Diff line Loading @@ -16,14 +16,11 @@ package com.android.wm.shell.bubbles import android.app.ActivityTaskManager import android.app.ActivityTaskManager.INVALID_TASK_ID import android.content.ComponentName import android.os.RemoteException import android.util.Log import androidx.annotation.VisibleForTesting import com.android.wm.shell.Flags import com.android.wm.shell.taskview.TaskView import com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS import java.util.concurrent.Executor /** Loading Loading @@ -89,21 +86,8 @@ class BubbleTaskView(val taskView: TaskView, executor: Executor) { * This should be called after all other cleanup animations have finished. */ fun cleanup() { if (taskId != INVALID_TASK_ID) { // Ensure the task is removed from WM if (ENABLE_SHELL_TRANSITIONS) { if (Flags.enableTaskViewControllerCleanup() || taskId != INVALID_TASK_ID) { taskView.removeTask() } else { try { ActivityTaskManager.getService().removeTask(taskId) } catch (e: RemoteException) { Log.w(TAG, e.message ?: "") } } } } private companion object { const val TAG = "BubbleTaskView" } }
libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java +8 −2 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.view.WindowInsets; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import com.android.wm.shell.Flags; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.SyncTransactionQueue; Loading Loading @@ -525,8 +526,13 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { */ void removeTask() { if (mTaskToken == null) { if (Flags.enableTaskViewControllerCleanup()) { // We don't have a task yet. Only clean up the controller mTaskViewTransitions.removeTaskView(this); } else { // Call to remove task before we have one, do nothing Slog.w(TAG, "Trying to remove a task that was never added? (no taskToken)"); } return; } mShellExecutor.execute(() -> { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java +32 −6 Original line number Diff line number Diff line Loading @@ -37,11 +37,14 @@ import android.window.WindowContainerTransaction; import androidx.annotation.VisibleForTesting; import com.android.wm.shell.Flags; import com.android.wm.shell.shared.TransitionUtil; import com.android.wm.shell.transition.Transitions; import java.util.ArrayList; import java.util.Map; import java.util.Objects; import java.util.WeakHashMap; /** * Handles Shell Transitions that involve TaskView tasks. Loading @@ -49,8 +52,15 @@ import java.util.Objects; public class TaskViewTransitions implements Transitions.TransitionHandler { static final String TAG = "TaskViewTransitions"; private final ArrayMap<TaskViewTaskController, TaskViewRequestedState> mTaskViews = new ArrayMap<>(); /** * Map of {@link TaskViewTaskController} to {@link TaskViewRequestedState}. * <p> * {@link TaskView} keeps a reference to the {@link TaskViewTaskController} instance and * manages its lifecycle. * Only keep a weak reference to the controller instance here to allow for it to be cleaned * up when its TaskView is no longer used. */ private final Map<TaskViewTaskController, TaskViewRequestedState> mTaskViews; private final ArrayList<PendingTransition> mPending = new ArrayList<>(); private final Transitions mTransitions; private final boolean[] mRegistered = new boolean[]{false}; Loading Loading @@ -95,6 +105,11 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { public TaskViewTransitions(Transitions transitions) { mTransitions = transitions; if (Flags.enableTaskViewControllerCleanup()) { mTaskViews = new WeakHashMap<>(); } else { mTaskViews = new ArrayMap<>(); } // Defer registration until the first TaskView because we want this to be the "first" in // priority when handling requests. // TODO(210041388): register here once we have an explicit ordering mechanism. Loading Loading @@ -208,10 +223,21 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { } private TaskViewTaskController findTaskView(ActivityManager.RunningTaskInfo taskInfo) { for (int i = 0; i < mTaskViews.size(); ++i) { if (mTaskViews.keyAt(i).getTaskInfo() == null) continue; if (taskInfo.token.equals(mTaskViews.keyAt(i).getTaskInfo().token)) { return mTaskViews.keyAt(i); if (Flags.enableTaskViewControllerCleanup()) { for (TaskViewTaskController controller : mTaskViews.keySet()) { if (controller.getTaskInfo() == null) continue; if (taskInfo.token.equals(controller.getTaskInfo().token)) { return controller; } } } else { ArrayMap<TaskViewTaskController, TaskViewRequestedState> taskViews = (ArrayMap<TaskViewTaskController, TaskViewRequestedState>) mTaskViews; for (int i = 0; i < taskViews.size(); ++i) { if (taskViews.keyAt(i).getTaskInfo() == null) continue; if (taskInfo.token.equals(taskViews.keyAt(i).getTaskInfo().token)) { return taskViews.keyAt(i); } } } return null; Loading