summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt160
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt103
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt4
4 files changed, 251 insertions, 18 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
index 7a33cbe761c1..9442367e82a3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
@@ -404,7 +404,7 @@ class OngoingActivityChipsViewModelTest : SysuiTestCase() {
}
fun assertIsCallChip(latest: OngoingActivityChipModel?, notificationKey: String) {
- assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
if (StatusBarConnectedDisplays.isEnabled) {
assertNotificationIcon(latest, notificationKey)
return
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
index 78103a9906c4..a03500e5f08f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
@@ -18,15 +18,20 @@ package com.android.systemui.statusbar.chips.ui.viewmodel
import android.content.DialogInterface
import android.content.packageManager
+import android.content.res.Configuration
+import android.content.res.mainResources
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
+import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.view.View
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.Expandable
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.display.data.repository.displayStateRepository
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.mediaprojection.data.model.MediaProjectionState
@@ -48,21 +53,21 @@ import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsVie
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsScreenRecordChip
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsShareToAppChip
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.getStopActionFromDialog
-import com.android.systemui.statusbar.commandline.commandRegistry
+import com.android.systemui.statusbar.core.StatusBarRootModernization
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.promoted.shared.model.PromotedNotificationContentModel
import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
+import com.android.systemui.statusbar.notification.shared.CallType
import com.android.systemui.statusbar.phone.SystemUIDialog
+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 com.android.systemui.statusbar.phone.ongoingcall.shared.model.inCallModel
import com.android.systemui.testKosmos
import com.android.systemui.util.time.fakeSystemClock
import com.google.common.truth.Truth.assertThat
-import java.io.PrintWriter
-import java.io.StringWriter
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -85,15 +90,12 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() {
private val kosmos = testKosmos().useUnconfinedTestDispatcher()
private val testScope = kosmos.testScope
private val systemClock = kosmos.fakeSystemClock
- private val commandRegistry = kosmos.commandRegistry
private val screenRecordState = kosmos.screenRecordRepository.screenRecordState
private val mediaProjectionState = kosmos.fakeMediaProjectionRepository.mediaProjectionState
private val callRepo = kosmos.ongoingCallRepository
private val activeNotificationListRepository = kosmos.activeNotificationListRepository
- private val pw = PrintWriter(StringWriter())
-
private val mockSystemUIDialog = mock<SystemUIDialog>()
private val chipBackgroundView = mock<ChipBackgroundContainer>()
private val chipView =
@@ -202,6 +204,152 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() {
}
@Test
+ fun chips_oneChip_notSquished() =
+ testScope.runTest {
+ callRepo.setOngoingCallState(inCallModel(startTimeMs = 34, notificationKey = "call"))
+
+ val latest by collectLastValue(underTest.chips)
+
+ // The call chip isn't squished (squished chips would be icon only)
+ assertThat(latest!!.primary)
+ .isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
+ }
+
+ @Test
+ @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
+ fun chips_twoTimerChips_isSmallPortrait_andChipsModernizationDisabled_bothSquished() =
+ testScope.runTest {
+ screenRecordState.value = ScreenRecordModel.Recording
+ callRepo.setOngoingCallState(inCallModel(startTimeMs = 34, notificationKey = "call"))
+
+ val latest by collectLastValue(underTest.chips)
+
+ // Squished chips are icon only
+ assertThat(latest!!.primary)
+ .isInstanceOf(OngoingActivityChipModel.Shown.IconOnly::class.java)
+ assertThat(latest!!.secondary)
+ .isInstanceOf(OngoingActivityChipModel.Shown.IconOnly::class.java)
+ }
+
+ @Test
+ @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
+ fun chips_countdownChipAndTimerChip_countdownNotSquished_butTimerSquished() =
+ testScope.runTest {
+ screenRecordState.value = ScreenRecordModel.Starting(millisUntilStarted = 2000)
+ callRepo.setOngoingCallState(inCallModel(startTimeMs = 34, notificationKey = "call"))
+
+ val latest by collectLastValue(underTest.chips)
+
+ // The screen record countdown isn't squished to icon-only
+ assertThat(latest!!.primary)
+ .isInstanceOf(OngoingActivityChipModel.Shown.Countdown::class.java)
+ // But the call chip *is* squished
+ assertThat(latest!!.secondary)
+ .isInstanceOf(OngoingActivityChipModel.Shown.IconOnly::class.java)
+ }
+
+ @Test
+ @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
+ fun chips_numberOfChipsChanges_chipsGetSquishedAndUnsquished() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chips)
+
+ // WHEN there's only one chip
+ screenRecordState.value = ScreenRecordModel.Recording
+ callRepo.setOngoingCallState(OngoingCallModel.NoCall)
+
+ // The screen record isn't squished because it's the only one
+ assertThat(latest!!.primary)
+ .isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
+ assertThat(latest!!.secondary).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
+
+ // WHEN there's 2 chips
+ callRepo.setOngoingCallState(inCallModel(startTimeMs = 34, notificationKey = "call"))
+
+ // THEN they both become squished
+ assertThat(latest!!.primary)
+ .isInstanceOf(OngoingActivityChipModel.Shown.IconOnly::class.java)
+ // But the call chip *is* squished
+ assertThat(latest!!.secondary)
+ .isInstanceOf(OngoingActivityChipModel.Shown.IconOnly::class.java)
+
+ // WHEN we go back down to 1 chip
+ screenRecordState.value = ScreenRecordModel.DoingNothing
+
+ // THEN the remaining chip unsquishes
+ assertThat(latest!!.primary)
+ .isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
+ assertThat(latest!!.secondary).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
+ }
+
+ @Test
+ @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
+ fun chips_twoChips_isLandscape_notSquished() =
+ testScope.runTest {
+ screenRecordState.value = ScreenRecordModel.Recording
+ callRepo.setOngoingCallState(inCallModel(startTimeMs = 34, notificationKey = "call"))
+
+ // WHEN we're in landscape
+ val config =
+ Configuration(kosmos.mainResources.configuration).apply {
+ orientation = Configuration.ORIENTATION_LANDSCAPE
+ }
+ kosmos.fakeConfigurationRepository.onConfigurationChange(config)
+
+ val latest by collectLastValue(underTest.chips)
+
+ // THEN the chips aren't squished (squished chips would be icon only)
+ assertThat(latest!!.primary)
+ .isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
+ assertThat(latest!!.secondary)
+ .isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
+ }
+
+ @Test
+ @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
+ fun chips_twoChips_isLargeScreen_notSquished() =
+ testScope.runTest {
+ screenRecordState.value = ScreenRecordModel.Recording
+ callRepo.setOngoingCallState(inCallModel(startTimeMs = 34, notificationKey = "call"))
+
+ // WHEN we're on a large screen
+ kosmos.displayStateRepository.setIsLargeScreen(true)
+
+ val latest by collectLastValue(underTest.chips)
+
+ // THEN the chips aren't squished (squished chips would be icon only)
+ assertThat(latest!!.primary)
+ .isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
+ assertThat(latest!!.secondary)
+ .isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
+ }
+
+ @Test
+ @EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
+ fun chips_twoChips_chipsModernizationEnabled_notSquished() =
+ testScope.runTest {
+ screenRecordState.value = ScreenRecordModel.Recording
+ setNotifs(
+ listOf(
+ activeNotificationModel(
+ key = "call",
+ statusBarChipIcon = createStatusBarIconViewOrNull(),
+ callType = CallType.Ongoing,
+ whenTime = 499,
+ )
+ )
+ )
+
+ val latest by collectLastValue(underTest.chips)
+
+ // Squished chips would be icon only
+ assertThat(latest!!.primary)
+ .isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
+ assertThat(latest!!.secondary)
+ .isInstanceOf(OngoingActivityChipModel.Shown.Timer::class.java)
+ }
+
+ @Test
fun primaryChip_screenRecordShowAndShareToAppShow_screenRecordShown() =
testScope.runTest {
screenRecordState.value = ScreenRecordModel.Recording
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
index baa9d8b8b794..1451154d25ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
@@ -16,6 +16,9 @@
package com.android.systemui.statusbar.chips.ui.viewmodel
+import android.content.res.Configuration
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.LogBuffer
@@ -30,6 +33,7 @@ import com.android.systemui.statusbar.chips.screenrecord.ui.viewmodel.ScreenReco
import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.ShareToAppChipViewModel
import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModel
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
import com.android.systemui.util.kotlin.pairwise
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -37,7 +41,9 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
/**
@@ -56,8 +62,30 @@ constructor(
castToOtherDeviceChipViewModel: CastToOtherDeviceChipViewModel,
callChipViewModel: CallChipViewModel,
notifChipsViewModel: NotifChipsViewModel,
+ displayStateInteractor: DisplayStateInteractor,
+ configurationInteractor: ConfigurationInteractor,
@StatusBarChipsLog private val logger: LogBuffer,
) {
+ private val isLandscape: Flow<Boolean> =
+ configurationInteractor.configurationValues
+ .map { it.isLandscape }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+ private val isScreenReasonablyLarge: Flow<Boolean> =
+ combine(isLandscape, displayStateInteractor.isLargeScreen) { isLandscape, isLargeScreen ->
+ isLandscape || isLargeScreen
+ }
+ .distinctUntilChanged()
+ .onEach {
+ logger.log(
+ TAG,
+ LogLevel.DEBUG,
+ { bool1 = it },
+ { "isScreenReasonablyLarge: $bool1" },
+ )
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
private enum class ChipType {
ScreenRecord,
ShareToApp,
@@ -165,22 +193,72 @@ constructor(
)
private val internalChips: Flow<InternalMultipleOngoingActivityChipsModel> =
- incomingChipBundle.map { bundle ->
+ combine(incomingChipBundle, isScreenReasonablyLarge) { bundle, isScreenReasonablyLarge ->
// First: Find the most important chip.
val primaryChipResult = pickMostImportantChip(bundle)
- val primaryChip = primaryChipResult.mostImportantChip
- if (primaryChip is InternalChipModel.Hidden) {
- // If the primary chip is hidden, the secondary chip will also be hidden, so just
- // pass the same Hidden model for both.
- InternalMultipleOngoingActivityChipsModel(primaryChip, primaryChip)
- } else {
- // Then: Find the next most important chip.
- val secondaryChip =
- pickMostImportantChip(primaryChipResult.remainingChips).mostImportantChip
- InternalMultipleOngoingActivityChipsModel(primaryChip, secondaryChip)
+ when (val primaryChip = primaryChipResult.mostImportantChip) {
+ is InternalChipModel.Hidden -> {
+ // If the primary chip is hidden, the secondary chip will also be hidden, so
+ // just pass the same Hidden model for both.
+ InternalMultipleOngoingActivityChipsModel(primaryChip, primaryChip)
+ }
+ is InternalChipModel.Shown -> {
+ // Otherwise: Find the next most important chip.
+ val secondaryChip =
+ pickMostImportantChip(primaryChipResult.remainingChips).mostImportantChip
+ if (
+ secondaryChip is InternalChipModel.Shown &&
+ StatusBarNotifChips.isEnabled &&
+ !StatusBarChipsModernization.isEnabled &&
+ !isScreenReasonablyLarge
+ ) {
+ // If we have two showing chips and we don't have a ton of room
+ // (!isScreenReasonablyLarge), then we want to make both of them as small as
+ // possible so that we have the highest chance of showing both chips (as
+ // opposed to showing the primary chip with a lot of text and completely
+ // hiding the secondary chip).
+ // Also: If StatusBarChipsModernization is enabled, then we'll do the
+ // squishing in Compose instead.
+ InternalMultipleOngoingActivityChipsModel(
+ primaryChip.squish(),
+ secondaryChip.squish(),
+ )
+ } else {
+ InternalMultipleOngoingActivityChipsModel(primaryChip, secondaryChip)
+ }
+ }
}
}
+ /** Squishes the chip down to the smallest content possible. */
+ private fun InternalChipModel.Shown.squish(): InternalChipModel.Shown {
+ return when (model) {
+ // Icon-only is already maximum squished
+ is OngoingActivityChipModel.Shown.IconOnly -> this
+ // Countdown shows just a single digit, so already maximum squished
+ is OngoingActivityChipModel.Shown.Countdown -> this
+ // The other chips have icon+text, so we should hide the text
+ is OngoingActivityChipModel.Shown.Timer,
+ is OngoingActivityChipModel.Shown.ShortTimeDelta,
+ is OngoingActivityChipModel.Shown.Text ->
+ InternalChipModel.Shown(this.type, this.model.toIconOnly())
+ }
+ }
+
+ private fun OngoingActivityChipModel.Shown.toIconOnly(): OngoingActivityChipModel.Shown {
+ // If this chip doesn't have an icon, then it only has text and we should continue showing
+ // its text. (This is theoretically impossible because
+ // [OngoingActivityChipModel.Shown.Countdown] is the only chip without an icon, but protect
+ // against it just in case.)
+ val currentIcon = icon ?: return this
+ return OngoingActivityChipModel.Shown.IconOnly(
+ currentIcon,
+ colors,
+ onClickListenerLegacy,
+ clickBehavior,
+ )
+ }
+
/**
* A flow modeling the primary chip that should be shown in the status bar after accounting for
* possibly multiple ongoing activities and animation requirements.
@@ -327,6 +405,9 @@ constructor(
}
}
+ private val Configuration.isLandscape: Boolean
+ get() = orientation == Configuration.ORIENTATION_LANDSCAPE
+
companion object {
private val TAG = "ChipsViewModel".pad()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
index ee34aa642e51..212049a0ce52 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.chips.ui.viewmodel
+import com.android.systemui.biometrics.domain.interactor.displayStateInteractor
+import com.android.systemui.common.ui.domain.interactor.configurationInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.statusbar.chips.call.ui.viewmodel.callChipViewModel
@@ -34,6 +36,8 @@ val Kosmos.ongoingActivityChipsViewModel: OngoingActivityChipsViewModel by
castToOtherDeviceChipViewModel = castToOtherDeviceChipViewModel,
callChipViewModel = callChipViewModel,
notifChipsViewModel = notifChipsViewModel,
+ displayStateInteractor = displayStateInteractor,
+ configurationInteractor = configurationInteractor,
logger = statusBarChipsLogger,
)
}