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

Commit 284021ca authored by Richard MacGregor's avatar Richard MacGregor
Browse files

Do no redact emergency notifications

notifications from emergency assistance package should not be
hidden/redacted by the screen share protection feature

Bug: 332905289
Test: atest SensitiveNotificationProtectionControllerTest
Flag: ACONFIG com.android.systemui.screenshare_notification_hiding_bug_fix TRUNK_STAGING
Change-Id: Iece9b7b262a578a847e4b2dfa11074595dacbf45
parent 6cb7fe11
Loading
Loading
Loading
Loading
+72 −18
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.os.RemoteException;
import android.os.Trace;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.telephony.TelephonyManager;
import android.util.ArraySet;
import android.util.Log;

@@ -62,7 +63,10 @@ public class SensitiveNotificationProtectionControllerImpl
    private static final String LOG_TAG = "SNPC";
    private final SensitiveNotificationProtectionControllerLogger mLogger;
    private final PackageManager mPackageManager;
    private final ArraySet<String> mExemptPackages = new ArraySet<>();
    // Packages exempt from projection session protections (if they start a projection session)
    private final ArraySet<String> mSessionProtectionExemptPackages = new ArraySet<>();
    // Packages exempt from individual notification protections (if they post a notification)
    private final ArraySet<String> mNotificationProtectionExemptPackages = new ArraySet<>();
    private final ListenerSet<Runnable> mListeners = new ListenerSet<>();
    private volatile MediaProjectionInfo mProjection;
    private SensitiveNotificatioMediaProjectionSession mActiveMediaProjectionSession;
