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

Commit 2d07610d authored by Naomi Musgrave's avatar Naomi Musgrave Committed by Android (Google) Code Review
Browse files

Merge "[MediaProjection] clarify cases handled by controller" into udc-dev

parents 4422a56b 08e913c5
Loading
Loading
Loading
Loading
+73 −22
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DataClass;

import java.lang.annotation.Retention;
@@ -72,10 +71,17 @@ public final class ContentRecordingSession implements Parcelable {
     * If {@link #getContentToRecord()} is {@link RecordContent#RECORD_CONTENT_TASK}, then
     * represents the {@link android.window.WindowContainerToken} of the Task to record.
     */
    @VisibleForTesting
    @Nullable
    private IBinder mTokenToRecord = null;

    /**
     * When {@code true}, no mirroring should take place until the user has re-granted access to
     * the consent token. When {@code false}, recording can begin immediately.
     *
     * <p>Only set on the server side to sanitize any input from the client process.
     */
    private boolean mWaitingToRecord = false;

    /**
     * Default instance, with recording the display.
     */
@@ -109,9 +115,10 @@ public final class ContentRecordingSession implements Parcelable {
    }

    /**
     * Returns {@code true} when both sessions are for the same display.
     * Returns {@code true} when both sessions are on the same
     * {@link android.hardware.display.VirtualDisplay}.
     */
    public static boolean isSameDisplay(ContentRecordingSession session,
    public static boolean isProjectionOnSameDisplay(ContentRecordingSession session,
            ContentRecordingSession incomingSession) {
        return session != null && incomingSession != null
                && session.getDisplayId() == incomingSession.getDisplayId();
@@ -156,7 +163,8 @@ public final class ContentRecordingSession implements Parcelable {
    /* package-private */ ContentRecordingSession(
            int displayId,
            @RecordContent int contentToRecord,
            @VisibleForTesting @Nullable IBinder tokenToRecord) {
            @Nullable IBinder tokenToRecord,
            boolean waitingToRecord) {
        this.mDisplayId = displayId;
        this.mContentToRecord = contentToRecord;

@@ -169,8 +177,7 @@ public final class ContentRecordingSession implements Parcelable {
        }

        this.mTokenToRecord = tokenToRecord;
        com.android.internal.util.AnnotationValidations.validate(
                VisibleForTesting.class, null, mTokenToRecord);
        this.mWaitingToRecord = waitingToRecord;

        // onConstructed(); // You can define this method to get a callback
    }
@@ -200,10 +207,21 @@ public final class ContentRecordingSession implements Parcelable {
     * represents the {@link android.window.WindowContainerToken} of the Task to record.
     */
    @DataClass.Generated.Member
    public @VisibleForTesting @Nullable IBinder getTokenToRecord() {
    public @Nullable IBinder getTokenToRecord() {
        return mTokenToRecord;
    }

    /**
     * When {@code true}, no mirroring should take place until the user has re-granted access to
     * the consent token. When {@code false}, recording can begin immediately.
     *
     * <p>Only set on the server side to sanitize any input from the client process.
     */
    @DataClass.Generated.Member
    public boolean isWaitingToRecord() {
        return mWaitingToRecord;
    }

    /**
     * Unique logical identifier of the {@link android.hardware.display.VirtualDisplay} that has
     * recorded content rendered to its surface.
@@ -240,10 +258,20 @@ public final class ContentRecordingSession implements Parcelable {
     * represents the {@link android.window.WindowContainerToken} of the Task to record.
     */
    @DataClass.Generated.Member
    public @NonNull ContentRecordingSession setTokenToRecord(@VisibleForTesting @NonNull IBinder value) {
    public @NonNull ContentRecordingSession setTokenToRecord(@NonNull IBinder value) {
        mTokenToRecord = value;
        com.android.internal.util.AnnotationValidations.validate(
                VisibleForTesting.class, null, mTokenToRecord);
        return this;
    }

    /**
     * When {@code true}, no mirroring should take place until the user has re-granted access to
     * the consent token. When {@code false}, recording can begin immediately.
     *
     * <p>Only set on the server side to sanitize any input from the client process.
     */
    @DataClass.Generated.Member
    public @NonNull ContentRecordingSession setWaitingToRecord( boolean value) {
        mWaitingToRecord = value;
        return this;
    }

@@ -256,7 +284,8 @@ public final class ContentRecordingSession implements Parcelable {
        return "ContentRecordingSession { " +
                "displayId = " + mDisplayId + ", " +
                "contentToRecord = " + recordContentToString(mContentToRecord) + ", " +
                "tokenToRecord = " + mTokenToRecord +
                "tokenToRecord = " + mTokenToRecord + ", " +
                "waitingToRecord = " + mWaitingToRecord +
        " }";
    }

@@ -275,7 +304,8 @@ public final class ContentRecordingSession implements Parcelable {
        return true
                && mDisplayId == that.mDisplayId
                && mContentToRecord == that.mContentToRecord
                && java.util.Objects.equals(mTokenToRecord, that.mTokenToRecord);
                && java.util.Objects.equals(mTokenToRecord, that.mTokenToRecord)
                && mWaitingToRecord == that.mWaitingToRecord;
    }

    @Override
@@ -288,6 +318,7 @@ public final class ContentRecordingSession implements Parcelable {
        _hash = 31 * _hash + mDisplayId;
        _hash = 31 * _hash + mContentToRecord;
        _hash = 31 * _hash + java.util.Objects.hashCode(mTokenToRecord);
        _hash = 31 * _hash + Boolean.hashCode(mWaitingToRecord);
        return _hash;
    }

@@ -298,6 +329,7 @@ public final class ContentRecordingSession implements Parcelable {
        // void parcelFieldName(Parcel dest, int flags) { ... }

        byte flg = 0;
        if (mWaitingToRecord) flg |= 0x8;
        if (mTokenToRecord != null) flg |= 0x4;
        dest.writeByte(flg);
        dest.writeInt(mDisplayId);
@@ -317,6 +349,7 @@ public final class ContentRecordingSession implements Parcelable {
        // static FieldType unparcelFieldName(Parcel in) { ... }

        byte flg = in.readByte();
        boolean waitingToRecord = (flg & 0x8) != 0;
        int displayId = in.readInt();
        int contentToRecord = in.readInt();
        IBinder tokenToRecord = (flg & 0x4) == 0 ? null : (IBinder) in.readStrongBinder();
@@ -333,8 +366,7 @@ public final class ContentRecordingSession implements Parcelable {
        }

        this.mTokenToRecord = tokenToRecord;
        com.android.internal.util.AnnotationValidations.validate(
                VisibleForTesting.class, null, mTokenToRecord);
        this.mWaitingToRecord = waitingToRecord;

        // onConstructed(); // You can define this method to get a callback
    }
@@ -362,7 +394,8 @@ public final class ContentRecordingSession implements Parcelable {

        private int mDisplayId;
        private @RecordContent int mContentToRecord;
        private @VisibleForTesting @Nullable IBinder mTokenToRecord;
        private @Nullable IBinder mTokenToRecord;
        private boolean mWaitingToRecord;

        private long mBuilderFieldsSet = 0L;

@@ -400,17 +433,31 @@ public final class ContentRecordingSession implements Parcelable {
         * represents the {@link android.window.WindowContainerToken} of the Task to record.
         */
        @DataClass.Generated.Member
        public @NonNull Builder setTokenToRecord(@VisibleForTesting @NonNull IBinder value) {
        public @NonNull Builder setTokenToRecord(@NonNull IBinder value) {
            checkNotUsed();
            mBuilderFieldsSet |= 0x4;
            mTokenToRecord = value;
            return this;
        }

        /**
         * When {@code true}, no mirroring should take place until the user has re-granted access to
         * the consent token. When {@code false}, recording can begin immediately.
         *
         * <p>Only set on the server side to sanitize any input from the client process.
         */
        @DataClass.Generated.Member
        public @NonNull Builder setWaitingToRecord(boolean value) {
            checkNotUsed();
            mBuilderFieldsSet |= 0x8;
            mWaitingToRecord = value;
            return this;
        }

        /** Builds the instance. This builder should not be touched after calling this! */
        public @NonNull ContentRecordingSession build() {
            checkNotUsed();
            mBuilderFieldsSet |= 0x8; // Mark builder used
            mBuilderFieldsSet |= 0x10; // Mark builder used

            if ((mBuilderFieldsSet & 0x1) == 0) {
                mDisplayId = INVALID_DISPLAY;
@@ -421,15 +468,19 @@ public final class ContentRecordingSession implements Parcelable {
            if ((mBuilderFieldsSet & 0x4) == 0) {
                mTokenToRecord = null;
            }
            if ((mBuilderFieldsSet & 0x8) == 0) {
                mWaitingToRecord = false;
            }
            ContentRecordingSession o = new ContentRecordingSession(
                    mDisplayId,
                    mContentToRecord,
                    mTokenToRecord);
                    mTokenToRecord,
                    mWaitingToRecord);
            return o;
        }

        private void checkNotUsed() {
            if ((mBuilderFieldsSet & 0x8) != 0) {
            if ((mBuilderFieldsSet & 0x10) != 0) {
                throw new IllegalStateException(
                        "This Builder should not be reused. Use a new Builder instance instead");
            }
@@ -437,10 +488,10 @@ public final class ContentRecordingSession implements Parcelable {
    }

    @DataClass.Generated(
            time = 1645803878639L,
            time = 1678817765846L,
            codegenVersion = "1.0.23",
            sourceFile = "frameworks/base/core/java/android/view/ContentRecordingSession.java",
            inputSignatures = "public static final  int RECORD_CONTENT_DISPLAY\npublic static final  int RECORD_CONTENT_TASK\nprivate  int mDisplayId\nprivate @android.view.ContentRecordingSession.RecordContent int mContentToRecord\nprivate @com.android.internal.annotations.VisibleForTesting @android.annotation.Nullable android.os.IBinder mTokenToRecord\npublic static  android.view.ContentRecordingSession createDisplaySession(android.os.IBinder)\npublic static  android.view.ContentRecordingSession createTaskSession(android.os.IBinder)\npublic static  boolean isValid(android.view.ContentRecordingSession)\npublic static  boolean isSameDisplay(android.view.ContentRecordingSession,android.view.ContentRecordingSession)\nclass ContentRecordingSession extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true, genSetters=true, genEqualsHashCode=true)")
            inputSignatures = "public static final  int RECORD_CONTENT_DISPLAY\npublic static final  int RECORD_CONTENT_TASK\nprivate  int mDisplayId\nprivate @android.view.ContentRecordingSession.RecordContent int mContentToRecord\nprivate @android.annotation.Nullable android.os.IBinder mTokenToRecord\nprivate  boolean mWaitingToRecord\npublic static  android.view.ContentRecordingSession createDisplaySession(android.os.IBinder)\npublic static  android.view.ContentRecordingSession createTaskSession(android.os.IBinder)\npublic static  boolean isValid(android.view.ContentRecordingSession)\npublic static  boolean isProjectionOnSameDisplay(android.view.ContentRecordingSession,android.view.ContentRecordingSession)\nclass ContentRecordingSession extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true, genSetters=true, genEqualsHashCode=true)")
    @Deprecated
    private void __metadata() {}

+1 −1
Original line number Diff line number Diff line
@@ -85,7 +85,7 @@ public enum ProtoLogGroup implements IProtoLogGroup {
            Consts.TAG_WM),
    WM_DEBUG_WINDOW_INSETS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
            Consts.TAG_WM),
    WM_DEBUG_CONTENT_RECORDING(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
    WM_DEBUG_CONTENT_RECORDING(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
            Consts.TAG_WM),
    WM_DEBUG_WALLPAPER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM),
    WM_DEBUG_BACK_PREVIEW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
+7 −5
Original line number Diff line number Diff line
@@ -89,20 +89,22 @@ public class ContentRecordingSessionTest {
    }

    @Test
    public void testIsSameDisplay() {
        assertThat(ContentRecordingSession.isSameDisplay(null, null)).isFalse();
    public void testIsProjectionOnSameDisplay() {
        assertThat(ContentRecordingSession.isProjectionOnSameDisplay(null, null)).isFalse();
        ContentRecordingSession session = ContentRecordingSession.createDisplaySession(
                WINDOW_TOKEN);
        session.setDisplayId(DEFAULT_DISPLAY);
        assertThat(ContentRecordingSession.isSameDisplay(session, null)).isFalse();
        assertThat(ContentRecordingSession.isProjectionOnSameDisplay(session, null)).isFalse();

        ContentRecordingSession incomingSession = ContentRecordingSession.createDisplaySession(
                WINDOW_TOKEN);
        incomingSession.setDisplayId(DEFAULT_DISPLAY);
        assertThat(ContentRecordingSession.isSameDisplay(session, incomingSession)).isTrue();
        assertThat(ContentRecordingSession.isProjectionOnSameDisplay(session,
                incomingSession)).isTrue();

        incomingSession.setDisplayId(DEFAULT_DISPLAY + 1);
        assertThat(ContentRecordingSession.isSameDisplay(session, incomingSession)).isFalse();
        assertThat(ContentRecordingSession.isProjectionOnSameDisplay(session,
                incomingSession)).isFalse();
    }

    @Test
+152 −146

File changed.

Preview size limit exceeded, changes collapsed.

+37 −30
Original line number Diff line number Diff line
@@ -143,14 +143,15 @@ final class ContentRecorder implements WindowContainerListener {
            // Recording has already begun, but update recording since the display is now on.
            if (mRecordedWindowContainer == null) {
                ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                        "Unexpectedly null window container; unable to update recording for "
                                + "display %d",
                        "Content Recording: Unexpectedly null window container; unable to update "
                                + "recording for display %d",
                        mDisplayContent.getDisplayId());
                return;
            }

            ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                    "Display %d was already recording, so apply transformations if necessary",
                    "Content Recording: Display %d was already recording, so apply "
                            + "transformations if necessary",
                    mDisplayContent.getDisplayId());
            // Retrieve the size of the region to record, and continue with the update
            // if the bounds or orientation has changed.
@@ -161,8 +162,8 @@ final class ContentRecorder implements WindowContainerListener {
                Point surfaceSize = fetchSurfaceSizeIfPresent();
                if (surfaceSize != null) {
                    ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                            "Going ahead with updating recording for display %d to new "
                                    + "bounds %s and/or orientation %d.",
                            "Content Recording: Going ahead with updating recording for display "
                                    + "%d to new bounds %s and/or orientation %d.",
                            mDisplayContent.getDisplayId(), recordedContentBounds,
                            recordedContentOrientation);
                    updateMirroredSurface(mDisplayContent.mWmService.mTransactionFactory.get(),
@@ -171,8 +172,9 @@ final class ContentRecorder implements WindowContainerListener {
                    // If the surface removed, do nothing. We will handle this via onDisplayChanged
                    // (the display will be off if the surface is removed).
                    ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                            "Unable to update recording for display %d to new bounds %s"
                                    + " and/or orientation %d, since the surface is not available.",
                            "Content Recording: Unable to update recording for display %d to new "
                                    + "bounds %s and/or orientation %d, since the surface is not "
                                    + "available.",
                            mDisplayContent.getDisplayId(), recordedContentBounds,
                            recordedContentOrientation);
                }
@@ -189,8 +191,8 @@ final class ContentRecorder implements WindowContainerListener {
            return;
        }
        ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                "Display %d has content (%b) so pause recording", mDisplayContent.getDisplayId(),
                mDisplayContent.getLastHasContent());
                "Content Recording: Display %d has content (%b) so pause recording",
                mDisplayContent.getDisplayId(), mDisplayContent.getLastHasContent());
        // If the display is not on and it is a virtual display, then it no longer has an
        // associated surface to write output to.
        // If the display now has content, stop mirroring to it.
@@ -231,7 +233,8 @@ final class ContentRecorder implements WindowContainerListener {
     */
    private void stopMediaProjection() {
        ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                "Stop MediaProjection on virtual display %d", mDisplayContent.getDisplayId());
                "Content Recording: Stop MediaProjection on virtual display %d",
                mDisplayContent.getDisplayId());
        if (mMediaProjectionManager != null) {
            mMediaProjectionManager.stopActiveProjection();
        }
@@ -283,13 +286,14 @@ final class ContentRecorder implements WindowContainerListener {
        final Point surfaceSize = fetchSurfaceSizeIfPresent();
        if (surfaceSize == null) {
            ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                    "Unable to start recording for display %d since the surface is not "
                            + "available.",
                    "Content Recording: Unable to start recording for display %d since the "
                            + "surface is not available.",
                    mDisplayContent.getDisplayId());
            return;
        }
        ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                "Display %d has no content and is on, so start recording for state %d",
                "Content Recording: Display %d has no content and is on, so start recording for "
                        + "state %d",
                mDisplayContent.getDisplayId(), mDisplayContent.getDisplay().getState());

        // Create a mirrored hierarchy for the SurfaceControl of the DisplayArea to capture.
@@ -349,7 +353,7 @@ final class ContentRecorder implements WindowContainerListener {
        if (tokenToRecord == null) {
            handleStartRecordingFailed();
            ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                    "Unable to start recording due to null token for display %d",
                    "Content Recording: Unable to start recording due to null token for display %d",
                    mDisplayContent.getDisplayId());
            return null;
        }
@@ -359,13 +363,14 @@ final class ContentRecorder implements WindowContainerListener {
                        mDisplayContent.mWmService.mWindowContextListenerController.getContainer(
                                tokenToRecord);
                if (wc == null) {
                    // Fall back to screenrecording using the data sent to DisplayManager
                    // Fall back to mirroring using the data sent to DisplayManager
                    mDisplayContent.mWmService.mDisplayManagerInternal.setWindowManagerMirroring(
                            mDisplayContent.getDisplayId(), false);
                    handleStartRecordingFailed();
                    ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                            "Unable to retrieve window container to start recording for "
                                    + "display %d", mDisplayContent.getDisplayId());
                            "Content Recording: Unable to retrieve window container to start "
                                    + "recording for display %d",
                            mDisplayContent.getDisplayId());
                    return null;
                }
                // TODO(206461622) Migrate to using the RootDisplayArea
@@ -375,7 +380,7 @@ final class ContentRecorder implements WindowContainerListener {
                        KEY_RECORD_TASK_FEATURE, false)) {
                    handleStartRecordingFailed();
                    ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                            "Unable to record task since feature is disabled %d",
                            "Content Recording: Unable to record task since feature is disabled %d",
                            mDisplayContent.getDisplayId());
                    return null;
                }
@@ -383,8 +388,9 @@ final class ContentRecorder implements WindowContainerListener {
                if (taskToRecord == null) {
                    handleStartRecordingFailed();
                    ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                            "Unable to retrieve task to start recording for "
                                    + "display %d", mDisplayContent.getDisplayId());
                            "Content Recording: Unable to retrieve task to start recording for "
                                    + "display %d",
                            mDisplayContent.getDisplayId());
                } else {
                    taskToRecord.registerWindowContainerListener(this);
                }
@@ -394,7 +400,8 @@ final class ContentRecorder implements WindowContainerListener {
                // capture for the entire display.
                handleStartRecordingFailed();
                ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                        "Unable to start recording due to invalid region for display %d",
                        "Content Recording: Unable to start recording due to invalid region for "
                                + "display %d",
                        mDisplayContent.getDisplayId());
                return null;
        }
@@ -488,8 +495,8 @@ final class ContentRecorder implements WindowContainerListener {
            // State of virtual display will change to 'ON' when the surface is set.
            // will get event DISPLAY_DEVICE_EVENT_CHANGED
            ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                    "Provided surface for recording on display %d is not present, so do not"
                            + " update the surface",
                    "Content Recording: Provided surface for recording on display %d is not "
                            + "present, so do not update the surface",
                    mDisplayContent.getDisplayId());
            return null;
        }
@@ -500,7 +507,7 @@ final class ContentRecorder implements WindowContainerListener {
    @Override
    public void onRemoved() {
        ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                "Recorded task is removed, so stop recording on display %d",
                "Content Recording: Recorded task is removed, so stop recording on display %d",
                mDisplayContent.getDisplayId());

        unregisterListener();
@@ -551,8 +558,8 @@ final class ContentRecorder implements WindowContainerListener {
                mIMediaProjectionManager.stopActiveProjection();
            } catch (RemoteException e) {
                ProtoLog.e(WM_DEBUG_CONTENT_RECORDING,
                        "Unable to tell MediaProjectionManagerService to stop the active "
                                + "projection: %s",
                        "Content Recording: Unable to tell MediaProjectionManagerService to stop "
                                + "the active projection: %s",
                        e);
            }
        }
@@ -568,8 +575,8 @@ final class ContentRecorder implements WindowContainerListener {
                        height);
            } catch (RemoteException e) {
                ProtoLog.e(WM_DEBUG_CONTENT_RECORDING,
                        "Unable to tell MediaProjectionManagerService about resizing the active "
                                + "projection: %s",
                        "Content Recording: Unable to tell MediaProjectionManagerService about "
                                + "resizing the active projection: %s",
                        e);
            }
        }
@@ -585,8 +592,8 @@ final class ContentRecorder implements WindowContainerListener {
                        isVisible);
            } catch (RemoteException e) {
                ProtoLog.e(WM_DEBUG_CONTENT_RECORDING,
                        "Unable to tell MediaProjectionManagerService about visibility change on "
                                + "the active projection: %s",
                        "Content Recording: Unable to tell MediaProjectionManagerService about "
                                + "visibility change on the active projection: %s",
                        e);
            }
        }
Loading