From 38aa601aa20cf52f3bb366351891e1f815d3188d Mon Sep 17 00:00:00 2001 From: Caitlin Cassidy Date: Wed, 5 Jan 2022 21:18:27 +0000 Subject: [PATCH] [Media TTT] Add the aidl interface for the sender and a service that implements it. More callbacks will be added in future CLs. Bug: 203800643 Bug: 203800347 Test: manual (verify `adb shell cmd statusbar media-ttt-chip-add-sender Tablet MoveCloserToTransfer` still triggers chip) Test: media.taptotransfer tests Change-Id: Ic44b770e8c98f7c9a06a0846fd166e4c8d51ea7d --- packages/SystemUI/AndroidManifest.xml | 6 ++ packages/SystemUI/res/values/strings.xml | 4 +- .../mediattt/IDeviceSenderCallback.aidl | 45 +++++++++++ .../systemui/media/dagger/MediaModule.java | 11 +++ .../MediaTttCommandLineHelper.kt | 81 ++++++++++++++++--- .../taptotransfer/sender/ChipStateSender.kt | 9 ++- .../sender/MediaTttSenderService.kt | 63 +++++++++++++++ .../MediaTttCommandLineHelperTest.kt | 27 +++++-- .../MediaTttChipControllerSenderTest.kt | 16 ++-- .../sender/MediaTttSenderServiceTest.kt | 40 +++++++++ 10 files changed, 271 insertions(+), 31 deletions(-) create mode 100644 packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderCallback.aidl create mode 100644 packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderService.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderServiceTest.kt diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 1e9a41e4d0b80..36cd135b7ffc9 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -843,6 +843,12 @@ android:singleUser="true" android:permission="android.permission.BIND_DREAM_SERVICE" /> + + + + diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 99508a5fc73a7..aebddc9d98f36 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2187,8 +2187,8 @@ Undo - - Move closer to play on %1$s + + Move closer to play on %1$s Playing on %1$s diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderCallback.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderCallback.aidl new file mode 100644 index 0000000000000..f34b8d657d33c --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/mediattt/IDeviceSenderCallback.aidl @@ -0,0 +1,45 @@ +/* + * 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.shared.mediattt; + +import android.media.MediaRoute2Info; + +/** + * A callback interface that can be invoked to trigger media transfer events on System UI. + * + * This interface is for the *sender* device, which is the device currently playing media. This + * sender device can transfer the media to a different device, called the receiver. + * + * System UI will implement this interface and other services will invoke it. + */ +interface IDeviceSenderCallback { + /** + * Invoke to notify System UI that this device (the sender) is close to a receiver device, so + * the user can potentially *start* a cast to the receiver device if the user moves their device + * a bit closer. + * + * Important notes: + * - When this callback triggers, the device is close enough to inform the user that + * transferring is an option, but the device is *not* close enough to actually initiate a + * transfer yet. + * - This callback is for *starting* a cast. It should be used when this device is currently + * playing media locally and the media should be transferred to be played on the receiver + * device instead. + */ + // TODO(b/203800643): Add the otherDeviceInfo parameter. + oneway void closeToReceiverToStartCast(in MediaRoute2Info mediaInfo); +} diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java index 558f0e6342555..d1fe7d449bdd8 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java +++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java @@ -16,6 +16,7 @@ package com.android.systemui.media.dagger; +import android.app.Service; import android.content.Context; import android.view.WindowManager; @@ -30,6 +31,7 @@ import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper; import com.android.systemui.media.taptotransfer.MediaTttFlags; import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver; import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender; +import com.android.systemui.media.taptotransfer.sender.MediaTttSenderService; import com.android.systemui.statusbar.commandline.CommandRegistry; import com.android.systemui.util.concurrency.DelayableExecutor; @@ -38,8 +40,11 @@ import java.util.concurrent.Executor; import javax.inject.Named; +import dagger.Binds; import dagger.Module; import dagger.Provides; +import dagger.multibindings.ClassKey; +import dagger.multibindings.IntoMap; /** Dagger module for the media package. */ @Module @@ -128,4 +133,10 @@ public interface MediaModule { mediaTttChipControllerReceiver, mainExecutor)); } + + /** Inject into MediaTttSenderService. */ + @Binds + @IntoMap + @ClassKey(MediaTttSenderService.class) + Service bindMediaTttSenderService(MediaTttSenderService service); } diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt index 5a86723677b19..0078b958a38b5 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt @@ -16,9 +16,14 @@ package com.android.systemui.media.taptotransfer +import android.content.ComponentName import android.content.Context +import android.content.Intent +import android.content.ServiceConnection import android.graphics.Color import android.graphics.drawable.Icon +import android.media.MediaRoute2Info +import android.os.IBinder import android.util.Log import androidx.annotation.VisibleForTesting import com.android.systemui.R @@ -27,9 +32,11 @@ import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender -import com.android.systemui.media.taptotransfer.sender.MoveCloserToTransfer +import com.android.systemui.media.taptotransfer.sender.MediaTttSenderService +import com.android.systemui.media.taptotransfer.sender.MoveCloserToStartCast import com.android.systemui.media.taptotransfer.sender.TransferInitiated import com.android.systemui.media.taptotransfer.sender.TransferSucceeded +import com.android.systemui.shared.mediattt.IDeviceSenderCallback import com.android.systemui.statusbar.commandline.Command import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.util.concurrency.DelayableExecutor @@ -44,11 +51,14 @@ import javax.inject.Inject @SysUISingleton class MediaTttCommandLineHelper @Inject constructor( commandRegistry: CommandRegistry, - context: Context, + private val context: Context, private val mediaTttChipControllerSender: MediaTttChipControllerSender, private val mediaTttChipControllerReceiver: MediaTttChipControllerReceiver, @Main private val mainExecutor: DelayableExecutor, ) { + private var senderCallback: IDeviceSenderCallback? = null + private val senderServiceConnection = SenderServiceConnection() + private val appIconDrawable = Icon.createWithResource(context, R.drawable.ic_avatar_user).loadDrawable(context).also { it.setTint(Color.YELLOW) @@ -68,14 +78,19 @@ class MediaTttCommandLineHelper @Inject constructor( inner class AddChipCommandSender : Command { override fun execute(pw: PrintWriter, args: List) { val otherDeviceName = args[0] + val mediaInfo = MediaRoute2Info.Builder("id", "Test Name") + .addFeature("feature") + .build() + when (args[1]) { - MOVE_CLOSER_TO_TRANSFER_COMMAND_NAME -> { - mediaTttChipControllerSender.displayChip( - MoveCloserToTransfer( - appIconDrawable, APP_ICON_CONTENT_DESCRIPTION, otherDeviceName - ) - ) + MOVE_CLOSER_TO_START_CAST_COMMAND_NAME -> { + runOnService { senderCallback -> + senderCallback.closeToReceiverToStartCast(mediaInfo) + } } + + // TODO(b/203800643): Migrate other commands to invoke the service instead of the + // controller. TRANSFER_INITIATED_COMMAND_NAME -> { val futureTask = FutureTask { fakeUndoRunnable } mediaTttChipControllerSender.displayChip( @@ -101,7 +116,7 @@ class MediaTttCommandLineHelper @Inject constructor( } else -> { pw.println("Chip type must be one of " + - "$MOVE_CLOSER_TO_TRANSFER_COMMAND_NAME, " + + "$MOVE_CLOSER_TO_START_CAST_COMMAND_NAME, " + "$TRANSFER_INITIATED_COMMAND_NAME, " + TRANSFER_SUCCEEDED_COMMAND_NAME ) @@ -114,19 +129,40 @@ class MediaTttCommandLineHelper @Inject constructor( "$ADD_CHIP_COMMAND_SENDER_TAG " ) } + + private fun runOnService(command: SenderCallbackCommand) { + val currentServiceCallback = senderCallback + if (currentServiceCallback != null) { + command.run(currentServiceCallback) + } else { + bindService(command) + } + } + + private fun bindService(command: SenderCallbackCommand) { + senderServiceConnection.pendingCommand = command + val binding = context.bindService( + Intent(context, MediaTttSenderService::class.java), + senderServiceConnection, + Context.BIND_AUTO_CREATE + ) + Log.i(TAG, "Starting service binding? $binding") + } } /** A command to REMOVE the media ttt chip on the SENDER device. */ inner class RemoveChipCommandSender : Command { override fun execute(pw: PrintWriter, args: List) { mediaTttChipControllerSender.removeChip() + if (senderCallback != null) { + context.unbindService(senderServiceConnection) + } } override fun help(pw: PrintWriter) { pw.println("Usage: adb shell cmd statusbar $REMOVE_CHIP_COMMAND_SENDER_TAG") } } - /** A command to DISPLAY the media ttt chip on the RECEIVER device. */ inner class AddChipCommandReceiver : Command { override fun execute(pw: PrintWriter, args: List) { @@ -149,6 +185,29 @@ class MediaTttCommandLineHelper @Inject constructor( } } + /** A service connection for [IDeviceSenderCallback]. */ + private inner class SenderServiceConnection : ServiceConnection { + // A command that should be run when the service gets connected. + var pendingCommand: SenderCallbackCommand? = null + + override fun onServiceConnected(className: ComponentName, service: IBinder) { + val newCallback = IDeviceSenderCallback.Stub.asInterface(service) + senderCallback = newCallback + pendingCommand?.run(newCallback) + pendingCommand = null + } + + override fun onServiceDisconnected(className: ComponentName) { + senderCallback = null + } + } + + /** An interface defining a command that should be run on the sender callback. */ + private fun interface SenderCallbackCommand { + /** Runs the command on the provided [senderCallback]. */ + fun run(senderCallback: IDeviceSenderCallback) + } + private val fakeUndoRunnable = Runnable { Log.i(TAG, "Undo runnable triggered") } @@ -163,7 +222,7 @@ const val ADD_CHIP_COMMAND_RECEIVER_TAG = "media-ttt-chip-add-receiver" @VisibleForTesting const val REMOVE_CHIP_COMMAND_RECEIVER_TAG = "media-ttt-chip-remove-receiver" @VisibleForTesting -val MOVE_CLOSER_TO_TRANSFER_COMMAND_NAME = MoveCloserToTransfer::class.simpleName!! +val MOVE_CLOSER_TO_START_CAST_COMMAND_NAME = MoveCloserToStartCast::class.simpleName!! @VisibleForTesting val TRANSFER_INITIATED_COMMAND_NAME = TransferInitiated::class.simpleName!! @VisibleForTesting diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt index b1f6faaba924a..dd434e7756fbe 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt @@ -40,17 +40,18 @@ sealed class ChipStateSender( ) : MediaTttChipState(appIconDrawable, appIconContentDescription) /** - * A state representing that the two devices are close but not close enough to initiate a transfer. - * The chip will instruct the user to move closer in order to initiate the transfer. + * A state representing that the two devices are close but not close enough to *start* a cast to + * the receiver device. The chip will instruct the user to move closer in order to initiate the + * transfer to the receiver. */ -class MoveCloserToTransfer( +class MoveCloserToStartCast( appIconDrawable: Drawable, appIconContentDescription: String, otherDeviceName: String, ) : ChipStateSender( appIconDrawable, appIconContentDescription, - R.string.media_move_closer_to_transfer, + R.string.media_move_closer_to_start_cast, otherDeviceName ) diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderService.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderService.kt new file mode 100644 index 0000000000000..a7e70fa1b29ac --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderService.kt @@ -0,0 +1,63 @@ +/* + * 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.Service +import android.content.Context +import android.content.Intent +import android.graphics.Color +import android.graphics.drawable.Icon +import android.media.MediaRoute2Info +import android.os.IBinder +import com.android.systemui.R +import com.android.systemui.shared.mediattt.IDeviceSenderCallback +import javax.inject.Inject + +/** + * Service that allows external handlers to trigger the media chip on the sender device. + */ +class MediaTttSenderService @Inject constructor( + context: Context, + val controller: MediaTttChipControllerSender +) : Service() { + + // TODO(b/203800643): Add logging when callbacks trigger. + private val binder: IBinder = object : IDeviceSenderCallback.Stub() { + override fun closeToReceiverToStartCast(mediaInfo: MediaRoute2Info) { + this@MediaTttSenderService.closeToReceiverToStartCast(mediaInfo) + } + } + + // TODO(b/203800643): Use the app icon from the media info instead of a fake one. + private val fakeAppIconDrawable = + Icon.createWithResource(context, R.drawable.ic_avatar_user).loadDrawable(context).also { + it.setTint(Color.YELLOW) + } + + override fun onBind(intent: Intent?): IBinder = binder + + private fun closeToReceiverToStartCast(mediaInfo: MediaRoute2Info) { + val chipState = MoveCloserToStartCast( + appIconDrawable = fakeAppIconDrawable, + appIconContentDescription = mediaInfo.name.toString(), + otherDeviceName = FAKE_DEVICE_NAME + ) + controller.displayChip(chipState) + } +} + +private const val FAKE_DEVICE_NAME = "Fake Other Device Name" diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt index dec5a100e20d2..abf53d3031396 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt @@ -16,23 +16,28 @@ package com.android.systemui.media.taptotransfer +import android.content.ComponentName import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender -import com.android.systemui.media.taptotransfer.sender.MoveCloserToTransfer +import com.android.systemui.media.taptotransfer.sender.MediaTttSenderService import com.android.systemui.media.taptotransfer.sender.TransferInitiated import com.android.systemui.media.taptotransfer.sender.TransferSucceeded +import com.android.systemui.shared.mediattt.IDeviceSenderCallback import com.android.systemui.statusbar.commandline.Command import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.time.FakeSystemClock +import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.mockito.Mock +import org.mockito.Mockito.anyString import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations import java.io.PrintWriter import java.io.StringWriter @@ -51,10 +56,19 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { private lateinit var mediaTttChipControllerSender: MediaTttChipControllerSender @Mock private lateinit var mediaTttChipControllerReceiver: MediaTttChipControllerReceiver + @Mock + private lateinit var mediaSenderService: IDeviceSenderCallback.Stub + private lateinit var mediaSenderServiceComponentName: ComponentName @Before fun setUp() { MockitoAnnotations.initMocks(this) + + mediaSenderServiceComponentName = ComponentName(context, MediaTttSenderService::class.java) + context.addMockService(mediaSenderServiceComponentName, mediaSenderService) + whenever(mediaSenderService.queryLocalInterface(anyString())).thenReturn(mediaSenderService) + whenever(mediaSenderService.asBinder()).thenReturn(mediaSenderService) + mediaTttCommandLineHelper = MediaTttCommandLineHelper( commandRegistry, @@ -102,10 +116,11 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { } @Test - fun sender_moveCloserToTransfer_chipDisplayWithCorrectState() { - commandRegistry.onShellCommand(pw, getMoveCloserToTransferCommand()) + fun sender_moveCloserToStartCast_serviceCallbackCalled() { + commandRegistry.onShellCommand(pw, getMoveCloserToStartCastCommand()) - verify(mediaTttChipControllerSender).displayChip(any(MoveCloserToTransfer::class.java)) + assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue() + verify(mediaSenderService).closeToReceiverToStartCast(any()) } @Test @@ -143,11 +158,11 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() { verify(mediaTttChipControllerReceiver).removeChip() } - private fun getMoveCloserToTransferCommand(): Array = + private fun getMoveCloserToStartCastCommand(): Array = arrayOf( ADD_CHIP_COMMAND_SENDER_TAG, DEVICE_NAME, - MOVE_CLOSER_TO_TRANSFER_COMMAND_NAME + MOVE_CLOSER_TO_START_CAST_COMMAND_NAME ) private fun getTransferInitiatedCommand(): Array = diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt index caef5b901e0f8..ecc4c46634b98 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt @@ -66,8 +66,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { } @Test - fun moveCloserToTransfer_appIcon_chipTextContainsDeviceName_noLoadingIcon_noUndo() { - controllerSender.displayChip(moveCloserToTransfer()) + fun moveCloserToStartCast_appIcon_chipTextContainsDeviceName_noLoadingIcon_noUndo() { + controllerSender.displayChip(moveCloserToStartCast()) val chipView = getChipView() assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable) @@ -192,8 +192,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { } @Test - fun changeFromCloserToTransferToTransferInitiated_loadingIconAppears() { - controllerSender.displayChip(moveCloserToTransfer()) + fun changeFromCloserToStartToTransferInitiated_loadingIconAppears() { + controllerSender.displayChip(moveCloserToStartCast()) controllerSender.displayChip(transferInitiated()) assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.VISIBLE) @@ -216,9 +216,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { } @Test - fun changeFromTransferSucceededToMoveCloser_undoButtonDisappears() { + fun changeFromTransferSucceededToMoveCloserToStart_undoButtonDisappears() { controllerSender.displayChip(transferSucceeded()) - controllerSender.displayChip(moveCloserToTransfer()) + controllerSender.displayChip(moveCloserToStartCast()) assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.GONE) } @@ -240,8 +240,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { } /** Helper method providing default parameters to not clutter up the tests. */ - private fun moveCloserToTransfer() = - MoveCloserToTransfer(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME) + private fun moveCloserToStartCast() = + MoveCloserToStartCast(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME) /** Helper method providing default parameters to not clutter up the tests. */ private fun transferInitiated( diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderServiceTest.kt new file mode 100644 index 0000000000000..5849ed55f1333 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderServiceTest.kt @@ -0,0 +1,40 @@ +package com.android.systemui.media.taptotransfer.sender + +import android.media.MediaRoute2Info +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.shared.mediattt.IDeviceSenderCallback +import com.android.systemui.util.mockito.any +import org.junit.Before +import org.junit.Test +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +class MediaTttSenderServiceTest : SysuiTestCase() { + + private lateinit var service: MediaTttSenderService + private lateinit var callback: IDeviceSenderCallback + + @Mock + private lateinit var controller: MediaTttChipControllerSender + + private val mediaInfo = MediaRoute2Info.Builder("id", "Test Name") + .addFeature("feature") + .build() + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + service = MediaTttSenderService(context, controller) + callback = IDeviceSenderCallback.Stub.asInterface(service.onBind(null)) + } + + @Test + fun closeToReceiverToStartCast_controllerTriggeredWithMoveCloserToStartCastState() { + callback.closeToReceiverToStartCast(mediaInfo) + + verify(controller).displayChip(any()) + } +}