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

Commit 7271fd34 authored by Julia Reynolds's avatar Julia Reynolds Committed by Android (Google) Code Review
Browse files

Merge "Fix logic for person level of group summaries" into main

parents cc48e509 e0a8d08b
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -52,10 +52,8 @@ import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.people.NotificationPersonExtractor;
import com.android.systemui.util.DeviceConfigProxyFake;

import org.jetbrains.annotations.NotNull;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+3 −6
Original line number Diff line number Diff line
@@ -16,14 +16,11 @@

package com.android.systemui.statusbar.notification.collection.coordinator

import android.app.Flags
import android.app.NotificationChannel
import android.app.NotificationChannel.SYSTEM_RESERVED_IDS
import android.app.NotificationManager.IMPORTANCE_DEFAULT
import android.app.NotificationManager.IMPORTANCE_HIGH
import android.app.NotificationManager.IMPORTANCE_LOW
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -91,13 +88,13 @@ class ConversationCoordinatorTest : SysuiTestCase() {
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        peopleNotificationIdentifier =
            PeopleNotificationIdentifierImpl(mock(), GroupMembershipManagerImpl())
            PeopleNotificationIdentifierImpl(GroupMembershipManagerImpl())
        coordinator =
            ConversationCoordinator(
                peopleNotificationIdentifier,
                conversationIconManager,
                HighPriorityProvider(peopleNotificationIdentifier, GroupMembershipManagerImpl()),
                headerController
                headerController,
            )

        coordinator.attach(pipeline)
@@ -234,7 +231,7 @@ class ConversationCoordinatorTest : SysuiTestCase() {

    private fun makeEntryOfPeopleType(
        @PeopleNotificationType type: Int,
        buildBlock: NotificationEntryBuilder.() -> Unit = {}
        buildBlock: NotificationEntryBuilder.() -> Unit = {},
    ): NotificationEntry {
        val channel: NotificationChannel = mock()
        whenever(channel.isImportantConversation).thenReturn(type == TYPE_IMPORTANT_PERSON)
+62 −113
Original line number Diff line number Diff line
@@ -15,148 +15,97 @@
 */
package com.android.systemui.statusbar.notification.people

import android.app.Notification
import android.app.NotificationChannel
import android.content.pm.ShortcutInfo
import android.service.notification.NotificationListenerService.Ranking
import android.service.notification.StatusBarNotification
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.RankingBuilder
import com.android.systemui.statusbar.notification.collection.BundleEntry
import com.android.systemui.statusbar.notification.collection.BundleSpec
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_FULL_PERSON
import com.android.systemui.statusbar.notification.collection.InternalNotificationsApi
import com.android.systemui.statusbar.notification.collection.buildSummaryNotificationEntry
import com.android.systemui.statusbar.notification.collection.makeEntryOfPeopleType
import com.android.systemui.statusbar.notification.collection.render.groupMembershipManager
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
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.Mockito
import org.mockito.Mockito.mock


@SmallTest
@RunWith(AndroidJUnit4::class)
class PeopleNotificationIdentifierTest : SysuiTestCase() {

    private val kosmos = testKosmos()
    private lateinit var underTest: PeopleNotificationIdentifierImpl

    private val summary1 = notificationEntry("foo", 1, summary = true)
    private val summary2 = notificationEntry("bar", 1, summary = true)
    private val entries =
        listOf<GroupEntry>(
            GroupEntryBuilder()
                .setSummary(summary1)
                .setChildren(
                    listOf(
                        notificationEntry("foo", 2),
                        notificationEntry("foo", 3),
                        notificationEntry("foo", 4)
                    )
                )
                .build(),
            GroupEntryBuilder()
                .setSummary(summary2)
                .setChildren(
                    listOf(
                        notificationEntry("bar", 2),
                        notificationEntry("bar", 3),
                        notificationEntry("bar", 4)
                    )
                )
                .build()
        )

    private fun notificationEntry(
        pkg: String,
        id: Int,
        summary: Boolean = false
    ): NotificationEntry {
        val sbn = mock(StatusBarNotification::class.java)
        Mockito.`when`(sbn.key).thenReturn("key")
        Mockito.`when`(sbn.notification).thenReturn(mock(Notification::class.java))
        if (summary)
            Mockito.`when`(sbn.notification.isGroupSummary).thenReturn(true)
        return NotificationEntryBuilder().setPkg(pkg)
            .setId(id)
            .setSbn(sbn)
            .build().apply {
                row = mock(ExpandableNotificationRow::class.java)
            }
    }

    private fun personRanking(entry: NotificationEntry, personType: Int): Ranking {
        val channel = NotificationChannel("person", "person", 4)
        channel.setConversationId("parent", "person")
        channel.setImportantConversation(true)

        val br = RankingBuilder(entry.ranking)

        when (personType) {
            TYPE_NON_PERSON -> br.setIsConversation(false)
            TYPE_PERSON -> {
                br.setIsConversation(true)
                br.setShortcutInfo(null)
    @Before
    fun setUp() {
        underTest = PeopleNotificationIdentifierImpl(kosmos.groupMembershipManager)
    }

            TYPE_IMPORTANT_PERSON -> {
                br.setIsConversation(true)
                br.setShortcutInfo(mock(ShortcutInfo::class.java))
                br.setChannel(channel)
    @Test
    fun getPeopleNotificationType_entryIsImportant() {
        assertThat(
                underTest.getPeopleNotificationType(
                    kosmos.makeEntryOfPeopleType(TYPE_IMPORTANT_PERSON)
                )
            )
            .isEqualTo(TYPE_IMPORTANT_PERSON)
    }

            else -> {
                br.setIsConversation(true)
                br.setShortcutInfo(mock(ShortcutInfo::class.java))
            }
        }
    @Test
    fun getPeopleNotificationType_importantChild() {
        val child = kosmos.makeEntryOfPeopleType(TYPE_PERSON)
        val child2 = kosmos.makeEntryOfPeopleType(TYPE_IMPORTANT_PERSON)
        val summary = kosmos.buildSummaryNotificationEntry(listOf(child, child2))

        return br.build()
        assertThat(underTest.getPeopleNotificationType(summary)).isEqualTo(TYPE_IMPORTANT_PERSON)
    }

    @Before
    fun setUp() {
        val personExtractor = object : NotificationPersonExtractor {
            public override fun isPersonNotification(sbn: StatusBarNotification): Boolean {
                return true
            }
        }
    @Test
    fun getPeopleNotificationType_noImportantChildren() {
        val child = kosmos.makeEntryOfPeopleType(TYPE_PERSON)
        val child2 = kosmos.makeEntryOfPeopleType(TYPE_PERSON)
        val summary = kosmos.buildSummaryNotificationEntry(listOf(child, child2))

        underTest = PeopleNotificationIdentifierImpl(
            personExtractor,
            GroupMembershipManagerImpl()
        )
        assertThat(underTest.getPeopleNotificationType(summary)).isEqualTo(TYPE_PERSON)
    }

    private val Ranking.personTypeInfo
        get() = when {
            !isConversation -> TYPE_NON_PERSON
            conversationShortcutInfo == null -> TYPE_PERSON
            channel?.isImportantConversation == true -> TYPE_IMPORTANT_PERSON
            else -> TYPE_FULL_PERSON
    @Test
    fun getPeopleNotificationType_nestedGroup() {
        val child = kosmos.makeEntryOfPeopleType(TYPE_PERSON)
        val innerSummary = kosmos.buildSummaryNotificationEntry(listOf(child))
        val child1 = kosmos.makeEntryOfPeopleType(TYPE_PERSON)
        val child2 = kosmos.makeEntryOfPeopleType(TYPE_IMPORTANT_PERSON)
        val summary = kosmos.buildSummaryNotificationEntry(listOf(child1, child2, innerSummary))

        assertThat(underTest.getPeopleNotificationType(summary)).isEqualTo(TYPE_IMPORTANT_PERSON)
    }

    @Test
    fun getPeopleNotificationType_entryIsImportant() {
        summary1.setRanking(personRanking(summary1, TYPE_IMPORTANT_PERSON))

        assertThat(underTest.getPeopleNotificationType(summary1)).isEqualTo(TYPE_IMPORTANT_PERSON)
    fun getPeopleNotificationType_circularGroup() {
        val child = kosmos.makeEntryOfPeopleType(TYPE_PERSON)
        val innerSummary = kosmos.buildSummaryNotificationEntry(listOf(child))
        val child1 = kosmos.makeEntryOfPeopleType(TYPE_PERSON)
        val child2 = kosmos.makeEntryOfPeopleType(TYPE_IMPORTANT_PERSON)
        val summary = kosmos.buildSummaryNotificationEntry(listOf(child1, child2, innerSummary))
        (summary.parent as? GroupEntry)?.rawChildren?.add(summary)

        assertThat(underTest.getPeopleNotificationType(summary)).isEqualTo(TYPE_IMPORTANT_PERSON)
    }

    @OptIn(InternalNotificationsApi::class)
    @Test
    fun getPeopleNotificationType_importantChild() {
        entries.get(0).getChildren().get(0).setRanking(
            personRanking(entries.get(0).getChildren().get(0), TYPE_IMPORTANT_PERSON)
        )

        assertThat(entries.get(0).summary?.let { underTest.getPeopleNotificationType(it) })
            .isEqualTo(TYPE_IMPORTANT_PERSON)
    fun getPeopleNotificationType_groupInBundle() {
        val bundleEntry = BundleEntry(BundleSpec.NEWS)
        val child1 = kosmos.makeEntryOfPeopleType(TYPE_PERSON)
        val child2 = kosmos.makeEntryOfPeopleType(TYPE_IMPORTANT_PERSON)
        val summary = kosmos.buildSummaryNotificationEntry(listOf(child1, child2))
        summary.parent?.parent = bundleEntry
        bundleEntry.addChild(summary)

        assertThat(underTest.getPeopleNotificationType(summary)).isEqualTo(TYPE_IMPORTANT_PERSON)
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -186,7 +186,7 @@ public class NotificationChildrenContainerTest extends SysuiTestCase {
    @Test
    @DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
    public void testRecreateNotificationHeader_hasHeader() {
        mChildrenContainer.recreateNotificationHeader(null, false);
        mChildrenContainer.recreateNotificationHeader(null);
        Assert.assertNotNull("Children container must have a header after recreation",
                mChildrenContainer.getCurrentHeaderView());
    }
+0 −49
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.notification.people

import android.service.notification.StatusBarNotification
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.NotificationPersonExtractorPlugin
import com.android.systemui.statusbar.policy.ExtensionController
import javax.inject.Inject

interface NotificationPersonExtractor {
    fun isPersonNotification(sbn: StatusBarNotification): Boolean
}

@SysUISingleton
class NotificationPersonExtractorPluginBoundary @Inject constructor(
    extensionController: ExtensionController
) : NotificationPersonExtractor {

    private var plugin: NotificationPersonExtractorPlugin? = null

    init {
        plugin = extensionController
                .newExtension(NotificationPersonExtractorPlugin::class.java)
                .withPlugin(NotificationPersonExtractorPlugin::class.java)
                .withCallback { extractor ->
                    plugin = extractor
                }
                .build()
                .get()
    }

    override fun isPersonNotification(sbn: StatusBarNotification): Boolean =
            plugin?.isPersonNotification(sbn) ?: false
}
Loading