Add UiEventLogger to TemporaryView

Adds three UiEvents for temporary view and introduce instance id in the
logs to match with the events comming from Media TTT.
Adds instance id in the temporary view info for logging purposes.

Bug: 280338222.
Test: manually tested with adb commands with some logs added to make
sure the same instance id is being logged in both tap-to-transfer and
temporary view UI events.
Test: atest MediaTttChipControllerReceiverTest
Test: atest MediaTttReceiverUiEventLoggerTest
Test: atest MediaTttSenderCoordinatorTest
Test: atest MediaTttSenderLoggerTest
Test: atest MediaTttSenderUiEventLoggerTest
Test: atest TemporaryViewDisplayControllerTest
Test: atest TemporaryViewLoggerTest
Test: atest TemporaryViewUiEventLoggerTest
Test: atest TemporaryViewUiEventLoggerTest

Change-Id: I0e8c8ddb5b366305f51881169361a11b855ef580
This commit is contained in:
Michael Mikhail
2023-05-05 15:27:41 +00:00
parent 453c9a158a
commit b1bcb4166f
20 changed files with 327 additions and 35 deletions

View File

@@ -37,6 +37,7 @@ import android.view.View.ACCESSIBILITY_LIVE_REGION_NONE
import com.android.internal.widget.CachingIconView
import com.android.systemui.R
import com.android.app.animation.Interpolators
import com.android.internal.logging.InstanceId
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.ui.binder.TintedIconViewBinder
import com.android.systemui.dagger.SysUISingleton
@@ -49,6 +50,7 @@ import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
import com.android.systemui.temporarydisplay.TemporaryViewInfo
import com.android.systemui.temporarydisplay.TemporaryViewUiEventLogger
import com.android.systemui.temporarydisplay.ViewPriority
import com.android.systemui.util.animation.AnimationUtil.Companion.frames
import com.android.systemui.util.concurrency.DelayableExecutor
@@ -82,6 +84,7 @@ open class MediaTttChipControllerReceiver @Inject constructor(
wakeLockBuilder: WakeLock.Builder,
systemClock: SystemClock,
private val rippleController: MediaTttReceiverRippleController,
private val temporaryViewUiEventLogger: TemporaryViewUiEventLogger,
) : TemporaryViewDisplayController<ChipReceiverInfo, MediaTttReceiverLogger>(
context,
logger,
@@ -94,6 +97,7 @@ open class MediaTttChipControllerReceiver @Inject constructor(
R.layout.media_ttt_chip_receiver,
wakeLockBuilder,
systemClock,
temporaryViewUiEventLogger,
) {
@SuppressLint("WrongConstant") // We're allowed to use LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
override val windowLayoutParams = commonWindowLayoutParams.apply {
@@ -125,6 +129,11 @@ open class MediaTttChipControllerReceiver @Inject constructor(
}
}
// A map to store instance id per route info id.
private var instanceMap: MutableMap<String, InstanceId> = mutableMapOf()
private val displayListener = Listener { id, _ -> instanceMap.remove(id) }
private fun updateMediaTapToTransferReceiverDisplay(
@StatusBarManager.MediaTransferReceiverState displayState: Int,
routeInfo: MediaRoute2Info,
@@ -139,12 +148,18 @@ open class MediaTttChipControllerReceiver @Inject constructor(
logger.logStateChangeError(displayState)
return
}
uiEventLogger.logReceiverStateChange(chipState)
val instanceId: InstanceId = instanceMap[routeInfo.id]
?: temporaryViewUiEventLogger.getNewInstanceId()
uiEventLogger.logReceiverStateChange(chipState, instanceId)
if (chipState != ChipStateReceiver.CLOSE_TO_SENDER) {
removeView(routeInfo.id, removalReason = chipState.name)
return
}
// Save instance id to use for logging view events.
instanceMap[routeInfo.id] = instanceId
if (appIcon == null) {
displayView(
ChipReceiverInfo(
@@ -152,6 +167,7 @@ open class MediaTttChipControllerReceiver @Inject constructor(
appIconDrawableOverride = null,
appName,
id = routeInfo.id,
instanceId = instanceId,
)
)
return
@@ -166,6 +182,7 @@ open class MediaTttChipControllerReceiver @Inject constructor(
drawable,
appName,
id = routeInfo.id,
instanceId = instanceId,
)
)
},
@@ -180,6 +197,7 @@ open class MediaTttChipControllerReceiver @Inject constructor(
if (mediaTttFlags.isMediaTttEnabled()) {
commandQueue.addCallback(commandQueueCallbacks)
}
registerListener(displayListener)
}
override fun updateView(newInfo: ChipReceiverInfo, currentView: ViewGroup) {
@@ -342,4 +360,5 @@ data class ChipReceiverInfo(
override val wakeReason: String = MediaTttUtils.WAKE_REASON_RECEIVER,
override val id: String,
override val priority: ViewPriority = ViewPriority.NORMAL,
override val instanceId: InstanceId,
) : TemporaryViewInfo()

View File

@@ -16,6 +16,7 @@
package com.android.systemui.media.taptotransfer.receiver
import com.android.internal.logging.InstanceId
import com.android.internal.logging.UiEvent
import com.android.internal.logging.UiEventLogger
import com.android.systemui.dagger.SysUISingleton
@@ -25,8 +26,8 @@ import javax.inject.Inject
@SysUISingleton
class MediaTttReceiverUiEventLogger @Inject constructor(private val logger: UiEventLogger) {
/** Logs that the receiver chip has changed states. */
fun logReceiverStateChange(chipState: ChipStateReceiver) {
logger.log(chipState.uiEvent)
fun logReceiverStateChange(chipState: ChipStateReceiver, instanceId: InstanceId) {
logger.log(chipState.uiEvent, instanceId)
}
}

View File

@@ -20,6 +20,7 @@ import android.app.StatusBarManager
import android.content.Context
import android.media.MediaRoute2Info
import android.view.View
import com.android.internal.logging.InstanceId
import com.android.internal.logging.UiEventLogger
import com.android.internal.statusbar.IUndoMediaTransferCallback
import com.android.systemui.CoreStartable
@@ -59,8 +60,8 @@ constructor(
// Since the media transfer display is similar to a heads-up notification, use the same timeout.
private val defaultTimeout = context.resources.getInteger(R.integer.heads_up_notification_decay)
// A map to store current chip state per id.
private var stateMap: MutableMap<String, ChipStateSender> = mutableMapOf()
// A map to store instance id and current chip state per id.
private var stateMap: MutableMap<String, Pair<InstanceId, ChipStateSender>> = mutableMapOf()
private val commandQueueCallbacks =
object : CommandQueue.Callbacks {
@@ -98,7 +99,10 @@ constructor(
return
}
val currentStateForId: ChipStateSender? = stateMap[routeInfo.id]
val currentStateForId: ChipStateSender? = stateMap[routeInfo.id]?.second
val instanceId: InstanceId =
stateMap[routeInfo.id]?.first
?: chipbarCoordinator.tempViewUiEventLogger.getNewInstanceId()
if (!ChipStateSender.isValidStateTransition(currentStateForId, chipState)) {
// ChipStateSender.FAR_FROM_RECEIVER is the default state when there is no state.
logger.logInvalidStateTransitionError(
@@ -107,7 +111,7 @@ constructor(
)
return
}
uiEventLogger.logSenderStateChange(chipState)
uiEventLogger.logSenderStateChange(chipState, instanceId)
if (chipState == ChipStateSender.FAR_FROM_RECEIVER) {
// Return early if we're not displaying a chip for this ID anyway
@@ -131,7 +135,7 @@ constructor(
removeIdFromStore(routeInfo.id, reason = removalReason)
chipbarCoordinator.removeView(routeInfo.id, removalReason)
} else {
stateMap[routeInfo.id] = chipState
stateMap[routeInfo.id] = Pair(instanceId, chipState)
logger.logStateMap(stateMap)
chipbarCoordinator.registerListener(displayListener)
chipbarCoordinator.displayView(
@@ -141,6 +145,7 @@ constructor(
undoCallback,
context,
logger,
instanceId,
)
)
}
@@ -155,6 +160,7 @@ constructor(
undoCallback: IUndoMediaTransferCallback?,
context: Context,
logger: MediaTttSenderLogger,
instanceId: InstanceId,
): ChipbarInfo {
val packageName = routeInfo.clientPackageName
val otherDeviceName =
@@ -190,6 +196,7 @@ constructor(
chipStateSender.endItem.uiEventOnClick,
chipStateSender.endItem.newState,
routeInfo,
instanceId,
)
} else {
null
@@ -203,6 +210,7 @@ constructor(
timeoutMs = timeout,
id = routeInfo.id,
priority = ViewPriority.NORMAL,
instanceId = instanceId,
)
}
@@ -217,10 +225,11 @@ constructor(
uiEvent: UiEventLogger.UiEventEnum,
@StatusBarManager.MediaTransferSenderState newState: Int,
routeInfo: MediaRoute2Info,
instanceId: InstanceId,
): ChipbarEndItem.Button {
val onClickListener =
View.OnClickListener {
uiEventLogger.logUndoClicked(uiEvent)
uiEventLogger.logUndoClicked(uiEvent, instanceId)
undoCallback.onUndoTriggered()
// The external service should eventually send us a new TransferTriggered state, but

View File

@@ -17,6 +17,7 @@
package com.android.systemui.media.taptotransfer.sender
import android.app.StatusBarManager
import com.android.internal.logging.InstanceId
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogLevel
@@ -86,7 +87,7 @@ constructor(
}
/** Logs the current contents of the state map. */
fun logStateMap(map: Map<String, ChipStateSender>) {
fun logStateMap(map: Map<String, Pair<InstanceId, ChipStateSender>>) {
buffer.log(
TAG,
LogLevel.DEBUG,

View File

@@ -17,6 +17,7 @@
package com.android.systemui.media.taptotransfer.sender
import android.util.Log
import com.android.internal.logging.InstanceId
import com.android.internal.logging.UiEvent
import com.android.internal.logging.UiEventLogger
import com.android.systemui.dagger.SysUISingleton
@@ -26,8 +27,8 @@ import javax.inject.Inject
@SysUISingleton
class MediaTttSenderUiEventLogger @Inject constructor(private val logger: UiEventLogger) {
/** Logs that the sender chip has changed states. */
fun logSenderStateChange(chipState: ChipStateSender) {
logger.log(chipState.uiEvent)
fun logSenderStateChange(chipState: ChipStateSender, instanceId: InstanceId) {
logger.log(chipState.uiEvent, instanceId)
}
/**
@@ -35,10 +36,11 @@ class MediaTttSenderUiEventLogger @Inject constructor(private val logger: UiEven
*
* @param undoUiEvent the uiEvent specific to which undo button was clicked.
*/
fun logUndoClicked(undoUiEvent: UiEventLogger.UiEventEnum) {
fun logUndoClicked(undoUiEvent: UiEventLogger.UiEventEnum, instanceId: InstanceId) {
val isUndoEvent =
undoUiEvent == MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_RECEIVER_CLICKED
|| undoUiEvent ==
undoUiEvent ==
MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_RECEIVER_CLICKED ||
undoUiEvent ==
MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_THIS_DEVICE_CLICKED
if (!isUndoEvent) {
Log.w(
@@ -47,7 +49,7 @@ class MediaTttSenderUiEventLogger @Inject constructor(private val logger: UiEven
)
return
}
logger.log(undoUiEvent)
logger.log(undoUiEvent, instanceId)
}
}

View File

@@ -79,6 +79,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
@LayoutRes private val viewLayoutRes: Int,
private val wakeLockBuilder: WakeLock.Builder,
private val systemClock: SystemClock,
internal val tempViewUiEventLogger: TemporaryViewUiEventLogger,
) : CoreStartable, Dumpable {
/**
* Window layout params that will be used as a starting point for the [windowLayoutParams] of
@@ -207,6 +208,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
private fun showNewView(newDisplayInfo: DisplayInfo, timeout: Int) {
logger.logViewAddition(newDisplayInfo.info)
tempViewUiEventLogger.logViewAdded(newDisplayInfo.info.instanceId)
createAndAcquireWakeLock(newDisplayInfo)
updateTimeout(newDisplayInfo, timeout)
inflateAndUpdateView(newDisplayInfo)

View File

@@ -16,6 +16,8 @@
package com.android.systemui.temporarydisplay
import com.android.internal.logging.InstanceId
/**
* A superclass view state used with [TemporaryViewDisplayController].
*/
@@ -45,6 +47,9 @@ abstract class TemporaryViewInfo {
/** The priority for this view. */
abstract val priority: ViewPriority
/** Instance ID for logging purposes */
abstract val instanceId: InstanceId?
}
const val DEFAULT_TIMEOUT_MILLIS = 10000

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.temporarydisplay
import com.android.internal.logging.InstanceId
import com.android.internal.logging.InstanceIdSequence
import com.android.internal.logging.UiEvent
import com.android.internal.logging.UiEventLogger
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
private const val INSTANCE_ID_MAX = 1 shl 20
/** A helper class to log events related to the temporary view */
@SysUISingleton
class TemporaryViewUiEventLogger @Inject constructor(val logger: UiEventLogger) {
private val instanceIdSequence = InstanceIdSequence(INSTANCE_ID_MAX)
/** Get a new instance ID for a new media control */
fun getNewInstanceId(): InstanceId {
return instanceIdSequence.newInstanceId()
}
/** Logs that view is added */
fun logViewAdded(instanceId: InstanceId?) {
logger.log(TemporaryViewUiEvent.TEMPORARY_VIEW_ADDED, instanceId)
}
/** Logs that view is manually dismissed by user */
fun logViewManuallyDismissed(instanceId: InstanceId?) {
logger.log(TemporaryViewUiEvent.TEMPORARY_VIEW_MANUALLY_DISMISSED, instanceId)
}
}
enum class TemporaryViewUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum {
@UiEvent(doc = "The temporary view was added to window manager") TEMPORARY_VIEW_ADDED(1389),
@UiEvent(doc = "The temporary view was manually dismissed")
TEMPORARY_VIEW_MANUALLY_DISMISSED(1390);
override fun getId() = metricId
}

View File

@@ -52,6 +52,7 @@ import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
import com.android.systemui.temporarydisplay.TemporaryViewUiEventLogger
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.time.SystemClock
import com.android.systemui.util.view.ViewUtil
@@ -92,6 +93,7 @@ constructor(
private val vibratorHelper: VibratorHelper,
wakeLockBuilder: WakeLock.Builder,
systemClock: SystemClock,
tempViewUiEventLogger: TemporaryViewUiEventLogger,
) :
TemporaryViewDisplayController<ChipbarInfo, ChipbarLogger>(
context,
@@ -105,6 +107,7 @@ constructor(
R.layout.chipbar,
wakeLockBuilder,
systemClock,
tempViewUiEventLogger,
) {
private lateinit var parent: ChipbarRootView
@@ -315,6 +318,7 @@ constructor(
)
return
}
tempViewUiEventLogger.logViewManuallyDismissed(currentDisplayInfo.info.instanceId)
removeView(currentDisplayInfo.info.id, SWIPE_UP_GESTURE_REASON)
updateGestureListening()
}

View File

@@ -19,6 +19,7 @@ package com.android.systemui.temporarydisplay.chipbar
import android.os.VibrationEffect
import android.view.View
import androidx.annotation.AttrRes
import com.android.internal.logging.InstanceId
import com.android.systemui.R
import com.android.systemui.common.shared.model.Text
import com.android.systemui.common.shared.model.TintedIcon
@@ -47,6 +48,7 @@ data class ChipbarInfo(
override val timeoutMs: Int,
override val id: String,
override val priority: ViewPriority,
override val instanceId: InstanceId?,
) : TemporaryViewInfo() {
companion object {
// LINT.IfChange

View File

@@ -26,6 +26,7 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.media.taptotransfer.MediaTttFlags
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.temporarydisplay.TemporaryViewUiEventLogger
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.time.SystemClock
import com.android.systemui.util.view.ViewUtil
@@ -48,6 +49,7 @@ class FakeMediaTttChipControllerReceiver(
wakeLockBuilder: WakeLock.Builder,
systemClock: SystemClock,
rippleController: MediaTttReceiverRippleController,
temporaryViewUiEventLogger: TemporaryViewUiEventLogger,
) :
MediaTttChipControllerReceiver(
commandQueue,
@@ -66,6 +68,7 @@ class FakeMediaTttChipControllerReceiver(
wakeLockBuilder,
systemClock,
rippleController,
temporaryViewUiEventLogger,
) {
override fun animateViewOut(view: ViewGroup, removalReason: String?, onAnimationEnd: Runnable) {
// Just bypass the animation in tests

View File

@@ -31,6 +31,7 @@ import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
import android.widget.ImageView
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
@@ -38,6 +39,7 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.media.taptotransfer.MediaTttFlags
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.temporarydisplay.TemporaryViewUiEventLogger
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
@@ -90,6 +92,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
private lateinit var fakeAppIconDrawable: Drawable
private lateinit var uiEventLoggerFake: UiEventLoggerFake
private lateinit var receiverUiEventLogger: MediaTttReceiverUiEventLogger
private lateinit var temporaryViewUiEventLogger: TemporaryViewUiEventLogger
private lateinit var fakeClock: FakeSystemClock
private lateinit var fakeExecutor: FakeExecutor
private lateinit var fakeWakeLockBuilder: WakeLockFake.Builder
@@ -114,6 +117,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
uiEventLoggerFake = UiEventLoggerFake()
receiverUiEventLogger = MediaTttReceiverUiEventLogger(uiEventLoggerFake)
temporaryViewUiEventLogger = TemporaryViewUiEventLogger(uiEventLoggerFake)
fakeWakeLock = WakeLockFake()
fakeWakeLockBuilder = WakeLockFake.Builder(context)
@@ -136,6 +140,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
fakeWakeLockBuilder,
fakeClock,
rippleController,
temporaryViewUiEventLogger,
)
controllerReceiver.start()
@@ -166,6 +171,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
fakeWakeLockBuilder,
fakeClock,
rippleController,
temporaryViewUiEventLogger,
)
controllerReceiver.start()
@@ -186,6 +192,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
MediaTttReceiverUiEvents.MEDIA_TTT_RECEIVER_CLOSE_TO_SENDER.id
)
assertThat(uiEventLoggerFake.logs[0].instanceId).isNotNull()
}
@Test
@@ -201,6 +208,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
MediaTttReceiverUiEvents.MEDIA_TTT_RECEIVER_FAR_FROM_SENDER.id
)
assertThat(uiEventLoggerFake.logs[0].instanceId).isNotNull()
}
@Test
@@ -216,6 +224,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
MediaTttReceiverUiEvents.MEDIA_TTT_RECEIVER_TRANSFER_TO_RECEIVER_SUCCEEDED.id
)
assertThat(uiEventLoggerFake.logs[0].instanceId).isNotNull()
}
@Test
@@ -231,6 +240,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(
MediaTttReceiverUiEvents.MEDIA_TTT_RECEIVER_TRANSFER_TO_RECEIVER_FAILED.id
)
assertThat(uiEventLoggerFake.logs[0].instanceId).isNotNull()
}
@Test
@@ -275,6 +285,25 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
verify(windowManager).removeView(viewCaptor.value)
}
@Test
fun commandQueueCallback_closeThenSucceeded_sameViewInstanceId() {
commandQueueCallback.updateMediaTapToTransferReceiverDisplay(
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER,
routeInfo,
null,
null
)
commandQueueCallback.updateMediaTapToTransferReceiverDisplay(
StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
routeInfo,
null,
null
)
assertThat(uiEventLoggerFake[0].instanceId).isEqualTo(uiEventLoggerFake[1].instanceId)
}
@Test
fun commandQueueCallback_closeThenFailed_chipShownThenHidden() {
commandQueueCallback.updateMediaTapToTransferReceiverDisplay(
@@ -349,6 +378,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
appIconDrawableOverride = null,
appNameOverride = null,
id = "id",
instanceId = InstanceId.fakeInstanceId(0),
)
)
@@ -371,6 +401,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
drawableOverride,
appNameOverride = null,
id = "id",
instanceId = InstanceId.fakeInstanceId(0),
)
)
@@ -388,6 +419,7 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
appIconDrawableOverride = null,
appNameOverride,
id = "id",
instanceId = InstanceId.fakeInstanceId(0),
)
)
@@ -442,7 +474,13 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
.addFeature("feature")
.setClientPackageName(packageName)
.build()
return ChipReceiverInfo(routeInfo, null, null, id = "id")
return ChipReceiverInfo(
routeInfo,
null,
null,
id = "id",
instanceId = InstanceId.fakeInstanceId(0),
)
}
private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)

View File

@@ -1,6 +1,7 @@
package com.android.systemui.media.taptotransfer.receiver
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -21,10 +22,12 @@ class MediaTttReceiverUiEventLoggerTest : SysuiTestCase() {
@Test
fun logReceiverStateChange_eventAssociatedWithStateIsLogged() {
val state = ChipStateReceiver.CLOSE_TO_SENDER
val instanceId = InstanceId.fakeInstanceId(0)
logger.logReceiverStateChange(state)
logger.logReceiverStateChange(state, instanceId)
assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(state.uiEvent.id)
assertThat(uiEventLoggerFake.logs[0].instanceId).isEqualTo(instanceId)
}
}

View File

@@ -46,6 +46,7 @@ import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
import com.android.systemui.temporarydisplay.TemporaryViewUiEventLogger
import com.android.systemui.temporarydisplay.chipbar.ChipbarAnimator
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
import com.android.systemui.temporarydisplay.chipbar.ChipbarLogger
@@ -108,6 +109,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
private lateinit var fakeExecutor: FakeExecutor
private lateinit var uiEventLoggerFake: UiEventLoggerFake
private lateinit var uiEventLogger: MediaTttSenderUiEventLogger
private lateinit var tempViewUiEventLogger: TemporaryViewUiEventLogger
private val defaultTimeout = context.resources.getInteger(R.integer.heads_up_notification_decay)
@Before
@@ -137,6 +139,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
uiEventLoggerFake = UiEventLoggerFake()
uiEventLogger = MediaTttSenderUiEventLogger(uiEventLoggerFake)
tempViewUiEventLogger = TemporaryViewUiEventLogger(uiEventLoggerFake)
chipbarCoordinator =
ChipbarCoordinator(
@@ -156,6 +159,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
vibratorHelper,
fakeWakeLockBuilder,
fakeClock,
tempViewUiEventLogger,
)
chipbarCoordinator.start()
@@ -352,8 +356,8 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
.isEqualTo(ChipStateSender.TRANSFER_TO_RECEIVER_SUCCEEDED.getExpectedStateText())
assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.GONE)
assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.GONE)
// Event index 1 since initially displaying the triggered chip would also log an event.
assertThat(uiEventLoggerFake.eventId(1))
// Event index 2 since initially displaying the triggered chip would also log two events.
assertThat(uiEventLoggerFake.eventId(2))
.isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_SUCCEEDED.id)
verify(vibratorHelper, never())
.vibrate(
@@ -365,6 +369,24 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
)
}
@Test
fun commandQueueCallback_transferToReceiverSucceeded_sameViewInstanceId() {
displayReceiverTriggered()
reset(vibratorHelper)
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
routeInfo,
null
)
// Event index 2 since initially displaying the triggered chip would also log two events.
assertThat(uiEventLoggerFake.eventId(2))
.isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_SUCCEEDED.id)
verify(vibratorHelper, never()).vibrate(any<VibrationEffect>())
assertThat(uiEventLoggerFake.logs[0].instanceId)
.isEqualTo(uiEventLoggerFake.logs[2].instanceId)
}
@Test
fun transferToReceiverSucceeded_nullUndoCallback_noUndo() {
displayReceiverTriggered()
@@ -410,9 +432,9 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
getChipbarView().getUndoButton().performClick()
// Event index 2 since initially displaying the triggered and succeeded chip would also log
// Event index 3 since initially displaying the triggered and succeeded chip would also log
// events.
assertThat(uiEventLoggerFake.eventId(2))
assertThat(uiEventLoggerFake.eventId(3))
.isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_RECEIVER_CLICKED.id)
assertThat(undoCallbackCalled).isTrue()
assertThat(getChipbarView().getChipText())
@@ -436,8 +458,8 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
.isEqualTo(ChipStateSender.TRANSFER_TO_THIS_DEVICE_SUCCEEDED.getExpectedStateText())
assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.GONE)
assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.GONE)
// Event index 1 since initially displaying the triggered chip would also log an event.
assertThat(uiEventLoggerFake.eventId(1))
// Event index 2 since initially displaying the triggered chip would also log two events.
assertThat(uiEventLoggerFake.eventId(2))
.isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_SUCCEEDED.id)
verify(vibratorHelper, never())
.vibrate(
@@ -494,9 +516,9 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
getChipbarView().getUndoButton().performClick()
// Event index 2 since initially displaying the triggered and succeeded chip would also log
// Event index 3 since initially displaying the triggered and succeeded chip would also log
// events.
assertThat(uiEventLoggerFake.eventId(2))
assertThat(uiEventLoggerFake.eventId(3))
.isEqualTo(
MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_THIS_DEVICE_CLICKED.id
)
@@ -523,8 +545,8 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.GONE)
assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.GONE)
assertThat(chipbarView.getErrorIcon().visibility).isEqualTo(View.VISIBLE)
// Event index 1 since initially displaying the triggered chip would also log an event.
assertThat(uiEventLoggerFake.eventId(1))
// Event index 2 since initially displaying the triggered chip would also log two events.
assertThat(uiEventLoggerFake.eventId(2))
.isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_FAILED.id)
verify(vibratorHelper)
.vibrate(
@@ -559,7 +581,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.GONE)
assertThat(chipbarView.getErrorIcon().visibility).isEqualTo(View.VISIBLE)
// Event index 1 since initially displaying the triggered chip would also log an event.
assertThat(uiEventLoggerFake.eventId(1))
assertThat(uiEventLoggerFake.eventId(2))
.isEqualTo(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_THIS_DEVICE_FAILED.id)
verify(vibratorHelper)
.vibrate(
@@ -1082,6 +1104,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
@Test
fun newState_viewListenerRegistered() {
val mockChipbarCoordinator = mock<ChipbarCoordinator>()
whenever(mockChipbarCoordinator.tempViewUiEventLogger).thenReturn(tempViewUiEventLogger)
underTest =
MediaTttSenderCoordinator(
mockChipbarCoordinator,
@@ -1109,6 +1132,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
@Test
fun onInfoPermanentlyRemoved_viewListenerUnregistered() {
val mockChipbarCoordinator = mock<ChipbarCoordinator>()
whenever(mockChipbarCoordinator.tempViewUiEventLogger).thenReturn(tempViewUiEventLogger)
underTest =
MediaTttSenderCoordinator(
mockChipbarCoordinator,
@@ -1142,6 +1166,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
@Test
fun onInfoPermanentlyRemoved_wrongId_viewListenerNotUnregistered() {
val mockChipbarCoordinator = mock<ChipbarCoordinator>()
whenever(mockChipbarCoordinator.tempViewUiEventLogger).thenReturn(tempViewUiEventLogger)
underTest =
MediaTttSenderCoordinator(
mockChipbarCoordinator,
@@ -1174,6 +1199,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
@Test
fun farFromReceiverState_viewListenerUnregistered() {
val mockChipbarCoordinator = mock<ChipbarCoordinator>()
whenever(mockChipbarCoordinator.tempViewUiEventLogger).thenReturn(tempViewUiEventLogger)
underTest =
MediaTttSenderCoordinator(
mockChipbarCoordinator,
@@ -1210,6 +1236,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
@Test
fun statesWithDifferentIds_onInfoPermanentlyRemovedForOneId_viewListenerNotUnregistered() {
val mockChipbarCoordinator = mock<ChipbarCoordinator>()
whenever(mockChipbarCoordinator.tempViewUiEventLogger).thenReturn(tempViewUiEventLogger)
underTest =
MediaTttSenderCoordinator(
mockChipbarCoordinator,

View File

@@ -17,6 +17,7 @@
package com.android.systemui.media.taptotransfer.sender
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.LogBuffer
@@ -91,8 +92,16 @@ class MediaTttSenderLoggerTest : SysuiTestCase() {
fun logStateMap_bufferHasInfo() {
val map =
mapOf(
"123" to ChipStateSender.ALMOST_CLOSE_TO_START_CAST,
"456" to ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED,
"123" to
Pair(
InstanceId.fakeInstanceId(100),
ChipStateSender.ALMOST_CLOSE_TO_START_CAST
),
"456" to
Pair(
InstanceId.fakeInstanceId(200),
ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED
),
)
logger.logStateMap(map)

View File

@@ -1,6 +1,7 @@
package com.android.systemui.media.taptotransfer.sender
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
@@ -21,26 +22,32 @@ class MediaTttSenderUiEventLoggerTest : SysuiTestCase() {
@Test
fun logSenderStateChange_eventAssociatedWithStateIsLogged() {
val state = ChipStateSender.ALMOST_CLOSE_TO_END_CAST
logger.logSenderStateChange(state)
logger.logSenderStateChange(state, instanceId)
assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(state.uiEvent.id)
assertThat(uiEventLoggerFake.get(0).instanceId).isEqualTo(instanceId)
}
@Test
fun logUndoClicked_undoEventLogged() {
val undoEvent = MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_THIS_DEVICE_CLICKED
logger.logUndoClicked(undoEvent)
logger.logUndoClicked(undoEvent, instanceId)
assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
assertThat(uiEventLoggerFake.eventId(0)).isEqualTo(undoEvent.id)
assertThat(uiEventLoggerFake.get(0).instanceId).isEqualTo(instanceId)
}
@Test
fun logUndoClicked_notUndoEvent_eventNotLogged() {
logger.logUndoClicked(MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_FAILED)
val state = MediaTttSenderUiEvents.MEDIA_TTT_SENDER_TRANSFER_TO_RECEIVER_FAILED
logger.logUndoClicked(state, instanceId)
assertThat(uiEventLoggerFake.numLogs()).isEqualTo(0)
}
}
private val instanceId = InstanceId.fakeInstanceId(0)

View File

@@ -24,6 +24,8 @@ import android.view.ViewGroup
import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.dagger.qualifiers.Main
@@ -60,6 +62,9 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
private lateinit var fakeWakeLockBuilder: WakeLockFake.Builder
private lateinit var fakeWakeLock: WakeLockFake
private lateinit var fakeUiEventLogger: UiEventLoggerFake
private lateinit var uiEventLogger: TemporaryViewUiEventLogger
@Mock
private lateinit var logger: TemporaryViewLogger<ViewInfo>
@Mock
@@ -87,6 +92,9 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
fakeWakeLockBuilder = WakeLockFake.Builder(context)
fakeWakeLockBuilder.setWakeLock(fakeWakeLock)
fakeUiEventLogger = UiEventLoggerFake()
uiEventLogger = TemporaryViewUiEventLogger(fakeUiEventLogger)
underTest = TestController(
context,
logger,
@@ -98,6 +106,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
powerManager,
fakeWakeLockBuilder,
fakeClock,
uiEventLogger,
)
underTest.start()
}
@@ -126,6 +135,8 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
underTest.displayView(info)
verify(logger).logViewAddition(info)
assertThat(fakeUiEventLogger.eventId(0))
.isEqualTo(TemporaryViewUiEvent.TEMPORARY_VIEW_ADDED.id)
}
@Test
@@ -1029,6 +1040,9 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
verify(logger).logViewRemoval(DEFAULT_ID, reason)
verify(configurationController).removeCallback(any())
assertThat(listener.permanentlyRemovedIds).containsExactly(DEFAULT_ID)
assertThat(fakeUiEventLogger.logs.size).isEqualTo(1)
assertThat(fakeUiEventLogger.eventId(0))
.isEqualTo(TemporaryViewUiEvent.TEMPORARY_VIEW_ADDED.id)
}
@Test
@@ -1133,6 +1147,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
powerManager: PowerManager,
wakeLockBuilder: WakeLock.Builder,
systemClock: SystemClock,
uiEventLogger: TemporaryViewUiEventLogger,
) : TemporaryViewDisplayController<ViewInfo, TemporaryViewLogger<ViewInfo>>(
context,
logger,
@@ -1145,6 +1160,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
R.layout.chipbar,
wakeLockBuilder,
systemClock,
uiEventLogger,
) {
var mostRecentViewInfo: ViewInfo? = null
@@ -1168,6 +1184,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
override val timeoutMs: Int = TIMEOUT_MS.toInt(),
override val id: String = DEFAULT_ID,
override val priority: ViewPriority = ViewPriority.NORMAL,
override val instanceId: InstanceId = InstanceId.fakeInstanceId(0),
) : TemporaryViewInfo()
inner class Listener : TemporaryViewDisplayController.Listener {

View File

@@ -17,6 +17,7 @@
package com.android.systemui.temporarydisplay
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.log.LogBuffer
@@ -50,6 +51,7 @@ class TemporaryViewLoggerTest : SysuiTestCase() {
override val priority: ViewPriority = ViewPriority.CRITICAL
override val windowTitle: String = "Test Window Title"
override val wakeReason: String = "wake reason"
override val instanceId: InstanceId = InstanceId.fakeInstanceId(0)
}
logger.logViewAddition(info)

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.temporarydisplay
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@SmallTest
class TemporaryViewUiEventLoggerTest : SysuiTestCase() {
private lateinit var uiEventLoggerFake: UiEventLoggerFake
private lateinit var logger: TemporaryViewUiEventLogger
@Before
fun setup() {
uiEventLoggerFake = UiEventLoggerFake()
logger = TemporaryViewUiEventLogger(uiEventLoggerFake)
}
@Test
fun testViewAdded() {
logger.logViewAdded(InstanceId.fakeInstanceId(123))
assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
assertThat(uiEventLoggerFake.eventId(0))
.isEqualTo(TemporaryViewUiEvent.TEMPORARY_VIEW_ADDED.id)
}
@Test
fun testMultipleViewsAdded_differentInstanceIds() {
logger.logViewAdded(logger.getNewInstanceId())
logger.logViewAdded(logger.getNewInstanceId())
assertThat(uiEventLoggerFake.numLogs()).isEqualTo(2)
assertThat(uiEventLoggerFake.eventId(0))
.isEqualTo(TemporaryViewUiEvent.TEMPORARY_VIEW_ADDED.id)
assertThat(uiEventLoggerFake.eventId(1))
.isEqualTo(TemporaryViewUiEvent.TEMPORARY_VIEW_ADDED.id)
assertThat(uiEventLoggerFake.logs[0].instanceId.id)
.isNotEqualTo(uiEventLoggerFake.logs[1].instanceId.id)
}
@Test
fun testViewManuallyDismissed() {
logger.logViewManuallyDismissed(InstanceId.fakeInstanceId(123))
assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
assertThat(uiEventLoggerFake.eventId(0))
.isEqualTo(TemporaryViewUiEvent.TEMPORARY_VIEW_MANUALLY_DISMISSED.id)
}
}

View File

@@ -30,6 +30,7 @@ import android.widget.ImageView
import android.widget.TextView
import androidx.core.animation.doOnCancel
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
@@ -43,6 +44,8 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.temporarydisplay.TemporaryViewUiEvent
import com.android.systemui.temporarydisplay.TemporaryViewUiEventLogger
import com.android.systemui.temporarydisplay.ViewPriority
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
@@ -87,6 +90,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
private lateinit var fakeClock: FakeSystemClock
private lateinit var fakeExecutor: FakeExecutor
private lateinit var uiEventLoggerFake: UiEventLoggerFake
private lateinit var uiEventLogger: TemporaryViewUiEventLogger
@Before
fun setUp() {
@@ -101,6 +105,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
fakeWakeLockBuilder.setWakeLock(fakeWakeLock)
uiEventLoggerFake = UiEventLoggerFake()
uiEventLogger = TemporaryViewUiEventLogger(uiEventLoggerFake)
chipbarAnimator = TestChipbarAnimator()
underTest =
@@ -121,6 +126,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
vibratorHelper,
fakeWakeLockBuilder,
fakeClock,
uiEventLogger,
)
underTest.start()
}
@@ -632,7 +638,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
}
@Test
fun swipeToDismiss_swipeOccurs_viewDismissed() {
fun swipeToDismiss_swipeOccurs_viewDismissed_manuallyDismissedLogged() {
underTest.displayView(
createChipbarInfo(
Icon.Resource(R.drawable.ic_cake, contentDescription = null),
@@ -649,6 +655,9 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
callbackCaptor.value.invoke(MotionEvent.obtain(0L, 0L, 0, 0f, 0f, 0))
verify(windowManager).removeView(view)
assertThat(uiEventLoggerFake.numLogs()).isEqualTo(2)
assertThat(uiEventLoggerFake.eventId(1))
.isEqualTo(TemporaryViewUiEvent.TEMPORARY_VIEW_MANUALLY_DISMISSED.id)
}
@Test
@@ -665,6 +674,11 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
val callbackCaptor = argumentCaptor<(MotionEvent) -> Unit>()
verify(swipeGestureHandler).addOnGestureDetectedCallback(any(), capture(callbackCaptor))
// only one log for view addition
assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
assertThat(uiEventLoggerFake.eventId(0))
.isEqualTo(TemporaryViewUiEvent.TEMPORARY_VIEW_ADDED.id)
// WHEN the view is updated to not allow swipe-to-dismiss
underTest.displayView(
createChipbarInfo(
@@ -683,6 +697,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
// THEN it is ignored and view isn't removed
verify(windowManager, never()).removeView(view)
assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
}
private fun createChipbarInfo(
@@ -703,6 +718,7 @@ class ChipbarCoordinatorTest : SysuiTestCase() {
timeoutMs = TIMEOUT,
id = DEVICE_ID,
priority = ViewPriority.NORMAL,
instanceId = InstanceId.fakeInstanceId(0),
)
}