Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt +127 −8 Original line number Diff line number Diff line Loading @@ -30,11 +30,13 @@ import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository import com.android.systemui.statusbar.notification.data.model.activeNotificationModel import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository import com.android.systemui.statusbar.notification.shared.CallType import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel import com.android.systemui.statusbar.window.fakeStatusBarWindowControllerStore import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest Loading Loading @@ -72,7 +74,7 @@ class OngoingCallInteractorTest : SysuiTestCase() { whenTime = 1000L, callType = CallType.Ongoing, statusBarChipIcon = testIconView, contentIntent = testIntent contentIntent = testIntent, ) ) } Loading @@ -95,7 +97,9 @@ class OngoingCallInteractorTest : SysuiTestCase() { .apply { addIndividualNotif( activeNotificationModel( key = "notif1", whenTime = 1000L, callType = CallType.Ongoing key = "notif1", whenTime = 1000L, callType = CallType.Ongoing, ) ) } Loading @@ -114,7 +118,9 @@ class OngoingCallInteractorTest : SysuiTestCase() { .apply { addIndividualNotif( activeNotificationModel( key = "notif1", whenTime = 1000L, callType = CallType.Ongoing key = "notif1", whenTime = 1000L, callType = CallType.Ongoing, ) ) } Loading @@ -138,7 +144,7 @@ class OngoingCallInteractorTest : SysuiTestCase() { key = "notif1", whenTime = 1000L, callType = CallType.Ongoing, uid = UID uid = UID, ) ) } Loading @@ -161,7 +167,7 @@ class OngoingCallInteractorTest : SysuiTestCase() { key = "notif1", whenTime = 1000L, callType = CallType.Ongoing, uid = UID uid = UID, ) ) } Loading @@ -185,13 +191,12 @@ class OngoingCallInteractorTest : SysuiTestCase() { key = "notif1", whenTime = 1000L, callType = CallType.Ongoing, uid = UID uid = UID, ) ) } .build() assertThat(latest) .isInstanceOf(OngoingCallModel.InCall::class.java) assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java) // App becomes visible kosmos.activityManagerRepository.fake.setIsAppVisible(UID, true) Loading @@ -202,6 +207,120 @@ class OngoingCallInteractorTest : SysuiTestCase() { assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java) } @Test fun ongoingCallNotification_setsRequiresStatusBarVisibleTrue() = kosmos.runTest { val ongoingCallState by collectLastValue(underTest.ongoingCallState) val requiresStatusBarVisibleInRepository by collectLastValue( kosmos.fakeStatusBarModeRepository.defaultDisplay .ongoingProcessRequiresStatusBarVisible ) val requiresStatusBarVisibleInWindowController by collectLastValue( kosmos.fakeStatusBarWindowControllerStore.defaultDisplay .ongoingProcessRequiresStatusBarVisible ) repository.activeNotifications.value = ActiveNotificationsStore.Builder() .apply { addIndividualNotif( activeNotificationModel( key = "notif1", whenTime = 1000L, callType = CallType.Ongoing, uid = UID, ) ) } .build() assertThat(ongoingCallState).isInstanceOf(OngoingCallModel.InCall::class.java) assertThat(requiresStatusBarVisibleInRepository).isTrue() assertThat(requiresStatusBarVisibleInWindowController).isTrue() } @Test fun notificationRemoved_setsRequiresStatusBarVisibleFalse() = kosmos.runTest { val ongoingCallState by collectLastValue(underTest.ongoingCallState) val requiresStatusBarVisibleInRepository by collectLastValue( kosmos.fakeStatusBarModeRepository.defaultDisplay .ongoingProcessRequiresStatusBarVisible ) val requiresStatusBarVisibleInWindowController by collectLastValue( kosmos.fakeStatusBarWindowControllerStore.defaultDisplay .ongoingProcessRequiresStatusBarVisible ) repository.activeNotifications.value = ActiveNotificationsStore.Builder() .apply { addIndividualNotif( activeNotificationModel( key = "notif1", whenTime = 1000L, callType = CallType.Ongoing, uid = UID, ) ) } .build() repository.activeNotifications.value = ActiveNotificationsStore() assertThat(ongoingCallState).isInstanceOf(OngoingCallModel.NoCall::class.java) assertThat(requiresStatusBarVisibleInRepository).isFalse() assertThat(requiresStatusBarVisibleInWindowController).isFalse() } @Test fun ongoingCallNotification_appBecomesVisible_setsRequiresStatusBarVisibleFalse() = kosmos.runTest { val ongoingCallState by collectLastValue(underTest.ongoingCallState) val requiresStatusBarVisibleInRepository by collectLastValue( kosmos.fakeStatusBarModeRepository.defaultDisplay .ongoingProcessRequiresStatusBarVisible ) val requiresStatusBarVisibleInWindowController by collectLastValue( kosmos.fakeStatusBarWindowControllerStore.defaultDisplay .ongoingProcessRequiresStatusBarVisible ) kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = false repository.activeNotifications.value = ActiveNotificationsStore.Builder() .apply { addIndividualNotif( activeNotificationModel( key = "notif1", whenTime = 1000L, callType = CallType.Ongoing, uid = UID, ) ) } .build() assertThat(ongoingCallState).isInstanceOf(OngoingCallModel.InCall::class.java) assertThat(requiresStatusBarVisibleInRepository).isTrue() assertThat(requiresStatusBarVisibleInWindowController).isTrue() kosmos.activityManagerRepository.fake.setIsAppVisible(UID, true) assertThat(ongoingCallState) .isInstanceOf(OngoingCallModel.InCallWithVisibleApp::class.java) assertThat(requiresStatusBarVisibleInRepository).isFalse() assertThat(requiresStatusBarVisibleInWindowController).isFalse() } companion object { private const val UID = 885 } Loading packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt +34 −2 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import com.android.systemui.statusbar.phone.BoundsPair import com.android.systemui.statusbar.phone.LetterboxAppearanceCalculator import com.android.systemui.statusbar.phone.StatusBarBoundsProvider import com.android.systemui.statusbar.phone.fragment.dagger.HomeStatusBarComponent import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization import com.android.systemui.statusbar.phone.ongoingcall.data.repository.OngoingCallRepository import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel import dagger.assisted.Assisted Loading Loading @@ -89,6 +90,9 @@ interface StatusBarModePerDisplayRepository : OnStatusBarViewInitializedListener /** The current mode of the status bar. */ val statusBarMode: StateFlow<StatusBarMode> /** Whether the status bar is forced to be visible because of an ongoing call */ val ongoingProcessRequiresStatusBarVisible: StateFlow<Boolean> /** * Requests for the status bar to be shown transiently. * Loading @@ -110,6 +114,12 @@ interface StatusBarModePerDisplayRepository : OnStatusBarViewInitializedListener * if needed. */ fun stop() /** * Called when an ongoing process needs to prevent the status bar from being hidden in any * state. */ fun setOngoingProcessRequiresStatusBarVisible(requiredVisible: Boolean) } class StatusBarModePerDisplayRepositoryImpl Loading Loading @@ -195,6 +205,16 @@ constructor( statusBarBoundsProvider.addChangeListener(listener) } private val _ongoingProcessRequiresStatusBarVisible = MutableStateFlow(false) override val ongoingProcessRequiresStatusBarVisible = _ongoingProcessRequiresStatusBarVisible.asStateFlow() override fun setOngoingProcessRequiresStatusBarVisible( requiredVisible: Boolean ) { _ongoingProcessRequiresStatusBarVisible.value = requiredVisible } override val isInFullscreenMode: StateFlow<Boolean> = _originalStatusBarAttributes .map { params -> Loading Loading @@ -235,16 +255,28 @@ constructor( isTransientShown, isInFullscreenMode, ongoingCallRepository.ongoingCallState, ) { modifiedAttributes, isTransientShown, isInFullscreenMode, ongoingCallState -> _ongoingProcessRequiresStatusBarVisible, ) { modifiedAttributes, isTransientShown, isInFullscreenMode, ongoingCallStateLegacy, ongoingProcessRequiresStatusBarVisible -> if (modifiedAttributes == null) { null } else { val hasOngoingCall = if (StatusBarChipsModernization.isEnabled) { ongoingProcessRequiresStatusBarVisible } else { ongoingCallStateLegacy is OngoingCallModel.InCall } val statusBarMode = toBarMode( modifiedAttributes.appearance, isTransientShown, isInFullscreenMode, hasOngoingCall = ongoingCallState is OngoingCallModel.InCall, hasOngoingCall, ) StatusBarAppearance( statusBarMode, Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt +76 −37 Original line number Diff line number Diff line Loading @@ -21,17 +21,22 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.Logger import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLog import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel import com.android.systemui.statusbar.window.StatusBarWindowControllerStore import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn /** Loading @@ -47,7 +52,9 @@ import kotlinx.coroutines.flow.stateIn @SysUISingleton class OngoingCallInteractor @Inject constructor( @Application private val scope: CoroutineScope, activityManagerRepository: ActivityManagerRepository, private val activityManagerRepository: ActivityManagerRepository, private val statusBarModeRepositoryStore: StatusBarModeRepositoryStore, private val statusBarWindowControllerStore: StatusBarWindowControllerStore, activeNotificationsInteractor: ActiveNotificationsInteractor, @OngoingCallLog private val logBuffer: LogBuffer, ) { Loading @@ -58,22 +65,45 @@ class OngoingCallInteractor @Inject constructor( */ val ongoingCallState: StateFlow<OngoingCallModel> = activeNotificationsInteractor.ongoingCallNotification .flatMapLatest { notificationModel -> when (notificationModel) { null -> { .flatMapLatest { notification -> createOngoingCallStateFlow( notification = notification ) } .onEach { state -> setStatusBarRequiredForOngoingCall(state) } .stateIn( scope = scope, started = SharingStarted.WhileSubscribed(), initialValue = OngoingCallModel.NoCall ) private fun createOngoingCallStateFlow( notification: ActiveNotificationModel? ): Flow<OngoingCallModel> { if (notification == null) { logger.d("No active call notification - hiding chip") flowOf(OngoingCallModel.NoCall) return flowOf(OngoingCallModel.NoCall) } else -> combine( flowOf(notificationModel), return combine( flowOf(notification), activityManagerRepository.createIsAppVisibleFlow( creationUid = notificationModel.uid, creationUid = notification.uid, logger = logger, identifyingLogTag = TAG, ), ) ) { model, isVisible -> when { deriveOngoingCallState(model, isVisible) } } private fun deriveOngoingCallState( model: ActiveNotificationModel, isVisible: Boolean ): OngoingCallModel { return when { isVisible -> { logger.d({ "Call app is visible: uid=$int1" }) { int1 = model.uid Loading @@ -90,14 +120,23 @@ class OngoingCallInteractor @Inject constructor( startTimeMs = model.whenTime, notificationIconView = model.statusBarChipIconView, intent = model.contentIntent, notificationKey = model.key, notificationKey = model.key ) } } } private fun setStatusBarRequiredForOngoingCall(state: OngoingCallModel) { val statusBarRequired = state is OngoingCallModel.InCall // TODO(b/382808183): Create a single repository that can be utilized in // `statusBarModeRepositoryStore` and `statusBarWindowControllerStore` so we do not need // two separate calls to force the status bar to stay visible. statusBarModeRepositoryStore.defaultDisplay.setOngoingProcessRequiresStatusBarVisible( statusBarRequired ) statusBarWindowControllerStore.defaultDisplay .setOngoingProcessRequiresStatusBarVisible(statusBarRequired) } } .stateIn(scope, SharingStarted.WhileSubscribed(), OngoingCallModel.NoCall) companion object { private val TAG = "OngoingCall" Loading packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt +4 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ class FakeStatusBarModePerDisplayRepository : StatusBarModePerDisplayRepository override val isInFullscreenMode = MutableStateFlow(false) override val statusBarAppearance = MutableStateFlow<StatusBarAppearance?>(null) override val statusBarMode = MutableStateFlow(StatusBarMode.TRANSPARENT) override val ongoingProcessRequiresStatusBarVisible = MutableStateFlow(false) override fun showTransient() { isTransientShown.value = true Loading @@ -59,6 +60,9 @@ class FakeStatusBarModePerDisplayRepository : StatusBarModePerDisplayRepository override fun start() {} override fun stop() {} override fun setOngoingProcessRequiresStatusBarVisible(requiredVisible: Boolean) { ongoingProcessRequiresStatusBarVisible.value = requiredVisible } override fun onStatusBarViewInitialized(component: HomeStatusBarComponent) {} Loading packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorKosmos.kt +4 −0 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ import com.android.systemui.activity.data.repository.activityManagerRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor import com.android.systemui.statusbar.window.fakeStatusBarWindowControllerStore val Kosmos.ongoingCallInteractor: OngoingCallInteractor by Kosmos.Fixture { Loading @@ -28,6 +30,8 @@ val Kosmos.ongoingCallInteractor: OngoingCallInteractor by scope = applicationCoroutineScope, activeNotificationsInteractor = activeNotificationsInteractor, activityManagerRepository = activityManagerRepository, statusBarModeRepositoryStore = fakeStatusBarModeRepository, statusBarWindowControllerStore = fakeStatusBarWindowControllerStore, logBuffer = logcatLogBuffer("OngoingCallInteractorKosmos"), ) } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt +127 −8 Original line number Diff line number Diff line Loading @@ -30,11 +30,13 @@ import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository import com.android.systemui.statusbar.notification.data.model.activeNotificationModel import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository import com.android.systemui.statusbar.notification.shared.CallType import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel import com.android.systemui.statusbar.window.fakeStatusBarWindowControllerStore import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest Loading Loading @@ -72,7 +74,7 @@ class OngoingCallInteractorTest : SysuiTestCase() { whenTime = 1000L, callType = CallType.Ongoing, statusBarChipIcon = testIconView, contentIntent = testIntent contentIntent = testIntent, ) ) } Loading @@ -95,7 +97,9 @@ class OngoingCallInteractorTest : SysuiTestCase() { .apply { addIndividualNotif( activeNotificationModel( key = "notif1", whenTime = 1000L, callType = CallType.Ongoing key = "notif1", whenTime = 1000L, callType = CallType.Ongoing, ) ) } Loading @@ -114,7 +118,9 @@ class OngoingCallInteractorTest : SysuiTestCase() { .apply { addIndividualNotif( activeNotificationModel( key = "notif1", whenTime = 1000L, callType = CallType.Ongoing key = "notif1", whenTime = 1000L, callType = CallType.Ongoing, ) ) } Loading @@ -138,7 +144,7 @@ class OngoingCallInteractorTest : SysuiTestCase() { key = "notif1", whenTime = 1000L, callType = CallType.Ongoing, uid = UID uid = UID, ) ) } Loading @@ -161,7 +167,7 @@ class OngoingCallInteractorTest : SysuiTestCase() { key = "notif1", whenTime = 1000L, callType = CallType.Ongoing, uid = UID uid = UID, ) ) } Loading @@ -185,13 +191,12 @@ class OngoingCallInteractorTest : SysuiTestCase() { key = "notif1", whenTime = 1000L, callType = CallType.Ongoing, uid = UID uid = UID, ) ) } .build() assertThat(latest) .isInstanceOf(OngoingCallModel.InCall::class.java) assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java) // App becomes visible kosmos.activityManagerRepository.fake.setIsAppVisible(UID, true) Loading @@ -202,6 +207,120 @@ class OngoingCallInteractorTest : SysuiTestCase() { assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java) } @Test fun ongoingCallNotification_setsRequiresStatusBarVisibleTrue() = kosmos.runTest { val ongoingCallState by collectLastValue(underTest.ongoingCallState) val requiresStatusBarVisibleInRepository by collectLastValue( kosmos.fakeStatusBarModeRepository.defaultDisplay .ongoingProcessRequiresStatusBarVisible ) val requiresStatusBarVisibleInWindowController by collectLastValue( kosmos.fakeStatusBarWindowControllerStore.defaultDisplay .ongoingProcessRequiresStatusBarVisible ) repository.activeNotifications.value = ActiveNotificationsStore.Builder() .apply { addIndividualNotif( activeNotificationModel( key = "notif1", whenTime = 1000L, callType = CallType.Ongoing, uid = UID, ) ) } .build() assertThat(ongoingCallState).isInstanceOf(OngoingCallModel.InCall::class.java) assertThat(requiresStatusBarVisibleInRepository).isTrue() assertThat(requiresStatusBarVisibleInWindowController).isTrue() } @Test fun notificationRemoved_setsRequiresStatusBarVisibleFalse() = kosmos.runTest { val ongoingCallState by collectLastValue(underTest.ongoingCallState) val requiresStatusBarVisibleInRepository by collectLastValue( kosmos.fakeStatusBarModeRepository.defaultDisplay .ongoingProcessRequiresStatusBarVisible ) val requiresStatusBarVisibleInWindowController by collectLastValue( kosmos.fakeStatusBarWindowControllerStore.defaultDisplay .ongoingProcessRequiresStatusBarVisible ) repository.activeNotifications.value = ActiveNotificationsStore.Builder() .apply { addIndividualNotif( activeNotificationModel( key = "notif1", whenTime = 1000L, callType = CallType.Ongoing, uid = UID, ) ) } .build() repository.activeNotifications.value = ActiveNotificationsStore() assertThat(ongoingCallState).isInstanceOf(OngoingCallModel.NoCall::class.java) assertThat(requiresStatusBarVisibleInRepository).isFalse() assertThat(requiresStatusBarVisibleInWindowController).isFalse() } @Test fun ongoingCallNotification_appBecomesVisible_setsRequiresStatusBarVisibleFalse() = kosmos.runTest { val ongoingCallState by collectLastValue(underTest.ongoingCallState) val requiresStatusBarVisibleInRepository by collectLastValue( kosmos.fakeStatusBarModeRepository.defaultDisplay .ongoingProcessRequiresStatusBarVisible ) val requiresStatusBarVisibleInWindowController by collectLastValue( kosmos.fakeStatusBarWindowControllerStore.defaultDisplay .ongoingProcessRequiresStatusBarVisible ) kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = false repository.activeNotifications.value = ActiveNotificationsStore.Builder() .apply { addIndividualNotif( activeNotificationModel( key = "notif1", whenTime = 1000L, callType = CallType.Ongoing, uid = UID, ) ) } .build() assertThat(ongoingCallState).isInstanceOf(OngoingCallModel.InCall::class.java) assertThat(requiresStatusBarVisibleInRepository).isTrue() assertThat(requiresStatusBarVisibleInWindowController).isTrue() kosmos.activityManagerRepository.fake.setIsAppVisible(UID, true) assertThat(ongoingCallState) .isInstanceOf(OngoingCallModel.InCallWithVisibleApp::class.java) assertThat(requiresStatusBarVisibleInRepository).isFalse() assertThat(requiresStatusBarVisibleInWindowController).isFalse() } companion object { private const val UID = 885 } Loading
packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt +34 −2 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import com.android.systemui.statusbar.phone.BoundsPair import com.android.systemui.statusbar.phone.LetterboxAppearanceCalculator import com.android.systemui.statusbar.phone.StatusBarBoundsProvider import com.android.systemui.statusbar.phone.fragment.dagger.HomeStatusBarComponent import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization import com.android.systemui.statusbar.phone.ongoingcall.data.repository.OngoingCallRepository import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel import dagger.assisted.Assisted Loading Loading @@ -89,6 +90,9 @@ interface StatusBarModePerDisplayRepository : OnStatusBarViewInitializedListener /** The current mode of the status bar. */ val statusBarMode: StateFlow<StatusBarMode> /** Whether the status bar is forced to be visible because of an ongoing call */ val ongoingProcessRequiresStatusBarVisible: StateFlow<Boolean> /** * Requests for the status bar to be shown transiently. * Loading @@ -110,6 +114,12 @@ interface StatusBarModePerDisplayRepository : OnStatusBarViewInitializedListener * if needed. */ fun stop() /** * Called when an ongoing process needs to prevent the status bar from being hidden in any * state. */ fun setOngoingProcessRequiresStatusBarVisible(requiredVisible: Boolean) } class StatusBarModePerDisplayRepositoryImpl Loading Loading @@ -195,6 +205,16 @@ constructor( statusBarBoundsProvider.addChangeListener(listener) } private val _ongoingProcessRequiresStatusBarVisible = MutableStateFlow(false) override val ongoingProcessRequiresStatusBarVisible = _ongoingProcessRequiresStatusBarVisible.asStateFlow() override fun setOngoingProcessRequiresStatusBarVisible( requiredVisible: Boolean ) { _ongoingProcessRequiresStatusBarVisible.value = requiredVisible } override val isInFullscreenMode: StateFlow<Boolean> = _originalStatusBarAttributes .map { params -> Loading Loading @@ -235,16 +255,28 @@ constructor( isTransientShown, isInFullscreenMode, ongoingCallRepository.ongoingCallState, ) { modifiedAttributes, isTransientShown, isInFullscreenMode, ongoingCallState -> _ongoingProcessRequiresStatusBarVisible, ) { modifiedAttributes, isTransientShown, isInFullscreenMode, ongoingCallStateLegacy, ongoingProcessRequiresStatusBarVisible -> if (modifiedAttributes == null) { null } else { val hasOngoingCall = if (StatusBarChipsModernization.isEnabled) { ongoingProcessRequiresStatusBarVisible } else { ongoingCallStateLegacy is OngoingCallModel.InCall } val statusBarMode = toBarMode( modifiedAttributes.appearance, isTransientShown, isInFullscreenMode, hasOngoingCall = ongoingCallState is OngoingCallModel.InCall, hasOngoingCall, ) StatusBarAppearance( statusBarMode, Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt +76 −37 Original line number Diff line number Diff line Loading @@ -21,17 +21,22 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.Logger import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLog import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel import com.android.systemui.statusbar.window.StatusBarWindowControllerStore import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn /** Loading @@ -47,7 +52,9 @@ import kotlinx.coroutines.flow.stateIn @SysUISingleton class OngoingCallInteractor @Inject constructor( @Application private val scope: CoroutineScope, activityManagerRepository: ActivityManagerRepository, private val activityManagerRepository: ActivityManagerRepository, private val statusBarModeRepositoryStore: StatusBarModeRepositoryStore, private val statusBarWindowControllerStore: StatusBarWindowControllerStore, activeNotificationsInteractor: ActiveNotificationsInteractor, @OngoingCallLog private val logBuffer: LogBuffer, ) { Loading @@ -58,22 +65,45 @@ class OngoingCallInteractor @Inject constructor( */ val ongoingCallState: StateFlow<OngoingCallModel> = activeNotificationsInteractor.ongoingCallNotification .flatMapLatest { notificationModel -> when (notificationModel) { null -> { .flatMapLatest { notification -> createOngoingCallStateFlow( notification = notification ) } .onEach { state -> setStatusBarRequiredForOngoingCall(state) } .stateIn( scope = scope, started = SharingStarted.WhileSubscribed(), initialValue = OngoingCallModel.NoCall ) private fun createOngoingCallStateFlow( notification: ActiveNotificationModel? ): Flow<OngoingCallModel> { if (notification == null) { logger.d("No active call notification - hiding chip") flowOf(OngoingCallModel.NoCall) return flowOf(OngoingCallModel.NoCall) } else -> combine( flowOf(notificationModel), return combine( flowOf(notification), activityManagerRepository.createIsAppVisibleFlow( creationUid = notificationModel.uid, creationUid = notification.uid, logger = logger, identifyingLogTag = TAG, ), ) ) { model, isVisible -> when { deriveOngoingCallState(model, isVisible) } } private fun deriveOngoingCallState( model: ActiveNotificationModel, isVisible: Boolean ): OngoingCallModel { return when { isVisible -> { logger.d({ "Call app is visible: uid=$int1" }) { int1 = model.uid Loading @@ -90,14 +120,23 @@ class OngoingCallInteractor @Inject constructor( startTimeMs = model.whenTime, notificationIconView = model.statusBarChipIconView, intent = model.contentIntent, notificationKey = model.key, notificationKey = model.key ) } } } private fun setStatusBarRequiredForOngoingCall(state: OngoingCallModel) { val statusBarRequired = state is OngoingCallModel.InCall // TODO(b/382808183): Create a single repository that can be utilized in // `statusBarModeRepositoryStore` and `statusBarWindowControllerStore` so we do not need // two separate calls to force the status bar to stay visible. statusBarModeRepositoryStore.defaultDisplay.setOngoingProcessRequiresStatusBarVisible( statusBarRequired ) statusBarWindowControllerStore.defaultDisplay .setOngoingProcessRequiresStatusBarVisible(statusBarRequired) } } .stateIn(scope, SharingStarted.WhileSubscribed(), OngoingCallModel.NoCall) companion object { private val TAG = "OngoingCall" Loading
packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt +4 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ class FakeStatusBarModePerDisplayRepository : StatusBarModePerDisplayRepository override val isInFullscreenMode = MutableStateFlow(false) override val statusBarAppearance = MutableStateFlow<StatusBarAppearance?>(null) override val statusBarMode = MutableStateFlow(StatusBarMode.TRANSPARENT) override val ongoingProcessRequiresStatusBarVisible = MutableStateFlow(false) override fun showTransient() { isTransientShown.value = true Loading @@ -59,6 +60,9 @@ class FakeStatusBarModePerDisplayRepository : StatusBarModePerDisplayRepository override fun start() {} override fun stop() {} override fun setOngoingProcessRequiresStatusBarVisible(requiredVisible: Boolean) { ongoingProcessRequiresStatusBarVisible.value = requiredVisible } override fun onStatusBarViewInitialized(component: HomeStatusBarComponent) {} Loading
packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorKosmos.kt +4 −0 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ import com.android.systemui.activity.data.repository.activityManagerRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor import com.android.systemui.statusbar.window.fakeStatusBarWindowControllerStore val Kosmos.ongoingCallInteractor: OngoingCallInteractor by Kosmos.Fixture { Loading @@ -28,6 +30,8 @@ val Kosmos.ongoingCallInteractor: OngoingCallInteractor by scope = applicationCoroutineScope, activeNotificationsInteractor = activeNotificationsInteractor, activityManagerRepository = activityManagerRepository, statusBarModeRepositoryStore = fakeStatusBarModeRepository, statusBarWindowControllerStore = fakeStatusBarWindowControllerStore, logBuffer = logcatLogBuffer("OngoingCallInteractorKosmos"), ) }