diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt index 303c7cd60148d..721c0ba4f8654 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt @@ -34,6 +34,7 @@ import com.android.systemui.log.SessionTracker import com.android.systemui.media.RingtonePlayer import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver +import com.android.systemui.media.taptotransfer.sender.MediaTttSenderCoordinator import com.android.systemui.power.PowerUI import com.android.systemui.recents.Recents import com.android.systemui.settings.dagger.MultiUserUtilsModule @@ -217,6 +218,12 @@ abstract class SystemUICoreStartableModule { @ClassKey(KeyguardLiftController::class) abstract fun bindKeyguardLiftController(sysui: KeyguardLiftController): CoreStartable + /** Inject into MediaTttSenderCoordinator. */ + @Binds + @IntoMap + @ClassKey(MediaTttSenderCoordinator::class) + abstract fun bindMediaTttSenderCoordinator(sysui: MediaTttSenderCoordinator): CoreStartable + /** Inject into MediaTttChipControllerReceiver. */ @Binds @IntoMap diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt index 0163031705462..089625ca8d9c3 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt @@ -53,6 +53,8 @@ import javax.inject.Inject * A controller to display and hide the Media Tap-To-Transfer chip on the **receiving** device. * * This chip is shown when a user is transferring media to/from a sending device and this device. + * + * TODO(b/245610654): Re-name this to be MediaTttReceiverCoordinator. */ @SysUISingleton class MediaTttChipControllerReceiver @Inject constructor( @@ -120,7 +122,7 @@ class MediaTttChipControllerReceiver @Inject constructor( uiEventLogger.logReceiverStateChange(chipState) if (chipState == ChipStateReceiver.FAR_FROM_SENDER) { - removeView(removalReason = ChipStateReceiver.FAR_FROM_SENDER::class.simpleName!!) + removeView(removalReason = ChipStateReceiver.FAR_FROM_SENDER.name) return } if (appIcon == null) { 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 new file mode 100644 index 0000000000000..5aaab14c1065e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2022 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.systemui.media.taptotransfer.sender + +import android.app.StatusBarManager +import android.content.Context +import android.media.MediaRoute2Info +import android.util.Log +import com.android.internal.statusbar.IUndoMediaTransferCallback +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.media.taptotransfer.MediaTttFlags +import com.android.systemui.media.taptotransfer.common.MediaTttLogger +import com.android.systemui.statusbar.CommandQueue +import com.android.systemui.temporarydisplay.chipbar.ChipSenderInfo +import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator +import com.android.systemui.temporarydisplay.chipbar.SENDER_TAG +import javax.inject.Inject + +/** + * A coordinator for showing/hiding the Media Tap-To-Transfer UI on the **sending** device. This UI + * is shown when a user is transferring media to/from this device and a receiver device. + */ +@SysUISingleton +class MediaTttSenderCoordinator +@Inject +constructor( + private val chipbarCoordinator: ChipbarCoordinator, + private val commandQueue: CommandQueue, + private val context: Context, + @MediaTttSenderLogger private val logger: MediaTttLogger, + private val mediaTttFlags: MediaTttFlags, + private val uiEventLogger: MediaTttSenderUiEventLogger, +) : CoreStartable { + + private val commandQueueCallbacks = + object : CommandQueue.Callbacks { + override fun updateMediaTapToTransferSenderDisplay( + @StatusBarManager.MediaTransferSenderState displayState: Int, + routeInfo: MediaRoute2Info, + undoCallback: IUndoMediaTransferCallback? + ) { + this@MediaTttSenderCoordinator.updateMediaTapToTransferSenderDisplay( + displayState, + routeInfo, + undoCallback + ) + } + } + + override fun start() { + if (mediaTttFlags.isMediaTttEnabled()) { + commandQueue.addCallback(commandQueueCallbacks) + } + } + + private fun updateMediaTapToTransferSenderDisplay( + @StatusBarManager.MediaTransferSenderState displayState: Int, + routeInfo: MediaRoute2Info, + undoCallback: IUndoMediaTransferCallback? + ) { + val chipState: ChipStateSender? = ChipStateSender.getSenderStateFromId(displayState) + val stateName = chipState?.name ?: "Invalid" + logger.logStateChange(stateName, routeInfo.id, routeInfo.clientPackageName) + + if (chipState == null) { + Log.e(SENDER_TAG, "Unhandled MediaTransferSenderState $displayState") + return + } + uiEventLogger.logSenderStateChange(chipState) + + if (chipState == ChipStateSender.FAR_FROM_RECEIVER) { + chipbarCoordinator.removeView(removalReason = ChipStateSender.FAR_FROM_RECEIVER.name) + } else { + chipbarCoordinator.displayView(ChipSenderInfo(chipState, routeInfo, undoCallback)) + } + } +} 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 2bce3482a7832..a2cd1420a41c0 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt @@ -16,12 +16,10 @@ package com.android.systemui.temporarydisplay.chipbar -import android.app.StatusBarManager import android.content.Context import android.graphics.Rect import android.media.MediaRoute2Info import android.os.PowerManager -import android.util.Log import android.view.Gravity import android.view.MotionEvent import android.view.View @@ -38,7 +36,6 @@ import com.android.systemui.animation.ViewHierarchyAnimator import com.android.systemui.classifier.FalsingCollector import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.media.taptotransfer.MediaTttFlags import com.android.systemui.media.taptotransfer.common.MediaTttLogger import com.android.systemui.media.taptotransfer.common.MediaTttUtils import com.android.systemui.media.taptotransfer.sender.ChipStateSender @@ -46,7 +43,6 @@ import com.android.systemui.media.taptotransfer.sender.MediaTttSenderLogger import com.android.systemui.media.taptotransfer.sender.MediaTttSenderUiEventLogger import com.android.systemui.media.taptotransfer.sender.TransferStatus import com.android.systemui.plugins.FalsingManager -import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.temporarydisplay.TemporaryDisplayRemovalReason import com.android.systemui.temporarydisplay.TemporaryViewDisplayController @@ -76,7 +72,6 @@ import javax.inject.Inject */ @SysUISingleton open class ChipbarCoordinator @Inject constructor( - private val commandQueue: CommandQueue, context: Context, @MediaTttSenderLogger logger: MediaTttLogger, windowManager: WindowManager, @@ -87,7 +82,6 @@ open class ChipbarCoordinator @Inject constructor( private val uiEventLogger: MediaTttSenderUiEventLogger, private val falsingManager: FalsingManager, private val falsingCollector: FalsingCollector, - private val mediaTttFlags: MediaTttFlags, private val viewUtil: ViewUtil, ) : TemporaryViewDisplayController( context, @@ -108,50 +102,14 @@ open class ChipbarCoordinator @Inject constructor( gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL) } - private val commandQueueCallbacks = object : CommandQueue.Callbacks { - override fun updateMediaTapToTransferSenderDisplay( - @StatusBarManager.MediaTransferSenderState displayState: Int, - routeInfo: MediaRoute2Info, - undoCallback: IUndoMediaTransferCallback? - ) { - this@ChipbarCoordinator.updateMediaTapToTransferSenderDisplay( - displayState, routeInfo, undoCallback - ) - } - } - - private fun updateMediaTapToTransferSenderDisplay( - @StatusBarManager.MediaTransferSenderState displayState: Int, - routeInfo: MediaRoute2Info, - undoCallback: IUndoMediaTransferCallback? - ) { - val chipState: ChipStateSender? = ChipStateSender.getSenderStateFromId(displayState) - val stateName = chipState?.name ?: "Invalid" - logger.logStateChange(stateName, routeInfo.id, routeInfo.clientPackageName) - - if (chipState == null) { - Log.e(SENDER_TAG, "Unhandled MediaTransferSenderState $displayState") - return - } - uiEventLogger.logSenderStateChange(chipState) - - if (chipState == ChipStateSender.FAR_FROM_RECEIVER) { - removeView(removalReason = ChipStateSender.FAR_FROM_RECEIVER.name) - } else { - displayView(ChipSenderInfo(chipState, routeInfo, undoCallback)) - } - } - - override fun start() { - if (mediaTttFlags.isMediaTttEnabled()) { - commandQueue.addCallback(commandQueueCallbacks) - } - } + override fun start() {} override fun updateView( newInfo: ChipSenderInfo, currentView: ViewGroup ) { + // TODO(b/245610654): Adding logging here. + val chipState = newInfo.state // Detect falsing touches on the chip. 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 new file mode 100644 index 0000000000000..616a349520ee9 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt @@ -0,0 +1,442 @@ +/* + * Copyright (C) 2022 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.systemui.media.taptotransfer.sender + +import android.app.StatusBarManager +import android.media.MediaRoute2Info +import android.os.PowerManager +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import android.view.accessibility.AccessibilityManager +import android.widget.TextView +import androidx.test.filters.SmallTest +import com.android.internal.logging.testing.UiEventLoggerFake +import com.android.internal.statusbar.IUndoMediaTransferCallback +import com.android.systemui.R +import com.android.systemui.SysuiTestCase +import com.android.systemui.classifier.FalsingCollector +import com.android.systemui.media.taptotransfer.MediaTttFlags +import com.android.systemui.media.taptotransfer.common.MediaTttLogger +import com.android.systemui.plugins.FalsingManager +import com.android.systemui.statusbar.CommandQueue +import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.temporarydisplay.chipbar.ChipSenderInfo +import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator +import com.android.systemui.temporarydisplay.chipbar.FakeChipbarCoordinator +import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.mockito.any +import com.android.systemui.util.time.FakeSystemClock +import com.android.systemui.util.view.ViewUtil +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Mock +import org.mockito.Mockito.never +import org.mockito.Mockito.reset +import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` as whenever +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +class MediaTttSenderCoordinatorTest : SysuiTestCase() { + private lateinit var underTest: MediaTttSenderCoordinator + + @Mock private lateinit var accessibilityManager: AccessibilityManager + @Mock private lateinit var commandQueue: CommandQueue + @Mock private lateinit var configurationController: ConfigurationController + @Mock private lateinit var falsingManager: FalsingManager + @Mock private lateinit var falsingCollector: FalsingCollector + @Mock private lateinit var logger: MediaTttLogger + @Mock private lateinit var mediaTttFlags: MediaTttFlags + @Mock private lateinit var powerManager: PowerManager + @Mock private lateinit var viewUtil: ViewUtil + @Mock private lateinit var windowManager: WindowManager + private lateinit var chipbarCoordinator: ChipbarCoordinator + private lateinit var commandQueueCallback: CommandQueue.Callbacks + private lateinit var fakeClock: FakeSystemClock + private lateinit var fakeExecutor: FakeExecutor + private lateinit var uiEventLoggerFake: UiEventLoggerFake + private lateinit var uiEventLogger: MediaTttSenderUiEventLogger + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + whenever(mediaTttFlags.isMediaTttEnabled()).thenReturn(true) + whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenReturn(1000) + + fakeClock = FakeSystemClock() + fakeExecutor = FakeExecutor(fakeClock) + + uiEventLoggerFake = UiEventLoggerFake() + uiEventLogger = MediaTttSenderUiEventLogger(uiEventLoggerFake) + + chipbarCoordinator = + FakeChipbarCoordinator( + context, + logger, + windowManager, + fakeExecutor, + accessibilityManager, + configurationController, + powerManager, + uiEventLogger, + falsingManager, + falsingCollector, + viewUtil, + ) + chipbarCoordinator.start() + + underTest = + MediaTttSenderCoordinator( + chipbarCoordinator, + commandQueue, + context, + logger, + mediaTttFlags, + uiEventLogger, + ) + underTest.start() + + val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java) + verify(commandQueue).addCallback(callbackCaptor.capture()) + commandQueueCallback = callbackCaptor.value!! + } + + @Test + fun commandQueueCallback_flagOff_noCallbackAdded() { + reset(commandQueue) + whenever(mediaTttFlags.isMediaTttEnabled()).thenReturn(false) + underTest = + MediaTttSenderCoordinator( + chipbarCoordinator, + commandQueue, + context, + logger, + mediaTttFlags, + uiEventLogger, + ) + underTest.start() + + verify(commandQueue, never()).addCallback(any()) + } + + @Test + fun commandQueueCallback_almostCloseToStartCast_triggersCorrectChip() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, + routeInfo, + null + ) + + assertThat(getChipView().getChipText()) + .isEqualTo(almostCloseToStartCast().state.getChipTextString(context, OTHER_DEVICE_NAME)) + assertThat(uiEventLoggerFake.eventId(0)) + .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_START_CAST.id) + } + + @Test + fun commandQueueCallback_almostCloseToEndCast_triggersCorrectChip() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST, + routeInfo, + null + ) + + assertThat(getChipView().getChipText()) + .isEqualTo(almostCloseToEndCast().state.getChipTextString(context, OTHER_DEVICE_NAME)) + assertThat(uiEventLoggerFake.eventId(0)) + .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_END_CAST.id) + } + + @Test + fun commandQueueCallback_transferToReceiverTriggered_triggersCorrectChip() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED, + routeInfo, + null + ) + + assertThat(getChipView().getChipText()) + .isEqualTo( + transferToReceiverTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME) + ) + assertThat(uiEventLoggerFake.eventId(0)) + .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_TRIGGERED.id) + } + + @Test + fun commandQueueCallback_transferToThisDeviceTriggered_triggersCorrectChip() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED, + routeInfo, + null + ) + + assertThat(getChipView().getChipText()) + .isEqualTo( + transferToThisDeviceTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME) + ) + assertThat(uiEventLoggerFake.eventId(0)) + .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_TRIGGERED.id) + } + + @Test + fun commandQueueCallback_transferToReceiverSucceeded_triggersCorrectChip() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, + routeInfo, + null + ) + + assertThat(getChipView().getChipText()) + .isEqualTo( + transferToReceiverSucceeded().state.getChipTextString(context, OTHER_DEVICE_NAME) + ) + assertThat(uiEventLoggerFake.eventId(0)) + .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_SUCCEEDED.id) + } + + @Test + fun commandQueueCallback_transferToThisDeviceSucceeded_triggersCorrectChip() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, + routeInfo, + null + ) + + assertThat(getChipView().getChipText()) + .isEqualTo( + transferToThisDeviceSucceeded().state.getChipTextString(context, OTHER_DEVICE_NAME) + ) + assertThat(uiEventLoggerFake.eventId(0)) + .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_SUCCEEDED.id) + } + + @Test + fun commandQueueCallback_transferToReceiverFailed_triggersCorrectChip() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED, + routeInfo, + null + ) + + assertThat(getChipView().getChipText()) + .isEqualTo( + transferToReceiverFailed().state.getChipTextString(context, OTHER_DEVICE_NAME) + ) + assertThat(uiEventLoggerFake.eventId(0)) + .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_FAILED.id) + } + + @Test + fun commandQueueCallback_transferToThisDeviceFailed_triggersCorrectChip() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED, + routeInfo, + null + ) + + assertThat(getChipView().getChipText()) + .isEqualTo( + transferToThisDeviceFailed().state.getChipTextString(context, OTHER_DEVICE_NAME) + ) + assertThat(uiEventLoggerFake.eventId(0)) + .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_FAILED.id) + } + + @Test + fun commandQueueCallback_farFromReceiver_noChipShown() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, + routeInfo, + null + ) + + verify(windowManager, never()).addView(any(), any()) + assertThat(uiEventLoggerFake.eventId(0)) + .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_FAR_FROM_RECEIVER.id) + } + + @Test + fun commandQueueCallback_almostCloseThenFarFromReceiver_chipShownThenHidden() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, + routeInfo, + null + ) + + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, + routeInfo, + null + ) + + val viewCaptor = ArgumentCaptor.forClass(View::class.java) + verify(windowManager).addView(viewCaptor.capture(), any()) + verify(windowManager).removeView(viewCaptor.value) + } + + @Test + fun commandQueueCallback_invalidStateParam_noChipShown() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay(100, routeInfo, null) + + verify(windowManager, never()).addView(any(), any()) + } + + @Test + fun receivesNewStateFromCommandQueue_isLogged() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, + routeInfo, + null + ) + + verify(logger).logStateChange(any(), any(), any()) + } + + @Test + fun transferToReceiverTriggeredThenFarFromReceiver_viewStillDisplayed() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED, + routeInfo, + null + ) + + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, + routeInfo, + null + ) + fakeExecutor.runAllReady() + + verify(windowManager, never()).removeView(any()) + verify(logger).logRemovalBypass(any(), any()) + } + + @Test + fun transferToThisDeviceTriggeredThenFarFromReceiver_viewStillDisplayed() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED, + routeInfo, + null + ) + + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, + routeInfo, + null + ) + fakeExecutor.runAllReady() + + verify(windowManager, never()).removeView(any()) + verify(logger).logRemovalBypass(any(), any()) + } + + @Test + fun transferToReceiverSucceededThenFarFromReceiver_viewStillDisplayed() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, + routeInfo, + null + ) + + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, + routeInfo, + null + ) + fakeExecutor.runAllReady() + + verify(windowManager, never()).removeView(any()) + verify(logger).logRemovalBypass(any(), any()) + } + + @Test + fun transferToThisDeviceSucceededThenFarFromReceiver_viewStillDisplayed() { + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, + routeInfo, + null + ) + + commandQueueCallback.updateMediaTapToTransferSenderDisplay( + StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, + routeInfo, + null + ) + fakeExecutor.runAllReady() + + verify(windowManager, never()).removeView(any()) + verify(logger).logRemovalBypass(any(), any()) + } + + private fun getChipView(): ViewGroup { + val viewCaptor = ArgumentCaptor.forClass(View::class.java) + verify(windowManager).addView(viewCaptor.capture(), any()) + return viewCaptor.value as ViewGroup + } + + private fun ViewGroup.getChipText(): String = + (this.requireViewById(R.id.text)).text as String + + /** Helper method providing default parameters to not clutter up the tests. */ + private fun almostCloseToStartCast() = + ChipSenderInfo(ChipStateSender.ALMOST_CLOSE_TO_START_CAST, routeInfo) + + /** Helper method providing default parameters to not clutter up the tests. */ + private fun almostCloseToEndCast() = + ChipSenderInfo(ChipStateSender.ALMOST_CLOSE_TO_END_CAST, routeInfo) + + /** Helper method providing default parameters to not clutter up the tests. */ + private fun transferToReceiverTriggered() = + ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_TRIGGERED, routeInfo) + + /** Helper method providing default parameters to not clutter up the tests. */ + private fun transferToThisDeviceTriggered() = + ChipSenderInfo(ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED, routeInfo) + + /** Helper method providing default parameters to not clutter up the tests. */ + private fun transferToReceiverSucceeded(undoCallback: IUndoMediaTransferCallback? = null) = + ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_SUCCEEDED, routeInfo, undoCallback) + + /** Helper method providing default parameters to not clutter up the tests. */ + private fun transferToThisDeviceSucceeded(undoCallback: IUndoMediaTransferCallback? = null) = + ChipSenderInfo(ChipStateSender.TRANSFER_TO_THIS_DEVICE_SUCCEEDED, routeInfo, undoCallback) + + /** Helper method providing default parameters to not clutter up the tests. */ + private fun transferToReceiverFailed() = + ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_FAILED, routeInfo) + + /** Helper method providing default parameters to not clutter up the tests. */ + private fun transferToThisDeviceFailed() = + ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_FAILED, routeInfo) +} + +private const val OTHER_DEVICE_NAME = "My Tablet" + +private val routeInfo = + MediaRoute2Info.Builder("id", OTHER_DEVICE_NAME) + .addFeature("feature") + .setClientPackageName("com.android.systemui") + .build() 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 f3b883741408b..2af48021d0994 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 @@ -16,8 +16,6 @@ package com.android.systemui.temporarydisplay.chipbar -import android.app.StatusBarManager -import android.content.Context import android.content.pm.ApplicationInfo import android.content.pm.PackageManager import android.graphics.drawable.Drawable @@ -37,16 +35,12 @@ import com.android.internal.statusbar.IUndoMediaTransferCallback import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingCollector -import com.android.systemui.media.taptotransfer.MediaTttFlags import com.android.systemui.media.taptotransfer.common.MediaTttLogger -import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger import com.android.systemui.media.taptotransfer.sender.ChipStateSender import com.android.systemui.media.taptotransfer.sender.MediaTttSenderUiEventLogger import com.android.systemui.media.taptotransfer.sender.MediaTttSenderUiEvents import com.android.systemui.plugins.FalsingManager -import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.policy.ConfigurationController -import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq @@ -60,7 +54,6 @@ import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.Mockito.never -import org.mockito.Mockito.reset import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations @@ -69,7 +62,7 @@ import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper class ChipbarCoordinatorTest : SysuiTestCase() { - private lateinit var underTest: TestChipbarCoordinator + private lateinit var underTest: FakeChipbarCoordinator @Mock private lateinit var packageManager: PackageManager @@ -82,20 +75,15 @@ class ChipbarCoordinatorTest : SysuiTestCase() { @Mock private lateinit var configurationController: ConfigurationController @Mock - private lateinit var mediaTttFlags: MediaTttFlags - @Mock private lateinit var powerManager: PowerManager @Mock private lateinit var windowManager: WindowManager @Mock - private lateinit var commandQueue: CommandQueue - @Mock private lateinit var falsingManager: FalsingManager @Mock private lateinit var falsingCollector: FalsingCollector @Mock private lateinit var viewUtil: ViewUtil - private lateinit var commandQueueCallback: CommandQueue.Callbacks private lateinit var fakeAppIconDrawable: Drawable private lateinit var fakeClock: FakeSystemClock private lateinit var fakeExecutor: FakeExecutor @@ -105,7 +93,6 @@ class ChipbarCoordinatorTest : SysuiTestCase() { @Before fun setUp() { MockitoAnnotations.initMocks(this) - whenever(mediaTttFlags.isMediaTttEnabled()).thenReturn(true) fakeAppIconDrawable = context.getDrawable(R.drawable.ic_cake)!! whenever(applicationInfo.loadLabel(packageManager)).thenReturn(APP_NAME) @@ -123,8 +110,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() { whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenReturn(TIMEOUT) - underTest = TestChipbarCoordinator( - commandQueue, + underTest = FakeChipbarCoordinator( context, logger, windowManager, @@ -135,221 +121,9 @@ class ChipbarCoordinatorTest : SysuiTestCase() { senderUiEventLogger, falsingManager, falsingCollector, - mediaTttFlags, viewUtil, ) underTest.start() - - val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java) - verify(commandQueue).addCallback(callbackCaptor.capture()) - commandQueueCallback = callbackCaptor.value!! - } - - @Test - fun commandQueueCallback_flagOff_noCallbackAdded() { - reset(commandQueue) - whenever(mediaTttFlags.isMediaTttEnabled()).thenReturn(false) - underTest = TestChipbarCoordinator( - commandQueue, - context, - logger, - windowManager, - fakeExecutor, - accessibilityManager, - configurationController, - powerManager, - senderUiEventLogger, - falsingManager, - falsingCollector, - mediaTttFlags, - viewUtil, - ) - underTest.start() - - verify(commandQueue, never()).addCallback(any()) - } - - @Test - fun commandQueueCallback_almostCloseToStartCast_triggersCorrectChip() { - commandQueueCallback.updateMediaTapToTransferSenderDisplay( - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, - routeInfo, - null - ) - - assertThat(getChipView().getChipText()).isEqualTo( - almostCloseToStartCast().state.getChipTextString(context, OTHER_DEVICE_NAME) - ) - assertThat(uiEventLoggerFake.eventId(0)).isEqualTo( - MediaTttSenderUiEvents.MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_START_CAST.id - ) - } - - @Test - fun commandQueueCallback_almostCloseToEndCast_triggersCorrectChip() { - commandQueueCallback.updateMediaTapToTransferSenderDisplay( - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST, - routeInfo, - null - ) - - assertThat(getChipView().getChipText()).isEqualTo( - almostCloseToEndCast().state.getChipTextString(context, OTHER_DEVICE_NAME) - ) - assertThat(uiEventLoggerFake.eventId(0)).isEqualTo( - MediaTttSenderUiEvents.MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_END_CAST.id - ) - } - - @Test - fun commandQueueCallback_transferToReceiverTriggered_triggersCorrectChip() { - commandQueueCallback.updateMediaTapToTransferSenderDisplay( - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED, - routeInfo, - null - ) - - assertThat(getChipView().getChipText()).isEqualTo( - transferToReceiverTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME) - ) - assertThat(uiEventLoggerFake.eventId(0)).isEqualTo( - MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_TRIGGERED.id - ) - } - - @Test - fun commandQueueCallback_transferToThisDeviceTriggered_triggersCorrectChip() { - commandQueueCallback.updateMediaTapToTransferSenderDisplay( - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED, - routeInfo, - null - ) - - assertThat(getChipView().getChipText()).isEqualTo( - transferToThisDeviceTriggered().state.getChipTextString(context, OTHER_DEVICE_NAME) - ) - assertThat(uiEventLoggerFake.eventId(0)).isEqualTo( - MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_TRIGGERED.id - ) - } - - @Test - fun commandQueueCallback_transferToReceiverSucceeded_triggersCorrectChip() { - commandQueueCallback.updateMediaTapToTransferSenderDisplay( - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, - routeInfo, - null - ) - - assertThat(getChipView().getChipText()).isEqualTo( - transferToReceiverSucceeded().state.getChipTextString(context, OTHER_DEVICE_NAME) - ) - assertThat(uiEventLoggerFake.eventId(0)).isEqualTo( - MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_SUCCEEDED.id - ) - } - - @Test - fun commandQueueCallback_transferToThisDeviceSucceeded_triggersCorrectChip() { - commandQueueCallback.updateMediaTapToTransferSenderDisplay( - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, - routeInfo, - null - ) - - assertThat(getChipView().getChipText()).isEqualTo( - transferToThisDeviceSucceeded().state.getChipTextString(context, OTHER_DEVICE_NAME) - ) - assertThat(uiEventLoggerFake.eventId(0)).isEqualTo( - MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_SUCCEEDED.id - ) - } - - @Test - fun commandQueueCallback_transferToReceiverFailed_triggersCorrectChip() { - commandQueueCallback.updateMediaTapToTransferSenderDisplay( - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED, - routeInfo, - null - ) - - assertThat(getChipView().getChipText()).isEqualTo( - transferToReceiverFailed().state.getChipTextString(context, OTHER_DEVICE_NAME) - ) - assertThat(uiEventLoggerFake.eventId(0)).isEqualTo( - MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_FAILED.id - ) - } - - @Test - fun commandQueueCallback_transferToThisDeviceFailed_triggersCorrectChip() { - commandQueueCallback.updateMediaTapToTransferSenderDisplay( - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED, - routeInfo, - null - ) - - assertThat(getChipView().getChipText()).isEqualTo( - transferToThisDeviceFailed().state.getChipTextString(context, OTHER_DEVICE_NAME) - ) - assertThat(uiEventLoggerFake.eventId(0)).isEqualTo( - MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_FAILED.id - ) - } - - @Test - fun commandQueueCallback_farFromReceiver_noChipShown() { - commandQueueCallback.updateMediaTapToTransferSenderDisplay( - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, - routeInfo, - null - ) - - verify(windowManager, never()).addView(any(), any()) - assertThat(uiEventLoggerFake.eventId(0)).isEqualTo( - MediaTttSenderUiEvents.MEDIA_TTT_SENDER_FAR_FROM_RECEIVER.id - ) - } - - @Test - fun commandQueueCallback_almostCloseThenFarFromReceiver_chipShownThenHidden() { - commandQueueCallback.updateMediaTapToTransferSenderDisplay( - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, - routeInfo, - null - ) - - commandQueueCallback.updateMediaTapToTransferSenderDisplay( - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, - routeInfo, - null - ) - - val viewCaptor = ArgumentCaptor.forClass(View::class.java) - verify(windowManager).addView(viewCaptor.capture(), any()) - verify(windowManager).removeView(viewCaptor.value) - } - - @Test - fun commandQueueCallback_invalidStateParam_noChipShown() { - commandQueueCallback.updateMediaTapToTransferSenderDisplay( - 100, - routeInfo, - null - ) - - verify(windowManager, never()).addView(any(), any()) - } - - @Test - fun receivesNewStateFromCommandQueue_isLogged() { - commandQueueCallback.updateMediaTapToTransferSenderDisplay( - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, - routeInfo, - null - ) - - verify(logger).logStateChange(any(), any(), any()) } @Test @@ -672,21 +446,6 @@ class ChipbarCoordinatorTest : SysuiTestCase() { verify(logger).logRemovalBypass(any(), any()) } - @Test - fun transferToReceiverTriggeredThenFarFromReceiver_viewStillDisplayed() { - underTest.displayView(transferToReceiverTriggered()) - - commandQueueCallback.updateMediaTapToTransferSenderDisplay( - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, - routeInfo, - null - ) - fakeExecutor.runAllReady() - - verify(windowManager, never()).removeView(any()) - verify(logger).logRemovalBypass(any(), any()) - } - @Test fun transferToReceiverTriggeredThenRemoveView_eventuallyTimesOut() { underTest.displayView(transferToReceiverTriggered()) @@ -719,21 +478,6 @@ class ChipbarCoordinatorTest : SysuiTestCase() { verify(windowManager).removeView(any()) } - @Test - fun transferToThisDeviceTriggeredThenFarFromReceiver_viewStillDisplayed() { - underTest.displayView(transferToThisDeviceTriggered()) - - commandQueueCallback.updateMediaTapToTransferSenderDisplay( - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, - routeInfo, - null - ) - fakeExecutor.runAllReady() - - verify(windowManager, never()).removeView(any()) - verify(logger).logRemovalBypass(any(), any()) - } - @Test fun transferToReceiverSucceededThenRemoveView_viewStillDisplayed() { underTest.displayView(transferToReceiverSucceeded()) @@ -755,21 +499,6 @@ class ChipbarCoordinatorTest : SysuiTestCase() { verify(windowManager).removeView(any()) } - @Test - fun transferToReceiverSucceededThenFarFromReceiver_viewStillDisplayed() { - underTest.displayView(transferToReceiverSucceeded()) - - commandQueueCallback.updateMediaTapToTransferSenderDisplay( - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, - routeInfo, - null - ) - fakeExecutor.runAllReady() - - verify(windowManager, never()).removeView(any()) - verify(logger).logRemovalBypass(any(), any()) - } - @Test fun transferToThisDeviceSucceededThenRemoveView_viewStillDisplayed() { underTest.displayView(transferToThisDeviceSucceeded()) @@ -791,21 +520,6 @@ class ChipbarCoordinatorTest : SysuiTestCase() { verify(windowManager).removeView(any()) } - @Test - fun transferToThisDeviceSucceededThenFarFromReceiver_viewStillDisplayed() { - underTest.displayView(transferToThisDeviceSucceeded()) - - commandQueueCallback.updateMediaTapToTransferSenderDisplay( - StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, - routeInfo, - null - ) - fakeExecutor.runAllReady() - - verify(windowManager, never()).removeView(any()) - verify(logger).logRemovalBypass(any(), any()) - } - private fun ViewGroup.getAppIconView() = this.requireViewById(R.id.app_icon) private fun ViewGroup.getChipText(): String = @@ -824,6 +538,10 @@ class ChipbarCoordinatorTest : SysuiTestCase() { return viewCaptor.value as ViewGroup } + // TODO(b/245610654): For now, the below methods are duplicated between this test and + // [MediaTttSenderCoordinatorTest]. Once we define a generic API for [ChipbarCoordinator], + // these will no longer be duplicated. + /** Helper method providing default parameters to not clutter up the tests. */ private fun almostCloseToStartCast() = ChipSenderInfo(ChipStateSender.ALMOST_CLOSE_TO_START_CAST, routeInfo) @@ -855,41 +573,6 @@ class ChipbarCoordinatorTest : SysuiTestCase() { /** Helper method providing default parameters to not clutter up the tests. */ private fun transferToThisDeviceFailed() = ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_FAILED, routeInfo) - - private class TestChipbarCoordinator( - commandQueue: CommandQueue, - context: Context, - @MediaTttReceiverLogger logger: MediaTttLogger, - windowManager: WindowManager, - mainExecutor: DelayableExecutor, - accessibilityManager: AccessibilityManager, - configurationController: ConfigurationController, - powerManager: PowerManager, - uiEventLogger: MediaTttSenderUiEventLogger, - falsingManager: FalsingManager, - falsingCollector: FalsingCollector, - mediaTttFlags: MediaTttFlags, - viewUtil: ViewUtil, - ) : ChipbarCoordinator( - commandQueue, - context, - logger, - windowManager, - mainExecutor, - accessibilityManager, - configurationController, - powerManager, - uiEventLogger, - falsingManager, - falsingCollector, - mediaTttFlags, - viewUtil, - ) { - override fun animateViewOut(view: ViewGroup, onAnimationEnd: Runnable) { - // Just bypass the animation in tests - onAnimationEnd.run() - } - } } private const val APP_NAME = "Fake app name" diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt new file mode 100644 index 0000000000000..10704ac8fc679 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2022 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.systemui.temporarydisplay.chipbar + +import android.content.Context +import android.os.PowerManager +import android.view.ViewGroup +import android.view.WindowManager +import android.view.accessibility.AccessibilityManager +import com.android.systemui.classifier.FalsingCollector +import com.android.systemui.media.taptotransfer.common.MediaTttLogger +import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger +import com.android.systemui.media.taptotransfer.sender.MediaTttSenderUiEventLogger +import com.android.systemui.plugins.FalsingManager +import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.util.concurrency.DelayableExecutor +import com.android.systemui.util.view.ViewUtil + +/** A fake implementation of [ChipbarCoordinator] for testing. */ +class FakeChipbarCoordinator( + context: Context, + @MediaTttReceiverLogger logger: MediaTttLogger, + windowManager: WindowManager, + mainExecutor: DelayableExecutor, + accessibilityManager: AccessibilityManager, + configurationController: ConfigurationController, + powerManager: PowerManager, + uiEventLogger: MediaTttSenderUiEventLogger, + falsingManager: FalsingManager, + falsingCollector: FalsingCollector, + viewUtil: ViewUtil, +) : + ChipbarCoordinator( + context, + logger, + windowManager, + mainExecutor, + accessibilityManager, + configurationController, + powerManager, + uiEventLogger, + falsingManager, + falsingCollector, + viewUtil, + ) { + override fun animateViewOut(view: ViewGroup, onAnimationEnd: Runnable) { + // Just bypass the animation in tests + onAnimationEnd.run() + } +}