Merge "(5/N)[MediaProjection] Send no frames until user reviews consent" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
9736133ffc
@@ -87,7 +87,7 @@ public final class ContentRecordingSession implements Parcelable {
|
|||||||
*
|
*
|
||||||
* <p>Only set on the server side to sanitize any input from the client process.
|
* <p>Only set on the server side to sanitize any input from the client process.
|
||||||
*/
|
*/
|
||||||
private boolean mWaitingToRecord = false;
|
private boolean mWaitingForConsent = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default instance, with recording the display.
|
* Default instance, with recording the display.
|
||||||
@@ -181,7 +181,7 @@ public final class ContentRecordingSession implements Parcelable {
|
|||||||
@RecordContent int contentToRecord,
|
@RecordContent int contentToRecord,
|
||||||
int displayToRecord,
|
int displayToRecord,
|
||||||
@Nullable IBinder tokenToRecord,
|
@Nullable IBinder tokenToRecord,
|
||||||
boolean waitingToRecord) {
|
boolean waitingForConsent) {
|
||||||
this.mVirtualDisplayId = virtualDisplayId;
|
this.mVirtualDisplayId = virtualDisplayId;
|
||||||
this.mContentToRecord = contentToRecord;
|
this.mContentToRecord = contentToRecord;
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ public final class ContentRecordingSession implements Parcelable {
|
|||||||
|
|
||||||
this.mDisplayToRecord = displayToRecord;
|
this.mDisplayToRecord = displayToRecord;
|
||||||
this.mTokenToRecord = tokenToRecord;
|
this.mTokenToRecord = tokenToRecord;
|
||||||
this.mWaitingToRecord = waitingToRecord;
|
this.mWaitingForConsent = waitingForConsent;
|
||||||
|
|
||||||
// onConstructed(); // You can define this method to get a callback
|
// onConstructed(); // You can define this method to get a callback
|
||||||
}
|
}
|
||||||
@@ -246,8 +246,8 @@ public final class ContentRecordingSession implements Parcelable {
|
|||||||
* <p>Only set on the server side to sanitize any input from the client process.
|
* <p>Only set on the server side to sanitize any input from the client process.
|
||||||
*/
|
*/
|
||||||
@DataClass.Generated.Member
|
@DataClass.Generated.Member
|
||||||
public boolean isWaitingToRecord() {
|
public boolean isWaitingForConsent() {
|
||||||
return mWaitingToRecord;
|
return mWaitingForConsent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -309,8 +309,8 @@ public final class ContentRecordingSession implements Parcelable {
|
|||||||
* <p>Only set on the server side to sanitize any input from the client process.
|
* <p>Only set on the server side to sanitize any input from the client process.
|
||||||
*/
|
*/
|
||||||
@DataClass.Generated.Member
|
@DataClass.Generated.Member
|
||||||
public @NonNull ContentRecordingSession setWaitingToRecord( boolean value) {
|
public @NonNull ContentRecordingSession setWaitingForConsent( boolean value) {
|
||||||
mWaitingToRecord = value;
|
mWaitingForConsent = value;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,7 +325,7 @@ public final class ContentRecordingSession implements Parcelable {
|
|||||||
"contentToRecord = " + recordContentToString(mContentToRecord) + ", " +
|
"contentToRecord = " + recordContentToString(mContentToRecord) + ", " +
|
||||||
"displayToRecord = " + mDisplayToRecord + ", " +
|
"displayToRecord = " + mDisplayToRecord + ", " +
|
||||||
"tokenToRecord = " + mTokenToRecord + ", " +
|
"tokenToRecord = " + mTokenToRecord + ", " +
|
||||||
"waitingToRecord = " + mWaitingToRecord +
|
"waitingForConsent = " + mWaitingForConsent +
|
||||||
" }";
|
" }";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,7 +346,7 @@ public final class ContentRecordingSession implements Parcelable {
|
|||||||
&& mContentToRecord == that.mContentToRecord
|
&& mContentToRecord == that.mContentToRecord
|
||||||
&& mDisplayToRecord == that.mDisplayToRecord
|
&& mDisplayToRecord == that.mDisplayToRecord
|
||||||
&& java.util.Objects.equals(mTokenToRecord, that.mTokenToRecord)
|
&& java.util.Objects.equals(mTokenToRecord, that.mTokenToRecord)
|
||||||
&& mWaitingToRecord == that.mWaitingToRecord;
|
&& mWaitingForConsent == that.mWaitingForConsent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -360,7 +360,7 @@ public final class ContentRecordingSession implements Parcelable {
|
|||||||
_hash = 31 * _hash + mContentToRecord;
|
_hash = 31 * _hash + mContentToRecord;
|
||||||
_hash = 31 * _hash + mDisplayToRecord;
|
_hash = 31 * _hash + mDisplayToRecord;
|
||||||
_hash = 31 * _hash + java.util.Objects.hashCode(mTokenToRecord);
|
_hash = 31 * _hash + java.util.Objects.hashCode(mTokenToRecord);
|
||||||
_hash = 31 * _hash + Boolean.hashCode(mWaitingToRecord);
|
_hash = 31 * _hash + Boolean.hashCode(mWaitingForConsent);
|
||||||
return _hash;
|
return _hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,7 +371,7 @@ public final class ContentRecordingSession implements Parcelable {
|
|||||||
// void parcelFieldName(Parcel dest, int flags) { ... }
|
// void parcelFieldName(Parcel dest, int flags) { ... }
|
||||||
|
|
||||||
byte flg = 0;
|
byte flg = 0;
|
||||||
if (mWaitingToRecord) flg |= 0x10;
|
if (mWaitingForConsent) flg |= 0x10;
|
||||||
if (mTokenToRecord != null) flg |= 0x8;
|
if (mTokenToRecord != null) flg |= 0x8;
|
||||||
dest.writeByte(flg);
|
dest.writeByte(flg);
|
||||||
dest.writeInt(mVirtualDisplayId);
|
dest.writeInt(mVirtualDisplayId);
|
||||||
@@ -392,7 +392,7 @@ public final class ContentRecordingSession implements Parcelable {
|
|||||||
// static FieldType unparcelFieldName(Parcel in) { ... }
|
// static FieldType unparcelFieldName(Parcel in) { ... }
|
||||||
|
|
||||||
byte flg = in.readByte();
|
byte flg = in.readByte();
|
||||||
boolean waitingToRecord = (flg & 0x10) != 0;
|
boolean waitingForConsent = (flg & 0x10) != 0;
|
||||||
int virtualDisplayId = in.readInt();
|
int virtualDisplayId = in.readInt();
|
||||||
int contentToRecord = in.readInt();
|
int contentToRecord = in.readInt();
|
||||||
int displayToRecord = in.readInt();
|
int displayToRecord = in.readInt();
|
||||||
@@ -411,7 +411,7 @@ public final class ContentRecordingSession implements Parcelable {
|
|||||||
|
|
||||||
this.mDisplayToRecord = displayToRecord;
|
this.mDisplayToRecord = displayToRecord;
|
||||||
this.mTokenToRecord = tokenToRecord;
|
this.mTokenToRecord = tokenToRecord;
|
||||||
this.mWaitingToRecord = waitingToRecord;
|
this.mWaitingForConsent = waitingForConsent;
|
||||||
|
|
||||||
// onConstructed(); // You can define this method to get a callback
|
// onConstructed(); // You can define this method to get a callback
|
||||||
}
|
}
|
||||||
@@ -441,7 +441,7 @@ public final class ContentRecordingSession implements Parcelable {
|
|||||||
private @RecordContent int mContentToRecord;
|
private @RecordContent int mContentToRecord;
|
||||||
private int mDisplayToRecord;
|
private int mDisplayToRecord;
|
||||||
private @Nullable IBinder mTokenToRecord;
|
private @Nullable IBinder mTokenToRecord;
|
||||||
private boolean mWaitingToRecord;
|
private boolean mWaitingForConsent;
|
||||||
|
|
||||||
private long mBuilderFieldsSet = 0L;
|
private long mBuilderFieldsSet = 0L;
|
||||||
|
|
||||||
@@ -506,10 +506,10 @@ public final class ContentRecordingSession implements Parcelable {
|
|||||||
* <p>Only set on the server side to sanitize any input from the client process.
|
* <p>Only set on the server side to sanitize any input from the client process.
|
||||||
*/
|
*/
|
||||||
@DataClass.Generated.Member
|
@DataClass.Generated.Member
|
||||||
public @NonNull Builder setWaitingToRecord(boolean value) {
|
public @NonNull Builder setWaitingForConsent(boolean value) {
|
||||||
checkNotUsed();
|
checkNotUsed();
|
||||||
mBuilderFieldsSet |= 0x10;
|
mBuilderFieldsSet |= 0x10;
|
||||||
mWaitingToRecord = value;
|
mWaitingForConsent = value;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -531,14 +531,14 @@ public final class ContentRecordingSession implements Parcelable {
|
|||||||
mTokenToRecord = null;
|
mTokenToRecord = null;
|
||||||
}
|
}
|
||||||
if ((mBuilderFieldsSet & 0x10) == 0) {
|
if ((mBuilderFieldsSet & 0x10) == 0) {
|
||||||
mWaitingToRecord = false;
|
mWaitingForConsent = false;
|
||||||
}
|
}
|
||||||
ContentRecordingSession o = new ContentRecordingSession(
|
ContentRecordingSession o = new ContentRecordingSession(
|
||||||
mVirtualDisplayId,
|
mVirtualDisplayId,
|
||||||
mContentToRecord,
|
mContentToRecord,
|
||||||
mDisplayToRecord,
|
mDisplayToRecord,
|
||||||
mTokenToRecord,
|
mTokenToRecord,
|
||||||
mWaitingToRecord);
|
mWaitingForConsent);
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,10 +551,10 @@ public final class ContentRecordingSession implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@DataClass.Generated(
|
@DataClass.Generated(
|
||||||
time = 1679855157534L,
|
time = 1683628463074L,
|
||||||
codegenVersion = "1.0.23",
|
codegenVersion = "1.0.23",
|
||||||
sourceFile = "frameworks/base/core/java/android/view/ContentRecordingSession.java",
|
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 mVirtualDisplayId\nprivate @android.view.ContentRecordingSession.RecordContent int mContentToRecord\nprivate int mDisplayToRecord\nprivate @android.annotation.Nullable android.os.IBinder mTokenToRecord\nprivate boolean mWaitingToRecord\npublic static android.view.ContentRecordingSession createDisplaySession(int)\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)")
|
inputSignatures = "public static final int RECORD_CONTENT_DISPLAY\npublic static final int RECORD_CONTENT_TASK\nprivate int mVirtualDisplayId\nprivate @android.view.ContentRecordingSession.RecordContent int mContentToRecord\nprivate int mDisplayToRecord\nprivate @android.annotation.Nullable android.os.IBinder mTokenToRecord\nprivate boolean mWaitingForConsent\npublic static android.view.ContentRecordingSession createDisplaySession(int)\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
|
@Deprecated
|
||||||
private void __metadata() {}
|
private void __metadata() {}
|
||||||
|
|
||||||
|
|||||||
@@ -1675,6 +1675,12 @@
|
|||||||
"group": "WM_DEBUG_CONFIGURATION",
|
"group": "WM_DEBUG_CONFIGURATION",
|
||||||
"at": "com\/android\/server\/am\/ActivityManagerService.java"
|
"at": "com\/android\/server\/am\/ActivityManagerService.java"
|
||||||
},
|
},
|
||||||
|
"-584061725": {
|
||||||
|
"message": "Content Recording: Accept session updating same display %d with granted consent, with an existing session %s",
|
||||||
|
"level": "VERBOSE",
|
||||||
|
"group": "WM_DEBUG_CONTENT_RECORDING",
|
||||||
|
"at": "com\/android\/server\/wm\/ContentRecordingController.java"
|
||||||
|
},
|
||||||
"-583031528": {
|
"-583031528": {
|
||||||
"message": "%s",
|
"message": "%s",
|
||||||
"level": "INFO",
|
"level": "INFO",
|
||||||
@@ -2167,6 +2173,12 @@
|
|||||||
"group": "WM_DEBUG_BACK_PREVIEW",
|
"group": "WM_DEBUG_BACK_PREVIEW",
|
||||||
"at": "com\/android\/server\/wm\/TaskFragment.java"
|
"at": "com\/android\/server\/wm\/TaskFragment.java"
|
||||||
},
|
},
|
||||||
|
"-125383273": {
|
||||||
|
"message": "Content Recording: waiting to record, so do nothing",
|
||||||
|
"level": "VERBOSE",
|
||||||
|
"group": "WM_DEBUG_CONTENT_RECORDING",
|
||||||
|
"at": "com\/android\/server\/wm\/ContentRecorder.java"
|
||||||
|
},
|
||||||
"-124316973": {
|
"-124316973": {
|
||||||
"message": "Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s",
|
"message": "Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s",
|
||||||
"level": "VERBOSE",
|
"level": "VERBOSE",
|
||||||
|
|||||||
@@ -1560,7 +1560,7 @@ public final class DisplayManagerService extends SystemService {
|
|||||||
// VirtualDisplay has been successfully constructed.
|
// VirtualDisplay has been successfully constructed.
|
||||||
session.setVirtualDisplayId(displayId);
|
session.setVirtualDisplayId(displayId);
|
||||||
// Don't start mirroring until user re-grants consent.
|
// Don't start mirroring until user re-grants consent.
|
||||||
session.setWaitingToRecord(waitForPermissionConsent);
|
session.setWaitingForConsent(waitForPermissionConsent);
|
||||||
|
|
||||||
// We set the content recording session here on the server side instead of using
|
// We set the content recording session here on the server side instead of using
|
||||||
// a second AIDL call in MediaProjection. By ensuring that a virtual display has
|
// a second AIDL call in MediaProjection. By ensuring that a virtual display has
|
||||||
|
|||||||
@@ -406,7 +406,7 @@ public final class MediaProjectionManagerService extends SystemService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mProjectionGrant.mSession == null
|
if (mProjectionGrant.mSession == null
|
||||||
|| !mProjectionGrant.mSession.isWaitingToRecord()) {
|
|| !mProjectionGrant.mSession.isWaitingForConsent()) {
|
||||||
Slog.w(TAG, "Reusing token: Ignore consent result " + consentResult
|
Slog.w(TAG, "Reusing token: Ignore consent result " + consentResult
|
||||||
+ " if not waiting for the result.");
|
+ " if not waiting for the result.");
|
||||||
return;
|
return;
|
||||||
@@ -445,7 +445,7 @@ public final class MediaProjectionManagerService extends SystemService
|
|||||||
*/
|
*/
|
||||||
private void setReviewedConsentSessionLocked(@Nullable ContentRecordingSession session) {
|
private void setReviewedConsentSessionLocked(@Nullable ContentRecordingSession session) {
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
session.setWaitingToRecord(false);
|
session.setWaitingForConsent(false);
|
||||||
session.setVirtualDisplayId(mProjectionGrant.mVirtualDisplayId);
|
session.setVirtualDisplayId(mProjectionGrant.mVirtualDisplayId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,7 +490,7 @@ public final class MediaProjectionManagerService extends SystemService
|
|||||||
// Supposedly the package has re-used the user's consent; confirm the provided details
|
// Supposedly the package has re-used the user's consent; confirm the provided details
|
||||||
// against the current projection token before re-using the current projection.
|
// against the current projection token before re-using the current projection.
|
||||||
if (mProjectionGrant == null || mProjectionGrant.mSession == null
|
if (mProjectionGrant == null || mProjectionGrant.mSession == null
|
||||||
|| !mProjectionGrant.mSession.isWaitingToRecord()) {
|
|| !mProjectionGrant.mSession.isWaitingForConsent()) {
|
||||||
Slog.e(TAG, "Reusing token: Not possible to reuse the current projection "
|
Slog.e(TAG, "Reusing token: Not possible to reuse the current projection "
|
||||||
+ "instance");
|
+ "instance");
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -276,6 +276,12 @@ final class ContentRecorder implements WindowContainerListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mContentRecordingSession.isWaitingForConsent()) {
|
||||||
|
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Content Recording: waiting to record, so do "
|
||||||
|
+ "nothing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mRecordedWindowContainer = retrieveRecordedWindowContainer();
|
mRecordedWindowContainer = retrieveRecordedWindowContainer();
|
||||||
if (mRecordedWindowContainer == null) {
|
if (mRecordedWindowContainer == null) {
|
||||||
// Either the token is missing, or the window associated with the token is missing.
|
// Either the token is missing, or the window associated with the token is missing.
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ final class ContentRecordingController {
|
|||||||
* Updates the current recording session.
|
* Updates the current recording session.
|
||||||
* <p>Handles the following scenarios:
|
* <p>Handles the following scenarios:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>Invalid scenarios: The incoming session is malformed, or the incoming session is
|
* <li>Invalid scenarios: The incoming session is malformed.</li>
|
||||||
* identical to the current session</li>
|
* <li>Ignored scenario: the incoming session is identical to the current session.</li>
|
||||||
* <li>Start Scenario: Starting a new session. Recording begins immediately.</li>
|
* <li>Start Scenario: Starting a new session. Recording begins immediately.</li>
|
||||||
* <li>Takeover Scenario: Occurs during a Start Scenario, if a pre-existing session was
|
* <li>Takeover Scenario: Occurs during a Start Scenario, if a pre-existing session was
|
||||||
* in-progress. For example, recording on VirtualDisplay "app_foo" was ongoing. A
|
* in-progress. For example, recording on VirtualDisplay "app_foo" was ongoing. A
|
||||||
@@ -66,6 +66,8 @@ final class ContentRecordingController {
|
|||||||
* begin.</li>
|
* begin.</li>
|
||||||
* <li>Stopping scenario: The incoming session is null and there is currently an ongoing
|
* <li>Stopping scenario: The incoming session is null and there is currently an ongoing
|
||||||
* session. The controller stops recording.</li>
|
* session. The controller stops recording.</li>
|
||||||
|
* <li>Updating scenario: There is an update for the same display, where recording
|
||||||
|
* was previously not taking place but is now permitted to go ahead.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param incomingSession The incoming recording session (either an update to a current session
|
* @param incomingSession The incoming recording session (either an update to a current session
|
||||||
@@ -78,20 +80,28 @@ final class ContentRecordingController {
|
|||||||
if (incomingSession != null && !ContentRecordingSession.isValid(incomingSession)) {
|
if (incomingSession != null && !ContentRecordingSession.isValid(incomingSession)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Invalid scenario: ignore identical incoming session.
|
final boolean hasSessionUpdatedWithConsent =
|
||||||
|
mSession != null && incomingSession != null && mSession.isWaitingForConsent()
|
||||||
|
&& !incomingSession.isWaitingForConsent();
|
||||||
if (ContentRecordingSession.isProjectionOnSameDisplay(mSession, incomingSession)) {
|
if (ContentRecordingSession.isProjectionOnSameDisplay(mSession, incomingSession)) {
|
||||||
// TODO(242833866): if incoming session is no longer waiting to record, allow
|
if (hasSessionUpdatedWithConsent) {
|
||||||
// the update through.
|
// Updating scenario: accept an incoming session updating the current display.
|
||||||
|
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
|
||||||
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
|
"Content Recording: Accept session updating same display %d with granted "
|
||||||
"Content Recording: Ignoring session on same display %d, with an existing "
|
+ "consent, with an existing session %s",
|
||||||
+ "session %s",
|
incomingSession.getVirtualDisplayId(), mSession.getVirtualDisplayId());
|
||||||
incomingSession.getVirtualDisplayId(), mSession.getVirtualDisplayId());
|
} else {
|
||||||
return;
|
// Ignored scenario: ignore identical incoming session.
|
||||||
|
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
|
||||||
|
"Content Recording: Ignoring session on same display %d, with an existing "
|
||||||
|
+ "session %s",
|
||||||
|
incomingSession.getVirtualDisplayId(), mSession.getVirtualDisplayId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DisplayContent incomingDisplayContent = null;
|
DisplayContent incomingDisplayContent = null;
|
||||||
// Start scenario: recording begins immediately.
|
|
||||||
if (incomingSession != null) {
|
if (incomingSession != null) {
|
||||||
|
// Start scenario: recording begins immediately.
|
||||||
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
|
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
|
||||||
"Content Recording: Handle incoming session on display %d, with a "
|
"Content Recording: Handle incoming session on display %d, with a "
|
||||||
+ "pre-existing session %s", incomingSession.getVirtualDisplayId(),
|
+ "pre-existing session %s", incomingSession.getVirtualDisplayId(),
|
||||||
@@ -106,11 +116,14 @@ final class ContentRecordingController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
incomingDisplayContent.setContentRecordingSession(incomingSession);
|
incomingDisplayContent.setContentRecordingSession(incomingSession);
|
||||||
// TODO(b/270118861): When user grants consent to re-use, explicitly ask ContentRecorder
|
// Updating scenario: Explicitly ask ContentRecorder to update, since no config or
|
||||||
// to update, since no config/display change arrives. Mark recording as black.
|
// display change will trigger an update from the DisplayContent.
|
||||||
|
if (hasSessionUpdatedWithConsent) {
|
||||||
|
incomingDisplayContent.updateRecording();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Takeover and stopping scenario: stop recording on the pre-existing session.
|
// Takeover and stopping scenario: stop recording on the pre-existing session.
|
||||||
if (mSession != null) {
|
if (mSession != null && !hasSessionUpdatedWithConsent) {
|
||||||
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
|
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
|
||||||
"Content Recording: Pause the recording session on display %s",
|
"Content Recording: Pause the recording session on display %s",
|
||||||
mDisplayContent.getDisplayId());
|
mDisplayContent.getDisplayId());
|
||||||
|
|||||||
@@ -6693,9 +6693,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Start recording if this DisplayContent no longer has content. Stop recording if it now
|
* Start recording if this DisplayContent no longer has content. Stop recording if it now
|
||||||
* has content or the display is not on.
|
* has content or the display is not on. Update recording if the content has changed (for
|
||||||
|
* example, the user has granted consent to token re-use, so we can now start mirroring).
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting void updateRecording() {
|
void updateRecording() {
|
||||||
if (mContentRecorder == null || !mContentRecorder.isContentRecordingSessionSet()) {
|
if (mContentRecorder == null || !mContentRecorder.isContentRecordingSessionSet()) {
|
||||||
if (!setDisplayMirroring()) {
|
if (!setDisplayMirroring()) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1079,7 +1079,7 @@ public class DisplayManagerServiceTest {
|
|||||||
verify(mMockProjectionService, atLeastOnce()).setContentRecordingSession(
|
verify(mMockProjectionService, atLeastOnce()).setContentRecordingSession(
|
||||||
mContentRecordingSessionCaptor.capture(), nullable(IMediaProjection.class));
|
mContentRecordingSessionCaptor.capture(), nullable(IMediaProjection.class));
|
||||||
ContentRecordingSession session = mContentRecordingSessionCaptor.getValue();
|
ContentRecordingSession session = mContentRecordingSessionCaptor.getValue();
|
||||||
assertThat(session.isWaitingToRecord()).isTrue();
|
assertThat(session.isWaitingForConsent()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1114,7 +1114,7 @@ public class DisplayManagerServiceTest {
|
|||||||
assertThat(session.getContentToRecord()).isEqualTo(RECORD_CONTENT_DISPLAY);
|
assertThat(session.getContentToRecord()).isEqualTo(RECORD_CONTENT_DISPLAY);
|
||||||
assertThat(session.getVirtualDisplayId()).isEqualTo(displayId);
|
assertThat(session.getVirtualDisplayId()).isEqualTo(displayId);
|
||||||
assertThat(session.getDisplayToRecord()).isEqualTo(displayToRecord);
|
assertThat(session.getDisplayToRecord()).isEqualTo(displayToRecord);
|
||||||
assertThat(session.isWaitingToRecord()).isFalse();
|
assertThat(session.isWaitingForConsent()).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ public class MediaProjectionManagerServiceTest {
|
|||||||
doReturn(mPackageManager).when(mContext).getPackageManager();
|
doReturn(mPackageManager).when(mContext).getPackageManager();
|
||||||
|
|
||||||
mClock = new OffsettableClock.Stopped();
|
mClock = new OffsettableClock.Stopped();
|
||||||
mWaitingDisplaySession.setWaitingToRecord(true);
|
mWaitingDisplaySession.setWaitingForConsent(true);
|
||||||
mWaitingDisplaySession.setVirtualDisplayId(5);
|
mWaitingDisplaySession.setVirtualDisplayId(5);
|
||||||
|
|
||||||
mAppInfo.targetSdkVersion = 32;
|
mAppInfo.targetSdkVersion = 32;
|
||||||
@@ -484,7 +484,7 @@ public class MediaProjectionManagerServiceTest {
|
|||||||
mSessionCaptor.capture());
|
mSessionCaptor.capture());
|
||||||
// Examine latest value.
|
// Examine latest value.
|
||||||
final ContentRecordingSession capturedSession = mSessionCaptor.getValue();
|
final ContentRecordingSession capturedSession = mSessionCaptor.getValue();
|
||||||
assertThat(capturedSession.isWaitingToRecord()).isFalse();
|
assertThat(capturedSession.isWaitingForConsent()).isFalse();
|
||||||
assertThat(capturedSession.getVirtualDisplayId()).isEqualTo(INVALID_DISPLAY);
|
assertThat(capturedSession.getVirtualDisplayId()).isEqualTo(INVALID_DISPLAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,8 @@ public class ContentRecorderTests extends WindowTestsBase {
|
|||||||
private Task mTask;
|
private Task mTask;
|
||||||
private final ContentRecordingSession mDisplaySession =
|
private final ContentRecordingSession mDisplaySession =
|
||||||
ContentRecordingSession.createDisplaySession(DEFAULT_DISPLAY);
|
ContentRecordingSession.createDisplaySession(DEFAULT_DISPLAY);
|
||||||
|
private final ContentRecordingSession mWaitingDisplaySession =
|
||||||
|
ContentRecordingSession.createDisplaySession(DEFAULT_DISPLAY);
|
||||||
private ContentRecordingSession mTaskSession;
|
private ContentRecordingSession mTaskSession;
|
||||||
private static Point sSurfaceSize;
|
private static Point sSurfaceSize;
|
||||||
private ContentRecorder mContentRecorder;
|
private ContentRecorder mContentRecorder;
|
||||||
@@ -120,6 +122,10 @@ public class ContentRecorderTests extends WindowTestsBase {
|
|||||||
mTaskSession = ContentRecordingSession.createTaskSession(sTaskWindowContainerToken);
|
mTaskSession = ContentRecordingSession.createTaskSession(sTaskWindowContainerToken);
|
||||||
mTaskSession.setVirtualDisplayId(displayId);
|
mTaskSession.setVirtualDisplayId(displayId);
|
||||||
|
|
||||||
|
// GIVEN a session is waiting for the user to review consent.
|
||||||
|
mWaitingDisplaySession.setVirtualDisplayId(displayId);
|
||||||
|
mWaitingDisplaySession.setWaitingForConsent(true);
|
||||||
|
|
||||||
mConfigListener = new ConfigListener();
|
mConfigListener = new ConfigListener();
|
||||||
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
|
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
|
||||||
mContext.getMainExecutor(), mConfigListener);
|
mContext.getMainExecutor(), mConfigListener);
|
||||||
@@ -220,6 +226,18 @@ public class ContentRecorderTests extends WindowTestsBase {
|
|||||||
assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
|
assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateRecording_waitingForConsent() {
|
||||||
|
mContentRecorder.setContentRecordingSession(mWaitingDisplaySession);
|
||||||
|
mContentRecorder.updateRecording();
|
||||||
|
assertThat(mContentRecorder.isCurrentlyRecording()).isFalse();
|
||||||
|
|
||||||
|
|
||||||
|
mContentRecorder.setContentRecordingSession(mDisplaySession);
|
||||||
|
mContentRecorder.updateRecording();
|
||||||
|
assertThat(mContentRecorder.isCurrentlyRecording()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnConfigurationChanged_neverRecording() {
|
public void testOnConfigurationChanged_neverRecording() {
|
||||||
mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);
|
mContentRecorder.onConfigurationChanged(ORIENTATION_PORTRAIT);
|
||||||
|
|||||||
@@ -24,10 +24,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
|||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.Mockito.atLeastOnce;
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
import android.view.ContentRecordingSession;
|
import android.view.ContentRecordingSession;
|
||||||
|
|
||||||
@@ -36,6 +34,8 @@ import androidx.test.filters.SmallTest;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for the {@link ContentRecordingController} class.
|
* Tests for the {@link ContentRecordingController} class.
|
||||||
@@ -49,12 +49,20 @@ import org.junit.runner.RunWith;
|
|||||||
public class ContentRecordingControllerTests extends WindowTestsBase {
|
public class ContentRecordingControllerTests extends WindowTestsBase {
|
||||||
private final ContentRecordingSession mDefaultSession =
|
private final ContentRecordingSession mDefaultSession =
|
||||||
ContentRecordingSession.createDisplaySession(DEFAULT_DISPLAY);
|
ContentRecordingSession.createDisplaySession(DEFAULT_DISPLAY);
|
||||||
|
private final ContentRecordingSession mWaitingDisplaySession =
|
||||||
|
ContentRecordingSession.createDisplaySession(DEFAULT_DISPLAY);
|
||||||
|
|
||||||
private int mVirtualDisplayId;
|
private int mVirtualDisplayId;
|
||||||
private DisplayContent mVirtualDisplayContent;
|
private DisplayContent mVirtualDisplayContent;
|
||||||
|
private WindowContainer.RemoteToken mRootTaskToken;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private WindowContainer mTaskWindowContainer;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
// GIVEN the VirtualDisplay associated with the session (so the display has state ON).
|
// GIVEN the VirtualDisplay associated with the session (so the display has state ON).
|
||||||
mVirtualDisplayContent = new TestDisplayContent.Builder(mAtm, 500, 600).build();
|
mVirtualDisplayContent = new TestDisplayContent.Builder(mAtm, 500, 600).build();
|
||||||
mVirtualDisplayId = mVirtualDisplayContent.getDisplayId();
|
mVirtualDisplayId = mVirtualDisplayContent.getDisplayId();
|
||||||
@@ -62,6 +70,11 @@ public class ContentRecordingControllerTests extends WindowTestsBase {
|
|||||||
spyOn(mVirtualDisplayContent);
|
spyOn(mVirtualDisplayContent);
|
||||||
|
|
||||||
mDefaultSession.setVirtualDisplayId(mVirtualDisplayId);
|
mDefaultSession.setVirtualDisplayId(mVirtualDisplayId);
|
||||||
|
mWaitingDisplaySession.setVirtualDisplayId(mVirtualDisplayId);
|
||||||
|
mWaitingDisplaySession.setWaitingForConsent(true);
|
||||||
|
|
||||||
|
mRootTaskToken = new WindowContainer.RemoteToken(mTaskWindowContainer);
|
||||||
|
mTaskWindowContainer.mRemoteToken = mRootTaskToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -92,7 +105,7 @@ public class ContentRecordingControllerTests extends WindowTestsBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetContentRecordingSessionLocked_newDisplaySession_accepted() {
|
public void testSetContentRecordingSessionLocked_newSession_accepted() {
|
||||||
ContentRecordingController controller = new ContentRecordingController();
|
ContentRecordingController controller = new ContentRecordingController();
|
||||||
// GIVEN a valid display session.
|
// GIVEN a valid display session.
|
||||||
// WHEN updating the session.
|
// WHEN updating the session.
|
||||||
@@ -104,15 +117,37 @@ public class ContentRecordingControllerTests extends WindowTestsBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetContentRecordingSessionLocked_updateCurrentDisplaySession_notAccepted() {
|
public void testSetContentRecordingSessionLocked_updateSession_noLongerWaiting_accepted() {
|
||||||
|
ContentRecordingController controller = new ContentRecordingController();
|
||||||
|
// GIVEN a valid display session already in place.
|
||||||
|
controller.setContentRecordingSessionLocked(mWaitingDisplaySession, mWm);
|
||||||
|
verify(mVirtualDisplayContent, atLeastOnce()).setContentRecordingSession(
|
||||||
|
mWaitingDisplaySession);
|
||||||
|
|
||||||
|
// WHEN updating the session on the same display, so no longer waiting to record.
|
||||||
|
ContentRecordingSession sessionUpdate = ContentRecordingSession.createTaskSession(
|
||||||
|
mRootTaskToken.toWindowContainerToken().asBinder());
|
||||||
|
sessionUpdate.setVirtualDisplayId(mVirtualDisplayId);
|
||||||
|
sessionUpdate.setWaitingForConsent(false);
|
||||||
|
controller.setContentRecordingSessionLocked(sessionUpdate, mWm);
|
||||||
|
|
||||||
|
ContentRecordingSession resultingSession = controller.getContentRecordingSessionLocked();
|
||||||
|
// THEN the session was accepted.
|
||||||
|
assertThat(resultingSession).isEqualTo(sessionUpdate);
|
||||||
|
verify(mVirtualDisplayContent, atLeastOnce()).setContentRecordingSession(sessionUpdate);
|
||||||
|
verify(mVirtualDisplayContent).updateRecording();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetContentRecordingSessionLocked_invalidUpdateSession_notWaiting_notAccepted() {
|
||||||
ContentRecordingController controller = new ContentRecordingController();
|
ContentRecordingController controller = new ContentRecordingController();
|
||||||
// GIVEN a valid display session already in place.
|
// GIVEN a valid display session already in place.
|
||||||
controller.setContentRecordingSessionLocked(mDefaultSession, mWm);
|
controller.setContentRecordingSessionLocked(mDefaultSession, mWm);
|
||||||
verify(mVirtualDisplayContent, atLeastOnce()).setContentRecordingSession(mDefaultSession);
|
verify(mVirtualDisplayContent, atLeastOnce()).setContentRecordingSession(mDefaultSession);
|
||||||
|
|
||||||
// WHEN updating the session on the same display.
|
// WHEN updating the session on the same display.
|
||||||
ContentRecordingSession sessionUpdate =
|
ContentRecordingSession sessionUpdate = ContentRecordingSession.createTaskSession(
|
||||||
ContentRecordingSession.createTaskSession(mock(IBinder.class));
|
mRootTaskToken.toWindowContainerToken().asBinder());
|
||||||
sessionUpdate.setVirtualDisplayId(mVirtualDisplayId);
|
sessionUpdate.setVirtualDisplayId(mVirtualDisplayId);
|
||||||
controller.setContentRecordingSessionLocked(sessionUpdate, mWm);
|
controller.setContentRecordingSessionLocked(sessionUpdate, mWm);
|
||||||
|
|
||||||
@@ -123,7 +158,7 @@ public class ContentRecordingControllerTests extends WindowTestsBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetContentRecordingSessionLocked_disableCurrentDisplaySession_accepted() {
|
public void testSetContentRecordingSessionLocked_disableCurrentSession_accepted() {
|
||||||
ContentRecordingController controller = new ContentRecordingController();
|
ContentRecordingController controller = new ContentRecordingController();
|
||||||
// GIVEN a valid display session already in place.
|
// GIVEN a valid display session already in place.
|
||||||
controller.setContentRecordingSessionLocked(mDefaultSession, mWm);
|
controller.setContentRecordingSessionLocked(mDefaultSession, mWm);
|
||||||
@@ -141,7 +176,7 @@ public class ContentRecordingControllerTests extends WindowTestsBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetContentRecordingSessionLocked_takeOverCurrentDisplaySession_accepted() {
|
public void testSetContentRecordingSessionLocked_takeOverCurrentSession_accepted() {
|
||||||
ContentRecordingController controller = new ContentRecordingController();
|
ContentRecordingController controller = new ContentRecordingController();
|
||||||
// GIVEN a valid display session already in place.
|
// GIVEN a valid display session already in place.
|
||||||
controller.setContentRecordingSessionLocked(mDefaultSession, mWm);
|
controller.setContentRecordingSessionLocked(mDefaultSession, mWm);
|
||||||
|
|||||||
Reference in New Issue
Block a user