Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9610140b authored by Mady Mellor's avatar Mady Mellor
Browse files

Tests for optional bubble overflow

- Test that BSV is created to show / not show the overflow
- Test that BSV is updated to show / not show the overflow
- Test that BubbleController calls BSV.showOverflow appropriately

Flag: com.android.wm.shell.enable_optional_bubble_overflow
Test: atest BubblesTest BubbleStackViewTest
Bug: 334175587
Change-Id: I9d3fd40034fd6eac2ce9f68c3d277962d71d462a
parent 149f436f
Loading
Loading
Loading
Loading
+122 −6
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.content.res.Resources
import android.graphics.Color
import android.graphics.drawable.Icon
import android.os.UserHandle
import android.platform.test.flag.junit.SetFlagsRule
import android.view.IWindowManager
import android.view.WindowManager
import android.view.WindowManagerGlobal
@@ -33,6 +34,7 @@ import androidx.test.platform.app.InstrumentationRegistry
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.internal.protolog.common.ProtoLog
import com.android.launcher3.icons.BubbleIconFactory
import com.android.wm.shell.Flags
import com.android.wm.shell.R
import com.android.wm.shell.bubbles.Bubbles.SysuiProxy
import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix
@@ -44,19 +46,24 @@ import com.android.wm.shell.taskview.TaskViewTaskController
import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.MoreExecutors.directExecutor
import org.junit.After
import java.util.concurrent.Semaphore
import java.util.concurrent.TimeUnit
import java.util.function.Consumer
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.mock
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import java.util.concurrent.Semaphore
import java.util.concurrent.TimeUnit
import java.util.function.Consumer

/** Unit tests for [BubbleStackView]. */
@SmallTest
@RunWith(AndroidJUnit4::class)
class BubbleStackViewTest {

    @get:Rule val setFlagsRule = SetFlagsRule()

    private val context = ApplicationProvider.getApplicationContext<Context>()
    private lateinit var positioner: BubblePositioner
    private lateinit var iconFactory: BubbleIconFactory
@@ -66,6 +73,8 @@ class BubbleStackViewTest {
    private lateinit var windowManager: IWindowManager
    private lateinit var bubbleTaskViewFactory: BubbleTaskViewFactory
    private lateinit var bubbleData: BubbleData
    private lateinit var bubbleStackViewManager: FakeBubbleStackViewManager
    private var sysuiProxy = mock<SysuiProxy>()

    @Before
    fun setUp() {
@@ -86,7 +95,6 @@ class BubbleStackViewTest {
                )
            )
        positioner = BubblePositioner(context, windowManager)
        val bubbleStackViewManager = FakeBubbleStackViewManager()
        bubbleData =
            BubbleData(
                context,
@@ -95,8 +103,7 @@ class BubbleStackViewTest {
                BubbleEducationController(context),
                shellExecutor
            )

        val sysuiProxy = mock<SysuiProxy>()
        bubbleStackViewManager = FakeBubbleStackViewManager()
        expandedViewManager = FakeBubbleExpandedViewManager()
        bubbleTaskViewFactory = FakeBubbleTaskViewFactory()
        bubbleStackView =
@@ -234,6 +241,115 @@ class BubbleStackViewTest {
            .inOrder()
    }

    @EnableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW)
    @Test
    fun testCreateStackView_noOverflowContents_noOverflow() {
        bubbleStackView =
                BubbleStackView(
                        context,
                        bubbleStackViewManager,
                        positioner,
                        bubbleData,
                        null,
                        FloatingContentCoordinator(),
                        { sysuiProxy },
                        shellExecutor
                )

        assertThat(bubbleData.overflowBubbles).isEmpty()
        val bubbleOverflow = bubbleData.overflow
        // Overflow shouldn't be attached
        assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isEqualTo(-1)
    }

    @EnableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW)
    @Test
    fun testCreateStackView_hasOverflowContents_hasOverflow() {
        // Add a bubble to the overflow
        val bubble1 = createAndInflateChatBubble(key = "bubble1")
        bubbleData.notificationEntryUpdated(bubble1, false, false)
        bubbleData.dismissBubbleWithKey(bubble1.key, Bubbles.DISMISS_USER_GESTURE)
        assertThat(bubbleData.overflowBubbles).isNotEmpty()

        bubbleStackView =
                BubbleStackView(
                        context,
                        bubbleStackViewManager,
                        positioner,
                        bubbleData,
                        null,
                        FloatingContentCoordinator(),
                        { sysuiProxy },
                        shellExecutor
                )
        val bubbleOverflow = bubbleData.overflow
        assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isGreaterThan(-1)
    }

