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

Commit ce8b0ba3 authored by Nate Myren's avatar Nate Myren Committed by Android (Google) Code Review
Browse files

Merge "Convert notification redaction to tri-state" into main

parents c903e9d8 a3aa0416
Loading
Loading
Loading
Loading
+46 −22
Original line number Diff line number Diff line
@@ -31,6 +31,10 @@ import static android.os.UserHandle.USER_ALL;
import static android.provider.Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS;
import static android.provider.Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS;

import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_NONE;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_PUBLIC;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_SENSITIVE_CONTENT;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
@@ -280,8 +284,10 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {

        mBackgroundExecutor.runAllReady();

        assertTrue(mLockscreenUserManager.needsRedaction(mCurrentUserNotif));
        assertTrue(mLockscreenUserManager.needsRedaction(mSecondaryUserNotif));
        assertEquals(REDACTION_TYPE_PUBLIC,
                mLockscreenUserManager.getRedactionType(mCurrentUserNotif));
        assertEquals(REDACTION_TYPE_PUBLIC,
                mLockscreenUserManager.getRedactionType(mSecondaryUserNotif));
    }

    @Test
@@ -357,7 +363,8 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
        changeSetting(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);

        // THEN current user's notification is redacted
        assertTrue(mLockscreenUserManager.needsRedaction(mCurrentUserNotif));
        assertEquals(REDACTION_TYPE_PUBLIC,
                mLockscreenUserManager.getRedactionType(mCurrentUserNotif));
    }

    @Test
@@ -368,7 +375,8 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
        changeSetting(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);

        // THEN current user's notification isn't redacted
        assertFalse(mLockscreenUserManager.needsRedaction(mCurrentUserNotif));
        assertEquals(REDACTION_TYPE_NONE,
                mLockscreenUserManager.getRedactionType(mCurrentUserNotif));
    }

    @Test
@@ -385,7 +393,8 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
                .setChannel(channel)
                .setVisibilityOverride(VISIBILITY_NO_OVERRIDE).build());
        // THEN the notification is redacted
        assertTrue(mLockscreenUserManager.needsRedaction(mCurrentUserNotif));
        assertEquals(REDACTION_TYPE_PUBLIC,
                mLockscreenUserManager.getRedactionType(mCurrentUserNotif));
    }

    @Test
@@ -399,7 +408,8 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
                .setChannel(null)
                .setVisibilityOverride(VISIBILITY_NO_OVERRIDE).build());
        // THEN the notification is not redacted
        assertFalse(mLockscreenUserManager.needsRedaction(mCurrentUserNotif));
        assertEquals(REDACTION_TYPE_NONE,
                mLockscreenUserManager.getRedactionType(mCurrentUserNotif));
    }

    @Test
@@ -410,7 +420,8 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
        changeSetting(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);

        // THEN work profile notification is redacted
        assertTrue(mLockscreenUserManager.needsRedaction(mWorkProfileNotif));
        assertEquals(REDACTION_TYPE_PUBLIC,
                mLockscreenUserManager.getRedactionType(mWorkProfileNotif));
        assertFalse(mLockscreenUserManager.allowsManagedPrivateNotificationsInPublic());
    }

@@ -422,7 +433,8 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
        changeSetting(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);

        // THEN work profile notification isn't redacted
        assertFalse(mLockscreenUserManager.needsRedaction(mWorkProfileNotif));
        assertEquals(REDACTION_TYPE_NONE,
                mLockscreenUserManager.getRedactionType(mWorkProfileNotif));
        assertTrue(mLockscreenUserManager.allowsManagedPrivateNotificationsInPublic());
    }

