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

Commit 29e00674 authored by Richard MacGregor's avatar Richard MacGregor Committed by Android (Google) Code Review
Browse files

Merge "Hide secret notification while screenshare" into main

parents fa94b254 04fd5f80
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -16,12 +16,14 @@

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

import android.app.Notification
import android.os.UserHandle
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.server.notification.Flags.screenshareNotificationHiding
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
import com.android.systemui.statusbar.notification.DynamicPrivacyController
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
@@ -67,6 +69,17 @@ class SensitiveContentCoordinatorImpl @Inject constructor(
        invalidateList("onSensitiveStateChanged")
    }

    private val screenshareSecretFilter = object : NotifFilter("ScreenshareSecretFilter") {
        val NotificationEntry.isSecret
            get() = channel?.lockscreenVisibility == Notification.VISIBILITY_SECRET ||
                sbn.notification?.visibility == Notification.VISIBILITY_SECRET
        override fun shouldFilterOut(entry: NotificationEntry, now: Long): Boolean {
            return screenshareNotificationHiding() &&
                sensitiveNotificationProtectionController.isSensitiveStateActive &&
                entry.isSecret
        }
    }

    override fun attach(pipeline: NotifPipeline) {
        dynamicPrivacyController.addListener(this)
        if (screenshareNotificationHiding()) {
@@ -75,6 +88,9 @@ class SensitiveContentCoordinatorImpl @Inject constructor(
        }
        pipeline.addOnBeforeRenderListListener(this)
        pipeline.addPreRenderInvalidator(this)
        if (screenshareNotificationHiding()) {
            pipeline.addFinalizeFilter(screenshareSecretFilter)
        }
    }

    override fun onDynamicPrivacyChanged(): Unit = invalidateList("onDynamicPrivacyChanged")
+78 −0
Original line number Diff line number Diff line
@@ -16,7 +16,11 @@

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

import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.os.UserHandle
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.service.notification.StatusBarNotification
import androidx.test.filters.SmallTest
@@ -25,14 +29,17 @@ import com.android.server.notification.Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDIN
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.RankingBuilder
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.notification.DynamicPrivacyController
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -44,6 +51,8 @@ import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.withArgCaptor
import dagger.BindsInstance
import dagger.Component
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@@ -113,6 +122,49 @@ class SensitiveContentCoordinatorTest : SysuiTestCase() {
        verify(invalidationListener).onPluggableInvalidated(eq(invalidator), any())
    }

    @Test
    @DisableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING)
    fun screenshareSecretFilter_flagDisabled_filterNoAdded() {
        coordinator.attach(pipeline)

        verify(pipeline, never()).addFinalizeFilter(any(NotifFilter::class.java))
    }

    @Test
    @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING)
    fun screenshareSecretFilter_sensitiveInctive_noFiltersSecret() {
        whenever(sensitiveNotificationProtectionController.isSensitiveStateActive)
            .thenReturn(false)

        coordinator.attach(pipeline)
        val filter = withArgCaptor<NotifFilter> { verify(pipeline).addFinalizeFilter(capture()) }

        val defaultNotification = createNotificationEntry("test", false, false)
        val notificationWithSecretVisibility = createNotificationEntry("test", true, false)
        val notificationOnSecretChannel = createNotificationEntry("test", false, true)

        assertFalse(filter.shouldFilterOut(defaultNotification, 0))
        assertFalse(filter.shouldFilterOut(notificationWithSecretVisibility, 0))
        assertFalse(filter.shouldFilterOut(notificationOnSecretChannel, 0))
    }

    @Test
    @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING)
    fun screenshareSecretFilter_sensitiveActive_filtersSecret() {
        whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true)

        coordinator.attach(pipeline)
        val filter = withArgCaptor<NotifFilter> { verify(pipeline).addFinalizeFilter(capture()) }

        val defaultNotification = createNotificationEntry("test", false, false)
        val notificationWithSecretVisibility = createNotificationEntry("test", true, false)
        val notificationOnSecretChannel = createNotificationEntry("test", false, true)

        assertFalse(filter.shouldFilterOut(defaultNotification, 0))
        assertTrue(filter.shouldFilterOut(notificationWithSecretVisibility, 0))
        assertTrue(filter.shouldFilterOut(notificationOnSecretChannel, 0))
    }

    @Test
    fun onBeforeRenderList_deviceUnlocked_notifDoesNotNeedRedaction() {
        coordinator.attach(pipeline)
@@ -638,6 +690,32 @@ class SensitiveContentCoordinatorTest : SysuiTestCase() {
            override fun getRepresentativeEntry(): NotificationEntry = mockEntry
        }
    }

    private fun createNotificationEntry(
        packageName: String,
        secretVisibility: Boolean = false,
        secretChannelVisibility: Boolean = false,
    ): NotificationEntry {
        val notification = Notification()
        if (secretVisibility) {
            // Developer has marked notification as public
            notification.visibility = Notification.VISIBILITY_SECRET
        }
        val notificationEntry =
            NotificationEntryBuilder().setNotification(notification).setPkg(packageName).build()
        val channel = NotificationChannel("1", "1", NotificationManager.IMPORTANCE_HIGH)
        if (secretChannelVisibility) {
            // User doesn't allow notifications at the channel level
            channel.lockscreenVisibility = Notification.VISIBILITY_SECRET
        }
        notificationEntry.setRanking(
            RankingBuilder(notificationEntry.ranking)
                .setChannel(channel)
                .setVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE)
                .build()
        )
        return notificationEntry
    }
}

@CoordinatorScope