Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationStatsLoggerTest.kt +61 −21 Original line number Diff line number Diff line Loading @@ -169,6 +169,41 @@ class NotificationStatsLoggerTest : SysuiTestCase() { } } @Test fun onNotificationVisibilityChanged_thenShadeNotInteractive_noDuplicateLogs() = testScope.runTest { // GIVEN a visible Notifications is reported val (ranks, locations) = fakeNotificationMaps("key0") val callable = Callable { locations } underTest.onNotificationLocationsChanged(callable, ranks) runCurrent() clearInvocations(mockStatusBarService, mockNotificationListenerService) // WHEN the same Notification becomins invisible val emptyCallable = Callable { emptyMap<String, Int>() } underTest.onNotificationLocationsChanged(emptyCallable, ranks) // AND notifications become non interactible underTest.onLockscreenOrShadeNotInteractive(emptyList()) runCurrent() // THEN visibility changes are reported verify(mockStatusBarService) .onNotificationVisibilityChanged(eq(emptyArray()), visibilityArrayCaptor.capture()) val noLongerVisible = visibilityArrayCaptor.value assertThat(noLongerVisible).hasLength(1) assertThat(noLongerVisible[0]).apply { isKeyEqualTo("key0") isRankEqualTo(0) notVisible() isInMainArea() isCountEqualTo(1) } // AND nothing else is logged verifyNoMoreInteractions(mockStatusBarService) verifyNoMoreInteractions(mockNotificationListenerService) } @Test fun onNotificationListUpdated_itemsChangedPositions_nothingLogged() = testScope.runTest { Loading Loading @@ -253,14 +288,14 @@ class NotificationStatsLoggerTest : SysuiTestCase() { activeNotificationModel( key = "key0", uid = 0, packageName = "com.android.first" packageName = "com.android.first", ), activeNotificationModel( key = "key1", uid = 1, packageName = "com.android.second" packageName = "com.android.second", ), ), ) ) runCurrent() Loading @@ -286,7 +321,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = true, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() Loading @@ -296,7 +331,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { /* key = */ "key", /* userAction = */ true, /* expanded = */ true, NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal, ) } Loading @@ -308,7 +343,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = true, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() clearInvocations(mockStatusBarService) Loading @@ -318,7 +353,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = true, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() Loading @@ -334,7 +369,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = true, location = ExpandableViewState.LOCATION_BOTTOM_STACK_HIDDEN, isUserAction = true isUserAction = true, ) runCurrent() Loading @@ -350,7 +385,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = true, location = ExpandableViewState.LOCATION_GONE, isUserAction = false isUserAction = false, ) runCurrent() Loading @@ -366,7 +401,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { /* key = */ "key", /* userAction = */ false, /* expanded = */ true, NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal, ) } Loading @@ -378,7 +413,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = true, location = ExpandableViewState.LOCATION_GONE, isUserAction = false isUserAction = false, ) runCurrent() // AND we open the shade, so we log its events Loading @@ -404,7 +439,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { /* key = */ "key", /* userAction = */ false, /* expanded = */ true, NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal, ) } Loading @@ -416,7 +451,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = false, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = false isUserAction = false, ) runCurrent() Loading @@ -433,7 +468,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = true, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() Loading @@ -443,7 +478,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { /* key = */ "key", /* userAction = */ true, /* expanded = */ true, NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal, ) // AND the Notification is expanded again Loading @@ -451,7 +486,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = false, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() Loading @@ -461,7 +496,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { /* key = */ "key", /* userAction = */ true, /* expanded = */ false, NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal, ) } Loading @@ -473,14 +508,14 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key1", isExpanded = true, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() underTest.onNotificationExpansionChanged( key = "key2", isExpanded = true, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() clearInvocations(mockStatusBarService) Loading @@ -500,14 +535,14 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key1", isExpanded = true, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() underTest.onNotificationExpansionChanged( key = "key2", isExpanded = true, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() clearInvocations(mockStatusBarService) Loading Loading @@ -535,10 +570,15 @@ class NotificationStatsLoggerTest : SysuiTestCase() { private class NotificationVisibilitySubject(private val visibility: NotificationVisibility) { fun isKeyEqualTo(key: String) = assertThat(visibility.key).isEqualTo(key) fun isRankEqualTo(rank: Int) = assertThat(visibility.rank).isEqualTo(rank) fun isCountEqualTo(count: Int) = assertThat(visibility.count).isEqualTo(count) fun isVisible() = assertThat(this.visibility.visible).isTrue() fun notVisible() = assertThat(this.visibility.visible).isFalse() fun isInMainArea() = assertThat(this.visibility.location) .isEqualTo(NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA) Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationStatsLoggerImpl.kt +57 −47 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.stack.ui.view import android.service.notification.NotificationListenerService import androidx.annotation.VisibleForTesting import com.android.app.tracing.coroutines.TrackTracer import com.android.app.tracing.coroutines.launchTraced as launch import com.android.internal.statusbar.IStatusBarService import com.android.internal.statusbar.NotificationVisibility import com.android.systemui.dagger.SysUISingleton Loading @@ -33,8 +34,9 @@ import java.util.concurrent.ConcurrentHashMap import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import com.android.app.tracing.coroutines.launchTraced as launch import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.consumeEach import kotlinx.coroutines.withContext @VisibleForTesting const val UNKNOWN_RANK = -1 Loading @@ -49,31 +51,55 @@ constructor( private val notificationPanelLogger: NotificationPanelLogger, private val statusBarService: IStatusBarService, ) : NotificationStatsLogger { private val lastLoggedVisibilities = mutableMapOf<String, VisibilityState>() private var logVisibilitiesJob: Job? = null private val expansionStates: MutableMap<String, ExpansionState> = ConcurrentHashMap<String, ExpansionState>() @VisibleForTesting val lastReportedExpansionValues: MutableMap<String, Boolean> = ConcurrentHashMap<String, Boolean>() private val visibilityLogger = Channel<VisibilityAction>(capacity = 2, onBufferOverflow = BufferOverflow.DROP_OLDEST) init { applicationScope.launch { consumeVisibilityActions() } } private suspend fun consumeVisibilityActions() { val lastLoggedVisibilities = mutableMapOf<String, VisibilityState>() visibilityLogger.consumeEach { action -> val newVisibilities = when (action) { is VisibilityAction.Change -> action.visibilities is VisibilityAction.Clear -> emptyMap() } val newlyVisible = newVisibilities - lastLoggedVisibilities.keys val noLongerVisible = lastLoggedVisibilities - newVisibilities.keys maybeLogVisibilityChanges(newlyVisible, noLongerVisible, action.activeCount) updateExpansionStates(newlyVisible, noLongerVisible) TrackTracer.instantForGroup("Notifications", "Active", action.activeCount) TrackTracer.instantForGroup("Notifications", "Visible", newVisibilities.size) lastLoggedVisibilities.clear() lastLoggedVisibilities.putAll(newVisibilities) } } override fun onNotificationLocationsChanged( locationsProvider: Callable<Map<String, Int>>, notificationRanks: Map<String, Int>, ) { if (logVisibilitiesJob?.isActive == true) { return } logVisibilitiesJob = startLogVisibilitiesJob( newVisibilities = visibilityLogger.trySend( VisibilityAction.Change( visibilities = combine( visibilities = locationsProvider.call(), rankingsMap = notificationRanks rankingsMap = notificationRanks, ), activeNotifCount = notificationRanks.size, activeCount = notificationRanks.size, ) ) } Loading Loading @@ -125,7 +151,7 @@ constructor( /* expanded = */ expansionState.isExpanded, /* notificationLocation = */ expansionState.location .toNotificationLocation() .ordinal .ordinal, ) } } Loading @@ -138,7 +164,7 @@ constructor( withContext(bgDispatcher) { notificationPanelLogger.logPanelShown( isOnLockScreen, activeNotifications.toNotificationProto() activeNotifications.toNotificationProto(), ) } } Loading @@ -147,11 +173,7 @@ constructor( override fun onLockscreenOrShadeNotInteractive( activeNotifications: List<ActiveNotificationModel> ) { logVisibilitiesJob = startLogVisibilitiesJob( newVisibilities = emptyMap(), activeNotifCount = activeNotifications.size ) visibilityLogger.trySend(VisibilityAction.Clear(activeCount = activeNotifications.size)) } override fun onNotificationRemoved(key: String) { Loading @@ -167,29 +189,12 @@ constructor( private fun combine( visibilities: Map<String, Int>, rankingsMap: Map<String, Int> rankingsMap: Map<String, Int>, ): Map<String, VisibilityState> = visibilities.mapValues { entry -> VisibilityState(entry.key, entry.value, rankingsMap[entry.key] ?: UNKNOWN_RANK) } private fun startLogVisibilitiesJob( newVisibilities: Map<String, VisibilityState>, activeNotifCount: Int, ) = applicationScope.launch { val newlyVisible = newVisibilities - lastLoggedVisibilities.keys val noLongerVisible = lastLoggedVisibilities - newVisibilities.keys maybeLogVisibilityChanges(newlyVisible, noLongerVisible, activeNotifCount) updateExpansionStates(newlyVisible, noLongerVisible) TrackTracer.instantForGroup("Notifications", "Active", activeNotifCount) TrackTracer.instantForGroup("Notifications", "Visible", newVisibilities.size) lastLoggedVisibilities.clear() lastLoggedVisibilities.putAll(newVisibilities) } private suspend fun maybeLogVisibilityChanges( newlyVisible: Map<String, VisibilityState>, noLongerVisible: Map<String, VisibilityState>, Loading @@ -205,7 +210,7 @@ constructor( val noLongerVisibleAr = noLongerVisible.mapToNotificationVisibilitiesAr( visible = false, count = activeNotifCount count = activeNotifCount, ) withContext(bgDispatcher) { Loading @@ -218,7 +223,7 @@ constructor( private fun updateExpansionStates( newlyVisible: Map<String, VisibilityState>, noLongerVisible: Map<String, VisibilityState> noLongerVisible: Map<String, VisibilityState>, ) { expansionStates.forEach { (key, expansionState) -> if (newlyVisible.contains(key)) { Loading @@ -241,11 +246,16 @@ constructor( } } private data class VisibilityState( val key: String, val location: Int, val rank: Int, ) private sealed class VisibilityAction(open val activeCount: Int) { data class Change( val visibilities: Map<String, VisibilityState>, override val activeCount: Int, ) : VisibilityAction(activeCount) data class Clear(override val activeCount: Int) : VisibilityAction(activeCount) } private data class VisibilityState(val key: String, val location: Int, val rank: Int) private data class ExpansionState( val key: String, Loading Loading @@ -278,7 +288,7 @@ constructor( /* rank = */ state.rank, /* count = */ count, /* visible = */ visible, /* location = */ state.location.toNotificationLocation() /* location = */ state.location.toNotificationLocation(), ) } .toTypedArray() Loading packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationStatsLoggerKosmos.kt +1 −1 Original line number Diff line number Diff line Loading @@ -26,7 +26,7 @@ import com.android.systemui.statusbar.notification.logging.notificationPanelLogg val Kosmos.notificationStatsLogger by Fixture { NotificationStatsLoggerImpl( applicationScope = testScope, applicationScope = testScope.backgroundScope, bgDispatcher = testDispatcher, statusBarService = statusBarService, notificationListenerService = notificationListenerService, Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationStatsLoggerTest.kt +61 −21 Original line number Diff line number Diff line Loading @@ -169,6 +169,41 @@ class NotificationStatsLoggerTest : SysuiTestCase() { } } @Test fun onNotificationVisibilityChanged_thenShadeNotInteractive_noDuplicateLogs() = testScope.runTest { // GIVEN a visible Notifications is reported val (ranks, locations) = fakeNotificationMaps("key0") val callable = Callable { locations } underTest.onNotificationLocationsChanged(callable, ranks) runCurrent() clearInvocations(mockStatusBarService, mockNotificationListenerService) // WHEN the same Notification becomins invisible val emptyCallable = Callable { emptyMap<String, Int>() } underTest.onNotificationLocationsChanged(emptyCallable, ranks) // AND notifications become non interactible underTest.onLockscreenOrShadeNotInteractive(emptyList()) runCurrent() // THEN visibility changes are reported verify(mockStatusBarService) .onNotificationVisibilityChanged(eq(emptyArray()), visibilityArrayCaptor.capture()) val noLongerVisible = visibilityArrayCaptor.value assertThat(noLongerVisible).hasLength(1) assertThat(noLongerVisible[0]).apply { isKeyEqualTo("key0") isRankEqualTo(0) notVisible() isInMainArea() isCountEqualTo(1) } // AND nothing else is logged verifyNoMoreInteractions(mockStatusBarService) verifyNoMoreInteractions(mockNotificationListenerService) } @Test fun onNotificationListUpdated_itemsChangedPositions_nothingLogged() = testScope.runTest { Loading Loading @@ -253,14 +288,14 @@ class NotificationStatsLoggerTest : SysuiTestCase() { activeNotificationModel( key = "key0", uid = 0, packageName = "com.android.first" packageName = "com.android.first", ), activeNotificationModel( key = "key1", uid = 1, packageName = "com.android.second" packageName = "com.android.second", ), ), ) ) runCurrent() Loading @@ -286,7 +321,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = true, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() Loading @@ -296,7 +331,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { /* key = */ "key", /* userAction = */ true, /* expanded = */ true, NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal, ) } Loading @@ -308,7 +343,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = true, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() clearInvocations(mockStatusBarService) Loading @@ -318,7 +353,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = true, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() Loading @@ -334,7 +369,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = true, location = ExpandableViewState.LOCATION_BOTTOM_STACK_HIDDEN, isUserAction = true isUserAction = true, ) runCurrent() Loading @@ -350,7 +385,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = true, location = ExpandableViewState.LOCATION_GONE, isUserAction = false isUserAction = false, ) runCurrent() Loading @@ -366,7 +401,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { /* key = */ "key", /* userAction = */ false, /* expanded = */ true, NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal, ) } Loading @@ -378,7 +413,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = true, location = ExpandableViewState.LOCATION_GONE, isUserAction = false isUserAction = false, ) runCurrent() // AND we open the shade, so we log its events Loading @@ -404,7 +439,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { /* key = */ "key", /* userAction = */ false, /* expanded = */ true, NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal, ) } Loading @@ -416,7 +451,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = false, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = false isUserAction = false, ) runCurrent() Loading @@ -433,7 +468,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = true, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() Loading @@ -443,7 +478,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { /* key = */ "key", /* userAction = */ true, /* expanded = */ true, NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal, ) // AND the Notification is expanded again Loading @@ -451,7 +486,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key", isExpanded = false, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() Loading @@ -461,7 +496,7 @@ class NotificationStatsLoggerTest : SysuiTestCase() { /* key = */ "key", /* userAction = */ true, /* expanded = */ false, NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA.ordinal, ) } Loading @@ -473,14 +508,14 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key1", isExpanded = true, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() underTest.onNotificationExpansionChanged( key = "key2", isExpanded = true, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() clearInvocations(mockStatusBarService) Loading @@ -500,14 +535,14 @@ class NotificationStatsLoggerTest : SysuiTestCase() { key = "key1", isExpanded = true, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() underTest.onNotificationExpansionChanged( key = "key2", isExpanded = true, location = ExpandableViewState.LOCATION_MAIN_AREA, isUserAction = true isUserAction = true, ) runCurrent() clearInvocations(mockStatusBarService) Loading Loading @@ -535,10 +570,15 @@ class NotificationStatsLoggerTest : SysuiTestCase() { private class NotificationVisibilitySubject(private val visibility: NotificationVisibility) { fun isKeyEqualTo(key: String) = assertThat(visibility.key).isEqualTo(key) fun isRankEqualTo(rank: Int) = assertThat(visibility.rank).isEqualTo(rank) fun isCountEqualTo(count: Int) = assertThat(visibility.count).isEqualTo(count) fun isVisible() = assertThat(this.visibility.visible).isTrue() fun notVisible() = assertThat(this.visibility.visible).isFalse() fun isInMainArea() = assertThat(this.visibility.location) .isEqualTo(NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA) Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationStatsLoggerImpl.kt +57 −47 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.stack.ui.view import android.service.notification.NotificationListenerService import androidx.annotation.VisibleForTesting import com.android.app.tracing.coroutines.TrackTracer import com.android.app.tracing.coroutines.launchTraced as launch import com.android.internal.statusbar.IStatusBarService import com.android.internal.statusbar.NotificationVisibility import com.android.systemui.dagger.SysUISingleton Loading @@ -33,8 +34,9 @@ import java.util.concurrent.ConcurrentHashMap import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import com.android.app.tracing.coroutines.launchTraced as launch import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.consumeEach import kotlinx.coroutines.withContext @VisibleForTesting const val UNKNOWN_RANK = -1 Loading @@ -49,31 +51,55 @@ constructor( private val notificationPanelLogger: NotificationPanelLogger, private val statusBarService: IStatusBarService, ) : NotificationStatsLogger { private val lastLoggedVisibilities = mutableMapOf<String, VisibilityState>() private var logVisibilitiesJob: Job? = null private val expansionStates: MutableMap<String, ExpansionState> = ConcurrentHashMap<String, ExpansionState>() @VisibleForTesting val lastReportedExpansionValues: MutableMap<String, Boolean> = ConcurrentHashMap<String, Boolean>() private val visibilityLogger = Channel<VisibilityAction>(capacity = 2, onBufferOverflow = BufferOverflow.DROP_OLDEST) init { applicationScope.launch { consumeVisibilityActions() } } private suspend fun consumeVisibilityActions() { val lastLoggedVisibilities = mutableMapOf<String, VisibilityState>() visibilityLogger.consumeEach { action -> val newVisibilities = when (action) { is VisibilityAction.Change -> action.visibilities is VisibilityAction.Clear -> emptyMap() } val newlyVisible = newVisibilities - lastLoggedVisibilities.keys val noLongerVisible = lastLoggedVisibilities - newVisibilities.keys maybeLogVisibilityChanges(newlyVisible, noLongerVisible, action.activeCount) updateExpansionStates(newlyVisible, noLongerVisible) TrackTracer.instantForGroup("Notifications", "Active", action.activeCount) TrackTracer.instantForGroup("Notifications", "Visible", newVisibilities.size) lastLoggedVisibilities.clear() lastLoggedVisibilities.putAll(newVisibilities) } } override fun onNotificationLocationsChanged( locationsProvider: Callable<Map<String, Int>>, notificationRanks: Map<String, Int>, ) { if (logVisibilitiesJob?.isActive == true) { return } logVisibilitiesJob = startLogVisibilitiesJob( newVisibilities = visibilityLogger.trySend( VisibilityAction.Change( visibilities = combine( visibilities = locationsProvider.call(), rankingsMap = notificationRanks rankingsMap = notificationRanks, ), activeNotifCount = notificationRanks.size, activeCount = notificationRanks.size, ) ) } Loading Loading @@ -125,7 +151,7 @@ constructor( /* expanded = */ expansionState.isExpanded, /* notificationLocation = */ expansionState.location .toNotificationLocation() .ordinal .ordinal, ) } } Loading @@ -138,7 +164,7 @@ constructor( withContext(bgDispatcher) { notificationPanelLogger.logPanelShown( isOnLockScreen, activeNotifications.toNotificationProto() activeNotifications.toNotificationProto(), ) } } Loading @@ -147,11 +173,7 @@ constructor( override fun onLockscreenOrShadeNotInteractive( activeNotifications: List<ActiveNotificationModel> ) { logVisibilitiesJob = startLogVisibilitiesJob( newVisibilities = emptyMap(), activeNotifCount = activeNotifications.size ) visibilityLogger.trySend(VisibilityAction.Clear(activeCount = activeNotifications.size)) } override fun onNotificationRemoved(key: String) { Loading @@ -167,29 +189,12 @@ constructor( private fun combine( visibilities: Map<String, Int>, rankingsMap: Map<String, Int> rankingsMap: Map<String, Int>, ): Map<String, VisibilityState> = visibilities.mapValues { entry -> VisibilityState(entry.key, entry.value, rankingsMap[entry.key] ?: UNKNOWN_RANK) } private fun startLogVisibilitiesJob( newVisibilities: Map<String, VisibilityState>, activeNotifCount: Int, ) = applicationScope.launch { val newlyVisible = newVisibilities - lastLoggedVisibilities.keys val noLongerVisible = lastLoggedVisibilities - newVisibilities.keys maybeLogVisibilityChanges(newlyVisible, noLongerVisible, activeNotifCount) updateExpansionStates(newlyVisible, noLongerVisible) TrackTracer.instantForGroup("Notifications", "Active", activeNotifCount) TrackTracer.instantForGroup("Notifications", "Visible", newVisibilities.size) lastLoggedVisibilities.clear() lastLoggedVisibilities.putAll(newVisibilities) } private suspend fun maybeLogVisibilityChanges( newlyVisible: Map<String, VisibilityState>, noLongerVisible: Map<String, VisibilityState>, Loading @@ -205,7 +210,7 @@ constructor( val noLongerVisibleAr = noLongerVisible.mapToNotificationVisibilitiesAr( visible = false, count = activeNotifCount count = activeNotifCount, ) withContext(bgDispatcher) { Loading @@ -218,7 +223,7 @@ constructor( private fun updateExpansionStates( newlyVisible: Map<String, VisibilityState>, noLongerVisible: Map<String, VisibilityState> noLongerVisible: Map<String, VisibilityState>, ) { expansionStates.forEach { (key, expansionState) -> if (newlyVisible.contains(key)) { Loading @@ -241,11 +246,16 @@ constructor( } } private data class VisibilityState( val key: String, val location: Int, val rank: Int, ) private sealed class VisibilityAction(open val activeCount: Int) { data class Change( val visibilities: Map<String, VisibilityState>, override val activeCount: Int, ) : VisibilityAction(activeCount) data class Clear(override val activeCount: Int) : VisibilityAction(activeCount) } private data class VisibilityState(val key: String, val location: Int, val rank: Int) private data class ExpansionState( val key: String, Loading Loading @@ -278,7 +288,7 @@ constructor( /* rank = */ state.rank, /* count = */ count, /* visible = */ visible, /* location = */ state.location.toNotificationLocation() /* location = */ state.location.toNotificationLocation(), ) } .toTypedArray() Loading
packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationStatsLoggerKosmos.kt +1 −1 Original line number Diff line number Diff line Loading @@ -26,7 +26,7 @@ import com.android.systemui.statusbar.notification.logging.notificationPanelLogg val Kosmos.notificationStatsLogger by Fixture { NotificationStatsLoggerImpl( applicationScope = testScope, applicationScope = testScope.backgroundScope, bgDispatcher = testDispatcher, statusBarService = statusBarService, notificationListenerService = notificationListenerService, Loading