Loading libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerTest.kt +8 −1 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.isA import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.verify Loading @@ -94,6 +95,7 @@ class BubbleControllerTest(flags: FlagsParameterization) { private val displayImeController = mock<DisplayImeController>() private val displayInsetsController = mock<DisplayInsetsController>() private val userManager = mock<UserManager>() private val taskStackListener = mock<TaskStackListenerImpl>() private lateinit var bubbleController: BubbleController private lateinit var bubblePositioner: BubblePositioner Loading Loading @@ -164,6 +166,11 @@ class BubbleControllerTest(flags: FlagsParameterization) { getInstrumentation().waitForIdleSync() } @Test fun onInit_addsBubbleTaskStackListener() { verify(taskStackListener).addListener(isA<BubbleTaskStackListener>()) } @Test fun showOrHideNotesBubble_createsNoteBubble() { val intent = Intent(context, TestActivity::class.java) Loading Loading @@ -368,7 +375,7 @@ class BubbleControllerTest(flags: FlagsParameterization) { userManager, mock<LauncherApps>(), bubbleLogger, mock<TaskStackListenerImpl>(), taskStackListener, shellTaskOrganizer, bubblePositioner, displayController, Loading libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskStackListenerTest.kt 0 → 100644 +83 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.bubbles import android.app.ActivityManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.protolog.ProtoLog import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.stub import org.mockito.kotlin.verify /** Unit tests for [BubbleTaskStackListener]. */ @SmallTest @RunWith(AndroidJUnit4::class) class BubbleTaskStackListenerTest { private val bubble = mock<Bubble>() private val bubbleController = mock<BubbleController>() private val bubbleData = mock<BubbleData>() private val bubbleTaskStackListener = BubbleTaskStackListener( bubbleController, bubbleData, ) private val bubbleTaskId = 123 private val task = ActivityManager.RunningTaskInfo().apply { taskId = bubbleTaskId } @Before fun setUp() { ProtoLog.REQUIRE_PROTOLOGTOOL = false ProtoLog.init() } @Test fun onActivityRestartAttempt_inStackAppBubbleRestart_selectsAndExpandsStack() { bubbleData.stub { on { getBubbleInStackWithTaskId(bubbleTaskId) } doReturn bubble } bubbleTaskStackListener.onActivityRestartAttempt( task, homeTaskVisible = false, clearedTask = false, wasVisible = false, ) verify(bubbleData).setSelectedBubbleAndExpandStack(bubble) } @Test fun onActivityRestartAttempt_overflowAppBubbleRestart_promotesFromOverflow() { bubbleData.stub { on { getOverflowBubbleWithTaskId(bubbleTaskId) } doReturn bubble } bubbleTaskStackListener.onActivityRestartAttempt( task, homeTaskVisible = false, clearedTask = false, wasVisible = false, ) verify(bubbleController).promoteBubbleFromOverflow(bubble) verify(bubbleData).setExpanded(true) } } libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +1 −25 Original line number Diff line number Diff line Loading @@ -109,7 +109,6 @@ import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SingleInstanceRemoteListener; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.TaskStackListenerCallback; import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.onehanded.OneHandedController; Loading Loading @@ -495,30 +494,7 @@ public class BubbleController implements ConfigurationChangeListener, mTransitions.registerObserver(new BubblesTransitionObserver(this, mBubbleData)); mTaskStackListener.addListener(new TaskStackListenerCallback() { @Override public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) { final int taskId = task.taskId; Bubble bubble = mBubbleData.getBubbleInStackWithTaskId(taskId); if (bubble != null) { ProtoLog.d(WM_SHELL_BUBBLES, "onActivityRestartAttempt - taskId=%d selecting matching bubble=%s", taskId, bubble.getKey()); mBubbleData.setSelectedBubbleAndExpandStack(bubble); return; } bubble = mBubbleData.getOverflowBubbleWithTaskId(taskId); if (bubble != null) { ProtoLog.d(WM_SHELL_BUBBLES, "onActivityRestartAttempt - taskId=%d " + "selecting matching overflow bubble=%s", taskId, bubble.getKey()); promoteBubbleFromOverflow(bubble); mBubbleData.setExpanded(true); } } }); mTaskStackListener.addListener(new BubbleTaskStackListener(this, mBubbleData)); mDisplayController.addDisplayChangingController( (displayId, fromRotation, toRotation, newDisplayAreaInfo, t) -> { Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskStackListener.kt 0 → 100644 +83 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.bubbles import android.app.ActivityManager import com.android.internal.protolog.ProtoLog import com.android.wm.shell.common.TaskStackListenerCallback import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES /** * Listens for task stack changes and handles bubble interactions when activities are restarted. * * This class monitors task stack events to determine how bubbles should behave when their * associated activities are restarted. It handles scenarios where bubbles should be expanded. * * @property bubbleController The [BubbleController] to manage bubble promotions and expansions. * @property bubbleData The [BubbleData] to access and update bubble information. */ class BubbleTaskStackListener( private val bubbleController: BubbleController, private val bubbleData: BubbleData, ) : TaskStackListenerCallback { override fun onActivityRestartAttempt( task: ActivityManager.RunningTaskInfo, homeTaskVisible: Boolean, clearedTask: Boolean, wasVisible: Boolean, ) { val taskId = task.taskId bubbleData.getBubbleInStackWithTaskId(taskId)?.let { bubble -> selectAndExpandInStackBubble(bubble, task) return@onActivityRestartAttempt } bubbleData.getOverflowBubbleWithTaskId(taskId)?.let { bubble -> selectAndExpandOverflowBubble(bubble, task) } } /** Selects and expands a bubble that is currently in the stack. */ private fun selectAndExpandInStackBubble( bubble: Bubble, task: ActivityManager.RunningTaskInfo, ) { ProtoLog.d( WM_SHELL_BUBBLES, "selectAndExpandInStackBubble - taskId=%d selecting matching bubble=%s", task.taskId, bubble.key, ) bubbleData.setSelectedBubbleAndExpandStack(bubble) } /** Selects and expands a bubble that is currently in the overflow. */ private fun selectAndExpandOverflowBubble( bubble: Bubble, task: ActivityManager.RunningTaskInfo, ) { ProtoLog.d( WM_SHELL_BUBBLES, "selectAndExpandOverflowBubble - taskId=%d selecting matching overflow bubble=%s", task.taskId, bubble.key, ) bubbleController.promoteBubbleFromOverflow(bubble) bubbleData.setExpanded(true) } } Loading
libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerTest.kt +8 −1 Original line number Diff line number Diff line Loading @@ -75,6 +75,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.isA import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.verify Loading @@ -94,6 +95,7 @@ class BubbleControllerTest(flags: FlagsParameterization) { private val displayImeController = mock<DisplayImeController>() private val displayInsetsController = mock<DisplayInsetsController>() private val userManager = mock<UserManager>() private val taskStackListener = mock<TaskStackListenerImpl>() private lateinit var bubbleController: BubbleController private lateinit var bubblePositioner: BubblePositioner Loading Loading @@ -164,6 +166,11 @@ class BubbleControllerTest(flags: FlagsParameterization) { getInstrumentation().waitForIdleSync() } @Test fun onInit_addsBubbleTaskStackListener() { verify(taskStackListener).addListener(isA<BubbleTaskStackListener>()) } @Test fun showOrHideNotesBubble_createsNoteBubble() { val intent = Intent(context, TestActivity::class.java) Loading Loading @@ -368,7 +375,7 @@ class BubbleControllerTest(flags: FlagsParameterization) { userManager, mock<LauncherApps>(), bubbleLogger, mock<TaskStackListenerImpl>(), taskStackListener, shellTaskOrganizer, bubblePositioner, displayController, Loading
libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleTaskStackListenerTest.kt 0 → 100644 +83 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.bubbles import android.app.ActivityManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.protolog.ProtoLog import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.stub import org.mockito.kotlin.verify /** Unit tests for [BubbleTaskStackListener]. */ @SmallTest @RunWith(AndroidJUnit4::class) class BubbleTaskStackListenerTest { private val bubble = mock<Bubble>() private val bubbleController = mock<BubbleController>() private val bubbleData = mock<BubbleData>() private val bubbleTaskStackListener = BubbleTaskStackListener( bubbleController, bubbleData, ) private val bubbleTaskId = 123 private val task = ActivityManager.RunningTaskInfo().apply { taskId = bubbleTaskId } @Before fun setUp() { ProtoLog.REQUIRE_PROTOLOGTOOL = false ProtoLog.init() } @Test fun onActivityRestartAttempt_inStackAppBubbleRestart_selectsAndExpandsStack() { bubbleData.stub { on { getBubbleInStackWithTaskId(bubbleTaskId) } doReturn bubble } bubbleTaskStackListener.onActivityRestartAttempt( task, homeTaskVisible = false, clearedTask = false, wasVisible = false, ) verify(bubbleData).setSelectedBubbleAndExpandStack(bubble) } @Test fun onActivityRestartAttempt_overflowAppBubbleRestart_promotesFromOverflow() { bubbleData.stub { on { getOverflowBubbleWithTaskId(bubbleTaskId) } doReturn bubble } bubbleTaskStackListener.onActivityRestartAttempt( task, homeTaskVisible = false, clearedTask = false, wasVisible = false, ) verify(bubbleController).promoteBubbleFromOverflow(bubble) verify(bubbleData).setExpanded(true) } }
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +1 −25 Original line number Diff line number Diff line Loading @@ -109,7 +109,6 @@ import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SingleInstanceRemoteListener; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.TaskStackListenerCallback; import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.onehanded.OneHandedController; Loading Loading @@ -495,30 +494,7 @@ public class BubbleController implements ConfigurationChangeListener, mTransitions.registerObserver(new BubblesTransitionObserver(this, mBubbleData)); mTaskStackListener.addListener(new TaskStackListenerCallback() { @Override public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) { final int taskId = task.taskId; Bubble bubble = mBubbleData.getBubbleInStackWithTaskId(taskId); if (bubble != null) { ProtoLog.d(WM_SHELL_BUBBLES, "onActivityRestartAttempt - taskId=%d selecting matching bubble=%s", taskId, bubble.getKey()); mBubbleData.setSelectedBubbleAndExpandStack(bubble); return; } bubble = mBubbleData.getOverflowBubbleWithTaskId(taskId); if (bubble != null) { ProtoLog.d(WM_SHELL_BUBBLES, "onActivityRestartAttempt - taskId=%d " + "selecting matching overflow bubble=%s", taskId, bubble.getKey()); promoteBubbleFromOverflow(bubble); mBubbleData.setExpanded(true); } } }); mTaskStackListener.addListener(new BubbleTaskStackListener(this, mBubbleData)); mDisplayController.addDisplayChangingController( (displayId, fromRotation, toRotation, newDisplayAreaInfo, t) -> { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskStackListener.kt 0 → 100644 +83 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.bubbles import android.app.ActivityManager import com.android.internal.protolog.ProtoLog import com.android.wm.shell.common.TaskStackListenerCallback import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES /** * Listens for task stack changes and handles bubble interactions when activities are restarted. * * This class monitors task stack events to determine how bubbles should behave when their * associated activities are restarted. It handles scenarios where bubbles should be expanded. * * @property bubbleController The [BubbleController] to manage bubble promotions and expansions. * @property bubbleData The [BubbleData] to access and update bubble information. */ class BubbleTaskStackListener( private val bubbleController: BubbleController, private val bubbleData: BubbleData, ) : TaskStackListenerCallback { override fun onActivityRestartAttempt( task: ActivityManager.RunningTaskInfo, homeTaskVisible: Boolean, clearedTask: Boolean, wasVisible: Boolean, ) { val taskId = task.taskId bubbleData.getBubbleInStackWithTaskId(taskId)?.let { bubble -> selectAndExpandInStackBubble(bubble, task) return@onActivityRestartAttempt } bubbleData.getOverflowBubbleWithTaskId(taskId)?.let { bubble -> selectAndExpandOverflowBubble(bubble, task) } } /** Selects and expands a bubble that is currently in the stack. */ private fun selectAndExpandInStackBubble( bubble: Bubble, task: ActivityManager.RunningTaskInfo, ) { ProtoLog.d( WM_SHELL_BUBBLES, "selectAndExpandInStackBubble - taskId=%d selecting matching bubble=%s", task.taskId, bubble.key, ) bubbleData.setSelectedBubbleAndExpandStack(bubble) } /** Selects and expands a bubble that is currently in the overflow. */ private fun selectAndExpandOverflowBubble( bubble: Bubble, task: ActivityManager.RunningTaskInfo, ) { ProtoLog.d( WM_SHELL_BUBBLES, "selectAndExpandOverflowBubble - taskId=%d selecting matching overflow bubble=%s", task.taskId, bubble.key, ) bubbleController.promoteBubbleFromOverflow(bubble) bubbleData.setExpanded(true) } }