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

Commit 4cbf90ba authored by Steve Elliott's avatar Steve Elliott
Browse files

Include bundle icons in shelf

Flag: com.android.systemui.notification_bundle_ui
Fixes: 417723514
Test: atest
Test: manual - verify bundle icons are in shelf
Change-Id: Iaa83ea4f28599a01c1bf7bd795874e2ae850fd69
parent f199a60d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -151,7 +151,7 @@ private fun ContentScope.BundleHeaderContent(
        )

        if (collapsed) {
            val currentPreviewIcons by
            val currentPreviewIcons: List<Drawable> by
                viewModel.previewIcons.collectAsStateWithLifecycle(initialValue = emptyList())
            if (currentPreviewIcons.isNotEmpty()) {
                BundlePreviewIcons(
+94 −58
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@

package com.android.systemui.statusbar.notification.icon.domain.interactor

import android.content.applicationContext
import android.platform.test.annotations.DisableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -29,21 +30,15 @@ import com.android.systemui.statusbar.notification.data.model.activeNotification
import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
import com.android.systemui.statusbar.notification.data.repository.notificationsKeyguardViewStateRepository
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.domain.interactor.headsUpNotificationIconInteractor
import com.android.systemui.statusbar.notification.promoted.domain.interactor.aodPromotedNotificationInteractor
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentBuilder
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style.Base
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModels
import com.android.systemui.statusbar.notification.shared.byIsAmbient
import com.android.systemui.statusbar.notification.shared.byIsLastMessageFromReply
import com.android.systemui.statusbar.notification.shared.byIsPromoted
import com.android.systemui.statusbar.notification.shared.byIsPulsing
import com.android.systemui.statusbar.notification.shared.byIsRowDismissed
import com.android.systemui.statusbar.notification.shared.byIsSilent
import com.android.systemui.statusbar.notification.shared.byIsSuppressedFromStatusBar
import com.android.systemui.statusbar.notification.shared.byKey
import com.android.systemui.statusbar.notification.shared.byAssociatedNotifModel
import com.android.systemui.statusbar.notification.shared.byIconIsAmbient
import com.android.systemui.statusbar.notification.shared.byIconNotifKey
import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.eq
@@ -60,18 +55,23 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class NotificationIconsInteractorTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private val activeNotificationListRepository = kosmos.activeNotificationListRepository
    private val notificationsKeyguardInteractor = kosmos.notificationsKeyguardInteractor
    private val aodPromotedNotificationInteractor = kosmos.aodPromotedNotificationInteractor
    private val testScope
        get() = kosmos.testScope

    private val activeNotificationListRepository
        get() = kosmos.activeNotificationListRepository

    private val notificationsKeyguardInteractor
        get() = kosmos.notificationsKeyguardInteractor

    private val underTest =
        NotificationIconsInteractor(
            kosmos.activeNotificationsInteractor,
            kosmos.activeNotificationListRepository,
            kosmos.bubblesOptional,
            kosmos.headsUpNotificationIconInteractor,
            kosmos.aodPromotedNotificationInteractor,
            kosmos.notificationsKeyguardViewStateRepository,
            kosmos.applicationContext,
        )

    @Before
@@ -88,7 +88,9 @@ class NotificationIconsInteractorTest : SysuiTestCase() {
    fun filteredEntrySet() =
        testScope.runTest {
            val filteredSet by collectLastValue(underTest.filteredNotifSet())
            assertThat(filteredSet).containsExactlyElementsIn(testIcons)
            assertThat(filteredSet)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsExactlyElementsIn(testIcons)
        }

    @Test
@@ -96,31 +98,35 @@ class NotificationIconsInteractorTest : SysuiTestCase() {
        testScope.runTest {
            whenever(kosmos.bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
            val filteredSet by collectLastValue(underTest.filteredNotifSet())
            assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
            assertThat(filteredSet).comparingElementsUsing(byIconNotifKey).doesNotContain("notif1")
        }

    @Test
    fun filteredEntrySet_noAmbient() =
        testScope.runTest {
            val filteredSet by collectLastValue(underTest.filteredNotifSet(showAmbient = false))
            assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
            assertThat(filteredSet).comparingElementsUsing(byIconIsAmbient).doesNotContain(true)
            assertThat(filteredSet)
                .comparingElementsUsing(byIsSuppressedFromStatusBar)
                .doesNotContain(true)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsNoneIn(testIcons.filter { it.isSuppressedFromStatusBar })
        }

    @Test
    fun filteredEntrySet_noLowPriority() =
        testScope.runTest {
            val filteredSet by collectLastValue(underTest.filteredNotifSet(showLowPriority = false))
            assertThat(filteredSet).comparingElementsUsing(byIsSilent).doesNotContain(true)
            assertThat(filteredSet)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsNoneIn(testIcons.filter { it.isSilent })
        }

    @Test
    fun filteredEntrySet_noDismissed() =
        testScope.runTest {
            val filteredSet by collectLastValue(underTest.filteredNotifSet(showDismissed = false))
            assertThat(filteredSet).comparingElementsUsing(byIsRowDismissed).doesNotContain(true)
            assertThat(filteredSet)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsNoneIn(testIcons.filter { it.isRowDismissed })
        }

    @Test
@@ -129,8 +135,8 @@ class NotificationIconsInteractorTest : SysuiTestCase() {
            val filteredSet by
                collectLastValue(underTest.filteredNotifSet(showRepliedMessages = false))
            assertThat(filteredSet)
                .comparingElementsUsing(byIsLastMessageFromReply)
                .doesNotContain(true)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsNoneIn(testIcons.filter { it.isLastMessageFromReply })
        }

    @Test
@@ -138,7 +144,9 @@ class NotificationIconsInteractorTest : SysuiTestCase() {
        testScope.runTest {
            val filteredSet by collectLastValue(underTest.filteredNotifSet(showPulsing = false))
            notificationsKeyguardInteractor.setNotificationsFullyHidden(false)
            assertThat(filteredSet).comparingElementsUsing(byIsPulsing).doesNotContain(true)
            assertThat(filteredSet)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsNoneIn(testIcons.filter { it.isPulsing })
        }

    @Test
@@ -146,14 +154,18 @@ class NotificationIconsInteractorTest : SysuiTestCase() {
        testScope.runTest {
            val filteredSet by collectLastValue(underTest.filteredNotifSet(showPulsing = false))
            notificationsKeyguardInteractor.setNotificationsFullyHidden(true)
            assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
            assertThat(filteredSet)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsAnyIn(testIcons.filter { it.isPulsing })
        }

    @Test
    fun filteredEntrySet_showAodPromoted() {
        testScope.runTest {
            val filteredSet by collectLastValue(underTest.filteredNotifSet(showAodPromoted = true))
            assertThat(filteredSet).comparingElementsUsing(byIsPromoted).contains(true)
            assertThat(filteredSet)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsAnyIn(testIcons.filter { it.promotedContent != null })
        }
    }

@@ -161,7 +173,9 @@ class NotificationIconsInteractorTest : SysuiTestCase() {
    fun filteredEntrySet_noAodPromoted() {
        testScope.runTest {
            val filteredSet by collectLastValue(underTest.filteredNotifSet(showAodPromoted = false))
            assertThat(filteredSet).comparingElementsUsing(byIsPromoted).doesNotContain(true)
            assertThat(filteredSet)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsNoneIn(testIcons.filter { it.promotedContent != null })
        }
    }
}
@@ -170,9 +184,11 @@ class NotificationIconsInteractorTest : SysuiTestCase() {
@RunWith(AndroidJUnit4::class)
class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private val testScope
        get() = kosmos.testScope

    private val underTest = kosmos.alwaysOnDisplayNotificationIconsInteractor
    private val underTest
        get() = kosmos.alwaysOnDisplayNotificationIconsInteractor

    @Before
    fun setup() {
@@ -187,24 +203,26 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() {
        testScope.runTest {
            whenever(kosmos.bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
            val filteredSet by collectLastValue(underTest.aodNotifs)
            assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
            assertThat(filteredSet).comparingElementsUsing(byIconNotifKey).doesNotContain("notif1")
        }

    @Test
    fun filteredEntrySet_noAmbient() =
        testScope.runTest {
            val filteredSet by collectLastValue(underTest.aodNotifs)
            assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
            assertThat(filteredSet).comparingElementsUsing(byIconIsAmbient).doesNotContain(true)
            assertThat(filteredSet)
                .comparingElementsUsing(byIsSuppressedFromStatusBar)
                .doesNotContain(true)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsNoneIn(testIcons.filter { it.isSuppressedFromStatusBar })
        }

    @Test
    fun filteredEntrySet_noDismissed() =
        testScope.runTest {
            val filteredSet by collectLastValue(underTest.aodNotifs)
            assertThat(filteredSet).comparingElementsUsing(byIsRowDismissed).doesNotContain(true)
            assertThat(filteredSet)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsNoneIn(testIcons.filter { it.isRowDismissed })
        }

    @Test
@@ -212,8 +230,8 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() {
        testScope.runTest {
            val filteredSet by collectLastValue(underTest.aodNotifs)
            assertThat(filteredSet)
                .comparingElementsUsing(byIsLastMessageFromReply)
                .doesNotContain(true)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsNoneIn(testIcons.filter { it.isLastMessageFromReply })
        }

    @Test
@@ -222,7 +240,9 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() {
            val filteredSet by collectLastValue(underTest.aodNotifs)
            kosmos.fakeDeviceEntryBypassRepository.setBypassEnabled(false)
            kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(false)
            assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
            assertThat(filteredSet)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsAnyIn(testIcons.filter { it.isPulsing })
        }

    @Test
@@ -231,7 +251,9 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() {
            val filteredSet by collectLastValue(underTest.aodNotifs)
            kosmos.fakeDeviceEntryBypassRepository.setBypassEnabled(false)
            kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(true)
            assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
            assertThat(filteredSet)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsAnyIn(testIcons.filter { it.isPulsing })
        }

    @Test
@@ -240,7 +262,9 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() {
            val filteredSet by collectLastValue(underTest.aodNotifs)
            kosmos.fakeDeviceEntryBypassRepository.setBypassEnabled(true)
            kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(false)
            assertThat(filteredSet).comparingElementsUsing(byIsPulsing).doesNotContain(true)
            assertThat(filteredSet)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsNoneIn(testIcons.filter { it.isPulsing })
        }

    @Test
@@ -249,7 +273,9 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() {
            val filteredSet by collectLastValue(underTest.aodNotifs)
            kosmos.fakeDeviceEntryBypassRepository.setBypassEnabled(true)
            kosmos.notificationsKeyguardInteractor.setNotificationsFullyHidden(true)
            assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
            assertThat(filteredSet)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsAnyIn(testIcons.filter { it.isPulsing })
        }
}

@@ -280,17 +306,17 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() {
        testScope.runTest {
            whenever(kosmos.bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
            val filteredSet by collectLastValue(underTest.statusBarNotifs)
            assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
            assertThat(filteredSet).comparingElementsUsing(byIconNotifKey).doesNotContain("notif1")
        }

    @Test
    fun filteredEntrySet_noAmbient() =
        testScope.runTest {
            val filteredSet by collectLastValue(underTest.statusBarNotifs)
            assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
            assertThat(filteredSet).comparingElementsUsing(byIconIsAmbient).doesNotContain(true)
            assertThat(filteredSet)
                .comparingElementsUsing(byIsSuppressedFromStatusBar)
                .doesNotContain(true)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsNoneIn(testIcons.filter { it.isSuppressedFromStatusBar })
        }

    @Test
@@ -298,7 +324,9 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() {
        testScope.runTest {
            val filteredSet by collectLastValue(underTest.statusBarNotifs)
            kosmos.notificationListenerSettingsRepository.showSilentStatusIcons.value = false
            assertThat(filteredSet).comparingElementsUsing(byIsSilent).doesNotContain(true)
            assertThat(filteredSet)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsNoneIn(testIcons.filter { it.isSilent })
        }

    @Test
@@ -306,14 +334,18 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() {
        testScope.runTest {
            val filteredSet by collectLastValue(underTest.statusBarNotifs)
            kosmos.notificationListenerSettingsRepository.showSilentStatusIcons.value = true
            assertThat(filteredSet).comparingElementsUsing(byIsSilent).contains(true)
            assertThat(filteredSet)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsAnyIn(testIcons.filter { it.isSilent })
        }

    @Test
    fun filteredEntrySet_noDismissed() =
        testScope.runTest {
            val filteredSet by collectLastValue(underTest.statusBarNotifs)
            assertThat(filteredSet).comparingElementsUsing(byIsRowDismissed).doesNotContain(true)
            assertThat(filteredSet)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsNoneIn(testIcons.filter { it.isRowDismissed })
        }

    @Test
@@ -321,8 +353,8 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() {
        testScope.runTest {
            val filteredSet by collectLastValue(underTest.statusBarNotifs)
            assertThat(filteredSet)
                .comparingElementsUsing(byIsLastMessageFromReply)
                .doesNotContain(true)
                .comparingElementsUsing(byAssociatedNotifModel)
                .containsNoneIn(testIcons.filter { it.isLastMessageFromReply })
        }

    @Test
@@ -331,20 +363,24 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() {
        testScope.runTest {
            val filteredSet by collectLastValue(underTest.statusBarNotifs)
            kosmos.headsUpNotificationIconInteractor.setIsolatedIconNotificationKey("notif5")
            assertThat(filteredSet).comparingElementsUsing(byKey).contains("notif5")
            assertThat(filteredSet).comparingElementsUsing(byIconNotifKey).contains("notif5")
        }
}

private val testIcons =
    listOf(
        activeNotificationModel(key = "notif1"),
        activeNotificationModel(key = "notif2", isAmbient = true),
        activeNotificationModel(key = "notif3", isRowDismissed = true),
        activeNotificationModel(key = "notif4", isSilent = true),
        activeNotificationModel(key = "notif5", isLastMessageFromReply = true),
        activeNotificationModel(key = "notif6", isSuppressedFromStatusBar = true),
        activeNotificationModel(key = "notif7", isPulsing = true),
        activeNotificationModel(key = "notif8", promotedContent = promotedContent("notif8", Base)),
        activeNotificationModel(key = "notif1", groupKey = "g1"),
        activeNotificationModel(key = "notif2", groupKey = "g2", isAmbient = true),
        activeNotificationModel(key = "notif3", groupKey = "g3", isRowDismissed = true),
        activeNotificationModel(key = "notif4", groupKey = "g4", isSilent = true),
        activeNotificationModel(key = "notif5", groupKey = "g5", isLastMessageFromReply = true),
        activeNotificationModel(key = "notif6", groupKey = "g6", isSuppressedFromStatusBar = true),
        activeNotificationModel(key = "notif7", groupKey = "g7", isPulsing = true),
        activeNotificationModel(
            key = "notif8",
            groupKey = "g8",
            promotedContent = promotedContent("notif8", Base),
        ),
    )

private fun promotedContent(
+19 −20
Original line number Diff line number Diff line
@@ -15,30 +15,29 @@

package com.android.systemui.statusbar.notification.shared

import com.android.systemui.statusbar.notification.icon.domain.interactor.ActiveNotificationIconModel
import com.google.common.truth.Correspondence

val byKey: Correspondence<ActiveNotificationModel, String> =
    Correspondence.transforming({ it.key }, "has a key of")
val byIsAmbient: Correspondence<ActiveNotificationModel, Boolean> =
val byIconIsAmbient: Correspondence<ActiveNotificationIconModel, Boolean> =
    Correspondence.transforming({ it.isAmbient }, "has an isAmbient value of")
val byIsSuppressedFromStatusBar: Correspondence<ActiveNotificationModel, Boolean> =
val byAssociatedNotifModel: Correspondence<ActiveNotificationIconModel, ActiveNotificationModel> =
    Correspondence.transforming(
        { it.isSuppressedFromStatusBar },
        "has an isSuppressedFromStatusBar value of",
        /* actualTransform = */ { it },
        /* expectedTransform = */ { expected ->
            checkNotNull(expected)
            ActiveNotificationIconModel(
                expected.key,
                expected.groupKey!!,
                expected.shelfIcon,
                expected.statusBarIcon,
                expected.aodIcon,
                expected.isAmbient,
            )
val byIsSilent: Correspondence<ActiveNotificationModel, Boolean> =
    Correspondence.transforming({ it.isSilent }, "has an isSilent value of")
val byIsRowDismissed: Correspondence<ActiveNotificationModel, Boolean> =
    Correspondence.transforming({ it.isRowDismissed }, "has an isRowDismissed value of")
val byIsLastMessageFromReply: Correspondence<ActiveNotificationModel, Boolean> =
    Correspondence.transforming(
        { it.isLastMessageFromReply },
        "has an isLastMessageFromReply value of",
    )
val byIsPulsing: Correspondence<ActiveNotificationModel, Boolean> =
    Correspondence.transforming({ it.isPulsing }, "has an isPulsing value of")
val byIsPromoted: Correspondence<ActiveNotificationModel, Boolean> =
    Correspondence.transforming(
        { it.promotedContent != null },
        "has (or doesn't have) a promoted content model",
        },
        /* description = */ "is icon model of",
    )

val byIconNotifKey: Correspondence<ActiveNotificationIconModel, String> =
    Correspondence.transforming({ it.notifKey }, "has a notifKey of")
+20 −9
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.content.Context
import android.graphics.drawable.Icon
import android.service.notification.StatusBarNotification
import android.util.ArrayMap
import androidx.annotation.DrawableRes
import com.android.app.tracing.traceSection
import com.android.internal.logging.InstanceId
import com.android.systemui.dagger.qualifiers.Main
@@ -116,7 +117,11 @@ private class ActiveNotificationsStoreBuilder(
    private fun addBundleEntry(entry: BundleEntry) {
        val childModels = entry.children.mapNotNull { it.toModel() }
        builder.addBundle(
            existingModels.createOrReuseBundle(key = entry.key, children = childModels)
            existingModels.createOrReuseBundle(
                key = entry.key,
                iconResId = entry.bundleRepository.bundleIcon,
                children = childModels,
            )
        )
    }

@@ -132,19 +137,21 @@ private class ActiveNotificationsStoreBuilder(
        builder.setRankingsMap(flatMapToRankingsMap(entries))
    }

    fun flatMapToRankingsMap(entries: List<PipelineEntry>): Map<String, Int> {
    private fun flatMapToRankingsMap(entries: List<PipelineEntry>): Map<String, Int> {
        val result = ArrayMap<String, Int>()
        for (entry in entries) {
            when (entry) {
                is BundleEntry -> {
                    // TODO(b/410815667): Handle BundleEntry
                is BundleEntry -> flatMapToRankingsMap(entry, result)
                is ListEntry -> flatMapToRankingsMap(entry, result)
            }
                is ListEntry -> {
                    flatMapToRankingsMap(entry, result)
        }
        return result
    }

    private fun flatMapToRankingsMap(entry: BundleEntry, result: ArrayMap<String, Int>) {
        for (child in entry.children) {
            flatMapToRankingsMap(child, result)
        }
        return result
    }

    private fun flatMapToRankingsMap(entry: ListEntry, result: ArrayMap<String, Int>) {
@@ -396,17 +403,21 @@ private fun StatusBarNotification.toCallType(): CallType =

private fun ActiveNotificationsStore.createOrReuseBundle(
    key: String,
    @DrawableRes iconResId: Int,
    children: List<ActiveNotificationEntryModel>,
): ActiveBundleModel {
    return bundles[key]?.takeIf { it.isCurrent(key, children) } ?: ActiveBundleModel(key, children)
    return bundles[key]?.takeIf { it.isCurrent(key, iconResId, children) }
        ?: ActiveBundleModel(key, iconResId, children)
}

private fun ActiveBundleModel.isCurrent(
    key: String,
    @DrawableRes iconResId: Int,
    children: List<ActiveNotificationEntryModel>,
): Boolean {
    return when {
        key != this.key -> false
        iconResId != this.iconResId -> false
        !hasSameInstances(children, this.children) -> false
        else -> true
    }
+91 −22

File changed.

Preview size limit exceeded, changes collapsed.

Loading