Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f32b97a8 authored by Tianfan Zhang's avatar Tianfan Zhang
Browse files

Deduplicate the same app icons.

Bug: 421271205
Test: local
Flag: com.android.systemui.enable_underlay
Change-Id: I9d1f2d672b95283390d2e94a3fa064cc044fcbf9
parent e5d353a3
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -60,7 +60,7 @@ fun Chip(action: ActionViewModel, modifier: Modifier = Modifier) {
                .combinedClickable(onClick = action.onClick, onLongClick = action.onLongClick)
                .combinedClickable(onClick = action.onClick, onLongClick = action.onLongClick)
                .padding(start = 12.dp, end = 16.dp, top = 4.dp, bottom = 4.dp),
                .padding(start = 12.dp, end = 16.dp, top = 4.dp, bottom = 4.dp),
    ) {
    ) {
        val painter = rememberDrawablePainter(action.icon)
        val painter = rememberDrawablePainter(action.icon.drawable)
        Image(
        Image(
            painter = painter,
            painter = painter,
            contentDescription = action.label,
            contentDescription = action.label,
+19 −14
Original line number Original line Diff line number Diff line
@@ -71,6 +71,7 @@ import androidx.compose.ui.util.lerp
import com.android.compose.PlatformIconButton
import com.android.compose.PlatformIconButton
import com.android.compose.ui.graphics.painter.rememberDrawablePainter
import com.android.compose.ui.graphics.painter.rememberDrawablePainter
import com.android.systemui.ambientcue.ui.compose.modifier.animatedActionBorder
import com.android.systemui.ambientcue.ui.compose.modifier.animatedActionBorder
import com.android.systemui.ambientcue.ui.utils.FilterUtils
import com.android.systemui.ambientcue.ui.viewmodel.ActionType
import com.android.systemui.ambientcue.ui.viewmodel.ActionType
import com.android.systemui.ambientcue.ui.viewmodel.ActionViewModel
import com.android.systemui.ambientcue.ui.viewmodel.ActionViewModel
import com.android.systemui.res.R
import com.android.systemui.res.R
@@ -197,7 +198,8 @@ fun NavBarPill(
                ) {
                ) {
                    // Should have at most 1 expanded chip
                    // Should have at most 1 expanded chip
                    var expandedChip = false
                    var expandedChip = false
                    actions.fastForEachIndexed { index, action ->
                    val filteredActions = FilterUtils.filterActions(actions)
                    filteredActions.fastForEachIndexed { index, action ->
                        val isMrAction = action.actionType == ActionType.MR
                        val isMrAction = action.actionType == ActionType.MR


                        // Pill rounded container
                        // Pill rounded container
@@ -219,9 +221,9 @@ fun NavBarPill(
                                        shape = CircleShape,
                                        shape = CircleShape,
                                    )
                                    )
                                }
                                }
                            if ((actions.size == 1 || isMrAction) && !expandedChip) {
                            if ((filteredActions.size == 1 || isMrAction) && !expandedChip) {
                                expandedChip = true
                                expandedChip = true
                                val hasBackground = actions.size > 1
                                val hasBackground = filteredActions.size > 1
                                // Expanded chip for single action or MR
                                // Expanded chip for single action or MR
                                Row(
                                Row(
                                    horizontalArrangement = Arrangement.spacedBy(6.dp),
                                    horizontalArrangement = Arrangement.spacedBy(6.dp),
@@ -238,11 +240,12 @@ fun NavBarPill(
                                            .padding(4.dp),
                                            .padding(4.dp),
                                ) {
                                ) {
                                    Image(
                                    Image(
                                        painter = rememberDrawablePainter(action.icon),
                                        painter = rememberDrawablePainter(action.icon.drawable),
                                        contentDescription = action.label,
                                        contentDescription = action.label,
                                        modifier =
                                        modifier =
                                            Modifier.size(16.dp).then(iconBorder).clip(CircleShape),
                                            Modifier.size(16.dp).then(iconBorder).clip(CircleShape),
                                    )
                                    )
                                    if (!action.icon.repeated) {
                                        Text(
                                        Text(
                                            text = action.label,
                                            text = action.label,
                                            style = MaterialTheme.typography.labelMedium,
                                            style = MaterialTheme.typography.labelMedium,
@@ -252,16 +255,18 @@ fun NavBarPill(
                                            modifier = Modifier.widthIn(0.dp, maxPillWidth * 0.5f),
                                            modifier = Modifier.widthIn(0.dp, maxPillWidth * 0.5f),
                                        )
                                        )
                                    }
                                    }
                                }
                            } else {
                            } else {
                                // Smaller app icons
                                // Smaller app icons
                                Image(
                                Image(
                                    painter = rememberDrawablePainter(action.icon),
                                    painter = rememberDrawablePainter(action.icon.drawable),
                                    contentDescription = action.label,
                                    contentDescription = action.label,
                                    modifier =
                                    modifier =
                                        Modifier.then(
                                        Modifier.then(
                                                when (index) {
                                                when (index) {
                                                    0 -> Modifier.padding(start = 5.dp)
                                                    0 -> Modifier.padding(start = 5.dp)
                                                    actions.size - 1 -> Modifier.padding(end = 5.dp)
                                                    filteredActions.size - 1 ->
                                                        Modifier.padding(end = 5.dp)
                                                    else -> Modifier
                                                    else -> Modifier
                                                }
                                                }
                                            )
                                            )
+6 −3
Original line number Original line Diff line number Diff line
@@ -62,6 +62,7 @@ import androidx.compose.ui.util.fastForEach
import com.android.compose.PlatformIconButton
import com.android.compose.PlatformIconButton
import com.android.compose.ui.graphics.painter.rememberDrawablePainter
import com.android.compose.ui.graphics.painter.rememberDrawablePainter
import com.android.systemui.ambientcue.ui.compose.modifier.animatedActionBorder
import com.android.systemui.ambientcue.ui.compose.modifier.animatedActionBorder
import com.android.systemui.ambientcue.ui.utils.FilterUtils
import com.android.systemui.ambientcue.ui.viewmodel.ActionType
import com.android.systemui.ambientcue.ui.viewmodel.ActionType
import com.android.systemui.ambientcue.ui.viewmodel.ActionViewModel
import com.android.systemui.ambientcue.ui.viewmodel.ActionViewModel
import com.android.systemui.res.R
import com.android.systemui.res.R
@@ -167,6 +168,8 @@ fun ShortPill(
                .then(if (expanded) Modifier else Modifier.clickable { onClick() })
                .then(if (expanded) Modifier else Modifier.clickable { onClick() })
                .padding(4.dp)
                .padding(4.dp)


        val filteredActions = FilterUtils.filterActions(actions)

        if (horizontal) {
        if (horizontal) {
            Row(
            Row(
                horizontalArrangement = Arrangement.spacedBy(8.dp),
                horizontalArrangement = Arrangement.spacedBy(8.dp),
@@ -181,7 +184,7 @@ fun ShortPill(
                    verticalAlignment = Alignment.CenterVertically,
                    verticalAlignment = Alignment.CenterVertically,
                    modifier = pillModifier.defaultMinSize(minWidth = minSize),
                    modifier = pillModifier.defaultMinSize(minWidth = minSize),
                ) {
                ) {
                    actions.take(3).fastForEach { action ->
                    filteredActions.take(3).fastForEach { action ->
                        Icon(action, backgroundColor)
                        Icon(action, backgroundColor)
                        if (actions.size == 1) {
                        if (actions.size == 1) {
                            Text(
                            Text(
@@ -215,7 +218,7 @@ fun ShortPill(
                    verticalArrangement = Arrangement.spacedBy(-4.dp, Alignment.CenterVertically),
                    verticalArrangement = Arrangement.spacedBy(-4.dp, Alignment.CenterVertically),
                    modifier = pillModifier.defaultMinSize(minHeight = minSize),
                    modifier = pillModifier.defaultMinSize(minHeight = minSize),
                ) {
                ) {
                    actions.take(3).fastForEach { action -> Icon(action, backgroundColor) }
                    filteredActions.take(3).fastForEach { action -> Icon(action, backgroundColor) }
                }
                }


                CloseButton(
                CloseButton(
@@ -257,7 +260,7 @@ private fun CloseButton(
@Composable
@Composable
private fun Icon(action: ActionViewModel, backgroundColor: Color, modifier: Modifier = Modifier) {
private fun Icon(action: ActionViewModel, backgroundColor: Color, modifier: Modifier = Modifier) {
    Image(
    Image(
        painter = rememberDrawablePainter(action.icon),
        painter = rememberDrawablePainter(action.icon.drawable),
        contentDescription = action.label,
        contentDescription = action.label,
        modifier =
        modifier =
            modifier
            modifier
+7 −3
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.ambientcue.data.repository.ambientCueRepository
import com.android.systemui.ambientcue.data.repository.ambientCueRepository
import com.android.systemui.ambientcue.data.repository.fake
import com.android.systemui.ambientcue.data.repository.fake
import com.android.systemui.ambientcue.shared.model.ActionModel
import com.android.systemui.ambientcue.shared.model.ActionModel
import com.android.systemui.ambientcue.shared.model.IconModel
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.runTest
import com.android.systemui.res.R
import com.android.systemui.res.R
@@ -60,10 +61,13 @@ class AmbientCueInteractorTest : SysuiTestCase() {
                listOf(
                listOf(
                    ActionModel(
                    ActionModel(
                        icon =
                        icon =
                            IconModel(
                                applicationContext.resources.getDrawable(
                                applicationContext.resources.getDrawable(
                                    R.drawable.ic_content_paste_spark,
                                    R.drawable.ic_content_paste_spark,
                                    applicationContext.theme,
                                    applicationContext.theme,
                                ),
                                ),
                                "test.icon",
                            ),
                        label = "Sunday Morning",
                        label = "Sunday Morning",
                        attribution = null,
                        attribution = null,
                        onPerformAction = {},
                        onPerformAction = {},
+88 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2025 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.ambientcue.ui.utils

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.ambientcue.ui.viewmodel.ActionType
import com.android.systemui.ambientcue.ui.viewmodel.ActionViewModel
import com.android.systemui.ambientcue.ui.viewmodel.IconViewModel
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.mock

@RunWith(AndroidJUnit4::class)
@SmallTest
class FilterUtilsTest : SysuiTestCase() {
    private val kosmos = testKosmos()

    private lateinit var calendarAction1: ActionViewModel
    private lateinit var calendarAction2: ActionViewModel
    private lateinit var mapsAction: ActionViewModel

    @Before
    fun setUp() {
        calendarAction1 =
            ActionViewModel(
                icon = IconViewModel(mock(), "calendar_icon", false),
                label = "Sunday Morning",
                attribution = null,
                onClick = {},
                onLongClick = {},
                actionType = ActionType.MA,
            )
        calendarAction2 =
            ActionViewModel(
                icon = IconViewModel(mock(), "calendar_icon", false),
                label = "Sunday Evening",
                attribution = null,
                onClick = {},
                onLongClick = {},
                actionType = ActionType.MA,
            )
        mapsAction =
            ActionViewModel(
                icon = IconViewModel(mock(), "map_icon", false),
                label = "Philz Coffee San Carlos",
                onClick = {},
                onLongClick = {},
                actionType = ActionType.MA,
            )
    }

    @Test
    fun filterActions_noRepeatedAction_returnOriginalActions() {
        val filterActions = FilterUtils.filterActions(listOf(calendarAction1, mapsAction))

        assertThat(filterActions.size).isEqualTo(2)
        assertThat(filterActions).contains(calendarAction1)
        assertThat(filterActions).contains(mapsAction)
    }

    @Test
    fun filterActions_repeatedCalendarAction_filterCalendarAction() {
        val filterActions = FilterUtils.filterActions(listOf(calendarAction1, calendarAction2))

        assertThat(filterActions.size).isEqualTo(1)
        assertThat(filterActions[0].label).isEqualTo("Sunday Morning Sunday Evening")
        assertThat(filterActions[0].icon.repeated).isTrue()
    }
}
Loading