@@ -440,11 +452,14 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
        changeSetting(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);

        // THEN the work profile notification doesn't need to be redacted
        assertFalse(mLockscreenUserManager.needsRedaction(mWorkProfileNotif));
        assertEquals(REDACTION_TYPE_NONE,
                mLockscreenUserManager.getRedactionType(mWorkProfileNotif));

        // THEN the current user and secondary user notifications do need to be redacted
        assertTrue(mLockscreenUserManager.needsRedaction(mCurrentUserNotif));
        assertTrue(mLockscreenUserManager.needsRedaction(mSecondaryUserNotif));
        assertEquals(REDACTION_TYPE_PUBLIC,
                mLockscreenUserManager.getRedactionType(mCurrentUserNotif));
        assertEquals(REDACTION_TYPE_PUBLIC,
                mLockscreenUserManager.getRedactionType(mSecondaryUserNotif));
    }

    @Test
@@ -461,11 +476,14 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
        changeSetting(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);

        // THEN the work profile notification needs to be redacted
        assertTrue(mLockscreenUserManager.needsRedaction(mWorkProfileNotif));
        assertEquals(REDACTION_TYPE_PUBLIC,
                mLockscreenUserManager.getRedactionType(mWorkProfileNotif));

        // THEN the current user and secondary user notifications don't need to be redacted
        assertFalse(mLockscreenUserManager.needsRedaction(mCurrentUserNotif));
        assertFalse(mLockscreenUserManager.needsRedaction(mSecondaryUserNotif));
        assertEquals(REDACTION_TYPE_NONE,
                mLockscreenUserManager.getRedactionType(mCurrentUserNotif));
        assertEquals(REDACTION_TYPE_NONE,
                mLockscreenUserManager.getRedactionType(mSecondaryUserNotif));
    }

    @Test
@@ -481,18 +499,20 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {

        // THEN the secondary profile notification still needs to be redacted because the current
        // user's setting takes precedence
        assertTrue(mLockscreenUserManager.needsRedaction(mSecondaryUserNotif));
        assertEquals(REDACTION_TYPE_PUBLIC,
                mLockscreenUserManager.getRedactionType(mSecondaryUserNotif));
    }

    @Test
    public void testHasSensitiveContent_redacted() {
        // Allow private notifications for this user
        mSettings.putIntForUser(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0,
        mSettings.putIntForUser(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1,
                mCurrentUser.id);
        changeSetting(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);

        // Sensitive Content notifications are always redacted
        assertTrue(mLockscreenUserManager.needsRedaction(mSensitiveContentNotif));
        assertEquals(REDACTION_TYPE_SENSITIVE_CONTENT,
                mLockscreenUserManager.getRedactionType(mSensitiveContentNotif));
    }

    @Test
@@ -707,9 +727,11 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
                new Intent(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED)
                        .putExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, true));

        assertTrue(mLockscreenUserManager.needsRedaction(mCurrentUserNotif));
        assertEquals(REDACTION_TYPE_PUBLIC,
                mLockscreenUserManager.getRedactionType(mCurrentUserNotif));
        // it's a global field, confirm secondary too
        assertTrue(mLockscreenUserManager.needsRedaction(mSecondaryUserNotif));
        assertEquals(REDACTION_TYPE_PUBLIC,
                mLockscreenUserManager.getRedactionType(mSecondaryUserNotif));
        assertFalse(mLockscreenUserManager.userAllowsPrivateNotificationsInPublic(mCurrentUser.id));
        assertFalse(mLockscreenUserManager.userAllowsPrivateNotificationsInPublic(
                mSecondaryUser.id));
@@ -732,7 +754,8 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
        mLockscreenUserManager.mAllUsersReceiver.onReceive(mContext,
                new Intent(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED));

        assertTrue(mLockscreenUserManager.needsRedaction(mCurrentUserNotif));
        assertEquals(REDACTION_TYPE_PUBLIC,
                mLockscreenUserManager.getRedactionType(mCurrentUserNotif));

        verify(mDevicePolicyManager, atMost(1)).getKeyguardDisabledFeatures(any(), anyInt());
    }
@@ -763,7 +786,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
        mLockscreenUserManager.mAllUsersReceiver.onReceive(mContext,
                new Intent(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED));

        assertTrue(mLockscreenUserManager.needsRedaction(notifEntry));
        assertEquals(REDACTION_TYPE_PUBLIC, mLockscreenUserManager.getRedactionType(notifEntry));
    }

    @Test
