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

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

Merge "Do no redact emergency notifications" into main

parents 75799de7 284021ca
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"
    }
}