summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt135
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt113
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt7
6 files changed, 251 insertions, 48 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
index ca1413e48966..b19645fadbdf 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
@@ -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
@@ -72,7 +74,7 @@ class OngoingCallInteractorTest : SysuiTestCase() {
whenTime = 1000L,
callType = CallType.Ongoing,
statusBarChipIcon = testIconView,
- contentIntent = testIntent
+ contentIntent = testIntent,
)
)
}
@@ -95,7 +97,9 @@ class OngoingCallInteractorTest : SysuiTestCase() {
.apply {
addIndividualNotif(
activeNotificationModel(
- key = "notif1", whenTime = 1000L, callType = CallType.Ongoing
+ key = "notif1",
+ whenTime = 1000L,
+ callType = CallType.Ongoing,
)
)
}
@@ -114,7 +118,9 @@ class OngoingCallInteractorTest : SysuiTestCase() {
.apply {
addIndividualNotif(
activeNotificationModel(
- key = "notif1", whenTime = 1000L, callType = CallType.Ongoing
+ key = "notif1",
+ whenTime = 1000L,
+ callType = CallType.Ongoing,
)
)
}
@@ -138,7 +144,7 @@ class OngoingCallInteractorTest : SysuiTestCase() {
key = "notif1",
whenTime = 1000L,
callType = CallType.Ongoing,
- uid = UID
+ uid = UID,
)
)
}
@@ -161,7 +167,7 @@ class OngoingCallInteractorTest : SysuiTestCase() {
key = "notif1",
whenTime = 1000L,
callType = CallType.Ongoing,
- uid = UID
+ uid = UID,
)
)
}
@@ -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)
@@ -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
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
index cc91e2dc3a25..22c37df7db7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
@@ -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
@@ -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.
*
@@ -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
@@ -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 ->
@@ -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,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
index 4b71c0268f11..b7ccfa01c92c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
@@ -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
/**
@@ -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,
) {
@@ -58,46 +65,78 @@ class OngoingCallInteractor @Inject constructor(
*/
val ongoingCallState: StateFlow<OngoingCallModel> =
activeNotificationsInteractor.ongoingCallNotification
- .flatMapLatest { notificationModel ->
- when (notificationModel) {
- null -> {
- logger.d("No active call notification - hiding chip")
- flowOf(OngoingCallModel.NoCall)
- }
+ .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")
+ return flowOf(OngoingCallModel.NoCall)
+ }
+
+ return combine(
+ flowOf(notification),
+ activityManagerRepository.createIsAppVisibleFlow(
+ creationUid = notification.uid,
+ logger = logger,
+ identifyingLogTag = TAG,
+ )
+ ) { model, isVisible ->
+ deriveOngoingCallState(model, isVisible)
+ }
+ }
- else -> combine(
- flowOf(notificationModel),
- activityManagerRepository.createIsAppVisibleFlow(
- creationUid = notificationModel.uid,
- logger = logger,
- identifyingLogTag = TAG,
- ),
- ) { model, isVisible ->
- when {
- isVisible -> {
- logger.d({ "Call app is visible: uid=$int1" }) {
- int1 = model.uid
- }
- OngoingCallModel.InCallWithVisibleApp
- }
+ private fun deriveOngoingCallState(
+ model: ActiveNotificationModel,
+ isVisible: Boolean
+ ): OngoingCallModel {
+ return when {
+ isVisible -> {
+ logger.d({ "Call app is visible: uid=$int1" }) {
+ int1 = model.uid
+ }
+ OngoingCallModel.InCallWithVisibleApp
+ }
- else -> {
- logger.d({ "Active call detected: startTime=$long1 hasIcon=$bool1" }) {
- long1 = model.whenTime
- bool1 = model.statusBarChipIconView != null
- }
- OngoingCallModel.InCall(
- startTimeMs = model.whenTime,
- notificationIconView = model.statusBarChipIconView,
- intent = model.contentIntent,
- notificationKey = model.key,
- )
- }
- }
- }
+ else -> {
+ logger.d({ "Active call detected: startTime=$long1 hasIcon=$bool1" }) {
+ long1 = model.whenTime
+ bool1 = model.statusBarChipIconView != null
}
+ OngoingCallModel.InCall(
+ startTimeMs = model.whenTime,
+ notificationIconView = model.statusBarChipIconView,
+ intent = model.contentIntent,
+ notificationKey = model.key
+ )
}
- .stateIn(scope, SharingStarted.WhileSubscribed(), OngoingCallModel.NoCall)
+ }
+ }
+
+ 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)
+ }
companion object {
private val TAG = "OngoingCall"
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt
index 22f8767e1d55..3c2d004fcad7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt
@@ -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
@@ -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) {}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorKosmos.kt
index 51fb36fb2ead..9090e02b22b6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorKosmos.kt
@@ -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 {
@@ -28,6 +30,8 @@ val Kosmos.ongoingCallInteractor: OngoingCallInteractor by
scope = applicationCoroutineScope,
activeNotificationsInteractor = activeNotificationsInteractor,
activityManagerRepository = activityManagerRepository,
+ statusBarModeRepositoryStore = fakeStatusBarModeRepository,
+ statusBarWindowControllerStore = fakeStatusBarWindowControllerStore,
logBuffer = logcatLogBuffer("OngoingCallInteractorKosmos"),
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt
index a110a49ccba8..09e6a0eaa301 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt
@@ -20,6 +20,7 @@ import android.view.View
import android.view.ViewGroup
import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.fragments.FragmentHostManager
+import kotlinx.coroutines.flow.MutableStateFlow
import java.util.Optional
class FakeStatusBarWindowController : StatusBarWindowController {
@@ -30,6 +31,8 @@ class FakeStatusBarWindowController : StatusBarWindowController {
var isStopped = false
private set
+ val ongoingProcessRequiresStatusBarVisible = MutableStateFlow(false)
+
override val statusBarHeight: Int = 0
override fun refreshStatusBarHeight() {}
@@ -57,5 +60,7 @@ class FakeStatusBarWindowController : StatusBarWindowController {
override fun setForceStatusBarVisible(forceStatusBarVisible: Boolean) {}
- override fun setOngoingProcessRequiresStatusBarVisible(visible: Boolean) {}
+ override fun setOngoingProcessRequiresStatusBarVisible(visible: Boolean) {
+ ongoingProcessRequiresStatusBarVisible.value = visible
+ }
}