summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopup.kt65
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt21
7 files changed, 118 insertions, 18 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt
index 19acb2e9839c..2f6a2b51d625 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt
@@ -82,10 +82,6 @@ constructor(
chipId = PopupChipId.MediaControl,
icon = defaultIcon,
chipText = model.songName.toString(),
- isToggled = false,
- // TODO(b/385202114): Show a popup containing the media carousal when the chip is
- // toggled.
- onToggle = {},
hoverBehavior = createHoverBehavior(model),
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt
index 683b97166f3e..60615536ab67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt
@@ -53,10 +53,11 @@ sealed class PopupChipModel {
/** Default icon displayed on the chip */
val icon: Icon,
val chipText: String,
- val isToggled: Boolean = false,
- val onToggle: () -> Unit,
+ val isPopupShown: Boolean = false,
+ val showPopup: () -> Unit = {},
+ val hidePopup: () -> Unit = {},
val hoverBehavior: HoverBehavior = HoverBehavior.None,
) : PopupChipModel() {
- override val logName = "Shown(id=$chipId, toggled=$isToggled)"
+ override val logName = "Shown(id=$chipId, toggled=$isPopupShown)"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopup.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopup.kt
new file mode 100644
index 000000000000..8a66904ea59b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopup.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.featurepods.popups.ui.compose
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Popup
+import androidx.compose.ui.window.PopupProperties
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId
+import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel
+
+/**
+ * Displays a popup in the status bar area. The offset is calculated to draw the popup below the
+ * status bar.
+ */
+@Composable
+fun StatusBarPopup(viewModel: PopupChipModel.Shown) {
+ val density = Density(LocalContext.current)
+ Popup(
+ properties =
+ PopupProperties(
+ focusable = false,
+ dismissOnBackPress = true,
+ dismissOnClickOutside = true,
+ ),
+ offset =
+ IntOffset(
+ x = 0,
+ y = with(density) { dimensionResource(R.dimen.status_bar_height).roundToPx() },
+ ),
+ onDismissRequest = { viewModel.hidePopup() },
+ ) {
+ Box(modifier = Modifier.padding(8.dp).wrapContentSize()) {
+ when (viewModel.chipId) {
+ is PopupChipId.MediaControl -> {
+ // TODO(b/385202114): Populate MediaControlPopup contents.
+ }
+ }
+ // Future popup types will be handled here.
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt
index 34bef9d3ca3a..eb85d2f32f29 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt
@@ -52,14 +52,14 @@ import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipM
* the chip can show text containing contextual information.
*/
@Composable
-fun StatusBarPopupChip(model: PopupChipModel.Shown, modifier: Modifier = Modifier) {
- val hasHoverBehavior = model.hoverBehavior !is HoverBehavior.None
+fun StatusBarPopupChip(viewModel: PopupChipModel.Shown, modifier: Modifier = Modifier) {
+ val hasHoverBehavior = viewModel.hoverBehavior !is HoverBehavior.None
val hoverInteractionSource = remember { MutableInteractionSource() }
val isHovered by hoverInteractionSource.collectIsHoveredAsState()
- val isToggled = model.isToggled
+ val isPopupShown = viewModel.isPopupShown
val chipBackgroundColor =
- if (isToggled) {
+ if (isPopupShown) {
MaterialTheme.colorScheme.primaryContainer
} else {
MaterialTheme.colorScheme.surfaceContainerHighest
@@ -72,7 +72,7 @@ fun StatusBarPopupChip(model: PopupChipModel.Shown, modifier: Modifier = Modifie
.padding(vertical = 4.dp)
.animateContentSize()
.thenIf(hasHoverBehavior) { Modifier.hoverable(hoverInteractionSource) }
- .clickable { model.onToggle() },
+ .thenIf(!isPopupShown) { Modifier.clickable { viewModel.showPopup() } },
color = chipBackgroundColor,
) {
Row(
@@ -82,14 +82,14 @@ fun StatusBarPopupChip(model: PopupChipModel.Shown, modifier: Modifier = Modifie
) {
val iconColor =
if (isHovered) chipBackgroundColor else contentColorFor(chipBackgroundColor)
- val hoverBehavior = model.hoverBehavior
+ val hoverBehavior = viewModel.hoverBehavior
val iconBackgroundColor = contentColorFor(chipBackgroundColor)
val iconInteractionSource = remember { MutableInteractionSource() }
Icon(
icon =
when {
isHovered && hoverBehavior is HoverBehavior.Button -> hoverBehavior.icon
- else -> model.icon
+ else -> viewModel.icon
},
modifier =
Modifier.thenIf(isHovered) {
@@ -109,7 +109,7 @@ fun StatusBarPopupChip(model: PopupChipModel.Shown, modifier: Modifier = Modifie
)
Text(
- text = model.chipText,
+ text = viewModel.chipText,
style = MaterialTheme.typography.labelLarge,
softWrap = false,
overflow = TextOverflow.Ellipsis,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt
index d35674d8dd9f..16538c93cf35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt
@@ -31,10 +31,15 @@ fun StatusBarPopupChipsContainer(chips: List<PopupChipModel.Shown>, modifier: Mo
// TODO(b/385353140): Add padding and spacing for this container according to UX specs.
Box {
Row(
- modifier = Modifier.padding(horizontal = 8.dp),
+ modifier = modifier.padding(horizontal = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
- chips.forEach { chip -> StatusBarPopupChip(chip) }
+ chips.forEach { chip ->
+ StatusBarPopupChip(chip)
+ if (chip.isPopupShown) {
+ StatusBarPopup(chip)
+ }
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt
index 786794fd3b37..33bf90defb48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.statusbar.featurepods.media.ui.viewmodel.MediaControlChipViewModel
@@ -37,6 +39,9 @@ class StatusBarPopupChipsViewModel
constructor(mediaControlChip: MediaControlChipViewModel) : ExclusiveActivatable() {
private val hydrator: Hydrator = Hydrator("StatusBarPopupChipsViewModel.hydrator")
+ /** The ID of the current chip that is showing its popup, or `null` if no chip is shown. */
+ private var currentShownPopupChipId by mutableStateOf<PopupChipId?>(null)
+
private val incomingPopupChipBundle: PopupChipBundle by
hydrator.hydratedStateOf(
traceName = "incomingPopupChipBundle",
@@ -47,7 +52,14 @@ constructor(mediaControlChip: MediaControlChipViewModel) : ExclusiveActivatable(
val shownPopupChips: List<PopupChipModel.Shown> by derivedStateOf {
if (StatusBarPopupChips.isEnabled) {
val bundle = incomingPopupChipBundle
- listOfNotNull(bundle.media).filterIsInstance<PopupChipModel.Shown>()
+
+ listOfNotNull(bundle.media).filterIsInstance<PopupChipModel.Shown>().map { chip ->
+ chip.copy(
+ isPopupShown = chip.chipId == currentShownPopupChipId,
+ showPopup = { currentShownPopupChipId = chip.chipId },
+ hidePopup = { currentShownPopupChipId = null },
+ )
+ }
} else {
emptyList()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt
index 32b6dc0e8f3d..510d6fe2b776 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt
@@ -71,4 +71,25 @@ class StatusBarPopupChipsViewModelTest : SysuiTestCase() {
assertThat(shownPopupChips.first().chipId).isEqualTo(PopupChipId.MediaControl)
}
}
+
+ @Test
+ fun shownPopupChips_mediaChipToggled_popupShown() =
+ kosmos.runTest {
+ val shownPopupChips = underTest.shownPopupChips
+
+ val userMedia = MediaData(active = true, song = "test")
+ val instanceId = userMedia.instanceId
+
+ mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
+ mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId))
+
+ Snapshot.takeSnapshot {
+ assertThat(shownPopupChips).hasSize(1)
+ val mediaChip = shownPopupChips.first()
+ assertThat(mediaChip.isPopupShown).isFalse()
+
+ mediaChip.showPopup.invoke()
+ assertThat(shownPopupChips.first().isPopupShown).isTrue()
+ }
+ }
}