diff options
| author | 2024-10-29 17:04:42 +0000 | |
|---|---|---|
| committer | 2024-10-31 16:29:22 +0000 | |
| commit | f00a12f8d2951c24ecbf12256db079334cfae113 (patch) | |
| tree | a1919b9c18184bce1280343f312897a738cf5e81 | |
| parent | 0b7fa745f3c2919446e86e32ed45a41348c2f4b0 (diff) | |
Adds a new listener to propagate taskInfo changes when when change.mode is TRANSIT_CHANGE
To address an issue with task updates in Desktop Windowing not reflecting correctly in Overview when transitioning to FullScreen, notify listeners of task transit_change events. This will ensure the taskInfo in TopTaskTracker is updated when a task changes from freeform to fullscreen.
Fix: 356355595
Flag: com.android.window.flags.enable_task_stack_observer_in_shell
Test: Manual
Test: TaskStackTransitionObserverTest
Change-Id: I0e3f557098051069b2f1f7153aadbbce099197c0
4 files changed, 193 insertions, 16 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl index 245829ecafb3..371bdd5c6469 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl @@ -45,4 +45,7 @@ oneway interface IRecentTasksListener { /** A task has moved to front. */ oneway void onTaskMovedToFront(in RunningTaskInfo taskInfo); + + /** A task info has changed. */ + oneway void onTaskInfoChanged(in RunningTaskInfo taskInfo); }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java index 6086801491e2..a0ff4d426b29 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java @@ -289,6 +289,11 @@ public class RecentTasksController implements TaskStackListenerCallback, } @Override + public void onTaskChangedThroughTransition(@NonNull ActivityManager.RunningTaskInfo taskInfo) { + notifyTaskInfoChanged(taskInfo); + } + + @Override public void onTaskMovedToFrontThroughTransition( ActivityManager.RunningTaskInfo runningTaskInfo) { notifyTaskMovedToFront(runningTaskInfo); @@ -355,6 +360,19 @@ public class RecentTasksController implements TaskStackListenerCallback, } } + private void notifyTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { + if (mListener == null + || !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue() + || taskInfo.realActivity == null) { + return; + } + try { + mListener.onTaskInfoChanged(taskInfo); + } catch (RemoteException e) { + Slog.w(TAG, "Failed call onTaskInfoChanged", e); + } + } + private void notifyTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) { if (mListener == null || !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue() @@ -636,6 +654,11 @@ public class RecentTasksController implements TaskStackListenerCallback, public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) { mListener.call(l -> l.onTaskMovedToFront(taskInfo)); } + + @Override + public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { + mListener.call(l -> l.onTaskInfoChanged(taskInfo)); + } }; public IRecentTasksImpl(RecentTasksController controller) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt index 1af99f974a28..d28a462546f9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt @@ -20,8 +20,9 @@ import android.app.ActivityManager.RunningTaskInfo import android.os.IBinder import android.util.ArrayMap import android.view.SurfaceControl -import android.window.TransitionInfo +import android.view.WindowManager.TRANSIT_CHANGE import android.window.DesktopModeFlags +import android.window.TransitionInfo import com.android.wm.shell.shared.TransitionUtil import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.Transitions @@ -69,8 +70,10 @@ class TaskStackTransitionObserver( // Find the first task that is opening, this should be the one at the front after // the transition if (TransitionUtil.isOpeningType(change.mode)) { - notifyTaskStackTransitionObserverListeners(taskInfo) + notifyOnTaskMovedToFront(taskInfo) break + } else if (change.mode == TRANSIT_CHANGE) { + notifyOnTaskChanged(taskInfo) } } } @@ -95,15 +98,23 @@ class TaskStackTransitionObserver( taskStackTransitionObserverListeners.remove(taskStackTransitionObserverListener) } - private fun notifyTaskStackTransitionObserverListeners(taskInfo: RunningTaskInfo) { + private fun notifyOnTaskMovedToFront(taskInfo: RunningTaskInfo) { taskStackTransitionObserverListeners.forEach { (listener, executor) -> executor.execute { listener.onTaskMovedToFrontThroughTransition(taskInfo) } } } + private fun notifyOnTaskChanged(taskInfo: RunningTaskInfo) { + taskStackTransitionObserverListeners.forEach { (listener, executor) -> + executor.execute { listener.onTaskChangedThroughTransition(taskInfo) } + } + } + /** Listener to use to get updates regarding task stack from this observer */ interface TaskStackTransitionObserverListener { /** Called when a task is moved to front. */ fun onTaskMovedToFrontThroughTransition(taskInfo: RunningTaskInfo) {} + /** Called when a task info has changed. */ + fun onTaskChangedThroughTransition(taskInfo: RunningTaskInfo) {} } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt index afdb68776d04..efe4fb18f273 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt @@ -34,6 +34,7 @@ import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.TransitionInfoBuilder import com.android.wm.shell.transition.Transitions +import com.android.wm.shell.windowdecor.extension.isFullscreen import com.google.common.truth.Truth.assertThat import dagger.Lazy import org.junit.Before @@ -107,8 +108,8 @@ class TaskStackTransitionObserverTest { callOnTransitionFinished() executor.flushAll() - assertThat(listener.taskInfoToBeNotified.taskId).isEqualTo(change.taskInfo?.taskId) - assertThat(listener.taskInfoToBeNotified.windowingMode) + assertThat(listener.taskInfoOnTaskMovedToFront.taskId).isEqualTo(change.taskInfo?.taskId) + assertThat(listener.taskInfoOnTaskMovedToFront.windowingMode) .isEqualTo(change.taskInfo?.windowingMode) } @@ -130,8 +131,8 @@ class TaskStackTransitionObserverTest { callOnTransitionFinished() executor.flushAll() - assertThat(listener.taskInfoToBeNotified.taskId).isEqualTo(1) - assertThat(listener.taskInfoToBeNotified.windowingMode) + assertThat(listener.taskInfoOnTaskMovedToFront.taskId).isEqualTo(1) + assertThat(listener.taskInfoOnTaskMovedToFront.windowingMode) .isEqualTo(WindowConfiguration.WINDOWING_MODE_FULLSCREEN) } @@ -161,9 +162,9 @@ class TaskStackTransitionObserverTest { callOnTransitionFinished() executor.flushAll() - assertThat(listener.taskInfoToBeNotified.taskId) + assertThat(listener.taskInfoOnTaskMovedToFront.taskId) .isEqualTo(freeformOpenChange.taskInfo?.taskId) - assertThat(listener.taskInfoToBeNotified.windowingMode) + assertThat(listener.taskInfoOnTaskMovedToFront.windowingMode) .isEqualTo(freeformOpenChange.taskInfo?.windowingMode) } @@ -199,9 +200,15 @@ class TaskStackTransitionObserverTest { callOnTransitionFinished() executor.flushAll() - assertThat(listener.taskInfoToBeNotified.taskId).isEqualTo(change.taskInfo?.taskId) - assertThat(listener.taskInfoToBeNotified.windowingMode) + assertThat(listener.taskInfoOnTaskMovedToFront.taskId).isEqualTo(change.taskInfo?.taskId) + assertThat(listener.taskInfoOnTaskMovedToFront.windowingMode) .isEqualTo(change.taskInfo?.windowingMode) + + assertThat(listener.taskInfoOnTaskChanged.size).isEqualTo(1) + with(listener.taskInfoOnTaskChanged.last()) { + assertThat(taskId).isEqualTo(mergedChange.taskInfo?.taskId) + assertThat(windowingMode).isEqualTo(mergedChange.taskInfo?.windowingMode) + } } @Test @@ -236,18 +243,151 @@ class TaskStackTransitionObserverTest { callOnTransitionFinished() executor.flushAll() - assertThat(listener.taskInfoToBeNotified.taskId).isEqualTo(mergedChange.taskInfo?.taskId) - assertThat(listener.taskInfoToBeNotified.windowingMode) - .isEqualTo(mergedChange.taskInfo?.windowingMode) + assertThat(listener.taskInfoOnTaskMovedToFront.taskId) + .isEqualTo(mergedChange.taskInfo?.taskId) + assertThat(listener.taskInfoOnTaskMovedToFront.windowingMode) + .isEqualTo(mergedChange.taskInfo?.windowingMode) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) + fun taskChange_freeformWindowToFullscreenWindow_listenerNotified() { + val listener = TestListener() + val executor = TestShellExecutor() + transitionObserver.addTaskStackTransitionObserverListener(listener, executor) + val freeformState = + createChange( + WindowManager.TRANSIT_OPEN, + createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM) + ) + val transitionInfoOpen = + TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(freeformState).build() + callOnTransitionReady(transitionInfoOpen) + callOnTransitionFinished() + executor.flushAll() + + assertThat(listener.taskInfoOnTaskMovedToFront.taskId) + .isEqualTo(freeformState.taskInfo?.taskId) + assertThat(listener.taskInfoOnTaskMovedToFront.windowingMode) + .isEqualTo(freeformState.taskInfo?.windowingMode) + assertThat(listener.taskInfoOnTaskMovedToFront.isFullscreen).isEqualTo(false) + + // create change transition to update the windowing mode to full screen. + val fullscreenState = + createChange( + WindowManager.TRANSIT_CHANGE, + createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FULLSCREEN) + ) + val transitionInfoChange = + TransitionInfoBuilder(WindowManager.TRANSIT_CHANGE, 0) + .addChange(fullscreenState) + .build() + + callOnTransitionReady(transitionInfoChange) + callOnTransitionFinished() + executor.flushAll() + + // Asserting whether freeformState remains the same as before the change + assertThat(listener.taskInfoOnTaskMovedToFront.taskId) + .isEqualTo(freeformState.taskInfo?.taskId) + assertThat(listener.taskInfoOnTaskMovedToFront.isFullscreen).isEqualTo(false) + + // Asserting changes + assertThat(listener.taskInfoOnTaskChanged.size).isEqualTo(1) + with(listener.taskInfoOnTaskChanged.last()) { + assertThat(taskId).isEqualTo(fullscreenState.taskInfo?.taskId) + assertThat(isFullscreen).isEqualTo(true) + } + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) + fun singleTransition_withOpenAndChange_onlyOpenIsNotified() { + val listener = TestListener() + val executor = TestShellExecutor() + transitionObserver.addTaskStackTransitionObserverListener(listener, executor) + + // Creating multiple changes to be fired in a single transition + val freeformState = + createChange( + mode = WindowManager.TRANSIT_OPEN, + taskInfo = createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM) + ) + val fullscreenState = + createChange( + mode = WindowManager.TRANSIT_CHANGE, + taskInfo = createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FULLSCREEN) + ) + + val transitionInfoWithChanges = + TransitionInfoBuilder(WindowManager.TRANSIT_CHANGE, 0) + .addChange(freeformState) + .addChange(fullscreenState) + .build() + + callOnTransitionReady(transitionInfoWithChanges) + callOnTransitionFinished() + executor.flushAll() + + assertThat(listener.taskInfoOnTaskMovedToFront.taskId) + .isEqualTo(freeformState.taskInfo?.taskId) + assertThat(listener.taskInfoOnTaskMovedToFront.isFullscreen).isEqualTo(false) + assertThat(listener.taskInfoOnTaskChanged.size).isEqualTo(0) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) + fun singleTransition_withMultipleChanges_listenerNotified_forEachChange() { + val listener = TestListener() + val executor = TestShellExecutor() + transitionObserver.addTaskStackTransitionObserverListener(listener, executor) + + val taskId = 1 + + // Creating multiple changes to be fired in a single transition + val changes = + listOf( + WindowConfiguration.WINDOWING_MODE_FREEFORM, + WindowConfiguration.WINDOW_CONFIG_DISPLAY_ROTATION, + WindowConfiguration.WINDOWING_MODE_FULLSCREEN + ) + .map { change -> + createChange( + mode = WindowManager.TRANSIT_CHANGE, + taskInfo = createTaskInfo(taskId, change) + ) + } + + val transitionInfoWithChanges = + TransitionInfoBuilder(WindowManager.TRANSIT_CHANGE, 0) + .apply { changes.forEach { c -> this@apply.addChange(c) } } + .build() + + callOnTransitionReady(transitionInfoWithChanges) + callOnTransitionFinished() + executor.flushAll() + + assertThat(listener.taskInfoOnTaskChanged.size).isEqualTo(changes.size) + changes.forEachIndexed { index, change -> + assertThat(listener.taskInfoOnTaskChanged[index].taskId) + .isEqualTo(change.taskInfo?.taskId) + assertThat(listener.taskInfoOnTaskChanged[index].windowingMode) + .isEqualTo(change.taskInfo?.windowingMode) + } } class TestListener : TaskStackTransitionObserver.TaskStackTransitionObserverListener { - var taskInfoToBeNotified = ActivityManager.RunningTaskInfo() + var taskInfoOnTaskMovedToFront = ActivityManager.RunningTaskInfo() + var taskInfoOnTaskChanged = mutableListOf<ActivityManager.RunningTaskInfo>() override fun onTaskMovedToFrontThroughTransition( taskInfo: ActivityManager.RunningTaskInfo ) { - taskInfoToBeNotified = taskInfo + taskInfoOnTaskMovedToFront = taskInfo + } + + override fun onTaskChangedThroughTransition(taskInfo: ActivityManager.RunningTaskInfo) { + taskInfoOnTaskChanged += taskInfo } } |