@@ -784,7 +807,8 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
                new Intent(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED));

        mLockscreenUserManager.mUserChangedCallback.onUserChanging(mSecondaryUser.id, mContext);
        assertTrue(mLockscreenUserManager.needsRedaction(mSecondaryUserNotif));
        assertEquals(REDACTION_TYPE_PUBLIC,
                mLockscreenUserManager.getRedactionType(mSecondaryUserNotif));

        verify(mDevicePolicyManager, atMost(1)).getKeyguardDisabledFeatures(any(), anyInt());
    }
+9 −1
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@ import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_NONE
import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_PUBLIC
import com.android.systemui.statusbar.RankingBuilder
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
@@ -840,7 +842,13 @@ class SensitiveContentCoordinatorTest(flags: FlagsParameterization) : SysuiTestC
                whenever(sbn).thenReturn(mockSbn)
                whenever(row).thenReturn(mockRow)
            }
        whenever(lockscreenUserManager.needsRedaction(mockEntry)).thenReturn(needsRedaction)
        val redactionType =
            if (needsRedaction) {
                REDACTION_TYPE_PUBLIC
            } else {
                REDACTION_TYPE_NONE
            }
        whenever(lockscreenUserManager.getRedactionType(mockEntry)).thenReturn(redactionType)
        whenever(mockEntry.rowExists()).thenReturn(true)
        return object : ListEntry("key", 0) {
            override fun getRepresentativeEntry(): NotificationEntry = mockEntry
+7 −4
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@ import com.android.server.notification.Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDIN
import com.android.systemui.SysuiTestCase
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_NONE
import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTION_TYPE_PUBLIC
import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
@@ -42,6 +44,7 @@ import com.android.systemui.util.mockito.withArgCaptor
import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.util.settings.SecureSettings
import com.google.common.truth.Truth.assertThat
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import org.junit.Before
@@ -212,12 +215,12 @@ class NotifUiAdjustmentProviderTest : SysuiTestCase() {
        whenever(sensitiveNotifProtectionController.shouldProtectNotification(entry))
            .thenReturn(false)
        val oldAdjustment: NotifUiAdjustment = adjustmentProvider.calculateAdjustment(entry)
        assertFalse(oldAdjustment.needsRedaction)
        assertEquals(REDACTION_TYPE_NONE, oldAdjustment.redactionType)

        whenever(sensitiveNotifProtectionController.shouldProtectNotification(entry))
            .thenReturn(true)
        val newAdjustment = adjustmentProvider.calculateAdjustment(entry)
        assertTrue(newAdjustment.needsRedaction)
        assertEquals(REDACTION_TYPE_PUBLIC, newAdjustment.redactionType)

        // Then: need re-inflation
        assertTrue(NotifUiAdjustment.needReinflate(oldAdjustment, newAdjustment))
@@ -229,12 +232,12 @@ class NotifUiAdjustmentProviderTest : SysuiTestCase() {
        whenever(sensitiveNotifProtectionController.shouldProtectNotification(entry))
            .thenReturn(false)
        val oldAdjustment = adjustmentProvider.calculateAdjustment(entry)
        assertFalse(oldAdjustment.needsRedaction)
        assertEquals(REDACTION_TYPE_NONE, oldAdjustment.redactionType)

        whenever(sensitiveNotifProtectionController.shouldProtectNotification(entry))
            .thenReturn(true)
        val newAdjustment = adjustmentProvider.calculateAdjustment(entry)
        assertFalse(newAdjustment.needsRedaction)
        assertEquals(REDACTION_TYPE_NONE, newAdjustment.redactionType)

        // Then: need no re-inflation
        assertFalse(NotifUiAdjustment.needReinflate(oldAdjustment, newAdjustment))
+38 −2
Original line number Diff line number Diff line
@@ -14,19 +14,49 @@

package com.android.systemui.statusbar;

import android.annotation.IntDef;
import android.content.pm.UserInfo;
import android.util.SparseArray;

import com.android.systemui.statusbar.notification.collection.NotificationEntry;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

public interface NotificationLockscreenUserManager {
    String PERMISSION_SELF = "com.android.systemui.permission.SELF";
    String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
            = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(flag = true,
            prefix = {"REDACTION_TYPE_"},
            value = {
                    REDACTION_TYPE_NONE,
                    REDACTION_TYPE_PUBLIC,
                    REDACTION_TYPE_SENSITIVE_CONTENT})
    @interface RedactionType {}

    /**
     * Indicates that a notification requires no redaction
     */
    int REDACTION_TYPE_NONE = 0;

    /**
     * Indicates that a notification should have all content redacted, showing the public view.
     * Overrides all other redaction types.
     */
    int REDACTION_TYPE_PUBLIC = 1;

    /**
     * Indicates that a notification should have its main content redacted, due to detected
     * sensitive content, such as a One-Time Password
     */
    int REDACTION_TYPE_SENSITIVE_CONTENT = 1 << 1;

    /**
     * @param userId user Id
     * @return true if we re on a secure lock screen
     * @return true if we're on a secure lock screen
     */
    boolean isLockscreenPublicMode(int userId);

@@ -68,7 +98,13 @@ public interface NotificationLockscreenUserManager {

    void updatePublicMode();

    boolean needsRedaction(NotificationEntry entry);
    /**
     * Determine what type of redaction is needed, if any. Returns REDACTION_TYPE_NONE if no
     * redaction type is needed, REDACTION_TYPE_PUBLIC if private notifications are blocked, and
     * REDACTION_TYPE_SENSITIVE_CONTENT if sensitive content is detected, and REDACTION_TYPE_PUBLIC
     * doesn't apply.
     */
    @RedactionType int getRedactionType(NotificationEntry entry);

    /**
     * Has the given user chosen to allow their private (full) notifications to be shown even
+19 −8
Original line number Diff line number Diff line
@@ -654,8 +654,13 @@ public class NotificationLockscreenUserManagerImpl implements
        }
    }

    /** @return true if the entry needs redaction when on the lockscreen. */
    public boolean needsRedaction(NotificationEntry ent) {
    /**
     * Determine what type of redaction is needed, if any. Returns REDACTION_TYPE_NONE if no
     * redaction type is needed, REDACTION_TYPE_PUBLIC if private notifications are blocked, and
     * REDACTION_TYPE_SENSITIVE_CONTENT if sensitive content is detected, and REDACTION_TYPE_PUBLIC
     * doesn't apply.
     */
    public @RedactionType int getRedactionType(NotificationEntry ent) {
        int userId = ent.getSbn().getUserId();

        boolean isCurrentUserRedactingNotifs =
@@ -675,13 +680,19 @@ public class NotificationLockscreenUserManagerImpl implements
                ent.isNotificationVisibilityPrivate();
        boolean userForcesRedaction = packageHasVisibilityOverride(ent.getSbn().getKey());

        if (keyguardPrivateNotifications()) {
            return !mKeyguardAllowingNotifications || isNotifSensitive
                    || userForcesRedaction || (notificationRequestsRedaction && isNotifRedacted);
        } else {
            return userForcesRedaction || isNotifSensitive
                    || (notificationRequestsRedaction && isNotifRedacted);
        if (userForcesRedaction) {
            return REDACTION_TYPE_PUBLIC;
        }
        if (notificationRequestsRedaction && isNotifRedacted) {
            return REDACTION_TYPE_PUBLIC;
        }
        if (keyguardPrivateNotifications() && !mKeyguardAllowingNotifications) {
            return REDACTION_TYPE_PUBLIC;
        }
        if (isNotifSensitive) {
            return REDACTION_TYPE_SENSITIVE_CONTENT;
        }
        return REDACTION_TYPE_NONE;
    }

    private boolean packageHasVisibilityOverride(String key) {
Loading