1 /* 2 * Copyright (C) 2022 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.sender 18 19 import android.app.StatusBarManager 20 import android.content.pm.ApplicationInfo 21 import android.content.pm.PackageManager 22 import android.graphics.drawable.Drawable 23 import android.media.MediaRoute2Info 24 import android.os.PowerManager 25 import android.os.VibrationAttributes 26 import android.os.VibrationEffect 27 import android.testing.TestableLooper 28 import android.view.View 29 import android.view.ViewGroup 30 import android.view.WindowManager 31 import android.view.accessibility.AccessibilityManager 32 import android.widget.ImageView 33 import android.widget.TextView 34 import androidx.test.ext.junit.runners.AndroidJUnit4 35 import androidx.test.filters.SmallTest 36 import com.android.app.viewcapture.ViewCapture 37 import com.android.app.viewcapture.ViewCaptureAwareWindowManager 38 import com.android.internal.logging.testing.UiEventLoggerFake 39 import com.android.internal.statusbar.IUndoMediaTransferCallback 40 import com.android.systemui.SysuiTestCase 41 import com.android.systemui.classifier.FalsingCollector 42 import com.android.systemui.common.shared.model.Text.Companion.loadText 43 import com.android.systemui.dump.DumpManager 44 import com.android.systemui.plugins.FalsingManager 45 import com.android.systemui.res.R 46 import com.android.systemui.statusbar.CommandQueue 47 import com.android.systemui.statusbar.VibratorHelper 48 import com.android.systemui.statusbar.policy.ConfigurationController 49 import com.android.systemui.temporarydisplay.TemporaryViewDisplayController 50 import com.android.systemui.temporarydisplay.TemporaryViewUiEventLogger 51 import com.android.systemui.temporarydisplay.chipbar.ChipbarAnimator 52 import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator 53 import com.android.systemui.temporarydisplay.chipbar.ChipbarLogger 54 import com.android.systemui.temporarydisplay.chipbar.SwipeChipbarAwayGestureHandler 55 import com.android.systemui.util.concurrency.FakeExecutor 56 import com.android.systemui.util.mockito.any 57 import com.android.systemui.util.mockito.argumentCaptor 58 import com.android.systemui.util.mockito.capture 59 import com.android.systemui.util.mockito.eq 60 import com.android.systemui.util.mockito.mock 61 import com.android.systemui.util.time.FakeSystemClock 62 import com.android.systemui.util.view.ViewUtil 63 import com.android.systemui.util.wakelock.WakeLockFake 64 import com.google.common.truth.Truth.assertThat 65 import org.junit.Before 66 import org.junit.Test 67 import org.junit.runner.RunWith 68 import org.mockito.ArgumentCaptor 69 import org.mockito.Mock 70 import org.mockito.Mockito.atLeast 71 import org.mockito.Mockito.never 72 import org.mockito.Mockito.reset 73 import org.mockito.Mockito.verify 74 import org.mockito.Mockito.`when` as whenever 75 import org.mockito.MockitoAnnotations 76 77 @SmallTest 78 @RunWith(AndroidJUnit4::class) 79 @TestableLooper.RunWithLooper 80 class MediaTttSenderCoordinatorTest : SysuiTestCase() { 81 82 // Note: This tests are a bit like integration tests because they use a real instance of 83 // [ChipbarCoordinator] and verify that the coordinator displays the correct view, based on 84 // the inputs from [MediaTttSenderCoordinator]. 85 86 private lateinit var underTest: MediaTttSenderCoordinator 87 88 @Mock private lateinit var accessibilityManager: AccessibilityManager 89 @Mock private lateinit var applicationInfo: ApplicationInfo 90 @Mock private lateinit var commandQueue: CommandQueue 91 @Mock private lateinit var configurationController: ConfigurationController 92 @Mock private lateinit var dumpManager: DumpManager 93 @Mock private lateinit var falsingManager: FalsingManager 94 @Mock private lateinit var falsingCollector: FalsingCollector 95 @Mock private lateinit var chipbarLogger: ChipbarLogger 96 @Mock private lateinit var logger: MediaTttSenderLogger 97 @Mock private lateinit var packageManager: PackageManager 98 @Mock private lateinit var powerManager: PowerManager 99 @Mock private lateinit var viewUtil: ViewUtil 100 @Mock private lateinit var windowManager: WindowManager 101 @Mock private lateinit var vibratorHelper: VibratorHelper 102 @Mock private lateinit var swipeHandler: SwipeChipbarAwayGestureHandler 103 @Mock private lateinit var lazyViewCapture: Lazy<ViewCapture> 104 private lateinit var fakeWakeLockBuilder: WakeLockFake.Builder 105 private lateinit var fakeWakeLock: WakeLockFake 106 private lateinit var chipbarCoordinator: ChipbarCoordinator 107 private lateinit var commandQueueCallback: CommandQueue.Callbacks 108 private lateinit var fakeAppIconDrawable: Drawable 109 private lateinit var fakeClock: FakeSystemClock 110 private lateinit var fakeExecutor: FakeExecutor 111 private lateinit var uiEventLoggerFake: UiEventLoggerFake 112 private lateinit var uiEventLogger: MediaTttSenderUiEventLogger 113 private lateinit var tempViewUiEventLogger: TemporaryViewUiEventLogger 114 private val defaultTimeout = context.resources.getInteger(R.integer.heads_up_notification_decay) 115 116 @Before setUpnull117 fun setUp() { 118 MockitoAnnotations.initMocks(this) 119 whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenReturn(TIMEOUT) 120 121 fakeAppIconDrawable = context.getDrawable(R.drawable.ic_cake)!! 122 whenever(applicationInfo.loadLabel(packageManager)).thenReturn(APP_NAME) 123 whenever(packageManager.getApplicationIcon(PACKAGE_NAME)).thenReturn(fakeAppIconDrawable) 124 whenever( 125 packageManager.getApplicationInfo( 126 eq(PACKAGE_NAME), 127 any<PackageManager.ApplicationInfoFlags>(), 128 ) 129 ) 130 .thenReturn(applicationInfo) 131 context.setMockPackageManager(packageManager) 132 133 fakeClock = FakeSystemClock() 134 fakeExecutor = FakeExecutor(fakeClock) 135 136 fakeWakeLock = WakeLockFake() 137 fakeWakeLockBuilder = WakeLockFake.Builder(context) 138 fakeWakeLockBuilder.setWakeLock(fakeWakeLock) 139 140 uiEventLoggerFake = UiEventLoggerFake() 141 uiEventLogger = MediaTttSenderUiEventLogger(uiEventLoggerFake) 142 tempViewUiEventLogger = TemporaryViewUiEventLogger(uiEventLoggerFake) 143 144 chipbarCoordinator = 145 ChipbarCoordinator( 146 context, 147 chipbarLogger, 148 ViewCaptureAwareWindowManager( 149 windowManager, 150 lazyViewCapture, 151 isViewCaptureEnabled = false, 152 ), 153 fakeExecutor, 154 accessibilityManager, 155 configurationController, 156 dumpManager, 157 powerManager, 158 ChipbarAnimator(), 159 falsingManager, 160 falsingCollector, 161 swipeHandler, 162 viewUtil, 163 vibratorHelper, 164 fakeWakeLockBuilder, 165 fakeClock, 166 tempViewUiEventLogger, 167 ) 168 chipbarCoordinator.start() 169 170 underTest = 171 MediaTttSenderCoordinator( 172 chipbarCoordinator, 173 commandQueue, 174 context, 175 dumpManager, 176 logger, 177 uiEventLogger, 178 ) 179 underTest.start() 180 181 setCommandQueueCallback() 182 } 183 184 @Test commandQueueCallback_almostCloseToStartCast_triggersCorrectChipnull185 fun commandQueueCallback_almostCloseToStartCast_triggersCorrectChip() { 186 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 187 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, 188 routeInfo, 189 null, 190 ) 191 192 val chipbarView = getChipbarView() 193 assertThat(chipbarView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) 194 assertThat(chipbarView.getAppIconView().contentDescription).isEqualTo(APP_NAME) 195 assertThat(chipbarView.getChipText()) 196 .isEqualTo(ChipStateSender.ALMOST_CLOSE_TO_START_CAST.getExpectedStateText()) 197 assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.GONE) 198 assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.GONE) 199 assertThat(chipbarView.getErrorIcon().visibility).isEqualTo(View.GONE) 200 assertThat(uiEventLoggerFake.eventId(0)) 201 .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_START_CAST.id) 202 verify(vibratorHelper) 203 .vibrate(any(), any(), any<VibrationEffect>(), any(), any<VibrationAttributes>()) 204 } 205 206 @Test commandQueueCallback_almostCloseToStartCast_deviceNameBlank_showsDefaultDeviceNamenull207 fun commandQueueCallback_almostCloseToStartCast_deviceNameBlank_showsDefaultDeviceName() { 208 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 209 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, 210 routeInfoWithBlankDeviceName, 211 null, 212 ) 213 214 val chipbarView = getChipbarView() 215 assertThat(chipbarView.getChipText()) 216 .contains(context.getString(R.string.media_ttt_default_device_type)) 217 assertThat(chipbarView.getChipText()) 218 .isNotEqualTo(ChipStateSender.ALMOST_CLOSE_TO_START_CAST.getExpectedStateText()) 219 } 220 221 @Test commandQueueCallback_almostCloseToEndCast_triggersCorrectChipnull222 fun commandQueueCallback_almostCloseToEndCast_triggersCorrectChip() { 223 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 224 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST, 225 routeInfo, 226 null, 227 ) 228 229 val chipbarView = getChipbarView() 230 assertThat(chipbarView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) 231 assertThat(chipbarView.getAppIconView().contentDescription).isEqualTo(APP_NAME) 232 assertThat(chipbarView.getChipText()) 233 .isEqualTo(ChipStateSender.ALMOST_CLOSE_TO_END_CAST.getExpectedStateText()) 234 assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.GONE) 235 assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.GONE) 236 assertThat(chipbarView.getErrorIcon().visibility).isEqualTo(View.GONE) 237 assertThat(uiEventLoggerFake.eventId(0)) 238 .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_ALMOST_CLOSE_TO_END_CAST.id) 239 verify(vibratorHelper) 240 .vibrate(any(), any(), any<VibrationEffect>(), any(), any<VibrationAttributes>()) 241 } 242 243 @Test commandQueueCallback_transferToReceiverTriggered_triggersCorrectChipnull244 fun commandQueueCallback_transferToReceiverTriggered_triggersCorrectChip() { 245 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 246 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED, 247 routeInfo, 248 null, 249 ) 250 251 val chipbarView = getChipbarView() 252 assertThat(chipbarView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) 253 assertThat(chipbarView.getAppIconView().contentDescription).isEqualTo(APP_NAME) 254 assertThat(chipbarView.getChipText()) 255 .isEqualTo(ChipStateSender.TRANSFER_TO_RECEIVER_TRIGGERED.getExpectedStateText()) 256 assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.VISIBLE) 257 assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.GONE) 258 assertThat(chipbarView.getErrorIcon().visibility).isEqualTo(View.GONE) 259 assertThat(uiEventLoggerFake.eventId(0)) 260 .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_TRIGGERED.id) 261 verify(vibratorHelper) 262 .vibrate(any(), any(), any<VibrationEffect>(), any(), any<VibrationAttributes>()) 263 } 264 265 @Test commandQueueCallback_transferToReceiverTriggered_deviceNameBlank_showsDefaultDeviceNamenull266 fun commandQueueCallback_transferToReceiverTriggered_deviceNameBlank_showsDefaultDeviceName() { 267 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 268 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED, 269 routeInfoWithBlankDeviceName, 270 null, 271 ) 272 273 val chipbarView = getChipbarView() 274 assertThat(chipbarView.getChipText()) 275 .contains(context.getString(R.string.media_ttt_default_device_type)) 276 assertThat(chipbarView.getChipText()) 277 .isNotEqualTo(ChipStateSender.TRANSFER_TO_RECEIVER_TRIGGERED.getExpectedStateText()) 278 } 279 280 @Test commandQueueCallback_transferToThisDeviceTriggered_triggersCorrectChipnull281 fun commandQueueCallback_transferToThisDeviceTriggered_triggersCorrectChip() { 282 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 283 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED, 284 routeInfo, 285 null, 286 ) 287 288 val chipbarView = getChipbarView() 289 assertThat(chipbarView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) 290 assertThat(chipbarView.getAppIconView().contentDescription).isEqualTo(APP_NAME) 291 assertThat(chipbarView.getChipText()) 292 .isEqualTo(ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED.getExpectedStateText()) 293 assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.VISIBLE) 294 assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.GONE) 295 assertThat(chipbarView.getErrorIcon().visibility).isEqualTo(View.GONE) 296 assertThat(uiEventLoggerFake.eventId(0)) 297 .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_TRIGGERED.id) 298 verify(vibratorHelper) 299 .vibrate(any(), any(), any<VibrationEffect>(), any(), any<VibrationAttributes>()) 300 } 301 302 @Test commandQueueCallback_transferToReceiverSucceeded_triggersCorrectChipnull303 fun commandQueueCallback_transferToReceiverSucceeded_triggersCorrectChip() { 304 displayReceiverTriggered() 305 reset(vibratorHelper) 306 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 307 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, 308 routeInfo, 309 null, 310 ) 311 312 val chipbarView = getChipbarView() 313 assertThat(chipbarView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) 314 assertThat(chipbarView.getAppIconView().contentDescription).isEqualTo(APP_NAME) 315 assertThat(chipbarView.getChipText()) 316 .isEqualTo(ChipStateSender.TRANSFER_TO_RECEIVER_SUCCEEDED.getExpectedStateText()) 317 assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.GONE) 318 assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.GONE) 319 // Event index 2 since initially displaying the triggered chip would also log two events. 320 assertThat(uiEventLoggerFake.eventId(2)) 321 .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_SUCCEEDED.id) 322 verify(vibratorHelper, never()) 323 .vibrate(any(), any(), any<VibrationEffect>(), any(), any<VibrationAttributes>()) 324 } 325 326 @Test commandQueueCallback_transferToReceiverSucceeded_sameViewInstanceIdnull327 fun commandQueueCallback_transferToReceiverSucceeded_sameViewInstanceId() { 328 displayReceiverTriggered() 329 reset(vibratorHelper) 330 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 331 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, 332 routeInfo, 333 null, 334 ) 335 336 // Event index 2 since initially displaying the triggered chip would also log two events. 337 assertThat(uiEventLoggerFake.eventId(2)) 338 .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_SUCCEEDED.id) 339 verify(vibratorHelper, never()).vibrate(any<VibrationEffect>()) 340 assertThat(uiEventLoggerFake.logs[0].instanceId) 341 .isEqualTo(uiEventLoggerFake.logs[2].instanceId) 342 } 343 344 @Test transferToReceiverSucceeded_nullUndoCallback_noUndonull345 fun transferToReceiverSucceeded_nullUndoCallback_noUndo() { 346 displayReceiverTriggered() 347 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 348 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, 349 routeInfo, 350 /* undoCallback= */ null, 351 ) 352 353 val chipbarView = getChipbarView() 354 assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.GONE) 355 } 356 357 @Test transferToReceiverSucceeded_withUndoRunnable_undoVisiblenull358 fun transferToReceiverSucceeded_withUndoRunnable_undoVisible() { 359 displayReceiverTriggered() 360 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 361 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, 362 routeInfo, 363 /* undoCallback= */ object : IUndoMediaTransferCallback.Stub() { 364 override fun onUndoTriggered() {} 365 }, 366 ) 367 368 val chipbarView = getChipbarView() 369 assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.VISIBLE) 370 assertThat(chipbarView.getUndoButton().hasOnClickListeners()).isTrue() 371 } 372 373 @Test transferToReceiverSucceeded_undoButtonClick_switchesToTransferToThisDeviceTriggerednull374 fun transferToReceiverSucceeded_undoButtonClick_switchesToTransferToThisDeviceTriggered() { 375 var undoCallbackCalled = false 376 displayReceiverTriggered() 377 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 378 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, 379 routeInfo, 380 /* undoCallback= */ object : IUndoMediaTransferCallback.Stub() { 381 override fun onUndoTriggered() { 382 undoCallbackCalled = true 383 } 384 }, 385 ) 386 387 getChipbarView().getUndoButton().performClick() 388 389 // Event index 3 since initially displaying the triggered and succeeded chip would also log 390 // events. 391 assertThat(uiEventLoggerFake.eventId(3)) 392 .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_RECEIVER_CLICKED.id) 393 assertThat(undoCallbackCalled).isTrue() 394 assertThat(getChipbarView().getChipText()) 395 .isEqualTo(ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED.getExpectedStateText()) 396 } 397 398 @Test commandQueueCallback_transferToThisDeviceSucceeded_triggersCorrectChipnull399 fun commandQueueCallback_transferToThisDeviceSucceeded_triggersCorrectChip() { 400 displayThisDeviceTriggered() 401 reset(vibratorHelper) 402 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 403 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, 404 routeInfo, 405 null, 406 ) 407 408 val chipbarView = getChipbarView() 409 assertThat(chipbarView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) 410 assertThat(chipbarView.getAppIconView().contentDescription).isEqualTo(APP_NAME) 411 assertThat(chipbarView.getChipText()) 412 .isEqualTo(ChipStateSender.TRANSFER_TO_THIS_DEVICE_SUCCEEDED.getExpectedStateText()) 413 assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.GONE) 414 assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.GONE) 415 // Event index 2 since initially displaying the triggered chip would also log two events. 416 assertThat(uiEventLoggerFake.eventId(2)) 417 .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_SUCCEEDED.id) 418 verify(vibratorHelper, never()) 419 .vibrate(any(), any(), any<VibrationEffect>(), any(), any<VibrationAttributes>()) 420 } 421 422 @Test transferToThisDeviceSucceeded_nullUndoCallback_noUndonull423 fun transferToThisDeviceSucceeded_nullUndoCallback_noUndo() { 424 displayThisDeviceTriggered() 425 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 426 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, 427 routeInfo, 428 /* undoCallback= */ null, 429 ) 430 431 val chipbarView = getChipbarView() 432 assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.GONE) 433 } 434 435 @Test transferToThisDeviceSucceeded_withUndoRunnable_undoVisiblenull436 fun transferToThisDeviceSucceeded_withUndoRunnable_undoVisible() { 437 displayThisDeviceTriggered() 438 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 439 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, 440 routeInfo, 441 /* undoCallback= */ object : IUndoMediaTransferCallback.Stub() { 442 override fun onUndoTriggered() {} 443 }, 444 ) 445 446 val chipbarView = getChipbarView() 447 assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.VISIBLE) 448 assertThat(chipbarView.getUndoButton().hasOnClickListeners()).isTrue() 449 } 450 451 @Test transferToThisDeviceSucceeded_undoButtonClick_switchesToTransferToThisDeviceTriggerednull452 fun transferToThisDeviceSucceeded_undoButtonClick_switchesToTransferToThisDeviceTriggered() { 453 var undoCallbackCalled = false 454 displayThisDeviceTriggered() 455 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 456 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, 457 routeInfo, 458 /* undoCallback= */ object : IUndoMediaTransferCallback.Stub() { 459 override fun onUndoTriggered() { 460 undoCallbackCalled = true 461 } 462 }, 463 ) 464 465 getChipbarView().getUndoButton().performClick() 466 467 // Event index 3 since initially displaying the triggered and succeeded chip would also log 468 // events. 469 assertThat(uiEventLoggerFake.eventId(3)) 470 .isEqualTo( 471 MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_THIS_DEVICE_CLICKED.id 472 ) 473 assertThat(undoCallbackCalled).isTrue() 474 assertThat(getChipbarView().getChipText()) 475 .isEqualTo(ChipStateSender.TRANSFER_TO_RECEIVER_TRIGGERED.getExpectedStateText()) 476 } 477 478 @Test commandQueueCallback_transferToReceiverFailed_triggersCorrectChipnull479 fun commandQueueCallback_transferToReceiverFailed_triggersCorrectChip() { 480 displayReceiverTriggered() 481 reset(vibratorHelper) 482 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 483 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED, 484 routeInfo, 485 null, 486 ) 487 488 val chipbarView = getChipbarView() 489 assertThat(chipbarView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) 490 assertThat(chipbarView.getAppIconView().contentDescription).isEqualTo(APP_NAME) 491 assertThat(chipbarView.getChipText()) 492 .isEqualTo(ChipStateSender.TRANSFER_TO_RECEIVER_FAILED.getExpectedStateText()) 493 assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.GONE) 494 assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.GONE) 495 assertThat(chipbarView.getErrorIcon().visibility).isEqualTo(View.VISIBLE) 496 // Event index 2 since initially displaying the triggered chip would also log two events. 497 assertThat(uiEventLoggerFake.eventId(2)) 498 .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_FAILED.id) 499 verify(vibratorHelper) 500 .vibrate(any(), any(), any<VibrationEffect>(), any(), any<VibrationAttributes>()) 501 } 502 503 @Test commandQueueCallback_transferToThisDeviceFailed_triggersCorrectChipnull504 fun commandQueueCallback_transferToThisDeviceFailed_triggersCorrectChip() { 505 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 506 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED, 507 routeInfo, 508 null, 509 ) 510 reset(vibratorHelper) 511 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 512 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED, 513 routeInfo, 514 null, 515 ) 516 517 val chipbarView = getChipbarView() 518 assertThat(chipbarView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable) 519 assertThat(chipbarView.getAppIconView().contentDescription).isEqualTo(APP_NAME) 520 assertThat(chipbarView.getChipText()) 521 .isEqualTo(ChipStateSender.TRANSFER_TO_RECEIVER_FAILED.getExpectedStateText()) 522 assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.GONE) 523 assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.GONE) 524 assertThat(chipbarView.getErrorIcon().visibility).isEqualTo(View.VISIBLE) 525 // Event index 1 since initially displaying the triggered chip would also log an event. 526 assertThat(uiEventLoggerFake.eventId(2)) 527 .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_FAILED.id) 528 verify(vibratorHelper) 529 .vibrate(any(), any(), any<VibrationEffect>(), any(), any<VibrationAttributes>()) 530 } 531 532 @Test commandQueueCallback_farFromReceiver_noChipShownnull533 fun commandQueueCallback_farFromReceiver_noChipShown() { 534 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 535 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, 536 routeInfo, 537 null, 538 ) 539 540 verify(windowManager, never()).addView(any(), any()) 541 assertThat(uiEventLoggerFake.eventId(0)) 542 .isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_FAR_FROM_RECEIVER.id) 543 } 544 545 @Test commandQueueCallback_almostCloseThenFarFromReceiver_chipShownThenHiddennull546 fun commandQueueCallback_almostCloseThenFarFromReceiver_chipShownThenHidden() { 547 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 548 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, 549 routeInfo, 550 null, 551 ) 552 553 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 554 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, 555 routeInfo, 556 null, 557 ) 558 559 val viewCaptor = ArgumentCaptor.forClass(View::class.java) 560 verify(windowManager).addView(viewCaptor.capture(), any()) 561 verify(windowManager).removeView(viewCaptor.value) 562 verify(logger).logStateMapRemoval(eq(DEFAULT_ID), any()) 563 } 564 565 @Test commandQueueCallback_almostCloseThenFarFromReceiver_wakeLockAcquiredThenReleasednull566 fun commandQueueCallback_almostCloseThenFarFromReceiver_wakeLockAcquiredThenReleased() { 567 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 568 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, 569 routeInfo, 570 null, 571 ) 572 573 assertThat(fakeWakeLock.isHeld).isTrue() 574 575 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 576 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, 577 routeInfo, 578 null, 579 ) 580 581 assertThat(fakeWakeLock.isHeld).isFalse() 582 } 583 584 @Test commandQueueCallback_FarFromReceiver_wakeLockNeverReleasednull585 fun commandQueueCallback_FarFromReceiver_wakeLockNeverReleased() { 586 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 587 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, 588 routeInfo, 589 null, 590 ) 591 592 assertThat(fakeWakeLock.isHeld).isFalse() 593 } 594 595 @Test commandQueueCallback_invalidStateParam_noChipShownnull596 fun commandQueueCallback_invalidStateParam_noChipShown() { 597 commandQueueCallback.updateMediaTapToTransferSenderDisplay(100, routeInfo, null) 598 599 verify(windowManager, never()).addView(any(), any()) 600 } 601 602 @Test commandQueueCallback_receiverTriggeredThenAlmostStart_invalidTransitionLoggednull603 fun commandQueueCallback_receiverTriggeredThenAlmostStart_invalidTransitionLogged() { 604 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 605 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED, 606 routeInfo, 607 null, 608 ) 609 verify(windowManager).addView(any(), any()) 610 reset(windowManager) 611 612 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 613 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, 614 routeInfo, 615 null, 616 ) 617 618 verify(logger).logInvalidStateTransitionError(any(), any()) 619 verify(windowManager, never()).addView(any(), any()) 620 } 621 622 @Test commandQueueCallback_thisDeviceTriggeredThenAlmostEnd_invalidTransitionLoggednull623 fun commandQueueCallback_thisDeviceTriggeredThenAlmostEnd_invalidTransitionLogged() { 624 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 625 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED, 626 routeInfo, 627 null, 628 ) 629 verify(windowManager).addView(any(), any()) 630 reset(windowManager) 631 632 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 633 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST, 634 routeInfo, 635 null, 636 ) 637 638 verify(logger).logInvalidStateTransitionError(any(), any()) 639 verify(windowManager, never()).addView(any(), any()) 640 } 641 642 @Test commandQueueCallback_receiverSucceededThenThisDeviceSucceeded_invalidTransitionLoggednull643 fun commandQueueCallback_receiverSucceededThenThisDeviceSucceeded_invalidTransitionLogged() { 644 displayReceiverTriggered() 645 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 646 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, 647 routeInfo, 648 null, 649 ) 650 reset(windowManager) 651 652 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 653 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, 654 routeInfo, 655 null, 656 ) 657 658 verify(logger).logInvalidStateTransitionError(any(), any()) 659 verify(windowManager, never()).addView(any(), any()) 660 } 661 662 @Test commandQueueCallback_thisDeviceSucceededThenReceiverSucceeded_invalidTransitionLoggednull663 fun commandQueueCallback_thisDeviceSucceededThenReceiverSucceeded_invalidTransitionLogged() { 664 displayThisDeviceTriggered() 665 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 666 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, 667 routeInfo, 668 null, 669 ) 670 reset(windowManager) 671 672 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 673 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, 674 routeInfo, 675 null, 676 ) 677 678 verify(logger).logInvalidStateTransitionError(any(), any()) 679 verify(windowManager, never()).addView(any(), any()) 680 } 681 682 @Test commandQueueCallback_almostStartThenReceiverSucceeded_invalidTransitionLoggednull683 fun commandQueueCallback_almostStartThenReceiverSucceeded_invalidTransitionLogged() { 684 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 685 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, 686 routeInfo, 687 null, 688 ) 689 verify(windowManager).addView(any(), any()) 690 reset(windowManager) 691 692 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 693 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, 694 routeInfo, 695 null, 696 ) 697 698 verify(logger).logInvalidStateTransitionError(any(), any()) 699 verify(windowManager, never()).addView(any(), any()) 700 } 701 702 @Test commandQueueCallback_almostEndThenThisDeviceSucceeded_invalidTransitionLoggednull703 fun commandQueueCallback_almostEndThenThisDeviceSucceeded_invalidTransitionLogged() { 704 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 705 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST, 706 routeInfo, 707 null, 708 ) 709 verify(windowManager).addView(any(), any()) 710 reset(windowManager) 711 712 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 713 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, 714 routeInfo, 715 null, 716 ) 717 718 verify(logger).logInvalidStateTransitionError(any(), any()) 719 verify(windowManager, never()).addView(any(), any()) 720 } 721 722 @Test commandQueueCallback_AlmostStartThenReceiverFailed_invalidTransitionLoggednull723 fun commandQueueCallback_AlmostStartThenReceiverFailed_invalidTransitionLogged() { 724 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 725 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, 726 routeInfo, 727 null, 728 ) 729 verify(windowManager).addView(any(), any()) 730 reset(windowManager) 731 732 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 733 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED, 734 routeInfo, 735 null, 736 ) 737 738 verify(logger).logInvalidStateTransitionError(any(), any()) 739 verify(windowManager, never()).addView(any(), any()) 740 } 741 742 @Test commandQueueCallback_almostEndThenThisDeviceFailed_invalidTransitionLoggednull743 fun commandQueueCallback_almostEndThenThisDeviceFailed_invalidTransitionLogged() { 744 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 745 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST, 746 routeInfo, 747 null, 748 ) 749 verify(windowManager).addView(any(), any()) 750 reset(windowManager) 751 752 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 753 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED, 754 routeInfo, 755 null, 756 ) 757 758 verify(logger).logInvalidStateTransitionError(any(), any()) 759 verify(windowManager, never()).addView(any(), any()) 760 } 761 762 /** Regression test for b/266217596. */ 763 @Test toReceiver_triggeredThenFar_thenSucceeded_updatesToSucceedednull764 fun toReceiver_triggeredThenFar_thenSucceeded_updatesToSucceeded() { 765 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 766 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED, 767 routeInfo, 768 null, 769 ) 770 771 // WHEN a FAR command comes in 772 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 773 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, 774 routeInfo, 775 null, 776 ) 777 778 // THEN it is ignored and the chipbar is stilled displayed 779 val chipbarView = getChipbarView() 780 assertThat(chipbarView.getChipText()) 781 .isEqualTo(ChipStateSender.TRANSFER_TO_RECEIVER_TRIGGERED.getExpectedStateText()) 782 assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.VISIBLE) 783 verify(windowManager, never()).removeView(any()) 784 785 // WHEN a SUCCEEDED command comes in 786 val succeededRouteInfo = 787 MediaRoute2Info.Builder(DEFAULT_ID, "Tablet Succeeded") 788 .addFeature("feature") 789 .setClientPackageName(PACKAGE_NAME) 790 .build() 791 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 792 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, 793 succeededRouteInfo, 794 /* undoCallback= */ object : IUndoMediaTransferCallback.Stub() { 795 override fun onUndoTriggered() {} 796 }, 797 ) 798 799 // THEN it is *not* marked as an invalid transition and the chipbar updates to the succeeded 800 // state. (The "invalid transition" would be FAR => SUCCEEDED.) 801 assertThat(chipbarView.getChipText()) 802 .isEqualTo( 803 ChipStateSender.TRANSFER_TO_RECEIVER_SUCCEEDED.getExpectedStateText( 804 "Tablet Succeeded" 805 ) 806 ) 807 assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.GONE) 808 assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.VISIBLE) 809 } 810 811 /** Regression test for b/266217596. */ 812 @Test toThisDevice_triggeredThenFar_thenSucceeded_updatesToSucceedednull813 fun toThisDevice_triggeredThenFar_thenSucceeded_updatesToSucceeded() { 814 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 815 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED, 816 routeInfo, 817 null, 818 ) 819 820 // WHEN a FAR command comes in 821 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 822 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, 823 routeInfo, 824 null, 825 ) 826 827 // THEN it is ignored and the chipbar is stilled displayed 828 val chipbarView = getChipbarView() 829 assertThat(chipbarView.getChipText()) 830 .isEqualTo(ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED.getExpectedStateText()) 831 assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.VISIBLE) 832 verify(windowManager, never()).removeView(any()) 833 834 // WHEN a SUCCEEDED command comes in 835 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 836 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, 837 routeInfo, 838 /* undoCallback= */ object : IUndoMediaTransferCallback.Stub() { 839 override fun onUndoTriggered() {} 840 }, 841 ) 842 843 // THEN it is *not* marked as an invalid transition and the chipbar updates to the succeeded 844 // state. (The "invalid transition" would be FAR => SUCCEEDED.) 845 assertThat(chipbarView.getChipText()) 846 .isEqualTo( 847 ChipStateSender.TRANSFER_TO_THIS_DEVICE_SUCCEEDED.getExpectedStateText( 848 "Tablet Succeeded" 849 ) 850 ) 851 assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.GONE) 852 assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.VISIBLE) 853 } 854 855 @Test receivesNewStateFromCommandQueue_isLoggednull856 fun receivesNewStateFromCommandQueue_isLogged() { 857 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 858 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, 859 routeInfo, 860 null, 861 ) 862 863 verify(logger).logStateChange(any(), any(), any()) 864 } 865 866 @Test transferToReceiverTriggeredThenFarFromReceiver_viewStillDisplayedButStillTimesOutnull867 fun transferToReceiverTriggeredThenFarFromReceiver_viewStillDisplayedButStillTimesOut() { 868 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 869 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED, 870 routeInfo, 871 null, 872 ) 873 874 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 875 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, 876 routeInfo, 877 null, 878 ) 879 fakeExecutor.runAllReady() 880 881 verify(windowManager, never()).removeView(any()) 882 verify(logger).logRemovalBypass(any(), any()) 883 884 fakeClock.advanceTime(TIMEOUT + 1L) 885 886 verify(windowManager).removeView(any()) 887 } 888 889 @Test transferToThisDeviceTriggeredThenFarFromReceiver_viewStillDisplayedButDoesTimeOutnull890 fun transferToThisDeviceTriggeredThenFarFromReceiver_viewStillDisplayedButDoesTimeOut() { 891 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 892 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED, 893 routeInfo, 894 null, 895 ) 896 897 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 898 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, 899 routeInfo, 900 null, 901 ) 902 fakeExecutor.runAllReady() 903 904 verify(windowManager, never()).removeView(any()) 905 verify(logger).logRemovalBypass(any(), any()) 906 907 fakeClock.advanceTime(TIMEOUT + 1L) 908 909 verify(windowManager).removeView(any()) 910 } 911 912 @Test transferToReceiverSucceededThenFarFromReceiver_viewStillDisplayedButDoesTimeOutnull913 fun transferToReceiverSucceededThenFarFromReceiver_viewStillDisplayedButDoesTimeOut() { 914 displayReceiverTriggered() 915 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 916 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, 917 routeInfo, 918 null, 919 ) 920 921 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 922 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, 923 routeInfo, 924 null, 925 ) 926 fakeExecutor.runAllReady() 927 928 verify(windowManager, never()).removeView(any()) 929 verify(logger).logRemovalBypass(any(), any()) 930 931 fakeClock.advanceTime(TIMEOUT + 1L) 932 933 verify(windowManager).removeView(any()) 934 } 935 936 @Test transferToThisDeviceSucceededThenFarFromReceiver_viewStillDisplayedButDoesTimeOutnull937 fun transferToThisDeviceSucceededThenFarFromReceiver_viewStillDisplayedButDoesTimeOut() { 938 displayThisDeviceTriggered() 939 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 940 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, 941 routeInfo, 942 null, 943 ) 944 945 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 946 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, 947 routeInfo, 948 null, 949 ) 950 fakeExecutor.runAllReady() 951 952 verify(windowManager, never()).removeView(any()) 953 verify(logger).logRemovalBypass(any(), any()) 954 955 fakeClock.advanceTime(TIMEOUT + 1L) 956 957 verify(windowManager).removeView(any()) 958 } 959 960 @Test transferToReceiverSucceeded_thenUndo_thenFar_viewStillDisplayedButDoesTimeOutnull961 fun transferToReceiverSucceeded_thenUndo_thenFar_viewStillDisplayedButDoesTimeOut() { 962 displayReceiverTriggered() 963 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 964 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, 965 routeInfo, 966 object : IUndoMediaTransferCallback.Stub() { 967 override fun onUndoTriggered() {} 968 }, 969 ) 970 val chipbarView = getChipbarView() 971 assertThat(chipbarView.getChipText()) 972 .isEqualTo(ChipStateSender.TRANSFER_TO_RECEIVER_SUCCEEDED.getExpectedStateText()) 973 974 // Because [MediaTttSenderCoordinator] internally creates the undo callback, we should 975 // verify that the new state it triggers operates just like any other state. 976 getChipbarView().getUndoButton().performClick() 977 fakeExecutor.runAllReady() 978 979 // Verify that the click updated us to the triggered state 980 assertThat(chipbarView.getChipText()) 981 .isEqualTo(ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED.getExpectedStateText()) 982 983 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 984 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, 985 routeInfo, 986 null, 987 ) 988 fakeExecutor.runAllReady() 989 990 // Verify that we didn't remove the chipbar because it's in the triggered state 991 verify(windowManager, never()).removeView(any()) 992 verify(logger).logRemovalBypass(any(), any()) 993 994 fakeClock.advanceTime(TIMEOUT + 1L) 995 996 // Verify we eventually remove the chipbar 997 verify(windowManager).removeView(any()) 998 } 999 1000 @Test transferToThisDeviceSucceeded_thenUndo_thenFar_viewStillDisplayedButDoesTimeOutnull1001 fun transferToThisDeviceSucceeded_thenUndo_thenFar_viewStillDisplayedButDoesTimeOut() { 1002 displayThisDeviceTriggered() 1003 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1004 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, 1005 routeInfo, 1006 object : IUndoMediaTransferCallback.Stub() { 1007 override fun onUndoTriggered() {} 1008 }, 1009 ) 1010 val chipbarView = getChipbarView() 1011 assertThat(chipbarView.getChipText()) 1012 .isEqualTo(ChipStateSender.TRANSFER_TO_THIS_DEVICE_SUCCEEDED.getExpectedStateText()) 1013 1014 // Because [MediaTttSenderCoordinator] internally creates the undo callback, we should 1015 // verify that the new state it triggers operates just like any other state. 1016 getChipbarView().getUndoButton().performClick() 1017 fakeExecutor.runAllReady() 1018 1019 // Verify that the click updated us to the triggered state 1020 assertThat(chipbarView.getChipText()) 1021 .isEqualTo(ChipStateSender.TRANSFER_TO_RECEIVER_TRIGGERED.getExpectedStateText()) 1022 1023 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1024 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, 1025 routeInfo, 1026 null, 1027 ) 1028 fakeExecutor.runAllReady() 1029 1030 // Verify that we didn't remove the chipbar because it's in the triggered state 1031 verify(windowManager, never()).removeView(any()) 1032 verify(logger).logRemovalBypass(any(), any()) 1033 1034 fakeClock.advanceTime(TIMEOUT + 1L) 1035 1036 // Verify we eventually remove the chipbar 1037 verify(windowManager).removeView(any()) 1038 } 1039 1040 @Test newState_viewListenerRegisterednull1041 fun newState_viewListenerRegistered() { 1042 val mockChipbarCoordinator = mock<ChipbarCoordinator>() 1043 whenever(mockChipbarCoordinator.tempViewUiEventLogger).thenReturn(tempViewUiEventLogger) 1044 underTest = 1045 MediaTttSenderCoordinator( 1046 mockChipbarCoordinator, 1047 commandQueue, 1048 context, 1049 dumpManager, 1050 logger, 1051 uiEventLogger, 1052 ) 1053 underTest.start() 1054 // Re-set the command queue callback since we've created a new [MediaTttSenderCoordinator] 1055 // with a new callback. 1056 setCommandQueueCallback() 1057 1058 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1059 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST, 1060 routeInfo, 1061 null, 1062 ) 1063 1064 verify(mockChipbarCoordinator).registerListener(any()) 1065 } 1066 1067 @Test onInfoPermanentlyRemoved_viewListenerUnregisterednull1068 fun onInfoPermanentlyRemoved_viewListenerUnregistered() { 1069 val mockChipbarCoordinator = mock<ChipbarCoordinator>() 1070 whenever(mockChipbarCoordinator.tempViewUiEventLogger).thenReturn(tempViewUiEventLogger) 1071 underTest = 1072 MediaTttSenderCoordinator( 1073 mockChipbarCoordinator, 1074 commandQueue, 1075 context, 1076 dumpManager, 1077 logger, 1078 uiEventLogger, 1079 ) 1080 underTest.start() 1081 setCommandQueueCallback() 1082 1083 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1084 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST, 1085 routeInfo, 1086 null, 1087 ) 1088 1089 val listenerCaptor = argumentCaptor<TemporaryViewDisplayController.Listener>() 1090 verify(mockChipbarCoordinator).registerListener(capture(listenerCaptor)) 1091 1092 // WHEN the listener is notified that the view has been removed 1093 listenerCaptor.value.onInfoPermanentlyRemoved(DEFAULT_ID, "reason") 1094 1095 // THEN the media coordinator unregisters the listener 1096 verify(logger).logStateMapRemoval(DEFAULT_ID, "reason") 1097 verify(mockChipbarCoordinator).unregisterListener(listenerCaptor.value) 1098 } 1099 1100 @Test onInfoPermanentlyRemoved_wrongId_viewListenerNotUnregisterednull1101 fun onInfoPermanentlyRemoved_wrongId_viewListenerNotUnregistered() { 1102 val mockChipbarCoordinator = mock<ChipbarCoordinator>() 1103 whenever(mockChipbarCoordinator.tempViewUiEventLogger).thenReturn(tempViewUiEventLogger) 1104 underTest = 1105 MediaTttSenderCoordinator( 1106 mockChipbarCoordinator, 1107 commandQueue, 1108 context, 1109 dumpManager, 1110 logger, 1111 uiEventLogger, 1112 ) 1113 underTest.start() 1114 setCommandQueueCallback() 1115 1116 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1117 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST, 1118 routeInfo, 1119 null, 1120 ) 1121 1122 val listenerCaptor = argumentCaptor<TemporaryViewDisplayController.Listener>() 1123 verify(mockChipbarCoordinator).registerListener(capture(listenerCaptor)) 1124 1125 // WHEN the listener is notified that a different view has been removed 1126 listenerCaptor.value.onInfoPermanentlyRemoved("differentViewId", "reason") 1127 1128 // THEN the media coordinator doesn't unregister the listener 1129 verify(mockChipbarCoordinator, never()).unregisterListener(listenerCaptor.value) 1130 } 1131 1132 @Test farFromReceiverState_viewListenerUnregisterednull1133 fun farFromReceiverState_viewListenerUnregistered() { 1134 val mockChipbarCoordinator = mock<ChipbarCoordinator>() 1135 whenever(mockChipbarCoordinator.tempViewUiEventLogger).thenReturn(tempViewUiEventLogger) 1136 underTest = 1137 MediaTttSenderCoordinator( 1138 mockChipbarCoordinator, 1139 commandQueue, 1140 context, 1141 dumpManager, 1142 logger, 1143 uiEventLogger, 1144 ) 1145 underTest.start() 1146 setCommandQueueCallback() 1147 1148 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1149 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST, 1150 routeInfo, 1151 null, 1152 ) 1153 1154 val listenerCaptor = argumentCaptor<TemporaryViewDisplayController.Listener>() 1155 verify(mockChipbarCoordinator).registerListener(capture(listenerCaptor)) 1156 1157 // WHEN we go to the FAR_FROM_RECEIVER state 1158 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1159 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, 1160 routeInfo, 1161 null, 1162 ) 1163 1164 // THEN the media coordinator unregisters the listener 1165 verify(mockChipbarCoordinator).unregisterListener(listenerCaptor.value) 1166 } 1167 1168 @Test statesWithDifferentIds_onInfoPermanentlyRemovedForOneId_viewListenerNotUnregisterednull1169 fun statesWithDifferentIds_onInfoPermanentlyRemovedForOneId_viewListenerNotUnregistered() { 1170 val mockChipbarCoordinator = mock<ChipbarCoordinator>() 1171 whenever(mockChipbarCoordinator.tempViewUiEventLogger).thenReturn(tempViewUiEventLogger) 1172 underTest = 1173 MediaTttSenderCoordinator( 1174 mockChipbarCoordinator, 1175 commandQueue, 1176 context, 1177 dumpManager, 1178 logger, 1179 uiEventLogger, 1180 ) 1181 underTest.start() 1182 setCommandQueueCallback() 1183 1184 // WHEN there are two different media transfers with different IDs 1185 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1186 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST, 1187 MediaRoute2Info.Builder("route1", OTHER_DEVICE_NAME) 1188 .addFeature("feature") 1189 .setClientPackageName(PACKAGE_NAME) 1190 .build(), 1191 null, 1192 ) 1193 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1194 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST, 1195 MediaRoute2Info.Builder("route2", OTHER_DEVICE_NAME) 1196 .addFeature("feature") 1197 .setClientPackageName(PACKAGE_NAME) 1198 .build(), 1199 null, 1200 ) 1201 1202 val listenerCaptor = argumentCaptor<TemporaryViewDisplayController.Listener>() 1203 verify(mockChipbarCoordinator, atLeast(1)).registerListener(capture(listenerCaptor)) 1204 1205 // THEN one of them is removed 1206 listenerCaptor.value.onInfoPermanentlyRemoved("route1", "reason") 1207 1208 // THEN the media coordinator doesn't unregister the listener (since route2 is still active) 1209 verify(mockChipbarCoordinator, never()).unregisterListener(listenerCaptor.value) 1210 verify(logger).logStateMapRemoval("route1", "reason") 1211 } 1212 1213 /** Regression test for b/266218672. */ 1214 @Test twoIdsDisplayed_oldIdIsFar_viewStillDisplayednull1215 fun twoIdsDisplayed_oldIdIsFar_viewStillDisplayed() { 1216 // WHEN there are two different media transfers with different IDs 1217 val route1 = 1218 MediaRoute2Info.Builder("route1", OTHER_DEVICE_NAME) 1219 .addFeature("feature") 1220 .setClientPackageName(PACKAGE_NAME) 1221 .build() 1222 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1223 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST, 1224 route1, 1225 null, 1226 ) 1227 verify(windowManager).addView(any(), any()) 1228 reset(windowManager) 1229 1230 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1231 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, 1232 MediaRoute2Info.Builder("route2", "Route 2 name") 1233 .addFeature("feature") 1234 .setClientPackageName(PACKAGE_NAME) 1235 .build(), 1236 null, 1237 ) 1238 val newView = getChipbarView() 1239 1240 // WHEN there's a FAR event for the earlier one 1241 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1242 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER, 1243 route1, 1244 null, 1245 ) 1246 1247 // THEN it's ignored and the more recent one is still displayed 1248 assertThat(newView.getChipText()) 1249 .isEqualTo( 1250 ChipStateSender.ALMOST_CLOSE_TO_START_CAST.getExpectedStateText("Route 2 name") 1251 ) 1252 } 1253 1254 /** Regression test for b/266218672. */ 1255 @Test receiverSucceededThenTimedOut_internalStateResetAndCanDisplayAlmostCloseToEndnull1256 fun receiverSucceededThenTimedOut_internalStateResetAndCanDisplayAlmostCloseToEnd() { 1257 displayReceiverTriggered() 1258 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1259 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, 1260 routeInfo, 1261 null, 1262 ) 1263 1264 fakeClock.advanceTime(TIMEOUT + 1L) 1265 verify(windowManager).removeView(any()) 1266 1267 reset(windowManager) 1268 1269 // WHEN we try to show ALMOST_CLOSE_TO_END 1270 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1271 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST, 1272 routeInfo, 1273 null, 1274 ) 1275 1276 // THEN it succeeds 1277 val chipbarView = getChipbarView() 1278 assertThat(chipbarView.getChipText()) 1279 .isEqualTo(ChipStateSender.ALMOST_CLOSE_TO_END_CAST.getExpectedStateText()) 1280 } 1281 1282 /** Regression test for b/266218672. */ 1283 @Test receiverSucceededThenTimedOut_internalStateResetAndCanDisplayReceiverTriggerednull1284 fun receiverSucceededThenTimedOut_internalStateResetAndCanDisplayReceiverTriggered() { 1285 displayReceiverTriggered() 1286 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1287 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, 1288 routeInfo, 1289 null, 1290 ) 1291 1292 fakeClock.advanceTime(TIMEOUT + 1L) 1293 verify(windowManager).removeView(any()) 1294 1295 reset(windowManager) 1296 1297 // WHEN we try to show RECEIVER_TRIGGERED 1298 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1299 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED, 1300 routeInfo, 1301 null, 1302 ) 1303 1304 // THEN it succeeds 1305 val chipbarView = getChipbarView() 1306 assertThat(chipbarView.getChipText()) 1307 .isEqualTo(ChipStateSender.TRANSFER_TO_RECEIVER_TRIGGERED.getExpectedStateText()) 1308 assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.VISIBLE) 1309 } 1310 1311 /** Regression test for b/266218672. */ 1312 @Test toThisDeviceSucceededThenTimedOut_internalStateResetAndCanDisplayAlmostCloseToStartnull1313 fun toThisDeviceSucceededThenTimedOut_internalStateResetAndCanDisplayAlmostCloseToStart() { 1314 displayThisDeviceTriggered() 1315 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1316 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, 1317 routeInfo, 1318 null, 1319 ) 1320 1321 fakeClock.advanceTime(TIMEOUT + 1L) 1322 verify(windowManager).removeView(any()) 1323 1324 reset(windowManager) 1325 1326 // WHEN we try to show ALMOST_CLOSE_TO_START 1327 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1328 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, 1329 routeInfo, 1330 null, 1331 ) 1332 1333 // THEN it succeeds 1334 val chipbarView = getChipbarView() 1335 assertThat(chipbarView.getChipText()) 1336 .isEqualTo(ChipStateSender.ALMOST_CLOSE_TO_START_CAST.getExpectedStateText()) 1337 } 1338 1339 /** Regression test for b/266218672. */ 1340 @Test toThisDeviceSucceededThenTimedOut_internalStateResetAndCanDisplayThisDeviceTriggerednull1341 fun toThisDeviceSucceededThenTimedOut_internalStateResetAndCanDisplayThisDeviceTriggered() { 1342 displayThisDeviceTriggered() 1343 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1344 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED, 1345 routeInfo, 1346 null, 1347 ) 1348 1349 fakeClock.advanceTime(TIMEOUT + 1L) 1350 verify(windowManager).removeView(any()) 1351 1352 reset(windowManager) 1353 1354 // WHEN we try to show THIS_DEVICE_TRIGGERED 1355 val newRouteInfo = 1356 MediaRoute2Info.Builder(DEFAULT_ID, "New Name") 1357 .addFeature("feature") 1358 .setClientPackageName(PACKAGE_NAME) 1359 .build() 1360 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1361 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED, 1362 newRouteInfo, 1363 null, 1364 ) 1365 1366 // THEN it succeeds 1367 val chipbarView = getChipbarView() 1368 assertThat(chipbarView.getChipText()) 1369 .isEqualTo( 1370 ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED.getExpectedStateText("New Name") 1371 ) 1372 assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.VISIBLE) 1373 } 1374 1375 @Test almostClose_hasLongTimeout_eventuallyTimesOutnull1376 fun almostClose_hasLongTimeout_eventuallyTimesOut() { 1377 whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenAnswer { 1378 it.arguments[0] 1379 } 1380 1381 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1382 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST, 1383 routeInfo, 1384 null, 1385 ) 1386 1387 // WHEN the default timeout has passed 1388 fakeClock.advanceTime(defaultTimeout + 1L) 1389 1390 // THEN the view is still on-screen because it has a long timeout 1391 verify(windowManager, never()).removeView(any()) 1392 1393 // WHEN a very long amount of time has passed 1394 fakeClock.advanceTime(5L * defaultTimeout) 1395 1396 // THEN the view does time out 1397 verify(windowManager).removeView(any()) 1398 } 1399 1400 @Test loading_hasLongTimeout_eventuallyTimesOutnull1401 fun loading_hasLongTimeout_eventuallyTimesOut() { 1402 whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenAnswer { 1403 it.arguments[0] 1404 } 1405 1406 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1407 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED, 1408 routeInfo, 1409 null, 1410 ) 1411 1412 // WHEN the default timeout has passed 1413 fakeClock.advanceTime(defaultTimeout + 1L) 1414 1415 // THEN the view is still on-screen because it has a long timeout 1416 verify(windowManager, never()).removeView(any()) 1417 1418 // WHEN a very long amount of time has passed 1419 fakeClock.advanceTime(5L * defaultTimeout) 1420 1421 // THEN the view does time out 1422 verify(windowManager).removeView(any()) 1423 } 1424 1425 @Test succeeded_hasDefaultTimeoutnull1426 fun succeeded_hasDefaultTimeout() { 1427 whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenAnswer { 1428 it.arguments[0] 1429 } 1430 1431 displayReceiverTriggered() 1432 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1433 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED, 1434 routeInfo, 1435 null, 1436 ) 1437 1438 fakeClock.advanceTime(defaultTimeout + 1L) 1439 1440 verify(windowManager).removeView(any()) 1441 } 1442 1443 @Test failed_hasDefaultTimeoutnull1444 fun failed_hasDefaultTimeout() { 1445 whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenAnswer { 1446 it.arguments[0] 1447 } 1448 1449 displayThisDeviceTriggered() 1450 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1451 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED, 1452 routeInfo, 1453 null, 1454 ) 1455 1456 fakeClock.advanceTime(defaultTimeout + 1L) 1457 1458 verify(windowManager).removeView(any()) 1459 } 1460 getChipbarViewnull1461 private fun getChipbarView(): ViewGroup { 1462 val viewCaptor = ArgumentCaptor.forClass(View::class.java) 1463 verify(windowManager).addView(viewCaptor.capture(), any()) 1464 return viewCaptor.value as ViewGroup 1465 } 1466 ViewGroupnull1467 private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.start_icon) 1468 1469 private fun ViewGroup.getChipText(): String = 1470 (this.requireViewById<TextView>(R.id.text)).text as String 1471 1472 private fun ViewGroup.getLoadingIcon(): View = this.requireViewById(R.id.loading) 1473 1474 private fun ViewGroup.getErrorIcon(): View = this.requireViewById(R.id.error) 1475 1476 private fun ViewGroup.getUndoButton(): View = this.requireViewById(R.id.end_button) 1477 1478 private fun ChipStateSender.getExpectedStateText( 1479 otherDeviceName: String = OTHER_DEVICE_NAME 1480 ): String? { 1481 return this.getChipTextString(context, otherDeviceName).loadText(context) 1482 } 1483 1484 // display receiver triggered state helper method to make sure we start from a valid state 1485 // transition (FAR_FROM_RECEIVER -> TRANSFER_TO_RECEIVER_TRIGGERED). displayReceiverTriggerednull1486 private fun displayReceiverTriggered() { 1487 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1488 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED, 1489 routeInfo, 1490 null, 1491 ) 1492 } 1493 1494 // display this device triggered state helper method to make sure we start from a valid state 1495 // transition (FAR_FROM_RECEIVER -> TRANSFER_TO_THIS_DEVICE_TRIGGERED). displayThisDeviceTriggerednull1496 private fun displayThisDeviceTriggered() { 1497 commandQueueCallback.updateMediaTapToTransferSenderDisplay( 1498 StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED, 1499 routeInfo, 1500 null, 1501 ) 1502 } 1503 setCommandQueueCallbacknull1504 private fun setCommandQueueCallback() { 1505 val callbackCaptor = argumentCaptor<CommandQueue.Callbacks>() 1506 verify(commandQueue).addCallback(capture(callbackCaptor)) 1507 commandQueueCallback = callbackCaptor.value 1508 reset(commandQueue) 1509 } 1510 } 1511 1512 private const val DEFAULT_ID = "defaultId" 1513 private const val APP_NAME = "Fake app name" 1514 private const val OTHER_DEVICE_NAME = "My Tablet" 1515 private const val BLANK_DEVICE_NAME = " " 1516 private const val PACKAGE_NAME = "com.android.systemui" 1517 private const val TIMEOUT = 10000 1518 1519 private val routeInfo = 1520 MediaRoute2Info.Builder(DEFAULT_ID, OTHER_DEVICE_NAME) 1521 .addFeature("feature") 1522 .setClientPackageName(PACKAGE_NAME) 1523 .build() 1524 1525 private val routeInfoWithBlankDeviceName = 1526 MediaRoute2Info.Builder(DEFAULT_ID, BLANK_DEVICE_NAME) 1527 .addFeature("feature") 1528 .setClientPackageName(PACKAGE_NAME) 1529 .build() 1530