Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskStackListener.kt +8 −16 Original line number Diff line number Diff line Loading @@ -14,9 +14,6 @@ * limitations under the License. */ // Exports bubble task utilities (e.g., `isBubbleToFullscreen`) for Java interop. @file:JvmName("BubbleTaskUtils") package com.android.wm.shell.bubbles import android.app.ActivityManager Loading @@ -25,6 +22,7 @@ import com.android.internal.protolog.ProtoLog import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.bubbles.util.BubbleUtils.getExitBubbleTransaction import com.android.wm.shell.bubbles.util.BubbleUtils.isBubbleToFullscreen import com.android.wm.shell.bubbles.util.BubbleUtils.isBubbleToSplit import com.android.wm.shell.common.TaskStackListenerCallback import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES_NOISY Loading Loading @@ -63,9 +61,9 @@ class BubbleTaskStackListener( taskId) bubbleData.getBubbleInStackWithTaskId(taskId)?.let { bubble -> when { isBubbleToFullscreen(task) -> moveCollapsedInStackBubbleToFullscreen(bubble, task) isBubbleToSplit(task) -> return // skip split task restarts !isAppBubbleMovingToFront(task) -> selectAndExpandInStackBubble(bubble, task) task.isBubbleToFullscreen() -> moveCollapsedInStackBubbleToFullscreen(bubble, task) task.isBubbleToSplit(splitScreenController) -> return // skip split task restarts !task.isAppBubbleMovingToFront() -> selectAndExpandInStackBubble(bubble, task) } } } Loading @@ -78,15 +76,9 @@ class BubbleTaskStackListener( taskId) bubbleData.getBubbleInStackWithTaskId(taskId)?.let { bubble -> when { isBubbleToFullscreen(task) -> moveCollapsedInStackBubbleToFullscreen(bubble, task) } task.isBubbleToFullscreen() -> moveCollapsedInStackBubbleToFullscreen(bubble, task) } } private fun isBubbleToSplit(task: ActivityManager.RunningTaskInfo): Boolean { return task.hasParentTask() && splitScreenController.get() .map { it.isTaskRootOrStageRoot(task.parentTaskId) } .orElse(false) } /** Loading @@ -95,9 +87,9 @@ class BubbleTaskStackListener( * This occurs when a startActivity call resolves to an existing activity, causing the * task to move to front, and the mixed transition will then expand the bubble. */ private fun isAppBubbleMovingToFront(task: ActivityManager.RunningTaskInfo): Boolean { return task.activityType == ACTIVITY_TYPE_STANDARD && bubbleController.shouldBeAppBubble(task) private fun ActivityManager.RunningTaskInfo?.isAppBubbleMovingToFront(): Boolean { return this?.activityType == ACTIVITY_TYPE_STANDARD && bubbleController.shouldBeAppBubble(this) } /** Selects and expands a bubble that is currently in the stack. */ Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskView.kt +2 −1 Original line number Diff line number Diff line Loading @@ -108,7 +108,8 @@ class BubbleTaskView(val taskView: TaskView, executor: Executor) { * This should be called after all other cleanup animations have finished. */ fun cleanup() { if (isBubbleToFullscreen(taskView.taskInfo)) { val task = taskView.taskInfo if (task.isBubbleToFullscreen()) { taskView.unregisterTask() } else { taskView.removeTask() Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesTransitionObserver.java +11 −11 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static com.android.wm.shell.Flags.enableEnterSplitRemoveBubble; import static com.android.wm.shell.bubbles.util.BubbleUtils.getExitBubbleTransaction; import static com.android.wm.shell.bubbles.util.BubbleUtils.isBubbleToSplit; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES_NOISY; import android.app.ActivityManager; Loading Loading @@ -159,29 +160,28 @@ public class BubblesTransitionObserver implements Transitions.TransitionObserver private void removeBubbleIfLaunchingToSplit(@NonNull TransitionInfo info) { if (mSplitScreenController.get().isEmpty()) return; SplitScreenController splitScreenController = mSplitScreenController.get().get(); for (TransitionInfo.Change change : info.getChanges()) { ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); for (final TransitionInfo.Change change : info.getChanges()) { final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); if (taskInfo == null) continue; Bubble bubble = mBubbleData.getBubbleInStackWithTaskId(taskInfo.taskId); final Bubble bubble = mBubbleData.getBubbleInStackWithTaskId(taskInfo.taskId); if (bubble == null) continue; if (!splitScreenController.isTaskRootOrStageRoot(taskInfo.parentTaskId)) continue; if (!isBubbleToSplit(taskInfo, mSplitScreenController)) continue; // There is a bubble task that is moving to split screen ProtoLog.d(WM_SHELL_BUBBLES_NOISY, "BubblesTransitionObserver.onTransitionReady(): " + "removing bubble for task launching into split taskId=%d", taskInfo.taskId); TaskViewTaskController taskViewTaskController = bubble.getTaskView().getController(); ShellTaskOrganizer taskOrganizer = taskViewTaskController.getTaskOrganizer(); WindowContainerTransaction wct = getExitBubbleTransaction(taskInfo.token, final TaskViewTaskController controller = bubble.getTaskView().getController(); final ShellTaskOrganizer taskOrganizer = controller.getTaskOrganizer(); final WindowContainerTransaction wct = getExitBubbleTransaction(taskInfo.token, bubble.getTaskView().getCaptionInsetsOwner()); // Notify the task removal, but block all TaskViewTransitions during removal so we can // clear them without triggering final IBinder gate = new Binder(); mTaskViewTransitions.enqueueExternal(taskViewTaskController, () -> gate); mTaskViewTransitions.enqueueExternal(controller, () -> gate); taskOrganizer.applyTransaction(wct); taskViewTaskController.notifyTaskRemovalStarted(taskInfo); mTaskViewTransitions.removePendingTransitions(taskViewTaskController); controller.notifyTaskRemovalStarted(taskInfo); mTaskViewTransitions.removePendingTransitions(controller); mTaskViewTransitions.onExternalDone(gate); } } Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/util/BubbleUtils.kt +18 −4 Original line number Diff line number Diff line Loading @@ -25,6 +25,9 @@ import android.view.WindowInsets import android.window.WindowContainerToken import android.window.WindowContainerTransaction import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper import com.android.wm.shell.splitscreen.SplitScreenController import dagger.Lazy import java.util.Optional object BubbleUtils { Loading Loading @@ -126,13 +129,24 @@ object BubbleUtils { /** Returns true if the task is valid for Bubble. */ @JvmStatic fun isValidToBubble(taskInfo: ActivityManager.RunningTaskInfo?): Boolean { return taskInfo != null && taskInfo.supportsMultiWindow fun ActivityManager.RunningTaskInfo?.isValidToBubble(): Boolean { return this?.supportsMultiWindow == true } /** Determines if a bubble task is moving to fullscreen based on its windowing mode. */ fun isBubbleToFullscreen(task: ActivityManager.RunningTaskInfo?): Boolean { @JvmStatic fun ActivityManager.RunningTaskInfo?.isBubbleToFullscreen(): Boolean { return BubbleAnythingFlagHelper.enableCreateAnyBubble() && task?.windowingMode == WINDOWING_MODE_FULLSCREEN && this?.windowingMode == WINDOWING_MODE_FULLSCREEN } /** Determines if a bubble task is moving to split-screen based on its parent task. */ @JvmStatic fun ActivityManager.RunningTaskInfo?.isBubbleToSplit( splitScreenController: Lazy<Optional<SplitScreenController>>, ): Boolean { return this?.hasParentTask() == true && splitScreenController.get() .map { it.isTaskRootOrStageRoot(parentTaskId) } .orElse(false) } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskStackListener.kt +8 −16 Original line number Diff line number Diff line Loading @@ -14,9 +14,6 @@ * limitations under the License. */ // Exports bubble task utilities (e.g., `isBubbleToFullscreen`) for Java interop. @file:JvmName("BubbleTaskUtils") package com.android.wm.shell.bubbles import android.app.ActivityManager Loading @@ -25,6 +22,7 @@ import com.android.internal.protolog.ProtoLog import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.bubbles.util.BubbleUtils.getExitBubbleTransaction import com.android.wm.shell.bubbles.util.BubbleUtils.isBubbleToFullscreen import com.android.wm.shell.bubbles.util.BubbleUtils.isBubbleToSplit import com.android.wm.shell.common.TaskStackListenerCallback import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES_NOISY Loading Loading @@ -63,9 +61,9 @@ class BubbleTaskStackListener( taskId) bubbleData.getBubbleInStackWithTaskId(taskId)?.let { bubble -> when { isBubbleToFullscreen(task) -> moveCollapsedInStackBubbleToFullscreen(bubble, task) isBubbleToSplit(task) -> return // skip split task restarts !isAppBubbleMovingToFront(task) -> selectAndExpandInStackBubble(bubble, task) task.isBubbleToFullscreen() -> moveCollapsedInStackBubbleToFullscreen(bubble, task) task.isBubbleToSplit(splitScreenController) -> return // skip split task restarts !task.isAppBubbleMovingToFront() -> selectAndExpandInStackBubble(bubble, task) } } } Loading @@ -78,15 +76,9 @@ class BubbleTaskStackListener( taskId) bubbleData.getBubbleInStackWithTaskId(taskId)?.let { bubble -> when { isBubbleToFullscreen(task) -> moveCollapsedInStackBubbleToFullscreen(bubble, task) } task.isBubbleToFullscreen() -> moveCollapsedInStackBubbleToFullscreen(bubble, task) } } private fun isBubbleToSplit(task: ActivityManager.RunningTaskInfo): Boolean { return task.hasParentTask() && splitScreenController.get() .map { it.isTaskRootOrStageRoot(task.parentTaskId) } .orElse(false) } /** Loading @@ -95,9 +87,9 @@ class BubbleTaskStackListener( * This occurs when a startActivity call resolves to an existing activity, causing the * task to move to front, and the mixed transition will then expand the bubble. */ private fun isAppBubbleMovingToFront(task: ActivityManager.RunningTaskInfo): Boolean { return task.activityType == ACTIVITY_TYPE_STANDARD && bubbleController.shouldBeAppBubble(task) private fun ActivityManager.RunningTaskInfo?.isAppBubbleMovingToFront(): Boolean { return this?.activityType == ACTIVITY_TYPE_STANDARD && bubbleController.shouldBeAppBubble(this) } /** Selects and expands a bubble that is currently in the stack. */ Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskView.kt +2 −1 Original line number Diff line number Diff line Loading @@ -108,7 +108,8 @@ class BubbleTaskView(val taskView: TaskView, executor: Executor) { * This should be called after all other cleanup animations have finished. */ fun cleanup() { if (isBubbleToFullscreen(taskView.taskInfo)) { val task = taskView.taskInfo if (task.isBubbleToFullscreen()) { taskView.unregisterTask() } else { taskView.removeTask() Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesTransitionObserver.java +11 −11 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static com.android.wm.shell.Flags.enableEnterSplitRemoveBubble; import static com.android.wm.shell.bubbles.util.BubbleUtils.getExitBubbleTransaction; import static com.android.wm.shell.bubbles.util.BubbleUtils.isBubbleToSplit; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES_NOISY; import android.app.ActivityManager; Loading Loading @@ -159,29 +160,28 @@ public class BubblesTransitionObserver implements Transitions.TransitionObserver private void removeBubbleIfLaunchingToSplit(@NonNull TransitionInfo info) { if (mSplitScreenController.get().isEmpty()) return; SplitScreenController splitScreenController = mSplitScreenController.get().get(); for (TransitionInfo.Change change : info.getChanges()) { ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); for (final TransitionInfo.Change change : info.getChanges()) { final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); if (taskInfo == null) continue; Bubble bubble = mBubbleData.getBubbleInStackWithTaskId(taskInfo.taskId); final Bubble bubble = mBubbleData.getBubbleInStackWithTaskId(taskInfo.taskId); if (bubble == null) continue; if (!splitScreenController.isTaskRootOrStageRoot(taskInfo.parentTaskId)) continue; if (!isBubbleToSplit(taskInfo, mSplitScreenController)) continue; // There is a bubble task that is moving to split screen ProtoLog.d(WM_SHELL_BUBBLES_NOISY, "BubblesTransitionObserver.onTransitionReady(): " + "removing bubble for task launching into split taskId=%d", taskInfo.taskId); TaskViewTaskController taskViewTaskController = bubble.getTaskView().getController(); ShellTaskOrganizer taskOrganizer = taskViewTaskController.getTaskOrganizer(); WindowContainerTransaction wct = getExitBubbleTransaction(taskInfo.token, final TaskViewTaskController controller = bubble.getTaskView().getController(); final ShellTaskOrganizer taskOrganizer = controller.getTaskOrganizer(); final WindowContainerTransaction wct = getExitBubbleTransaction(taskInfo.token, bubble.getTaskView().getCaptionInsetsOwner()); // Notify the task removal, but block all TaskViewTransitions during removal so we can // clear them without triggering final IBinder gate = new Binder(); mTaskViewTransitions.enqueueExternal(taskViewTaskController, () -> gate); mTaskViewTransitions.enqueueExternal(controller, () -> gate); taskOrganizer.applyTransaction(wct); taskViewTaskController.notifyTaskRemovalStarted(taskInfo); mTaskViewTransitions.removePendingTransitions(taskViewTaskController); controller.notifyTaskRemovalStarted(taskInfo); mTaskViewTransitions.removePendingTransitions(controller); mTaskViewTransitions.onExternalDone(gate); } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/util/BubbleUtils.kt +18 −4 Original line number Diff line number Diff line Loading @@ -25,6 +25,9 @@ import android.view.WindowInsets import android.window.WindowContainerToken import android.window.WindowContainerTransaction import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper import com.android.wm.shell.splitscreen.SplitScreenController import dagger.Lazy import java.util.Optional object BubbleUtils { Loading Loading @@ -126,13 +129,24 @@ object BubbleUtils { /** Returns true if the task is valid for Bubble. */ @JvmStatic fun isValidToBubble(taskInfo: ActivityManager.RunningTaskInfo?): Boolean { return taskInfo != null && taskInfo.supportsMultiWindow fun ActivityManager.RunningTaskInfo?.isValidToBubble(): Boolean { return this?.supportsMultiWindow == true } /** Determines if a bubble task is moving to fullscreen based on its windowing mode. */ fun isBubbleToFullscreen(task: ActivityManager.RunningTaskInfo?): Boolean { @JvmStatic fun ActivityManager.RunningTaskInfo?.isBubbleToFullscreen(): Boolean { return BubbleAnythingFlagHelper.enableCreateAnyBubble() && task?.windowingMode == WINDOWING_MODE_FULLSCREEN && this?.windowingMode == WINDOWING_MODE_FULLSCREEN } /** Determines if a bubble task is moving to split-screen based on its parent task. */ @JvmStatic fun ActivityManager.RunningTaskInfo?.isBubbleToSplit( splitScreenController: Lazy<Optional<SplitScreenController>>, ): Boolean { return this?.hasParentTask() == true && splitScreenController.get() .map { it.isTaskRootOrStageRoot(parentTaskId) } .orElse(false) } }