1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.media.taptotransfer 18 19 import android.app.StatusBarManager 20 import android.content.Context 21 import android.media.MediaRoute2Info 22 import androidx.test.filters.SmallTest 23 import com.android.systemui.SysuiTestCase 24 import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver 25 import com.android.systemui.media.taptotransfer.sender.ChipStateSender 26 import com.android.systemui.statusbar.commandline.Command 27 import com.android.systemui.statusbar.commandline.CommandRegistry 28 import com.android.systemui.util.concurrency.FakeExecutor 29 import com.android.systemui.util.mockito.any 30 import com.android.systemui.util.mockito.argumentCaptor 31 import com.android.systemui.util.mockito.capture 32 import com.android.systemui.util.mockito.eq 33 import com.android.systemui.util.mockito.nullable 34 import com.android.systemui.util.time.FakeSystemClock 35 import com.google.common.truth.Truth.assertThat 36 import org.junit.Before 37 import org.junit.Test 38 import org.mockito.Mock 39 import org.mockito.Mockito.verify 40 import org.mockito.MockitoAnnotations 41 import java.io.PrintWriter 42 import java.io.StringWriter 43 import java.util.concurrent.Executor 44 45 @SmallTest 46 class MediaTttCommandLineHelperTest : SysuiTestCase() { 47 48 private val inlineExecutor = Executor { command -> command.run() } 49 private val commandRegistry = CommandRegistry(context, inlineExecutor) 50 private val pw = PrintWriter(StringWriter()) 51 52 private lateinit var mediaTttCommandLineHelper: MediaTttCommandLineHelper 53 54 @Mock 55 private lateinit var statusBarManager: StatusBarManager 56 57 @Before 58 fun setUp() { 59 MockitoAnnotations.initMocks(this) 60 context.addMockSystemService(Context.STATUS_BAR_SERVICE, statusBarManager) 61 mediaTttCommandLineHelper = 62 MediaTttCommandLineHelper( 63 commandRegistry, 64 context, 65 FakeExecutor(FakeSystemClock()), 66 ) 67 mediaTttCommandLineHelper.start() 68 } 69 70 @Test(expected = IllegalStateException::class) 71 fun constructor_senderCommandAlreadyRegistered() { 72 // Since creating the chip controller should automatically register the sender command, it 73 // should throw when registering it again. 74 commandRegistry.registerCommand(SENDER_COMMAND) { EmptyCommand() } 75 } 76 77 @Test(expected = IllegalStateException::class) 78 fun constructor_receiverCommandAlreadyRegistered() { 79 // Since creating the chip controller should automatically register the receiver command, it 80 // should throw when registering it again. 81 commandRegistry.registerCommand(RECEIVER_COMMAND) { EmptyCommand() } 82 } 83 84 @Test 85 fun sender_almostCloseToStartCast_serviceCallbackCalled() { 86 commandRegistry.onShellCommand( 87 pw, getSenderCommand(ChipStateSender.ALMOST_CLOSE_TO_START_CAST.name) 88 ) 89 90 val routeInfoCaptor = argumentCaptor<MediaRoute2Info>() 91 verify(statusBarManager).updateMediaTapToTransferSenderDisplay( 92 eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST), 93 capture(routeInfoCaptor), 94 nullable(), 95 nullable()) 96 assertThat(routeInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME) 97 } 98 99 @Test 100 fun sender_almostCloseToEndCast_serviceCallbackCalled() { 101 commandRegistry.onShellCommand( 102 pw, getSenderCommand(ChipStateSender.ALMOST_CLOSE_TO_END_CAST.name) 103 ) 104 105 val routeInfoCaptor = argumentCaptor<MediaRoute2Info>() 106 verify(statusBarManager).updateMediaTapToTransferSenderDisplay( 107 eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST), 108 capture(routeInfoCaptor), 109 nullable(), 110 nullable()) 111 assertThat(routeInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME) 112 } 113 114 @Test 115 fun sender_transferToReceiverTriggered_chipDisplayWithCorrectState() { 116 commandRegistry.onShellCommand( 117 pw, getSenderCommand(ChipStateSender.TRANSFER_TO_RECEIVER_TRIGGERED.name) 118 ) 119 120 val routeInfoCaptor = argumentCaptor<MediaRoute2Info>() 121 verify(statusBarManager).updateMediaTapToTransferSenderDisplay( 122 eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED), 123 capture(routeInfoCaptor), 124 nullable(), 125 nullable()) 126 assertThat(routeInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME) 127 } 128 129 @Test 130 fun sender_transferToThisDeviceTriggered_chipDisplayWithCorrectState() { 131 commandRegistry.onShellCommand( 132 pw, getSenderCommand(ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED.name) 133 ) 134 135 verify(statusBarManager).updateMediaTapToTransferSenderDisplay( 136 eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED), 137 any(), 138 nullable(), 139 nullable()) 140 } 141 142 @Test 143 fun sender_transferToReceiverSucceeded_chipDisplayWithCorrectState() { 144 commandRegistry.onShellCommand( 145 pw, getSenderCommand(ChipStateSender.TRANSFER_TO_RECEIVER_SUCCEEDED.name) 146 ) 147 148 val routeInfoCaptor = argumentCaptor<MediaRoute2Info>() 149 verify(statusBarManager).updateMediaTapToTransferSenderDisplay( 150 eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED), 151 capture(routeInfoCaptor), 152 nullable(), 153 nullable()) 154 assertThat(routeInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME) 155 } 156 157 @Test 158 fun sender_transferToThisDeviceSucceeded_chipDisplayWithCorrectState() { 159 commandRegistry.onShellCommand( 160 pw, getSenderCommand(ChipStateSender.TRANSFER_TO_THIS_DEVICE_SUCCEEDED.name) 161 ) 162 163 val routeInfoCaptor = argumentCaptor<MediaRoute2Info>() 164 verify(statusBarManager).updateMediaTapToTransferSenderDisplay( 165 eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED), 166 capture(routeInfoCaptor), 167 nullable(), 168 nullable()) 169 assertThat(routeInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME) 170 } 171 172 @Test 173 fun sender_transferToReceiverFailed_serviceCallbackCalled() { 174 commandRegistry.onShellCommand( 175 pw, getSenderCommand(ChipStateSender.TRANSFER_TO_RECEIVER_FAILED.name) 176 ) 177 178 verify(statusBarManager).updateMediaTapToTransferSenderDisplay( 179 eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED), 180 any(), 181 nullable(), 182 nullable()) 183 } 184 185 @Test 186 fun sender_transferToThisDeviceFailed_serviceCallbackCalled() { 187 commandRegistry.onShellCommand( 188 pw, getSenderCommand(ChipStateSender.TRANSFER_TO_THIS_DEVICE_FAILED.name) 189 ) 190 191 verify(statusBarManager).updateMediaTapToTransferSenderDisplay( 192 eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED), 193 any(), 194 nullable(), 195 nullable()) 196 } 197 198 @Test 199 fun sender_farFromReceiver_serviceCallbackCalled() { 200 commandRegistry.onShellCommand( 201 pw, getSenderCommand(ChipStateSender.FAR_FROM_RECEIVER.name) 202 ) 203 204 verify(statusBarManager).updateMediaTapToTransferSenderDisplay( 205 eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER), 206 any(), 207 nullable(), 208 nullable()) 209 } 210 211 @Test 212 fun receiver_closeToSender_serviceCallbackCalled() { 213 commandRegistry.onShellCommand( 214 pw, getReceiverCommand(ChipStateReceiver.CLOSE_TO_SENDER.name) 215 ) 216 217 verify(statusBarManager).updateMediaTapToTransferReceiverDisplay( 218 eq(StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER), 219 any(), 220 nullable(), 221 nullable() 222 ) 223 } 224 225 @Test 226 fun receiver_farFromSender_serviceCallbackCalled() { 227 commandRegistry.onShellCommand( 228 pw, getReceiverCommand(ChipStateReceiver.FAR_FROM_SENDER.name) 229 ) 230 231 verify(statusBarManager).updateMediaTapToTransferReceiverDisplay( 232 eq(StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER), 233 any(), 234 nullable(), 235 nullable() 236 ) 237 } 238 239 private fun getSenderCommand(displayState: String): Array<String> = 240 arrayOf(SENDER_COMMAND, DEVICE_NAME, displayState) 241 242 private fun getReceiverCommand(displayState: String): Array<String> = 243 arrayOf(RECEIVER_COMMAND, displayState) 244 245 class EmptyCommand : Command { 246 override fun execute(pw: PrintWriter, args: List<String>) { 247 } 248 249 override fun help(pw: PrintWriter) { 250 } 251 } 252 } 253 254 private const val DEVICE_NAME = "My Tablet" 255