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

Commit b4fdea64 authored by Marvin Ramin's avatar Marvin Ramin
Browse files

Update phone call end requirements

Only stop MediaProjection upon a phone call ending when the phone call
was started prior to the MediaProjection.

This way phone calls established during a MediaProjection session remain
active when the call ends.

Bug: 377877538
Test: atest MediaProjectionStopControllerTest
Flag: com.android.media.projection.flags.stop_media_projection_on_call_end
Change-Id: I112ce51add55655c2efdaa3726e546f541bf699a
parent aed43401
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -175,7 +175,7 @@ public final class MediaProjectionManagerService extends SystemService

    private void maybeStopMediaProjection(int reason) {
        synchronized (mLock) {
            if (!mMediaProjectionStopController.isExemptFromStopping(mProjectionGrant)) {
            if (!mMediaProjectionStopController.isExemptFromStopping(mProjectionGrant, reason)) {
                Slog.d(TAG, "Content Recording: Stopping MediaProjection due to "
                        + MediaProjectionStopController.stopReasonToString(reason));
                mProjectionGrant.stop();
@@ -1272,6 +1272,10 @@ public final class MediaProjectionManagerService extends SystemService
            return mDisplayId;
        }

        long getCreateTimeMillis() {
            return mCreateTimeMs;
        }

        @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
        @Override
        public boolean isValid() {
+21 −4
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.SystemClock;
import android.provider.Settings;
import android.telecom.TelecomManager;
import android.telephony.TelephonyCallback;
@@ -46,6 +47,8 @@ public class MediaProjectionStopController {

    private static final String TAG = "MediaProjectionStopController";
    @VisibleForTesting
    static final int STOP_REASON_UNKNOWN = 0;
    @VisibleForTesting
    static final int STOP_REASON_KEYGUARD = 1;
    @VisibleForTesting
    static final int STOP_REASON_CALL_END = 2;
@@ -61,6 +64,7 @@ public class MediaProjectionStopController {
    private final ContentResolver mContentResolver;

    private boolean mIsInCall;
    private long mLastCallStartTimeMillis;

    public MediaProjectionStopController(Context context, Consumer<Integer> stopReasonConsumer) {
        mStopReasonConsumer = stopReasonConsumer;
@@ -95,8 +99,8 @@ public class MediaProjectionStopController {
     * Checks whether the given projection grant is exempt from stopping restrictions.
     */
    public boolean isExemptFromStopping(
            MediaProjectionManagerService.MediaProjection projectionGrant) {
        return isExempt(projectionGrant, false);
            MediaProjectionManagerService.MediaProjection projectionGrant, int stopReason) {
        return isExempt(projectionGrant, stopReason, false);
    }

    /**
@@ -110,7 +114,8 @@ public class MediaProjectionStopController {
     * MediaProjection session
     */
    private boolean isExempt(
            MediaProjectionManagerService.MediaProjection projectionGrant, boolean forStart) {
            MediaProjectionManagerService.MediaProjection projectionGrant, int stopReason,
            boolean forStart) {
        if (projectionGrant == null || projectionGrant.packageName == null) {
            return true;
        }
@@ -151,6 +156,14 @@ public class MediaProjectionStopController {
            return true;
        }

        if (stopReason == STOP_REASON_CALL_END
                && projectionGrant.getCreateTimeMillis() < mLastCallStartTimeMillis) {
            Slog.v(TAG,
                    "Continuing MediaProjection as (phone) call started after MediaProjection was"
                            + " created.");
            return true;
        }

        return false;
    }

@@ -167,7 +180,7 @@ public class MediaProjectionStopController {
            return false;
        }

        if (isExempt(projectionGrant, true)) {
        if (isExempt(projectionGrant, STOP_REASON_UNKNOWN, true)) {
            return false;
        }
        return true;
@@ -188,9 +201,13 @@ public class MediaProjectionStopController {
            return;
        }
        boolean isInCall = mTelecomManager.isInCall();
        if (isInCall) {
            mLastCallStartTimeMillis = SystemClock.uptimeMillis();
        }
        if (isInCall == mIsInCall) {
            return;
        }

        if (mIsInCall && !isInCall) {
            mStopReasonConsumer.accept(STOP_REASON_CALL_END);
        }
+48 −9
Original line number Diff line number Diff line
@@ -194,12 +194,14 @@ public class MediaProjectionStopControllerTest {

    @Test
    public void testExemptFromStoppingNullProjection() throws Exception {
        assertThat(mStopController.isExemptFromStopping(null)).isTrue();
        assertThat(mStopController.isExemptFromStopping(null,
                MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
    }

    @Test
    public void testExemptFromStoppingInvalidProjection() throws Exception {
        assertThat(mStopController.isExemptFromStopping(createMediaProjection(null))).isTrue();
        assertThat(mStopController.isExemptFromStopping(createMediaProjection(null),
                MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
    }

    @Test
@@ -213,7 +215,8 @@ public class MediaProjectionStopControllerTest {
            Settings.Global.putInt(mContext.getContentResolver(),
                    DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 1);

            assertThat(mStopController.isExemptFromStopping(mediaProjection)).isTrue();
            assertThat(mStopController.isExemptFromStopping(mediaProjection,
                    MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
        } finally {
            Settings.Global.putInt(mContext.getContentResolver(),
                    DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, value);
@@ -230,7 +233,8 @@ public class MediaProjectionStopControllerTest {
                        eq(mediaProjection.uid), eq(mediaProjection.packageName),
                        nullable(String.class),
                        nullable(String.class));
        assertThat(mStopController.isExemptFromStopping(mediaProjection)).isTrue();
        assertThat(mStopController.isExemptFromStopping(mediaProjection,
                MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
    }

    @Test
@@ -244,7 +248,8 @@ public class MediaProjectionStopControllerTest {
                        doReturn(PackageManager.PERMISSION_DENIED).when(
                                mPackageManager).checkPermission(
                                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
                        assertThat(mStopController.isExemptFromStopping(mediaProjection)).isTrue();
                        assertThat(mStopController.isExemptFromStopping(mediaProjection,
                                MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
@@ -261,7 +266,8 @@ public class MediaProjectionStopControllerTest {
                packages.valueAt(0));
        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
        assertThat(mStopController.isExemptFromStopping(mediaProjection)).isTrue();
        assertThat(mStopController.isExemptFromStopping(mediaProjection,
                MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
    }

    @Test
@@ -270,7 +276,8 @@ public class MediaProjectionStopControllerTest {
                PACKAGE_NAME);
        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
        assertThat(mStopController.isExemptFromStopping(mediaProjection)).isTrue();
        assertThat(mStopController.isExemptFromStopping(mediaProjection,
                MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
    }

    @Test
@@ -278,7 +285,8 @@ public class MediaProjectionStopControllerTest {
        MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
        doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission(
                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
        assertThat(mStopController.isExemptFromStopping(mediaProjection)).isTrue();
        assertThat(mStopController.isExemptFromStopping(mediaProjection,
                MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue();
    }

    @Test
@@ -287,7 +295,8 @@ public class MediaProjectionStopControllerTest {
        mediaProjection.notifyVirtualDisplayCreated(1);
        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);
        assertThat(mStopController.isExemptFromStopping(mediaProjection)).isFalse();
        assertThat(mStopController.isExemptFromStopping(mediaProjection,
                MediaProjectionStopController.STOP_REASON_UNKNOWN)).isFalse();
    }

    @Test
@@ -368,6 +377,36 @@ public class MediaProjectionStopControllerTest {
        verify(mStopConsumer).accept(MediaProjectionStopController.STOP_REASON_CALL_END);
    }

    @Test
    @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END)
    public void testExemptFromStopping_callEnd_callBeforeMediaProjection() throws Exception {
        when(mTelecomManager.isInCall()).thenReturn(true);
        mStopController.callStateChanged();

        MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
        mediaProjection.notifyVirtualDisplayCreated(1);
        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);

        assertThat(mStopController.isExemptFromStopping(mediaProjection,
                MediaProjectionStopController.STOP_REASON_CALL_END)).isFalse();
    }

    @Test
    @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END)
    public void testExemptFromStopping_callEnd_callAfterMediaProjection() throws Exception {
        MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection();
        mediaProjection.notifyVirtualDisplayCreated(1);
        doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission(
                RECORD_SENSITIVE_CONTENT, mediaProjection.packageName);

        when(mTelecomManager.isInCall()).thenReturn(true);
        mStopController.callStateChanged();

        assertThat(mStopController.isExemptFromStopping(mediaProjection,
                MediaProjectionStopController.STOP_REASON_CALL_END)).isTrue();
    }

    private MediaProjectionManagerService.MediaProjection createMediaProjection()
            throws NameNotFoundException {
        return createMediaProjection(PACKAGE_NAME);