[4/5] Cover DragToBubbleController with tests.
Implement tests that check DragToBubbleController public API Bug: 411506181 Flag: com.android.wm.shell.enable_create_any_bubble Test: DragToBubbleController.kt Change-Id: I48fe5f45921fbedbe0f1921dfd21e9ecb14406bc
This commit is contained in:
@@ -39,18 +39,18 @@ import com.android.wm.shell.shared.bubbles.DraggedObject
|
||||
import com.android.wm.shell.shared.bubbles.DraggedObject.LauncherIcon
|
||||
import com.android.wm.shell.shared.bubbles.DropTargetManager
|
||||
import com.android.wm.shell.shared.bubbles.DropTargetManager.DragZoneChangedListener
|
||||
import com.google.common.annotations.VisibleForTesting
|
||||
|
||||
// TODO(b/411506181) add tests
|
||||
class DragToBubbleController(
|
||||
private val context: Context,
|
||||
private val bubbleBarContainer: FrameLayout,
|
||||
) : DragController.DragListener {
|
||||
|
||||
private val dropTargetManager: DropTargetManager
|
||||
@VisibleForTesting val dropTargetManager: DropTargetManager
|
||||
|
||||
private lateinit var bubbleBarLeftDropTarget: BubbleBarLocationDropTarget
|
||||
private lateinit var bubbleBarRightDropTarget: BubbleBarLocationDropTarget
|
||||
private lateinit var dragZoneFactory: DragZoneFactory
|
||||
@VisibleForTesting lateinit var bubbleBarLeftDropTarget: BubbleBarLocationDropTarget
|
||||
@VisibleForTesting lateinit var bubbleBarRightDropTarget: BubbleBarLocationDropTarget
|
||||
@VisibleForTesting lateinit var dragZoneFactory: DragZoneFactory
|
||||
private lateinit var systemUiProxy: SystemUiProxy
|
||||
private lateinit var bubbleBarViewController: BubbleBarViewController
|
||||
private val isRtl: Boolean
|
||||
|
||||
+301
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* 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.launcher3.taskbar.bubbles
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Insets
|
||||
import android.graphics.Rect
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.animation.AnimatorTestRule
|
||||
import androidx.test.core.app.ApplicationProvider.getApplicationContext
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import com.android.launcher3.DropTarget
|
||||
import com.android.launcher3.DropTarget.DragObject
|
||||
import com.android.launcher3.dragndrop.DragOptions
|
||||
import com.android.launcher3.model.data.AppInfo
|
||||
import com.android.quickstep.SystemUiProxy
|
||||
import com.android.wm.shell.shared.bubbles.BubbleBarLocation
|
||||
import com.android.wm.shell.shared.bubbles.DeviceConfig
|
||||
import com.android.wm.shell.shared.bubbles.DragZoneFactory
|
||||
import com.android.wm.shell.shared.bubbles.DragZoneFactory.BubbleBarPropertiesProvider
|
||||
import com.android.wm.shell.shared.bubbles.DragZoneFactory.SplitScreenModeChecker.SplitScreenMode
|
||||
import com.android.wm.shell.shared.bubbles.DropTargetView
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.never
|
||||
import org.mockito.kotlin.stub
|
||||
import org.mockito.kotlin.verify
|
||||
|
||||
/** Unit tests for [DragToBubbleControllerTest]. */
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class DragToBubbleControllerTest {
|
||||
|
||||
@get:Rule val animatorTestRule = AnimatorTestRule()
|
||||
|
||||
private val context = getApplicationContext<Context>()
|
||||
private val container = FrameLayout(context)
|
||||
private val bubbleBarViewController: BubbleBarViewController = mock()
|
||||
private val systemUiProxy: SystemUiProxy = mock()
|
||||
private val bubbleBarPropertiesProvider = FakeBubbleBarPropertiesProvider()
|
||||
private val testDragZonesFactory = createTestDragZoneFactory()
|
||||
private val dragObject = DragObject(context)
|
||||
private lateinit var dragToBubbleController: DragToBubbleController
|
||||
|
||||
private val dropTargetView: DropTargetView
|
||||
get() = dragToBubbleController.dropTargetManager.dropTargetView
|
||||
|
||||
private val secondDropTargetView: DropTargetView?
|
||||
get() = dragToBubbleController.dropTargetManager.secondDropTargetView
|
||||
|
||||
private val bubbleBarLeftDropTarget: DropTarget
|
||||
get() = dragToBubbleController.bubbleBarLeftDropTarget
|
||||
|
||||
private val bubbleBarRightDropTarget: DropTarget
|
||||
get() = dragToBubbleController.bubbleBarRightDropTarget
|
||||
|
||||
private val leftDropTargetRect: Rect
|
||||
get() = testDragZonesFactory.getBubbleBarDropRect(isLeftSide = true)
|
||||
|
||||
private val rightDropTargetRect: Rect
|
||||
get() = testDragZonesFactory.getBubbleBarDropRect(isLeftSide = false)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
dragToBubbleController = DragToBubbleController(context, container)
|
||||
dragToBubbleController.init(
|
||||
bubbleBarViewController,
|
||||
bubbleBarPropertiesProvider,
|
||||
systemUiProxy,
|
||||
)
|
||||
dragToBubbleController.dragZoneFactory = testDragZonesFactory
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dragStarted_noBubbleBar_dropZonesAdded() {
|
||||
dragToBubbleController.onDragStart(dragObject, DragOptions())
|
||||
|
||||
assertThat(container.childCount).isEqualTo(DROP_VIEWS_COUNT_NO_BUBBLE_BAR)
|
||||
assertThat(dropTargetView.parent).isEqualTo(container)
|
||||
assertThat(secondDropTargetView!!.parent).isEqualTo(container)
|
||||
assertThat(dropTargetView.alpha).isEqualTo(0f)
|
||||
assertThat(secondDropTargetView!!.alpha).isEqualTo(0f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dragStarted_hasBubbleBar_dropZonesAdded() {
|
||||
prepareBubbleBarViewController(hasBubbles = true)
|
||||
dragToBubbleController.onDragStart(dragObject, DragOptions())
|
||||
|
||||
assertThat(container.childCount).isEqualTo(DROP_VIEWS_COUNT)
|
||||
assertThat(dropTargetView.parent).isEqualTo(container)
|
||||
assertThat(dropTargetView.alpha).isEqualTo(0f)
|
||||
assertThat(secondDropTargetView).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dragEnded_allViewsRemoved() {
|
||||
dragToBubbleController.onDragStart(dragObject, DragOptions())
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().runOnMainSync {
|
||||
dragToBubbleController.onDragEnd()
|
||||
animatorTestRule.advanceTimeBy(250)
|
||||
}
|
||||
|
||||
assertThat(container.childCount).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun draggedToTheRightDropZone_noBubbles_dropTargetViewsShown() {
|
||||
dragToBubbleController.onDragStart(dragObject, DragOptions())
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().runOnMainSync {
|
||||
dragObject.updateXYToCenterOf(rightDropTargetRect)
|
||||
bubbleBarRightDropTarget.onDragEnter(dragObject)
|
||||
animatorTestRule.advanceTimeBy(250)
|
||||
}
|
||||
|
||||
assertThat(dropTargetView.alpha).isEqualTo(1f)
|
||||
assertThat(secondDropTargetView!!.alpha).isEqualTo(1f)
|
||||
verify(bubbleBarViewController, never()).animateBubbleBarLocation(any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun draggedToTheRightDropZone_hasBubblesOnTheRight_dropTargetViewShown() {
|
||||
prepareBubbleBarViewController(hasBubbles = true)
|
||||
dragToBubbleController.onDragStart(dragObject, DragOptions())
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().runOnMainSync {
|
||||
dragObject.updateXYToCenterOf(rightDropTargetRect)
|
||||
bubbleBarRightDropTarget.onDragEnter(dragObject)
|
||||
animatorTestRule.advanceTimeBy(250)
|
||||
}
|
||||
|
||||
assertThat(dropTargetView.alpha).isEqualTo(1f)
|
||||
assertThat(secondDropTargetView).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun draggedToTheRightDropZone_hasBubblesOnTheRight_bubbleBarLocationChangeNotRequested() {
|
||||
prepareBubbleBarViewController(hasBubbles = true)
|
||||
dragToBubbleController.onDragStart(dragObject, DragOptions())
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().runOnMainSync {
|
||||
dragObject.updateXYToCenterOf(rightDropTargetRect)
|
||||
bubbleBarRightDropTarget.onDragEnter(dragObject)
|
||||
animatorTestRule.advanceTimeBy(250)
|
||||
}
|
||||
verify(bubbleBarViewController, never()).animateBubbleBarLocation(any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun draggedToTheLeftDropZone_hasBubblesOnTheRight_bubbleBarLocationChangeRequested() {
|
||||
prepareBubbleBarViewController(
|
||||
hasBubbles = true,
|
||||
bubbleBarLocation = BubbleBarLocation.RIGHT,
|
||||
)
|
||||
dragToBubbleController.onDragStart(dragObject, DragOptions())
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().runOnMainSync {
|
||||
dragObject.updateXYToCenterOf(leftDropTargetRect)
|
||||
bubbleBarLeftDropTarget.onDragEnter(dragObject)
|
||||
}
|
||||
verify(bubbleBarViewController).animateBubbleBarLocation(BubbleBarLocation.LEFT)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun draggedToTheLeftDropZone_dragEnded_hasBubblesOnTheRight_locationRestored() {
|
||||
val bubbleBarOriginalLocation = BubbleBarLocation.RIGHT
|
||||
prepareBubbleBarViewController(
|
||||
hasBubbles = true,
|
||||
bubbleBarLocation = bubbleBarOriginalLocation,
|
||||
)
|
||||
dragToBubbleController.onDragStart(dragObject, DragOptions())
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().runOnMainSync {
|
||||
dragObject.updateXYToCenterOf(leftDropTargetRect)
|
||||
bubbleBarLeftDropTarget.onDragEnter(dragObject)
|
||||
dragObject.updateXY(x = 0, y = 0)
|
||||
bubbleBarLeftDropTarget.onDragExit(dragObject)
|
||||
dragToBubbleController.onDragEnd()
|
||||
}
|
||||
|
||||
verify(bubbleBarViewController).animateBubbleBarLocation(BubbleBarLocation.LEFT)
|
||||
verify(bubbleBarViewController).animateBubbleBarLocation(bubbleBarOriginalLocation)
|
||||
assertThat(container.childCount).isEqualTo(DROP_VIEWS_COUNT)
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().runOnMainSync {
|
||||
animatorTestRule.advanceTimeBy(250)
|
||||
}
|
||||
assertThat(container.childCount).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun droppedAtTheLeftDropZone_noBubblesOnTheRight_appBubbleCreationRequested() {
|
||||
val bubbleBarOriginalLocation = BubbleBarLocation.RIGHT
|
||||
prepareBubbleBarViewController(
|
||||
hasBubbles = false,
|
||||
bubbleBarLocation = bubbleBarOriginalLocation,
|
||||
)
|
||||
val packageName = "test.package"
|
||||
val itemIntent =
|
||||
Intent().apply {
|
||||
component = ComponentName(packageName, "TestClass")
|
||||
`package` = packageName
|
||||
}
|
||||
val appInfo = AppInfo().apply { intent = itemIntent }
|
||||
dragObject.dragInfo = appInfo
|
||||
|
||||
dragToBubbleController.onDragStart(dragObject, DragOptions())
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().runOnMainSync {
|
||||
dragObject.updateXYToCenterOf(leftDropTargetRect)
|
||||
bubbleBarLeftDropTarget.onDragEnter(dragObject)
|
||||
bubbleBarLeftDropTarget.onDragExit(dragObject)
|
||||
bubbleBarLeftDropTarget.onDrop(dragObject, DragOptions())
|
||||
}
|
||||
|
||||
verify(systemUiProxy).showAppBubble(itemIntent, appInfo.user, BubbleBarLocation.LEFT)
|
||||
}
|
||||
|
||||
private fun prepareBubbleBarViewController(
|
||||
hasBubbles: Boolean = false,
|
||||
bubbleBarLocation: BubbleBarLocation = BubbleBarLocation.RIGHT,
|
||||
) {
|
||||
bubbleBarViewController.stub {
|
||||
on { hasBubbles() } doReturn hasBubbles
|
||||
on { getBubbleBarLocation() } doReturn bubbleBarLocation
|
||||
}
|
||||
}
|
||||
|
||||
private fun DragObject.updateXYToCenterOf(rect: Rect) {
|
||||
updateXY(rect.centerX(), rect.centerY())
|
||||
}
|
||||
|
||||
private fun DragObject.updateXY(x: Int, y: Int) {
|
||||
this.x = x
|
||||
this.y = y
|
||||
}
|
||||
|
||||
private fun createTestDragZoneFactory(): DragZoneFactory {
|
||||
val deviceConfig =
|
||||
DeviceConfig(
|
||||
isLargeScreen = true,
|
||||
isSmallTablet = false,
|
||||
isLandscape = true,
|
||||
isRtl = false,
|
||||
windowBounds = Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT),
|
||||
insets = Insets.NONE,
|
||||
)
|
||||
return DragZoneFactory(
|
||||
context,
|
||||
deviceConfig,
|
||||
{ SplitScreenMode.NONE },
|
||||
{ false },
|
||||
bubbleBarPropertiesProvider,
|
||||
)
|
||||
}
|
||||
|
||||
private class FakeBubbleBarPropertiesProvider : BubbleBarPropertiesProvider {
|
||||
|
||||
override fun getHeight(): Int = BUBBLE_BAR_HEIGHT
|
||||
|
||||
override fun getWidth(): Int = BUBBLE_BAR_WIDTH
|
||||
|
||||
override fun getBottomPadding(): Int = BUBBLE_BAR_BOTTOM_PADDING
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val BUBBLE_BAR_WIDTH = 100
|
||||
const val BUBBLE_BAR_HEIGHT = 110
|
||||
const val BUBBLE_BAR_BOTTOM_PADDING = 70
|
||||
const val SCREEN_WIDTH = 2000
|
||||
const val SCREEN_HEIGHT = 1000
|
||||
const val DROP_VIEWS_COUNT = 1
|
||||
const val DROP_VIEWS_COUNT_NO_BUBBLE_BAR = 2
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user