Merge "BubbleController test for logging drag events" into main
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt
new file mode 100644
index 0000000..f535fbd
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2024 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.content.Context
+import android.content.pm.LauncherApps
+import android.graphics.Insets
+import android.graphics.Rect
+import android.os.Handler
+import android.os.UserManager
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import android.view.IWindowManager
+import android.view.WindowManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.internal.protolog.ProtoLog
+import com.android.internal.statusbar.IStatusBarService
+import com.android.wm.shell.Flags
+import com.android.wm.shell.ShellTaskOrganizer
+import com.android.wm.shell.WindowManagerShellWrapper
+import com.android.wm.shell.bubbles.Bubbles.SysuiProxy
+import com.android.wm.shell.bubbles.properties.ProdBubbleProperties
+import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayInsetsController
+import com.android.wm.shell.common.FloatingContentCoordinator
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.common.SyncTransactionQueue
+import com.android.wm.shell.common.TaskStackListenerImpl
+import com.android.wm.shell.draganddrop.DragAndDropController
+import com.android.wm.shell.shared.TransactionPool
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
+import com.android.wm.shell.shared.bubbles.BubbleBarUpdate
+import com.android.wm.shell.sysui.ShellCommandHandler
+import com.android.wm.shell.sysui.ShellController
+import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.taskview.TaskViewTransitions
+import com.android.wm.shell.transition.Transitions
+import com.google.common.truth.Truth.assertThat
+import com.google.common.util.concurrent.MoreExecutors.directExecutor
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+import java.util.Optional
+
+/** Tests for [BubbleController] when using bubble bar */
+@SmallTest
+@EnableFlags(Flags.FLAG_ENABLE_BUBBLE_BAR)
+@RunWith(AndroidJUnit4::class)
+class BubbleControllerBubbleBarTest {
+
+ companion object {
+ private const val SCREEN_WIDTH = 2000
+ private const val SCREEN_HEIGHT = 1000
+ }
+
+ @get:Rule val setFlagsRule = SetFlagsRule()
+
+ private val context = ApplicationProvider.getApplicationContext<Context>()
+
+ private lateinit var bubbleController: BubbleController
+ private lateinit var uiEventLoggerFake: UiEventLoggerFake
+ private lateinit var bubblePositioner: BubblePositioner
+ private lateinit var bubbleData: BubbleData
+ private lateinit var mainExecutor: TestExecutor
+ private lateinit var bgExecutor: TestExecutor
+
+ @Before
+ fun setUp() {
+ ProtoLog.REQUIRE_PROTOLOGTOOL = false
+ ProtoLog.init()
+
+ mainExecutor = TestExecutor()
+ bgExecutor = TestExecutor()
+
+ uiEventLoggerFake = UiEventLoggerFake()
+ val bubbleLogger = BubbleLogger(uiEventLoggerFake)
+
+ val deviceConfig =
+ DeviceConfig(
+ windowBounds = Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT),
+ isLargeScreen = true,
+ isSmallTablet = false,
+ isLandscape = true,
+ isRtl = false,
+ insets = Insets.of(10, 20, 30, 40),
+ )
+
+ bubblePositioner = BubblePositioner(context, deviceConfig)
+ bubblePositioner.isShowingInBubbleBar = true
+
+ bubbleData =
+ BubbleData(
+ context,
+ bubbleLogger,
+ bubblePositioner,
+ BubbleEducationController(context),
+ mainExecutor,
+ bgExecutor,
+ )
+
+ val shellInit = ShellInit(mainExecutor)
+
+ bubbleController =
+ createBubbleController(
+ shellInit,
+ bubbleData,
+ bubbleLogger,
+ bubblePositioner,
+ mainExecutor,
+ bgExecutor,
+ )
+ bubbleController.asBubbles().setSysuiProxy(Mockito.mock(SysuiProxy::class.java))
+
+ shellInit.init()
+
+ mainExecutor.flushAll()
+ bgExecutor.flushAll()
+
+ bubbleController.registerBubbleStateListener(FakeBubblesStateListener())
+ }
+
+ @After
+ fun tearDown() {
+ mainExecutor.flushAll()
+ bgExecutor.flushAll()
+ }
+
+ @Test
+ fun testEventLogging_bubbleBar_dragBarLeft() {
+ addBubble()
+
+ bubblePositioner.bubbleBarLocation = BubbleBarLocation.RIGHT
+
+ bubbleController.setBubbleBarLocation(
+ BubbleBarLocation.LEFT,
+ BubbleBarLocation.UpdateSource.DRAG_BAR,
+ )
+
+ // 2 events: add bubble + drag event
+ assertThat(uiEventLoggerFake.numLogs()).isEqualTo(2)
+ assertThat(uiEventLoggerFake.eventId(1))
+ .isEqualTo(BubbleLogger.Event.BUBBLE_BAR_MOVED_LEFT_DRAG_BAR.id)
+ }
+
+ @Test
+ fun testEventLogging_bubbleBar_dragBarRight() {
+ addBubble()
+
+ bubblePositioner.bubbleBarLocation = BubbleBarLocation.LEFT
+
+ bubbleController.setBubbleBarLocation(
+ BubbleBarLocation.RIGHT,
+ BubbleBarLocation.UpdateSource.DRAG_BAR,
+ )
+
+ // 2 events: add bubble + drag event
+ assertThat(uiEventLoggerFake.numLogs()).isEqualTo(2)
+ assertThat(uiEventLoggerFake.eventId(1))
+ .isEqualTo(BubbleLogger.Event.BUBBLE_BAR_MOVED_RIGHT_DRAG_BAR.id)
+ }
+
+ @Test
+ fun testEventLogging_bubbleBar_dragBubbleLeft() {
+ addBubble()
+
+ bubblePositioner.bubbleBarLocation = BubbleBarLocation.RIGHT
+
+ bubbleController.setBubbleBarLocation(
+ BubbleBarLocation.LEFT,
+ BubbleBarLocation.UpdateSource.DRAG_BUBBLE,
+ )
+
+ // 2 events: add bubble + drag event
+ assertThat(uiEventLoggerFake.numLogs()).isEqualTo(2)
+ assertThat(uiEventLoggerFake.eventId(1))
+ .isEqualTo(BubbleLogger.Event.BUBBLE_BAR_MOVED_LEFT_DRAG_BUBBLE.id)
+ }
+
+ @Test
+ fun testEventLogging_bubbleBar_dragBubbleRight() {
+ addBubble()
+
+ bubblePositioner.bubbleBarLocation = BubbleBarLocation.LEFT
+
+ bubbleController.setBubbleBarLocation(
+ BubbleBarLocation.RIGHT,
+ BubbleBarLocation.UpdateSource.DRAG_BUBBLE,
+ )
+
+ // 2 events: add bubble + drag event
+ assertThat(uiEventLoggerFake.numLogs()).isEqualTo(2)
+ assertThat(uiEventLoggerFake.eventId(1))
+ .isEqualTo(BubbleLogger.Event.BUBBLE_BAR_MOVED_RIGHT_DRAG_BUBBLE.id)
+ }
+
+ private fun addBubble(): Bubble {
+ val bubble = FakeBubbleFactory.createChatBubble(context)
+ bubble.setInflateSynchronously(true)
+ bubbleData.notificationEntryUpdated(
+ bubble,
+ /* suppressFlyout= */ true,
+ /* showInShade= */ true,
+ )
+ return bubble
+ }
+
+ private fun createBubbleController(
+ shellInit: ShellInit,
+ bubbleData: BubbleData,
+ bubbleLogger: BubbleLogger,
+ bubblePositioner: BubblePositioner,
+ mainExecutor: TestExecutor,
+ bgExecutor: TestExecutor,
+ ): BubbleController {
+ val shellCommandHandler = ShellCommandHandler()
+ val shellController =
+ ShellController(
+ context,
+ shellInit,
+ shellCommandHandler,
+ mock<DisplayInsetsController>(),
+ mainExecutor,
+ )
+ val surfaceSynchronizer = { obj: Runnable -> obj.run() }
+
+ val bubbleDataRepository =
+ BubbleDataRepository(
+ mock<LauncherApps>(),
+ mainExecutor,
+ bgExecutor,
+ BubblePersistentRepository(context),
+ )
+
+ val shellTaskOrganizer = mock<ShellTaskOrganizer>()
+ whenever(shellTaskOrganizer.executor).thenReturn(directExecutor())
+
+ return BubbleController(
+ context,
+ shellInit,
+ shellCommandHandler,
+ shellController,
+ bubbleData,
+ surfaceSynchronizer,
+ FloatingContentCoordinator(),
+ bubbleDataRepository,
+ mock<IStatusBarService>(),
+ mock<WindowManager>(),
+ WindowManagerShellWrapper(mainExecutor),
+ mock<UserManager>(),
+ mock<LauncherApps>(),
+ bubbleLogger,
+ mock<TaskStackListenerImpl>(),
+ shellTaskOrganizer,
+ bubblePositioner,
+ mock<DisplayController>(),
+ /* oneHandedOptional= */ Optional.empty(),
+ mock<DragAndDropController>(),
+ mainExecutor,
+ mock<Handler>(),
+ bgExecutor,
+ mock<TaskViewTransitions>(),
+ mock<Transitions>(),
+ SyncTransactionQueue(TransactionPool(), mainExecutor),
+ mock<IWindowManager>(),
+ ProdBubbleProperties,
+ )
+ }
+
+ private class TestExecutor : ShellExecutor {
+
+ private val runnables: MutableList<Runnable> = mutableListOf()
+
+ override fun execute(runnable: Runnable) {
+ runnables.add(runnable)
+ }
+
+ override fun executeDelayed(runnable: Runnable, delayMillis: Long) {
+ execute(runnable)
+ }
+
+ override fun removeCallbacks(runnable: Runnable?) {}
+
+ override fun hasCallback(runnable: Runnable?): Boolean = false
+
+ fun flushAll() {
+ while (runnables.isNotEmpty()) {
+ runnables.removeAt(0).run()
+ }
+ }
+ }
+
+ private class FakeBubblesStateListener : Bubbles.BubbleStateListener {
+ override fun onBubbleStateChange(update: BubbleBarUpdate?) {}
+
+ override fun animateBubbleBarLocation(location: BubbleBarLocation?) {}
+ }
+}
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/FakeBubbleFactory.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/FakeBubbleFactory.kt
index cb6fb62..3279d56 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/FakeBubbleFactory.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/FakeBubbleFactory.kt
@@ -32,10 +32,10 @@
return BubbleViewInfo().apply { bubbleBarExpandedView = bubbleExpandedView }
}
- fun createChatBubbleWithViewInfo(
+ fun createChatBubble(
context: Context,
key: String = "key",
- viewInfo: BubbleViewInfo,
+ viewInfo: BubbleViewInfo? = null,
): Bubble {
val bubble =
Bubble(
@@ -50,7 +50,9 @@
directExecutor(),
directExecutor(),
) {}
- bubble.setViewInfo(viewInfo)
+ if (viewInfo != null) {
+ bubble.setViewInfo(viewInfo)
+ }
return bubble
}
}
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt
index 3d34cba..7280f8a 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt
@@ -165,7 +165,7 @@
}
val viewInfo = FakeBubbleFactory.createViewInfo(bubbleBarExpandedView)
- bubble = FakeBubbleFactory.createChatBubbleWithViewInfo(context, viewInfo = viewInfo)
+ bubble = FakeBubbleFactory.createChatBubble(context, viewInfo = viewInfo)
}
@After
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 068b2d2..0fd4206 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -101,9 +101,13 @@
private int mBubbleBarTopOnScreen;
public BubblePositioner(Context context, WindowManager windowManager) {
+ this(context, DeviceConfig.create(context, windowManager));
+ }
+
+ public BubblePositioner(Context context, DeviceConfig deviceConfig) {
mContext = context;
- mDeviceConfig = DeviceConfig.create(context, windowManager);
- update(mDeviceConfig);
+ mDeviceConfig = deviceConfig;
+ update(deviceConfig);
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index aad8b4b..5d4d9e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -2575,78 +2575,6 @@
@EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
@Test
- public void testEventLogging_bubbleBar_dragBarLeft() {
- mBubbleProperties.mIsBubbleBarEnabled = true;
- mPositioner.setIsLargeScreen(true);
- mPositioner.setBubbleBarLocation(BubbleBarLocation.RIGHT);
- FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
- mBubbleController.registerBubbleStateListener(bubbleStateListener);
-
- mEntryListener.onEntryAdded(mRow);
- assertBarMode();
-
- mBubbleController.setBubbleBarLocation(BubbleBarLocation.LEFT,
- BubbleBarLocation.UpdateSource.DRAG_BAR);
-
- verify(mBubbleLogger).log(BubbleLogger.Event.BUBBLE_BAR_MOVED_LEFT_DRAG_BAR);
- }
-
- @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
- @Test
- public void testEventLogging_bubbleBar_dragBarRight() {
- mBubbleProperties.mIsBubbleBarEnabled = true;
- mPositioner.setIsLargeScreen(true);
- mPositioner.setBubbleBarLocation(BubbleBarLocation.LEFT);
- FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
- mBubbleController.registerBubbleStateListener(bubbleStateListener);
-
- mEntryListener.onEntryAdded(mRow);
- assertBarMode();
-
- mBubbleController.setBubbleBarLocation(BubbleBarLocation.RIGHT,
- BubbleBarLocation.UpdateSource.DRAG_BAR);
-
- verify(mBubbleLogger).log(BubbleLogger.Event.BUBBLE_BAR_MOVED_RIGHT_DRAG_BAR);
- }
-
- @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
- @Test
- public void testEventLogging_bubbleBar_dragBubbleLeft() {
- mBubbleProperties.mIsBubbleBarEnabled = true;
- mPositioner.setIsLargeScreen(true);
- mPositioner.setBubbleBarLocation(BubbleBarLocation.RIGHT);
- FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
- mBubbleController.registerBubbleStateListener(bubbleStateListener);
-
- mEntryListener.onEntryAdded(mRow);
- assertBarMode();
-
- mBubbleController.setBubbleBarLocation(BubbleBarLocation.LEFT,
- BubbleBarLocation.UpdateSource.DRAG_BUBBLE);
-
- verify(mBubbleLogger).log(BubbleLogger.Event.BUBBLE_BAR_MOVED_LEFT_DRAG_BUBBLE);
- }
-
- @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
- @Test
- public void testEventLogging_bubbleBar_dragBubbleRight() {
- mBubbleProperties.mIsBubbleBarEnabled = true;
- mPositioner.setIsLargeScreen(true);
- mPositioner.setBubbleBarLocation(BubbleBarLocation.LEFT);
- FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
- mBubbleController.registerBubbleStateListener(bubbleStateListener);
-
- mEntryListener.onEntryAdded(mRow);
- assertBarMode();
-
- mBubbleController.setBubbleBarLocation(BubbleBarLocation.RIGHT,
- BubbleBarLocation.UpdateSource.DRAG_BUBBLE);
-
- verify(mBubbleLogger).log(BubbleLogger.Event.BUBBLE_BAR_MOVED_RIGHT_DRAG_BUBBLE);
- }
-
- @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
- @Test
public void testEventLogging_bubbleBar_expandAndCollapse() {
mBubbleProperties.mIsBubbleBarEnabled = true;
mPositioner.setIsLargeScreen(true);