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

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

Merge changes Ib678f277,Ieaae2f9c into main

* changes:
  Fix notification visibility when screensharing
  Refactor NotificationEntry utility methods
parents c747d153 08f119b1
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -749,7 +749,7 @@ public class NotificationLockscreenUserManagerImpl implements
                || isNotifUserRedacted;

        boolean notificationRequestsRedaction =
                ent.getSbn().getNotification().visibility == Notification.VISIBILITY_PRIVATE;
                ent.isNotificationVisibilityPrivate();
        boolean userForcesRedaction = packageHasVisibilityOverride(ent.getSbn().getKey());

        if (keyguardPrivateNotifications()) {
@@ -767,9 +767,7 @@ public class NotificationLockscreenUserManagerImpl implements
        }
        NotificationEntry entry = mCommonNotifCollectionLazy.get().getEntry(key);
        if (mFeatureFlags.isEnabled(Flags.NOTIF_LS_BACKGROUND_THREAD)) {
            return entry != null && entry.getRanking().getChannel() != null
                    && entry.getRanking().getChannel().getLockscreenVisibility()
                    == Notification.VISIBILITY_PRIVATE;
            return entry != null && entry.isChannelVisibilityPrivate();
        } else {
            return entry != null
                    && entry.getRanking().getLockscreenVisibilityOverride()
+17 −0
Original line number Diff line number Diff line
@@ -998,6 +998,23 @@ public final class NotificationEntry extends ListEntry {
        return style == null ? "nostyle" : style.getSimpleName();
    }

    /**
     * Return {@code true} if notification's visibility is {@link Notification.VISIBILITY_PRIVATE}
     */
    public boolean isNotificationVisibilityPrivate() {
        return getSbn().getNotification().visibility == Notification.VISIBILITY_PRIVATE;
    }

    /**
     * Return {@code true} if notification's channel lockscreen visibility is
     * {@link Notification.VISIBILITY_PRIVATE}
     */
    public boolean isChannelVisibilityPrivate() {
        return getRanking().getChannel() != null
                && getRanking().getChannel().getLockscreenVisibility()
                == Notification.VISIBILITY_PRIVATE;
    }

    /** Information about a suggestion that is being edited. */
    public static class EditedSuggestionInfo {

+8 −3
Original line number Diff line number Diff line
@@ -221,10 +221,15 @@ public class SensitiveNotificationProtectionControllerImpl
        // Exempt foreground service notifications from protection in effort to keep screen share
        // stop actions easily accessible
        StatusBarNotification sbn = entry.getSbn();
        if (sbn.getNotification().isFgsOrUij()) {
            return !sbn.getPackageName().equals(projection.getPackageName());
        if (sbn.getNotification().isFgsOrUij()
                && sbn.getPackageName().equals(projection.getPackageName())) {
            return false;
        }

        return true;
        // Only protect/redact notifications if the developer has not explicitly set notification
        // visibility as public and users has not adjusted default channel visibility to private
        boolean notificationRequestsRedaction = entry.isNotificationVisibilityPrivate();
        boolean userForcesRedaction = entry.isChannelVisibilityPrivate();
        return notificationRequestsRedaction || userForcesRedaction;
    }
}
+61 −1
Original line number Diff line number Diff line
@@ -50,8 +50,8 @@ import android.testing.AndroidTestingRunner;

import androidx.test.filters.SmallTest;

import com.android.systemui.res.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder;
import com.android.systemui.util.time.FakeSystemClock;
@@ -279,6 +279,66 @@ public class NotificationEntryTest extends SysuiTestCase {
        assertTrue(mEntry.isStickyAndNotDemoted());
    }

    @Test
    public void testIsNotificationVisibilityPrivate_true() {
        assertTrue(mEntry.isNotificationVisibilityPrivate());
    }

    @Test
    public void testIsNotificationVisibilityPrivate_visibilityPublic_false() {
        Notification.Builder notification = new Notification.Builder(mContext, "")
                .setVisibility(Notification.VISIBILITY_PUBLIC)
                .setSmallIcon(R.drawable.ic_person)
                .setContentTitle("Title")
                .setContentText("Text");

        NotificationEntry entry = new NotificationEntryBuilder()
                .setPkg(TEST_PACKAGE_NAME)
                .setOpPkg(TEST_PACKAGE_NAME)
                .setUid(TEST_UID)
                .setChannel(mChannel)
                .setId(mId++)
                .setNotification(notification.build())
                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
                .build();

        assertFalse(entry.isNotificationVisibilityPrivate());
    }

    @Test
    public void testIsChannelVisibilityPrivate_true() {
        assertTrue(mEntry.isChannelVisibilityPrivate());
    }

    @Test
    public void testIsChannelVisibilityPrivate_visibilityPublic_false() {
        NotificationChannel channel =
                new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE);
        channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
        StatusBarNotification sbn = new SbnBuilder().build();
        Ranking ranking = new RankingBuilder()
                .setChannel(channel)
                .setKey(sbn.getKey())
                .build();
        NotificationEntry entry =
                new NotificationEntry(sbn, ranking, mClock.uptimeMillis());

        assertFalse(entry.isChannelVisibilityPrivate());
    }

    @Test
    public void testIsChannelVisibilityPrivate_entryHasNoChannel_false() {
        StatusBarNotification sbn = new SbnBuilder().build();
        Ranking ranking = new RankingBuilder()
                .setChannel(null)
                .setKey(sbn.getKey())
                .build();
        NotificationEntry entry =
                new NotificationEntry(sbn, ranking, mClock.uptimeMillis());

        assertFalse(entry.isChannelVisibilityPrivate());
    }

    @Test
    public void notificationDataEntry_testIsLastMessageFromReply() {
        Person.Builder person = new Person.Builder()
+66 −11
Original line number Diff line number Diff line
@@ -19,17 +19,24 @@ package com.android.systemui.statusbar.policy
import android.app.ActivityOptions
import android.app.IActivityManager
import android.app.Notification
import android.app.Notification.FLAG_FOREGROUND_SERVICE
import android.app.Notification.VISIBILITY_PRIVATE
import android.app.Notification.VISIBILITY_PUBLIC
import android.app.NotificationChannel
import android.app.NotificationManager.IMPORTANCE_HIGH
import android.app.NotificationManager.VISIBILITY_NO_OVERRIDE
import android.media.projection.MediaProjectionInfo
import android.media.projection.MediaProjectionManager
import android.platform.test.annotations.EnableFlags
import android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS
import android.service.notification.StatusBarNotification
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.server.notification.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.RankingBuilder
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.concurrency.mockExecutorHandler
import com.android.systemui.util.mockito.whenever
@@ -316,6 +323,25 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {

        assertFalse(controller.shouldProtectNotification(notificationEntry))
    }
    @Test
    fun shouldProtectNotification_projectionActive_publicNotification_false() {
        mediaProjectionCallback.onStart(mediaProjectionInfo)

        // App marked notification visibility as public
        val notificationEntry = setupPublicNotificationEntry(TEST_PROJECTION_PACKAGE_NAME)

        assertFalse(controller.shouldProtectNotification(notificationEntry))
    }

    @Test
    fun shouldProtectNotification_projectionActive_publicNotificationUserChannelOverride_true() {
        mediaProjectionCallback.onStart(mediaProjectionInfo)

        val notificationEntry =
            setupPublicNotificationEntryWithUserOverriddenChannel(TEST_PROJECTION_PACKAGE_NAME)

        assertTrue(controller.shouldProtectNotification(notificationEntry))
    }

    private fun setDisabledViaDeveloperOption() {
        globalSettings.putInt(DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 1)
@@ -336,21 +362,50 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {

    private fun setupNotificationEntry(
        packageName: String,
        isFgs: Boolean = false
        isFgs: Boolean = false,
        overrideVisibility: Boolean = false,
        overrideChannelVisibility: Boolean = false,
    ): NotificationEntry {
        val notificationEntry = mock(NotificationEntry::class.java)
        val sbn = mock(StatusBarNotification::class.java)
        val notification = mock(Notification::class.java)
        whenever(notificationEntry.sbn).thenReturn(sbn)
        whenever(sbn.packageName).thenReturn(packageName)
        whenever(sbn.notification).thenReturn(notification)
        whenever(notification.isFgsOrUij).thenReturn(isFgs)

        val notification = Notification()
        if (isFgs) {
            notification.flags = notification.flags or FLAG_FOREGROUND_SERVICE
        }
        if (overrideVisibility) {
            // Developer has marked notification as public
            notification.visibility = VISIBILITY_PUBLIC
        }
        val notificationEntry =
            NotificationEntryBuilder().setNotification(notification).setPkg(packageName).build()
        val channel = NotificationChannel("1", "1", IMPORTANCE_HIGH)
        if (overrideChannelVisibility) {
            // User doesn't allow private notifications at the channel level
            channel.lockscreenVisibility = VISIBILITY_PRIVATE
        }
        notificationEntry.setRanking(
            RankingBuilder(notificationEntry.ranking)
                .setChannel(channel)
                .setVisibilityOverride(VISIBILITY_NO_OVERRIDE)
                .build()
        )
        return notificationEntry
    }

    private fun setupFgsNotificationEntry(packageName: String): NotificationEntry {
        return setupNotificationEntry(packageName, /* isFgs= */ true)
        return setupNotificationEntry(packageName, isFgs = true)
    }

    private fun setupPublicNotificationEntry(packageName: String): NotificationEntry {
        return setupNotificationEntry(packageName, overrideVisibility = true)
    }

    private fun setupPublicNotificationEntryWithUserOverriddenChannel(
        packageName: String
    ): NotificationEntry {
        return setupNotificationEntry(
            packageName,
            overrideVisibility = true,
            overrideChannelVisibility = true
        )
    }

    companion object {