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

Commit 56e0f4a6 authored by Naomi Musgrave's avatar Naomi Musgrave Committed by Automerger Merge Worker
Browse files

Merge "[Partial Screenshare] Respond to task changes" into tm-qpr-dev am: f5a7752b

parents 997ef747 f5a7752b
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -1105,6 +1105,12 @@
      "group": "WM_DEBUG_TASKS",
      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
    },
    "-1018968224": {
      "message": "Recorded task is removed, so stop recording on display %d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/ContentRecorder.java"
    },
    "-1016578046": {
      "message": "Moving to %s Relaunching %s callers=%s",
      "level": "INFO",
@@ -2251,6 +2257,12 @@
      "group": "WM_DEBUG_FOCUS",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "96494268": {
      "message": "Stop MediaProjection on virtual display %d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONTENT_RECORDING",
      "at": "com\/android\/server\/wm\/ContentRecorder.java"
    },
    "100936473": {
      "message": "Wallpaper animation!",
      "level": "VERBOSE",
+0 −2
Original line number Diff line number Diff line
@@ -70,8 +70,6 @@ import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayGroupListener;
import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
import android.hardware.display.DisplayViewport;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
+9 −4
Original line number Diff line number Diff line
@@ -335,7 +335,7 @@ public final class MediaProjectionManagerService extends SystemService

        @Override // Binder call
        public void stopActiveProjection() {
            if (mContext.checkCallingPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
            if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_MEDIA_PROJECTION)
                    != PackageManager.PERMISSION_GRANTED) {
                throw new SecurityException("Requires MANAGE_MEDIA_PROJECTION in order to add "
                        + "projection callbacks");
@@ -393,9 +393,14 @@ public final class MediaProjectionManagerService extends SystemService
                    if (!isValidMediaProjection(projection)) {
                        throw new SecurityException("Invalid media projection");
                    }
                    LocalServices.getService(
                    if (!LocalServices.getService(
                            WindowManagerInternal.class).setContentRecordingSession(
                            incomingSession);
                            incomingSession)) {
                        // Unable to start mirroring, so tear down this projection.
                        if (mProjectionGrant != null) {
                            mProjectionGrant.stop();
                        }
                    }
                }
            } finally {
                Binder.restoreCallingIdentity(origId);
+81 −22
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.wm;

import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import static android.view.ContentRecordingSession.RECORD_CONTENT_DISPLAY;
import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;

@@ -26,6 +27,7 @@ import android.annotation.Nullable;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.media.projection.MediaProjectionManager;
import android.os.IBinder;
import android.provider.DeviceConfig;
import android.view.ContentRecordingSession;
@@ -38,7 +40,7 @@ import com.android.internal.protolog.common.ProtoLog;
/**
 * Manages content recording for a particular {@link DisplayContent}.
 */
final class ContentRecorder {
final class ContentRecorder implements WindowContainerListener {

    /**
     * The key for accessing the device config that controls if task recording is supported.
@@ -51,6 +53,8 @@ final class ContentRecorder {
    @NonNull
    private final DisplayContent mDisplayContent;

    @Nullable private final MediaProjectionManagerWrapper mMediaProjectionManager;

    /**
     * The session for content recording, or null if this DisplayContent is not being used for
     * recording.
@@ -73,8 +77,26 @@ final class ContentRecorder {
     */
    @Nullable private Rect mLastRecordedBounds = null;

    /**
     * The last configuration orientation.
     */
    private int mLastOrientation = ORIENTATION_UNDEFINED;

    ContentRecorder(@NonNull DisplayContent displayContent) {
        this(displayContent, () -> {
            MediaProjectionManager mpm = displayContent.mWmService.mContext.getSystemService(
                    MediaProjectionManager.class);
            if (mpm != null) {
                mpm.stopActiveProjection();
            }
        });
    }

    @VisibleForTesting
    ContentRecorder(@NonNull DisplayContent displayContent,
            @NonNull MediaProjectionManagerWrapper mediaProjectionManager) {
        mDisplayContent = displayContent;
        mMediaProjectionManager = mediaProjectionManager;
    }

    /**
@@ -95,7 +117,7 @@ final class ContentRecorder {
    }

    /**
     * Start recording if this DisplayContent no longer has content. Stop recording if it now
     * Start recording if this DisplayContent no longer has content. Pause recording if it now
     * has content or the display is not on.
     */
    @VisibleForTesting void updateRecording() {
@@ -187,7 +209,7 @@ final class ContentRecorder {
    /**
     * Stops recording on this DisplayContent, and updates the session details.
     */
    void remove() {
    void stopRecording() {
        if (mRecordedSurface != null) {
            // Do not wait for the mirrored surface to be garbage collected, but clean up
            // immediately.
@@ -195,7 +217,20 @@ final class ContentRecorder {
            mRecordedSurface = null;
            clearContentRecordingSession();
            // Do not need to force remove the VirtualDisplay; this is handled by the media
            // projection service.
            // projection service when the display is removed.
        }
    }


    /**
     * Ensure recording does not fall back to the display stack; ensure the recording is stopped
     * and the client notified by tearing down the virtual display.
     */
    void stopMediaProjection() {
        ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                "Stop MediaProjection on virtual display %d", mDisplayContent.getDisplayId());
        if (mMediaProjectionManager != null) {
            mMediaProjectionManager.stopActiveProjection();
        }
    }

@@ -326,6 +361,8 @@ final class ContentRecorder {
                    ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                            "Unable to retrieve task to start recording for "
                                    + "display %d", mDisplayContent.getDisplayId());
                } else {
                    taskToRecord.registerWindowContainerListener(this);
                }
                return taskToRecord;
            default:
@@ -342,9 +379,9 @@ final class ContentRecorder {
    /**
     * Exit this recording session.
     * <p>
     * If this is a task session, tear down the recording entirely. Do not fall back
     * to recording the entire display on the display stack; this would surprise the user
     * given they selected task capture.
     * If this is a task session, stop the recording entirely, including the MediaProjection.
     * Do not fall back to recording the entire display on the display stack; this would surprise
     * the user given they selected task capture.
     * </p><p>
     * If this is a display session, just stop recording by layer mirroring. Fall back to recording
     * from the display stack.
@@ -353,25 +390,14 @@ final class ContentRecorder {
    private void handleStartRecordingFailed() {
        final boolean shouldExitTaskRecording = mContentRecordingSession != null
                && mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK;
        if (shouldExitTaskRecording) {
            // Clean up the cached session first, since tearing down the display will generate
            // display
            // events which will trickle back to here.
            clearContentRecordingSession();
            tearDownVirtualDisplay();
        } else {
        clearContentRecordingSession();
        if (shouldExitTaskRecording) {
            // Clean up the cached session first to ensure recording doesn't re-start, since
            // tearing down the display will generate display events which will trickle back here.
            stopMediaProjection();
        }
    }

    /**
     * Ensure recording does not fall back to the display stack; ensure the recording is stopped
     * and the client notified by tearing down the virtual display.
     */
    private void tearDownVirtualDisplay() {
        // TODO(b/219761722) Clean up the VirtualDisplay if task mirroring fails
    }

    /**
     * Apply transformations to the mirrored surface to ensure the captured contents are scaled to
     * fit and centred in the output surface.
@@ -442,4 +468,37 @@ final class ContentRecorder {
        }
        return surfaceSize;
    }

    // WindowContainerListener
    @Override
    public void onRemoved() {
        ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                "Recorded task is removed, so stop recording on display %d",
                mDisplayContent.getDisplayId());
        Task recordedTask = mRecordedWindowContainer.asTask();
        if (recordedTask == null
                || mContentRecordingSession.getContentToRecord() != RECORD_CONTENT_TASK) {
            return;
        }
        recordedTask.unregisterWindowContainerListener(this);
        // Stop mirroring and teardown.
        clearContentRecordingSession();
        // Clean up the cached session first to ensure recording doesn't re-start, since
        // tearing down the display will generate display events which will trickle back here.
        stopMediaProjection();
    }

    // WindowContainerListener
    @Override
    public void onMergedOverrideConfigurationChanged(
            Configuration mergedOverrideConfiguration) {
        WindowContainerListener.super.onMergedOverrideConfigurationChanged(
                mergedOverrideConfiguration);
        onConfigurationChanged(mLastOrientation);
        mLastOrientation = mergedOverrideConfiguration.orientation;
    }

    @VisibleForTesting interface MediaProjectionManagerWrapper {
        void stopActiveProjection();
    }
}
+4 −6
Original line number Diff line number Diff line
@@ -56,14 +56,13 @@ final class ContentRecordingController {
     * Updates the current recording session. If a new display is taking over recording, then
     * stops the prior display from recording.
     *
     * @param incomingSession the new recording session. Should either be {@code null}, to stop
     *                        the current session, or a session on a new/different display than the
     *                        current session.
     * @param incomingSession the new recording session. Should either have a {@code null} token, to
     *                        stop the current session, or a session on a new/different display
     *                        than the current session.
     * @param wmService       the window manager service
     */
    void setContentRecordingSessionLocked(@Nullable ContentRecordingSession incomingSession,
            @NonNull WindowManagerService wmService) {
        // TODO(b/219761722) handle a null session arriving due to task setup failing
        if (incomingSession != null && (!ContentRecordingSession.isValid(incomingSession)
                || ContentRecordingSession.isSameDisplay(mSession, incomingSession))) {
            // Ignore an invalid session, or a session for the same display as currently recording.
@@ -82,8 +81,7 @@ final class ContentRecordingController {
        }
        if (mSession != null) {
            // Update the pre-existing display about the new session.
            ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                    "Pause the recording session on display %s",
            ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Pause the recording session on display %s",
                    mDisplayContent.getDisplayId());
            mDisplayContent.pauseRecording();
            mDisplayContent.setContentRecordingSession(null);
Loading