    @DisableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW)
    @Test
    fun testCreateStackView_noOverflowContents_hasOverflow() {
        bubbleStackView =
                BubbleStackView(
                        context,
                        bubbleStackViewManager,
                        positioner,
                        bubbleData,
                        null,
                        FloatingContentCoordinator(),
                        { sysuiProxy },
                        shellExecutor
                )

        assertThat(bubbleData.overflowBubbles).isEmpty()
        val bubbleOverflow = bubbleData.overflow
        assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isGreaterThan(-1)
    }

    @EnableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW)
    @Test
    fun showOverflow_true() {
        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            bubbleStackView.showOverflow(true)
        }
        InstrumentationRegistry.getInstrumentation().waitForIdleSync()

        val bubbleOverflow = bubbleData.overflow
        assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isGreaterThan(-1)
    }

    @EnableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW)
    @Test
    fun showOverflow_false() {
        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            bubbleStackView.showOverflow(true)
        }
        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
        val bubbleOverflow = bubbleData.overflow
        assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isGreaterThan(-1)

        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            bubbleStackView.showOverflow(false)
        }
        InstrumentationRegistry.getInstrumentation().waitForIdleSync()

        // The overflow should've been removed
        assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isEqualTo(-1)
    }

    @DisableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW)
    @Test
    fun showOverflow_ignored() {
        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            bubbleStackView.showOverflow(false)
        }
        InstrumentationRegistry.getInstrumentation().waitForIdleSync()

        // showOverflow should've been ignored, so the overflow would be attached
        val bubbleOverflow = bubbleData.overflow
        assertThat(bubbleStackView.getBubbleIndex(bubbleOverflow)).isGreaterThan(-1)
    }

    private fun createAndInflateChatBubble(key: String): Bubble {
        val icon = Icon.createWithResource(context.resources, R.drawable.bubble_ic_overflow_button)
        val shortcutInfo = ShortcutInfo.Builder(context, "fakeId").setIcon(icon).build()
+1 −1
Original line number Diff line number Diff line
@@ -3473,7 +3473,7 @@ public class BubbleStackView extends FrameLayout
     */
    int getBubbleIndex(@Nullable BubbleViewProvider provider) {
        if (provider == null) {
            return 0;
            return -1;
        }
        return mBubbleContainer.indexOfChild(provider.getIconView());
    }
+61 −0
Original line number Diff line number Diff line
@@ -152,6 +152,7 @@ import com.android.systemui.util.FakeEventLog;
import com.android.systemui.util.settings.FakeGlobalSettings;
import com.android.systemui.util.settings.SystemSettings;
import com.android.systemui.util.time.SystemClock;
import com.android.wm.shell.Flags;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.bubbles.Bubble;
@@ -2299,6 +2300,66 @@ public class BubblesTest extends SysuiTestCase {
        assertThat(bubbleStateListener.mStateChangeCalls).isEqualTo(0);
    }

    @EnableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW)
    @Test
    public void showBubbleOverflow_hasOverflowContents() {
        mEntryListener.onEntryAdded(mRow);
        mEntryListener.onEntryUpdated(mRow, /* fromSystem= */ true);
        assertThat(mBubbleData.getOverflowBubbles()).isEmpty();

        BubbleStackView stackView = mBubbleController.getStackView();
        spyOn(stackView);

        // Dismiss the bubble so it's in the overflow
        mBubbleController.removeBubble(mRow.getKey(), Bubbles.DISMISS_USER_GESTURE);
        assertThat(mBubbleData.getOverflowBubbles()).isNotEmpty();

        verify(stackView).showOverflow(eq(true));
    }

    @EnableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW)
    @Test
    public void showBubbleOverflow_isEmpty() {
        mEntryListener.onEntryAdded(mRow);
        mEntryListener.onEntryUpdated(mRow, /* fromSystem= */ true);
        assertThat(mBubbleData.getOverflowBubbles()).isEmpty();

        BubbleStackView stackView = mBubbleController.getStackView();
        spyOn(stackView);

        // Dismiss the bubble so it's in the overflow
        mBubbleController.removeBubble(mRow.getKey(), Bubbles.DISMISS_USER_GESTURE);
        assertThat(mBubbleData.getOverflowBubbles()).isNotEmpty();
        verify(stackView).showOverflow(eq(true));

        // Cancel the bubble so it's removed from the overflow
        mBubbleController.removeBubble(mRow.getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
        assertThat(mBubbleData.getOverflowBubbles()).isEmpty();
        verify(stackView).showOverflow(eq(false));
    }

    @DisableFlags(Flags.FLAG_ENABLE_OPTIONAL_BUBBLE_OVERFLOW)
    @Test
    public void showBubbleOverflow_ignored() {
        mEntryListener.onEntryAdded(mRow);
        mEntryListener.onEntryUpdated(mRow, /* fromSystem= */ true);
        assertThat(mBubbleData.getOverflowBubbles()).isEmpty();

        BubbleStackView stackView = mBubbleController.getStackView();
        spyOn(stackView);

        // Dismiss the bubble so it's in the overflow
        mBubbleController.removeBubble(mRow.getKey(), Bubbles.DISMISS_USER_GESTURE);
        assertThat(mBubbleData.getOverflowBubbles()).isNotEmpty();

        // Cancel the bubble so it's removed from the overflow
        mBubbleController.removeBubble(mRow.getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
        assertThat(mBubbleData.getOverflowBubbles()).isEmpty();

        // Show overflow should never be called if the flag is off
        verify(stackView, never()).showOverflow(anyBoolean());
    }

    /** Creates a bubble using the userId and package. */
    private Bubble createBubble(int userId, String pkg) {
        final UserHandle userHandle = new UserHandle(userId);