[Chipbar] Have MediaTttSenderCoordinator be responsible for not hiding
in certain cases.
Bug: 245610654
Test: manual: Send a TRANSFER_TRIGGERED event then FAR_FROM_RECEIVER
event and verify the chip is still displayed (i.e. the removal request
is ignored)
Test: manual: Send a ALMOST_CLOSE event then FAR_FROM_RECEIVER event and
verify the chip is hidden
Test: atest MediaTttSenderCoordinatorTest
Test: atest ChipbarCoordinatorTest
Change-Id: I8cd33a65ec48f37aa83179b348f60916df3990a8
Change-Id: Ic1f1d2fcb09727ebc24d649a26dcea40ca8287b2
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
index 5aaab14..224303a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
@@ -47,6 +47,8 @@
private val uiEventLogger: MediaTttSenderUiEventLogger,
) : CoreStartable {
+ private var displayedState: ChipStateSender? = null
+
private val commandQueueCallbacks =
object : CommandQueue.Callbacks {
override fun updateMediaTapToTransferSenderDisplay(
@@ -84,8 +86,27 @@
uiEventLogger.logSenderStateChange(chipState)
if (chipState == ChipStateSender.FAR_FROM_RECEIVER) {
- chipbarCoordinator.removeView(removalReason = ChipStateSender.FAR_FROM_RECEIVER.name)
+ // Return early if we're not displaying a chip anyway
+ val currentDisplayedState = displayedState ?: return
+
+ val removalReason = ChipStateSender.FAR_FROM_RECEIVER.name
+ if (
+ currentDisplayedState.transferStatus == TransferStatus.IN_PROGRESS ||
+ currentDisplayedState.transferStatus == TransferStatus.SUCCEEDED
+ ) {
+ // Don't remove the chip if we're in progress or succeeded, since the user should
+ // still be able to see the status of the transfer.
+ logger.logRemovalBypass(
+ removalReason,
+ bypassReason = "transferStatus=${currentDisplayedState.transferStatus.name}"
+ )
+ return
+ }
+
+ displayedState = null
+ chipbarCoordinator.removeView(removalReason)
} else {
+ displayedState = chipState
chipbarCoordinator.displayView(ChipSenderInfo(chipState, routeInfo, undoCallback))
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
index 5cbdf7c..d5d904c 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
@@ -131,7 +131,7 @@
)
cancelViewTimeout?.run()
cancelViewTimeout = mainExecutor.executeDelayed(
- { removeView(TemporaryDisplayRemovalReason.REASON_TIMEOUT) },
+ { removeView(REMOVAL_REASON_TIMEOUT) },
timeout.toLong()
)
}
@@ -175,9 +175,6 @@
*/
fun removeView(removalReason: String) {
val currentDisplayInfo = displayInfo ?: return
- if (shouldIgnoreViewRemoval(currentDisplayInfo.info, removalReason)) {
- return
- }
val currentView = currentDisplayInfo.view
animateViewOut(currentView) { windowManager.removeView(currentView) }
@@ -193,13 +190,6 @@
}
/**
- * Returns true if a view removal request should be ignored and false otherwise.
- *
- * Allows subclasses to keep the view visible for longer in certain circumstances.
- */
- open fun shouldIgnoreViewRemoval(info: T, removalReason: String): Boolean = false
-
- /**
* A method implemented by subclasses to update [currentView] based on [newInfo].
*/
abstract fun updateView(newInfo: T, currentView: ViewGroup)
@@ -236,10 +226,7 @@
)
}
-object TemporaryDisplayRemovalReason {
- const val REASON_TIMEOUT = "TIMEOUT"
- const val REASON_SCREEN_TAP = "SCREEN_TAP"
-}
+private const val REMOVAL_REASON_TIMEOUT = "TIMEOUT"
private data class IconInfo(
val iconName: String,
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
index a2cd142..1a25e4d 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
@@ -44,7 +44,6 @@
import com.android.systemui.media.taptotransfer.sender.TransferStatus
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.temporarydisplay.TemporaryDisplayRemovalReason
import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
import com.android.systemui.temporarydisplay.TemporaryViewInfo
import com.android.systemui.util.concurrency.DelayableExecutor
@@ -185,23 +184,6 @@
)
}
- override fun shouldIgnoreViewRemoval(info: ChipSenderInfo, removalReason: String): Boolean {
- // Don't remove the chip if we're in progress or succeeded, since the user should still be
- // able to see the status of the transfer. (But do remove it if it's finally timed out.)
- val transferStatus = info.state.transferStatus
- if (
- (transferStatus == TransferStatus.IN_PROGRESS ||
- transferStatus == TransferStatus.SUCCEEDED) &&
- removalReason != TemporaryDisplayRemovalReason.REASON_TIMEOUT
- ) {
- logger.logRemovalBypass(
- removalReason, bypassReason = "transferStatus=${transferStatus.name}"
- )
- return true
- }
- return false
- }
-
override fun getTouchableRegion(view: View, outRect: Rect) {
viewUtil.setRectToViewWindowLocation(view, outRect)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
index 616a349..110bbb8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
@@ -83,7 +83,7 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
whenever(mediaTttFlags.isMediaTttEnabled()).thenReturn(true)
- whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenReturn(1000)
+ whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenReturn(TIMEOUT)
fakeClock = FakeSystemClock()
fakeExecutor = FakeExecutor(fakeClock)
@@ -316,7 +316,7 @@
}
@Test
- fun transferToReceiverTriggeredThenFarFromReceiver_viewStillDisplayed() {
+ fun transferToReceiverTriggeredThenFarFromReceiver_viewStillDisplayedButStillTimesOut() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED,
routeInfo,
@@ -332,10 +332,14 @@
verify(windowManager, never()).removeView(any())
verify(logger).logRemovalBypass(any(), any())
+
+ fakeClock.advanceTime(TIMEOUT + 1L)
+
+ verify(windowManager).removeView(any())
}
@Test
- fun transferToThisDeviceTriggeredThenFarFromReceiver_viewStillDisplayed() {
+ fun transferToThisDeviceTriggeredThenFarFromReceiver_viewStillDisplayedButDoesTimeOut() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
routeInfo,
@@ -351,10 +355,14 @@
verify(windowManager, never()).removeView(any())
verify(logger).logRemovalBypass(any(), any())
+
+ fakeClock.advanceTime(TIMEOUT + 1L)
+
+ verify(windowManager).removeView(any())
}
@Test
- fun transferToReceiverSucceededThenFarFromReceiver_viewStillDisplayed() {
+ fun transferToReceiverSucceededThenFarFromReceiver_viewStillDisplayedButDoesTimeOut() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
routeInfo,
@@ -370,10 +378,14 @@
verify(windowManager, never()).removeView(any())
verify(logger).logRemovalBypass(any(), any())
+
+ fakeClock.advanceTime(TIMEOUT + 1L)
+
+ verify(windowManager).removeView(any())
}
@Test
- fun transferToThisDeviceSucceededThenFarFromReceiver_viewStillDisplayed() {
+ fun transferToThisDeviceSucceededThenFarFromReceiver_viewStillDisplayedButDoesTimeOut() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
routeInfo,
@@ -389,6 +401,10 @@
verify(windowManager, never()).removeView(any())
verify(logger).logRemovalBypass(any(), any())
+
+ fakeClock.advanceTime(TIMEOUT + 1L)
+
+ verify(windowManager).removeView(any())
}
private fun getChipView(): ViewGroup {
@@ -434,6 +450,7 @@
}
private const val OTHER_DEVICE_NAME = "My Tablet"
+private const val TIMEOUT = 10000
private val routeInfo =
MediaRoute2Info.Builder("id", OTHER_DEVICE_NAME)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
index b10aa12..b68eb88 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
@@ -63,8 +63,6 @@
@Mock
private lateinit var powerManager: PowerManager
- private var shouldIgnoreViewRemoval: Boolean = false
-
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -209,26 +207,6 @@
verify(windowManager, never()).removeView(any())
}
- @Test
- fun removeView_shouldIgnoreRemovalFalse_viewRemoved() {
- shouldIgnoreViewRemoval = false
- underTest.displayView(getState())
-
- underTest.removeView("reason")
-
- verify(windowManager).removeView(any())
- }
-
- @Test
- fun removeView_shouldIgnoreRemovalTrue_viewNotRemoved() {
- shouldIgnoreViewRemoval = true
- underTest.displayView(getState())
-
- underTest.removeView("reason")
-
- verify(windowManager, never()).removeView(any())
- }
-
private fun getState(name: String = "name") = ViewInfo(name)
private fun getConfigurationListener(): ConfigurationListener {
@@ -267,10 +245,6 @@
mostRecentViewInfo = newInfo
}
- override fun shouldIgnoreViewRemoval(info: ViewInfo, removalReason: String): Boolean {
- return shouldIgnoreViewRemoval
- }
-
override fun getTouchableRegion(view: View, outRect: Rect) {
outRect.setEmpty()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
index 2af4802..6225d0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
@@ -434,92 +434,6 @@
assertThat(getChipView().getFailureIcon().visibility).isEqualTo(View.VISIBLE)
}
- @Test
- fun transferToReceiverTriggeredThenRemoveView_viewStillDisplayed() {
- underTest.displayView(transferToReceiverTriggered())
- fakeClock.advanceTime(1000L)
-
- underTest.removeView("fakeRemovalReason")
- fakeExecutor.runAllReady()
-
- verify(windowManager, never()).removeView(any())
- verify(logger).logRemovalBypass(any(), any())
- }
-
- @Test
- fun transferToReceiverTriggeredThenRemoveView_eventuallyTimesOut() {
- underTest.displayView(transferToReceiverTriggered())
-
- underTest.removeView("fakeRemovalReason")
- fakeClock.advanceTime(TIMEOUT + 1L)
-
- verify(windowManager).removeView(any())
- }
-
- @Test
- fun transferToThisDeviceTriggeredThenRemoveView_viewStillDisplayed() {
- underTest.displayView(transferToThisDeviceTriggered())
- fakeClock.advanceTime(1000L)
-
- underTest.removeView("fakeRemovalReason")
- fakeExecutor.runAllReady()
-
- verify(windowManager, never()).removeView(any())
- verify(logger).logRemovalBypass(any(), any())
- }
-
- @Test
- fun transferToThisDeviceTriggeredThenRemoveView_eventuallyTimesOut() {
- underTest.displayView(transferToThisDeviceTriggered())
-
- underTest.removeView("fakeRemovalReason")
- fakeClock.advanceTime(TIMEOUT + 1L)
-
- verify(windowManager).removeView(any())
- }
-
- @Test
- fun transferToReceiverSucceededThenRemoveView_viewStillDisplayed() {
- underTest.displayView(transferToReceiverSucceeded())
-
- underTest.removeView("fakeRemovalReason")
- fakeExecutor.runAllReady()
-
- verify(windowManager, never()).removeView(any())
- verify(logger).logRemovalBypass(any(), any())
- }
-
- @Test
- fun transferToReceiverSucceededThenRemoveView_eventuallyTimesOut() {
- underTest.displayView(transferToReceiverSucceeded())
-
- underTest.removeView("fakeRemovalReason")
- fakeClock.advanceTime(TIMEOUT + 1L)
-
- verify(windowManager).removeView(any())
- }
-
- @Test
- fun transferToThisDeviceSucceededThenRemoveView_viewStillDisplayed() {
- underTest.displayView(transferToThisDeviceSucceeded())
-
- underTest.removeView("fakeRemovalReason")
- fakeExecutor.runAllReady()
-
- verify(windowManager, never()).removeView(any())
- verify(logger).logRemovalBypass(any(), any())
- }
-
- @Test
- fun transferToThisDeviceSucceededThenRemoveView_eventuallyTimesOut() {
- underTest.displayView(transferToThisDeviceSucceeded())
-
- underTest.removeView("fakeRemovalReason")
- fakeClock.advanceTime(TIMEOUT + 1L)
-
- verify(windowManager).removeView(any())
- }
-
private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
private fun ViewGroup.getChipText(): String =