[Media TTT] Log changes to the sender's current state map.
Also logs the current map when a dump occurs. Fixes: 265455911 Test: Manual: See sample logs in bug Test: atest MediaTttSenderCoordinatorTest MediaTttSenderLoggerTest Change-Id: I9487cfdc3bf90c4109b838f141f20121b18f1674
This commit is contained in:
@@ -23,9 +23,11 @@ import android.view.View
|
||||
import com.android.internal.logging.UiEventLogger
|
||||
import com.android.internal.statusbar.IUndoMediaTransferCallback
|
||||
import com.android.systemui.CoreStartable
|
||||
import com.android.systemui.Dumpable
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.common.shared.model.Text
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.media.taptotransfer.MediaTttFlags
|
||||
import com.android.systemui.media.taptotransfer.common.MediaTttUtils
|
||||
import com.android.systemui.statusbar.CommandQueue
|
||||
@@ -34,6 +36,7 @@ import com.android.systemui.temporarydisplay.ViewPriority
|
||||
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
|
||||
import com.android.systemui.temporarydisplay.chipbar.ChipbarEndItem
|
||||
import com.android.systemui.temporarydisplay.chipbar.ChipbarInfo
|
||||
import java.io.PrintWriter
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
@@ -47,14 +50,14 @@ constructor(
|
||||
private val chipbarCoordinator: ChipbarCoordinator,
|
||||
private val commandQueue: CommandQueue,
|
||||
private val context: Context,
|
||||
private val dumpManager: DumpManager,
|
||||
private val logger: MediaTttSenderLogger,
|
||||
private val mediaTttFlags: MediaTttFlags,
|
||||
private val uiEventLogger: MediaTttSenderUiEventLogger,
|
||||
) : CoreStartable {
|
||||
) : CoreStartable, Dumpable {
|
||||
|
||||
private var displayedState: ChipStateSender? = null
|
||||
// A map to store current chip state per id.
|
||||
// TODO(b/265455911): Log whenever we add or remove from the store.
|
||||
private var stateMap: MutableMap<String, ChipStateSender> = mutableMapOf()
|
||||
|
||||
private val commandQueueCallbacks =
|
||||
@@ -75,6 +78,7 @@ constructor(
|
||||
override fun start() {
|
||||
if (mediaTttFlags.isMediaTttEnabled()) {
|
||||
commandQueue.addCallback(commandQueueCallbacks)
|
||||
dumpManager.registerNormalDumpable(this)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,12 +108,13 @@ constructor(
|
||||
uiEventLogger.logSenderStateChange(chipState)
|
||||
|
||||
if (chipState == ChipStateSender.FAR_FROM_RECEIVER) {
|
||||
val removalReason = ChipStateSender.FAR_FROM_RECEIVER.name
|
||||
|
||||
// No need to store the state since it is the default state
|
||||
removeIdFromStore(routeInfo.id)
|
||||
removeIdFromStore(routeInfo.id, reason = removalReason)
|
||||
// Return early if we're not displaying a chip anyway
|
||||
val currentDisplayedState = displayedState ?: return
|
||||
|
||||
val removalReason = ChipStateSender.FAR_FROM_RECEIVER.name
|
||||
if (
|
||||
currentDisplayedState.transferStatus == TransferStatus.IN_PROGRESS ||
|
||||
currentDisplayedState.transferStatus == TransferStatus.SUCCEEDED
|
||||
@@ -127,6 +132,7 @@ constructor(
|
||||
chipbarCoordinator.removeView(routeInfo.id, removalReason)
|
||||
} else {
|
||||
stateMap[routeInfo.id] = chipState
|
||||
logger.logStateMap(stateMap)
|
||||
displayedState = chipState
|
||||
chipbarCoordinator.registerListener(displayListener)
|
||||
chipbarCoordinator.displayView(
|
||||
@@ -232,12 +238,19 @@ constructor(
|
||||
}
|
||||
|
||||
private val displayListener =
|
||||
TemporaryViewDisplayController.Listener { id -> removeIdFromStore(id) }
|
||||
TemporaryViewDisplayController.Listener { id, reason -> removeIdFromStore(id, reason) }
|
||||
|
||||
private fun removeIdFromStore(id: String) {
|
||||
private fun removeIdFromStore(id: String, reason: String) {
|
||||
logger.logStateMapRemoval(id, reason)
|
||||
stateMap.remove(id)
|
||||
logger.logStateMap(stateMap)
|
||||
if (stateMap.isEmpty()) {
|
||||
chipbarCoordinator.unregisterListener(displayListener)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dump(pw: PrintWriter, args: Array<out String>) {
|
||||
pw.println("Current sender states:")
|
||||
pw.println(stateMap.toString())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,29 @@ constructor(
|
||||
)
|
||||
}
|
||||
|
||||
/** Logs the current contents of the state map. */
|
||||
fun logStateMap(map: Map<String, ChipStateSender>) {
|
||||
buffer.log(
|
||||
TAG,
|
||||
LogLevel.DEBUG,
|
||||
{ str1 = map.toString() },
|
||||
{ "Current sender states: $str1" }
|
||||
)
|
||||
}
|
||||
|
||||
/** Logs that [id] has been removed from the state map due to [reason]. */
|
||||
fun logStateMapRemoval(id: String, reason: String) {
|
||||
buffer.log(
|
||||
TAG,
|
||||
LogLevel.DEBUG,
|
||||
{
|
||||
str1 = id
|
||||
str2 = reason
|
||||
},
|
||||
{ "State removal: id=$str1 reason=$str2" }
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "MediaTttSender"
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
|
||||
// appropriately.
|
||||
activeViews.remove(displayInfo)
|
||||
listeners.forEach {
|
||||
it.onInfoPermanentlyRemoved(id)
|
||||
it.onInfoPermanentlyRemoved(id, removalReason)
|
||||
}
|
||||
|
||||
// No need to time the view out since it's already gone
|
||||
@@ -393,7 +393,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
|
||||
activeViews.remove(it)
|
||||
logger.logViewExpiration(it.info)
|
||||
listeners.forEach { listener ->
|
||||
listener.onInfoPermanentlyRemoved(it.info.id)
|
||||
listener.onInfoPermanentlyRemoved(it.info.id, REMOVAL_REASON_TIME_EXPIRED)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -457,7 +457,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
|
||||
* Called whenever a [DisplayInfo] with the given [id] has been removed and will never be
|
||||
* displayed again (unless another call to [updateView] is made).
|
||||
*/
|
||||
fun onInfoPermanentlyRemoved(id: String)
|
||||
fun onInfoPermanentlyRemoved(id: String, reason: String)
|
||||
}
|
||||
|
||||
/** A container for all the display-related state objects. */
|
||||
@@ -494,6 +494,7 @@ abstract class TemporaryViewDisplayController<T : TemporaryViewInfo, U : Tempora
|
||||
}
|
||||
|
||||
private const val REMOVAL_REASON_TIMEOUT = "TIMEOUT"
|
||||
private const val REMOVAL_REASON_TIME_EXPIRED = "TIMEOUT_EXPIRED_BEFORE_REDISPLAY"
|
||||
private const val MIN_REQUIRED_TIME_FOR_REDISPLAY = 1000
|
||||
|
||||
private data class IconInfo(
|
||||
|
||||
@@ -161,6 +161,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
|
||||
chipbarCoordinator,
|
||||
commandQueue,
|
||||
context,
|
||||
dumpManager,
|
||||
logger,
|
||||
mediaTttFlags,
|
||||
uiEventLogger,
|
||||
@@ -179,6 +180,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
|
||||
chipbarCoordinator,
|
||||
commandQueue,
|
||||
context,
|
||||
dumpManager,
|
||||
logger,
|
||||
mediaTttFlags,
|
||||
uiEventLogger,
|
||||
@@ -540,6 +542,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
|
||||
val viewCaptor = ArgumentCaptor.forClass(View::class.java)
|
||||
verify(windowManager).addView(viewCaptor.capture(), any())
|
||||
verify(windowManager).removeView(viewCaptor.value)
|
||||
verify(logger).logStateMapRemoval(eq(DEFAULT_ID), any())
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -932,6 +935,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
|
||||
mockChipbarCoordinator,
|
||||
commandQueue,
|
||||
context,
|
||||
dumpManager,
|
||||
logger,
|
||||
mediaTttFlags,
|
||||
uiEventLogger,
|
||||
@@ -958,6 +962,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
|
||||
mockChipbarCoordinator,
|
||||
commandQueue,
|
||||
context,
|
||||
dumpManager,
|
||||
logger,
|
||||
mediaTttFlags,
|
||||
uiEventLogger,
|
||||
@@ -975,9 +980,10 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
|
||||
verify(mockChipbarCoordinator).registerListener(capture(listenerCaptor))
|
||||
|
||||
// WHEN the listener is notified that the view has been removed
|
||||
listenerCaptor.value.onInfoPermanentlyRemoved(DEFAULT_ID)
|
||||
listenerCaptor.value.onInfoPermanentlyRemoved(DEFAULT_ID, "reason")
|
||||
|
||||
// THEN the media coordinator unregisters the listener
|
||||
verify(logger).logStateMapRemoval(DEFAULT_ID, "reason")
|
||||
verify(mockChipbarCoordinator).unregisterListener(listenerCaptor.value)
|
||||
}
|
||||
|
||||
@@ -989,6 +995,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
|
||||
mockChipbarCoordinator,
|
||||
commandQueue,
|
||||
context,
|
||||
dumpManager,
|
||||
logger,
|
||||
mediaTttFlags,
|
||||
uiEventLogger,
|
||||
@@ -1006,7 +1013,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
|
||||
verify(mockChipbarCoordinator).registerListener(capture(listenerCaptor))
|
||||
|
||||
// WHEN the listener is notified that a different view has been removed
|
||||
listenerCaptor.value.onInfoPermanentlyRemoved("differentViewId")
|
||||
listenerCaptor.value.onInfoPermanentlyRemoved("differentViewId", "reason")
|
||||
|
||||
// THEN the media coordinator doesn't unregister the listener
|
||||
verify(mockChipbarCoordinator, never()).unregisterListener(listenerCaptor.value)
|
||||
@@ -1020,6 +1027,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
|
||||
mockChipbarCoordinator,
|
||||
commandQueue,
|
||||
context,
|
||||
dumpManager,
|
||||
logger,
|
||||
mediaTttFlags,
|
||||
uiEventLogger,
|
||||
@@ -1055,6 +1063,7 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
|
||||
mockChipbarCoordinator,
|
||||
commandQueue,
|
||||
context,
|
||||
dumpManager,
|
||||
logger,
|
||||
mediaTttFlags,
|
||||
uiEventLogger,
|
||||
@@ -1084,10 +1093,11 @@ class MediaTttSenderCoordinatorTest : SysuiTestCase() {
|
||||
verify(mockChipbarCoordinator, atLeast(1)).registerListener(capture(listenerCaptor))
|
||||
|
||||
// THEN one of them is removed
|
||||
listenerCaptor.value.onInfoPermanentlyRemoved("route1")
|
||||
listenerCaptor.value.onInfoPermanentlyRemoved("route1", "reason")
|
||||
|
||||
// THEN the media coordinator doesn't unregister the listener (since route2 is still active)
|
||||
verify(mockChipbarCoordinator, never()).unregisterListener(listenerCaptor.value)
|
||||
verify(logger).logStateMapRemoval("route1", "reason")
|
||||
}
|
||||
|
||||
private fun getChipbarView(): ViewGroup {
|
||||
|
||||
@@ -87,6 +87,32 @@ class MediaTttSenderLoggerTest : SysuiTestCase() {
|
||||
assertThat(actualString).contains(bypassReason)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun logStateMap_bufferHasInfo() {
|
||||
val map =
|
||||
mapOf(
|
||||
"123" to ChipStateSender.ALMOST_CLOSE_TO_START_CAST,
|
||||
"456" to ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED,
|
||||
)
|
||||
|
||||
logger.logStateMap(map)
|
||||
|
||||
val actualString = getStringFromBuffer()
|
||||
assertThat(actualString).contains("123")
|
||||
assertThat(actualString).contains(ChipStateSender.ALMOST_CLOSE_TO_START_CAST.name)
|
||||
assertThat(actualString).contains("456")
|
||||
assertThat(actualString).contains(ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED.name)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun logStateMapRemoval_bufferHasInfo() {
|
||||
logger.logStateMapRemoval("456", "testReason")
|
||||
|
||||
val actualString = getStringFromBuffer()
|
||||
assertThat(actualString).contains("456")
|
||||
assertThat(actualString).contains("testReason")
|
||||
}
|
||||
|
||||
private fun getStringFromBuffer(): String {
|
||||
val stringWriter = StringWriter()
|
||||
buffer.dump(PrintWriter(stringWriter), tailLength = 0)
|
||||
|
||||
@@ -1172,7 +1172,7 @@ class TemporaryViewDisplayControllerTest : SysuiTestCase() {
|
||||
|
||||
inner class Listener : TemporaryViewDisplayController.Listener {
|
||||
val permanentlyRemovedIds = mutableListOf<String>()
|
||||
override fun onInfoPermanentlyRemoved(id: String) {
|
||||
override fun onInfoPermanentlyRemoved(id: String, reason: String) {
|
||||
permanentlyRemovedIds.add(id)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user