Merge "[Chipbar] Have MediaTttSenderCoordinator be responsible for not hiding in certain cases." into tm-qpr-dev

This commit is contained in:
TreeHugger Robot
2022-10-18 16:12:24 +00:00
committed by Android (Google) Code Review
6 changed files with 46 additions and 151 deletions

View File

@@ -47,6 +47,8 @@ constructor(
private val uiEventLogger: MediaTttSenderUiEventLogger, private val uiEventLogger: MediaTttSenderUiEventLogger,
) : CoreStartable { ) : CoreStartable {
private var displayedState: ChipStateSender? = null
private val commandQueueCallbacks = private val commandQueueCallbacks =
object : CommandQueue.Callbacks { object : CommandQueue.Callbacks {
override fun updateMediaTapToTransferSenderDisplay( override fun updateMediaTapToTransferSenderDisplay(
@@ -84,8 +86,27 @@ constructor(
uiEventLogger.logSenderStateChange(chipState) uiEventLogger.logSenderStateChange(chipState)
if (chipState == ChipStateSender.FAR_FROM_RECEIVER) { 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 { } else {
displayedState = chipState
chipbarCoordinator.displayView(ChipSenderInfo(chipState, routeInfo, undoCallback)) chipbarCoordinator.displayView(ChipSenderInfo(chipState, routeInfo, undoCallback))
} }
} }

View File

@@ -131,7 +131,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
) )
cancelViewTimeout?.run() cancelViewTimeout?.run()
cancelViewTimeout = mainExecutor.executeDelayed( cancelViewTimeout = mainExecutor.executeDelayed(
{ removeView(TemporaryDisplayRemovalReason.REASON_TIMEOUT) }, { removeView(REMOVAL_REASON_TIMEOUT) },
timeout.toLong() timeout.toLong()
) )
} }
@@ -175,9 +175,6 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
*/ */
fun removeView(removalReason: String) { fun removeView(removalReason: String) {
val currentDisplayInfo = displayInfo ?: return val currentDisplayInfo = displayInfo ?: return
if (shouldIgnoreViewRemoval(currentDisplayInfo.info, removalReason)) {
return
}
val currentView = currentDisplayInfo.view val currentView = currentDisplayInfo.view
animateViewOut(currentView) { windowManager.removeView(currentView) } animateViewOut(currentView) { windowManager.removeView(currentView) }
@@ -192,13 +189,6 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
cancelViewTimeout?.run() cancelViewTimeout?.run()
} }
/**
* 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]. * A method implemented by subclasses to update [currentView] based on [newInfo].
*/ */
@@ -236,10 +226,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
) )
} }
object TemporaryDisplayRemovalReason { private const val REMOVAL_REASON_TIMEOUT = "TIMEOUT"
const val REASON_TIMEOUT = "TIMEOUT"
const val REASON_SCREEN_TAP = "SCREEN_TAP"
}
private data class IconInfo( private data class IconInfo(
val iconName: String, val iconName: String,

View File

@@ -44,7 +44,6 @@ import com.android.systemui.media.taptotransfer.sender.MediaTttSenderUiEventLogg
import com.android.systemui.media.taptotransfer.sender.TransferStatus import com.android.systemui.media.taptotransfer.sender.TransferStatus
import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.temporarydisplay.TemporaryDisplayRemovalReason
import com.android.systemui.temporarydisplay.TemporaryViewDisplayController import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
import com.android.systemui.temporarydisplay.TemporaryViewInfo import com.android.systemui.temporarydisplay.TemporaryViewInfo
import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.concurrency.DelayableExecutor
@@ -185,23 +184,6 @@ open class ChipbarCoordinator @Inject constructor(
) )
} }
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) { override fun getTouchableRegion(view: View, outRect: Rect) {
viewUtil.setRectToViewWindowLocation(view, outRect) viewUtil.setRectToViewWindowLocation(view, outRect)
} }

View File