@@ -161,6 +165,7 @@ public class SensitiveNotificationProtectionControllerImpl
            MediaProjectionManager mediaProjectionManager,
            IActivityManager activityManager,
            PackageManager packageManager,
            TelephonyManager telephonyManager,
            @Main Handler mainHandler,
            @Background Executor bgExecutor,
            SensitiveNotificationProtectionControllerLogger logger) {
@@ -191,26 +196,18 @@ public class SensitiveNotificationProtectionControllerImpl
        bgExecutor.execute(() -> developerOptionsObserver.onChange(true));

        bgExecutor.execute(() -> {
            ArraySet<String> exemptPackages = new ArraySet<>();
            // Exempt SystemUI
            exemptPackages.add(context.getPackageName());
            ArraySet<String> sessionProtectionExemptPackages =
                    getSessionProtectionExemptPackages(context, activityManager);

            // Exempt approved bug report handlers
            try {
                exemptPackages.addAll(activityManager.getBugreportWhitelistedPackages());
            } catch (RemoteException e) {
                Log.e(
                        LOG_TAG,
                        "Error adding bug report handlers to exemption, continuing without",
                        e);
                // silent failure, skip adding packages to exemption
            }
            ArraySet<String> notificationProtectionExemptPackages =
                    getNotificationProtectionExemptPackages(telephonyManager);

            // if currently projecting, notify listeners of exemption changes
            mainHandler.post(() -> {
                Trace.beginSection("SNPC.exemptPackagesUpdated");
                try {
                    updateExemptPackagesAndNotifyListeners(exemptPackages);
                    updateExemptPackagesAndNotifyListeners(sessionProtectionExemptPackages,
                            notificationProtectionExemptPackages);
                } finally {
                    Trace.endSection();
                }
@@ -220,15 +217,66 @@ public class SensitiveNotificationProtectionControllerImpl
        mediaProjectionManager.addCallback(mMediaProjectionCallback, mainHandler);
    }

    @NonNull
    private static ArraySet<String> getSessionProtectionExemptPackages(Context context,
            IActivityManager activityManager) {
        ArraySet<String> sessionProtectionExemptPackages = new ArraySet<>();
        // Exempt SystemUI
        sessionProtectionExemptPackages.add(context.getPackageName());

        // Exempt approved bug report handlers
        try {
            sessionProtectionExemptPackages.addAll(
                    activityManager.getBugreportWhitelistedPackages());
        } catch (RemoteException e) {
            Log.w(
                    LOG_TAG,
                    "Error adding bug report handlers to exemption, continuing without",
                    e);
            // silent failure, skip adding packages to exemption
        }
        return sessionProtectionExemptPackages;
    }

    @NonNull
    private static ArraySet<String> getNotificationProtectionExemptPackages(
            TelephonyManager telephonyManager) {
        ArraySet<String> notificationProtectionExemptPackages = new ArraySet<>();

        // Get Emergency Assistance Package, all notifications from this package should not be
        // hidden/redacted.
        if (screenshareNotificationHidingBugFix()) {
            try {
                String emergencyAssistancePackageName =
                        telephonyManager.getEmergencyAssistancePackageName();
                if (emergencyAssistancePackageName != null) {
                    notificationProtectionExemptPackages.add(emergencyAssistancePackageName);
                }
            } catch (IllegalStateException e) {
                Log.w(
                        LOG_TAG,
                        "Error adding emergency assistance package to exemption",
                        e);
                // silent failure, skip adding packages to exemption
            }
        }
        return notificationProtectionExemptPackages;
    }

    /**
     * Notify listeners of possible ProjectionState change regardless of current
     * isSensitiveStateActive value. Method used to ensure updates occur after mExemptPackages gets
     * updated, which directly changes the outcome of isSensitiveStateActive
     */
    @MainThread
    private void updateExemptPackagesAndNotifyListeners(ArraySet<String> exemptPackages) {
    private void updateExemptPackagesAndNotifyListeners(
            ArraySet<String> sessionProtectionExemptPackages,
            ArraySet<String> notificationProtectionExemptPackages) {
        Assert.isMainThread();
        mExemptPackages.addAll(exemptPackages);
        mSessionProtectionExemptPackages.addAll(sessionProtectionExemptPackages);
        if (screenshareNotificationHidingBugFix()) {
            mNotificationProtectionExemptPackages.addAll(notificationProtectionExemptPackages);
        }

        if (mProjection != null) {
            updateProjectionStateAndNotifyListeners(mProjection);
@@ -258,7 +306,8 @@ public class SensitiveNotificationProtectionControllerImpl
        if (mDisableScreenShareProtections) {
            Log.w(LOG_TAG, "Screen share protections disabled");
            return null;
        } else if (info != null && mExemptPackages.contains(info.getPackageName())) {
        } else if (info != null
                && mSessionProtectionExemptPackages.contains(info.getPackageName())) {
            Log.w(LOG_TAG, "Screen share protections exempt for package " + info.getPackageName());
            return null;
        } else if (info != null && canRecordSensitiveContent(info.getPackageName())) {
@@ -322,6 +371,11 @@ public class SensitiveNotificationProtectionControllerImpl
            return false; // do not hide/redact notifications from system uid
        }

        if (screenshareNotificationHidingBugFix()
                && mNotificationProtectionExemptPackages.contains(sbn.getPackageName())) {
            return false; // do not hide/redact notifications from emergency app
        }

        // 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();
+3 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.content.pm.PackageManager
import android.media.projection.MediaProjectionManager
import android.os.Handler
import android.platform.test.annotations.DisableFlags
import android.telephony.TelephonyManager
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.server.notification.Flags
@@ -46,6 +47,7 @@ class SensitiveNotificationProtectionControllerFlagDisabledTest : SysuiTestCase(
    @Mock private lateinit var activityManager: IActivityManager
    @Mock private lateinit var mediaProjectionManager: MediaProjectionManager
    @Mock private lateinit var packageManager: PackageManager
    @Mock private lateinit var telephonyManager: TelephonyManager
    private lateinit var controller: SensitiveNotificationProtectionControllerImpl

    @Before
@@ -59,6 +61,7 @@ class SensitiveNotificationProtectionControllerFlagDisabledTest : SysuiTestCase(
                mediaProjectionManager,
                activityManager,
                packageManager,
                telephonyManager,
                handler,
                FakeExecutor(FakeSystemClock()),
                logger
+27 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import android.platform.test.annotations.RequiresFlagsDisabled
import android.platform.test.annotations.RequiresFlagsEnabled
import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS
import android.telephony.TelephonyManager
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
@@ -89,6 +90,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
    @Mock private lateinit var activityManager: IActivityManager
    @Mock private lateinit var mediaProjectionManager: MediaProjectionManager
    @Mock private lateinit var packageManager: PackageManager
    @Mock private lateinit var telephonyManager: TelephonyManager
    @Mock private lateinit var listener1: Runnable
    @Mock private lateinit var listener2: Runnable
    @Mock private lateinit var listener3: Runnable
@@ -141,6 +143,9 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
        whenever(packageManager.checkPermission(anyString(), anyString()))
            .thenReturn(PackageManager.PERMISSION_DENIED)

        whenever(telephonyManager.getEmergencyAssistancePackageName())
            .thenReturn(EMERGENCY_ASSISTANCE_PACKAGE_NAME)

        executor = FakeExecutor(FakeSystemClock())
        globalSettings = FakeGlobalSettings()
        controller =
@@ -150,6 +155,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
                mediaProjectionManager,
                activityManager,
                packageManager,
                telephonyManager,
                mockExecutorHandler(executor),
                executor,
                logger
@@ -406,6 +412,26 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
        assertFalse(controller.shouldProtectNotification(notificationEntry))
    }

    @Test
    @DisableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING_BUG_FIX)
    fun shouldProtectNotification_projectionActive_isFromEmergencyPackage_fixDisabled_true() {
        mediaProjectionCallback.onStart(mediaProjectionInfo)

        val notificationEntry = setupNotificationEntry(EMERGENCY_ASSISTANCE_PACKAGE_NAME)

        assertTrue(controller.shouldProtectNotification(notificationEntry))
    }

    @Test
    @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING_BUG_FIX)
    fun shouldProtectNotification_projectionActive_isFromEmergencyPackage_false() {
        mediaProjectionCallback.onStart(mediaProjectionInfo)

        val notificationEntry = setupNotificationEntry(EMERGENCY_ASSISTANCE_PACKAGE_NAME)

        assertFalse(controller.shouldProtectNotification(notificationEntry))
    }

    @Test
    fun shouldProtectNotification_projectionActive_sysuiExempt_false() {
        // SystemUi context package name is exempt, but in test scenarios its
@@ -742,6 +768,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
        private const val TEST_PROJECTION_PACKAGE_NAME =
            "com.android.systemui.statusbar.policy.projectionpackage"
        private const val TEST_PACKAGE_NAME = "com.android.systemui.statusbar.policy.testpackage"
        private const val EMERGENCY_ASSISTANCE_PACKAGE_NAME = "com.android.test.emergencyassistance"
        private const val BUGREPORT_PACKAGE_NAME = "com.android.test.bugreporthandler"
    }
}