@@ -83,7 +83,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
fun setUp() { fun setUp() {
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
whenever(mediaTttFlags.isMediaTttEnabled()).thenReturn(true) whenever(mediaTttFlags.isMediaTttEnabled()).thenReturn(true)
whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenReturn(1000) whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenReturn(TIMEOUT)
fakeClock = FakeSystemClock() fakeClock = FakeSystemClock()
fakeExecutor = FakeExecutor(fakeClock) fakeExecutor = FakeExecutor(fakeClock)
@@ -316,7 +316,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
} }
@Test @Test
fun transferToReceiverTriggeredThenFarFromReceiver_viewStillDisplayed() { fun transferToReceiverTriggeredThenFarFromReceiver_viewStillDisplayedButStillTimesOut() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay( commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED, StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED,
routeInfo, routeInfo,
@@ -332,10 +332,14 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
verify(windowManager, never()).removeView(any()) verify(windowManager, never()).removeView(any())
verify(logger).logRemovalBypass(any(), any()) verify(logger).logRemovalBypass(any(), any())
fakeClock.advanceTime(TIMEOUT + 1L)
verify(windowManager).removeView(any())
} }
@Test @Test
fun transferToThisDeviceTriggeredThenFarFromReceiver_viewStillDisplayed() { fun transferToThisDeviceTriggeredThenFarFromReceiver_viewStillDisplayedButDoesTimeOut() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay( commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED, StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
routeInfo, routeInfo,
@@ -351,10 +355,14 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
verify(windowManager, never()).removeView(any()) verify(windowManager, never()).removeView(any())
verify(logger).logRemovalBypass(any(), any()) verify(logger).logRemovalBypass(any(), any())
fakeClock.advanceTime(TIMEOUT + 1L)
verify(windowManager).removeView(any())
} }
@Test @Test
fun transferToReceiverSucceededThenFarFromReceiver_viewStillDisplayed() { fun transferToReceiverSucceededThenFarFromReceiver_viewStillDisplayedButDoesTimeOut() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay( commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
routeInfo, routeInfo,
@@ -370,10 +378,14 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
verify(windowManager, never()).removeView(any()) verify(windowManager, never()).removeView(any())
verify(logger).logRemovalBypass(any(), any()) verify(logger).logRemovalBypass(any(), any())
fakeClock.advanceTime(TIMEOUT + 1L)
verify(windowManager).removeView(any())
} }
@Test @Test
fun transferToThisDeviceSucceededThenFarFromReceiver_viewStillDisplayed() { fun transferToThisDeviceSucceededThenFarFromReceiver_viewStillDisplayedButDoesTimeOut() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay( commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
routeInfo, routeInfo,
@@ -389,6 +401,10 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
verify(windowManager, never()).removeView(any()) verify(windowManager, never()).removeView(any())
verify(logger).logRemovalBypass(any(), any()) verify(logger).logRemovalBypass(any(), any())
fakeClock.advanceTime(TIMEOUT + 1L)
verify(windowManager).removeView(any())
} }
private fun getChipView(): ViewGroup { private fun getChipView(): ViewGroup {
@@ -434,6 +450,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
} }
private const val OTHER_DEVICE_NAME = "My Tablet" private const val OTHER_DEVICE_NAME = "My Tablet"
private const val TIMEOUT = 10000
private val routeInfo = private val routeInfo =
MediaRoute2Info.Builder("id", OTHER_DEVICE_NAME) MediaRoute2Info.Builder("id", OTHER_DEVICE_NAME)

View File

@@ -63,8 +63,6 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
@Mock @Mock
private lateinit var powerManager: PowerManager private lateinit var powerManager: PowerManager
private var shouldIgnoreViewRemoval: Boolean = false
@Before @Before
fun setUp() { fun setUp() {
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
@@ -209,26 +207,6 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
verify(windowManager, never()).removeView(any()) 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 getState(name: String = "name") = ViewInfo(name)
private fun getConfigurationListener(): ConfigurationListener { private fun getConfigurationListener(): ConfigurationListener {
@@ -267,10 +245,6 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
mostRecentViewInfo = newInfo mostRecentViewInfo = newInfo
} }
override fun shouldIgnoreViewRemoval(info: ViewInfo, removalReason: String): Boolean {
return shouldIgnoreViewRemoval
}
override fun getTouchableRegion(view: View, outRect: Rect) { override fun getTouchableRegion(view: View, outRect: Rect) {
outRect.setEmpty() outRect.setEmpty()
} }

View File

@@ -434,92 +434,6 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
assertThat(getChipView().getFailureIcon().visibility).isEqualTo(View.VISIBLE) 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.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
private fun ViewGroup.getChipText(): String = private fun ViewGroup.getChipText(): String =