(5/N)[MediaProjection] Send no frames until user reviews consent
When a host app re-uses a consent token, protect the user's data by ensuring no frames are sent out until the user has reviewed the permission dialog. Test: atest WmTests:ContentRecordingControllerTests Test: atest WmTests:ContentRecorderTests Bug: 271323540 Change-Id: I0451ac709b64414fc75f3dfbca5a3dbe9244682d
This commit is contained in:
@@ -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.
|
||||
*/
|
||||
private boolean mWaitingToRecord = false;
|
||||
private boolean mWaitingForConsent = false;
|
||||
|
||||
/**
|
||||
* Default instance, with recording the display.
|
||||
@@ -181,7 +181,7 @@ public final class ContentRecordingSession implements Parcelable {
|
||||
@RecordContent int contentToRecord,
|
||||
int displayToRecord,
|
||||
@Nullable IBinder tokenToRecord,
|
||||
boolean waitingToRecord) {
|
||||
boolean waitingForConsent) {
|
||||
this.mVirtualDisplayId = virtualDisplayId;
|
||||
this.mContentToRecord = contentToRecord;
|
||||
|
||||
@@ -195,7 +195,7 @@ public final class ContentRecordingSession implements Parcelable {
|
||||
|
||||
this.mDisplayToRecord = displayToRecord;
|
||||
this.mTokenToRecord = tokenToRecord;
|
||||
this.mWaitingToRecord = waitingToRecord;
|
||||
this.mWaitingForConsent = waitingForConsent;
|
||||
|
||||
// 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.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public boolean isWaitingToRecord() {
|
||||
return mWaitingToRecord;
|
||||
public boolean isWaitingForConsent() {
|
||||
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.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull ContentRecordingSession setWaitingToRecord( boolean value) {
|
||||
mWaitingToRecord = value;
|
||||
public @NonNull ContentRecordingSession setWaitingForConsent( boolean value) {
|
||||
mWaitingForConsent = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ public final class ContentRecordingSession implements Parcelable {
|
||||
"contentToRecord = " + recordContentToString(mContentToRecord) + ", " +
|
||||
"displayToRecord = " + mDisplayToRecord + ", " +
|
||||
"tokenToRecord = " + mTokenToRecord + ", " +
|
||||
"waitingToRecord = " + mWaitingToRecord +
|
||||
"waitingForConsent = " + mWaitingForConsent +
|
||||
" }";
|
||||
}
|
||||
|
||||
@@ -346,7 +346,7 @@ public final class ContentRecordingSession implements Parcelable {
|
||||
&& mContentToRecord == that.mContentToRecord
|
||||
&& mDisplayToRecord == that.mDisplayToRecord
|
||||
&& java.util.Objects.equals(mTokenToRecord, that.mTokenToRecord)
|
||||
&& mWaitingToRecord == that.mWaitingToRecord;
|
||||
&& mWaitingForConsent == that.mWaitingForConsent;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -360,7 +360,7 @@ public final class ContentRecordingSession implements Parcelable {
|
||||
_hash = 31 * _hash + mContentToRecord;
|
||||
_hash = 31 * _hash + mDisplayToRecord;
|
||||
_hash = 31 * _hash + java.util.Objects.hashCode(mTokenToRecord);
|
||||
_hash = 31 * _hash + Boolean.hashCode(mWaitingToRecord);
|
||||
_hash = 31 * _hash + Boolean.hashCode(mWaitingForConsent);
|
||||
return _hash;
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ public final class ContentRecordingSession implements Parcelable {
|
||||
// void parcelFieldName(Parcel dest, int flags) { ... }
|
||||
|
||||
byte flg = 0;
|
||||
if (mWaitingToRecord) flg |= 0x10;
|
||||
if (mWaitingForConsent) flg |= 0x10;
|
||||
if (mTokenToRecord != null) flg |= 0x8;
|
||||
dest.writeByte(flg);
|
||||
dest.writeInt(mVirtualDisplayId);
|
||||
@@ -392,7 +392,7 @@ public final class ContentRecordingSession implements Parcelable {
|
||||
// static FieldType unparcelFieldName(Parcel in) { ... }
|
||||
|
||||
byte flg = in.readByte();
|
||||
boolean waitingToRecord = (flg & 0x10) != 0;
|
||||
boolean waitingForConsent = (flg & 0x10) != 0;
|
||||
int virtualDisplayId = in.readInt();
|
||||
int contentToRecord = in.readInt();
|
||||
int displayToRecord = in.readInt();
|
||||
@@ -411,7 +411,7 @@ public final class ContentRecordingSession implements Parcelable {
|
||||
|
||||
this.mDisplayToRecord = displayToRecord;
|
||||
this.mTokenToRecord = tokenToRecord;
|
||||
this.mWaitingToRecord = waitingToRecord;
|
||||
this.mWaitingForConsent = waitingForConsent;
|
||||
|
||||
// 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 int mDisplayToRecord;
|
||||
private @Nullable IBinder mTokenToRecord;
|
||||
private boolean mWaitingToRecord;
|
||||
private boolean mWaitingForConsent;
|
||||
|
||||
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.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull Builder setWaitingToRecord(boolean value) {
|
||||
public @NonNull Builder setWaitingForConsent(boolean value) {
|
||||
checkNotUsed();
|
||||
mBuilderFieldsSet |= 0x10;
|
||||
mWaitingToRecord = value;
|
||||
mWaitingForConsent = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -531,14 +531,14 @@ public final class ContentRecordingSession implements Parcelable {
|
||||
mTokenToRecord = null;
|
||||
}
|
||||
if ((mBuilderFieldsSet & 0x10) == 0) {
|
||||
mWaitingToRecord = false;
|
||||
mWaitingForConsent = false;
|
||||
}
|
||||
ContentRecordingSession o = new ContentRecordingSession(
|
||||
mVirtualDisplayId,
|
||||
mContentToRecord,
|
||||
mDisplayToRecord,
|
||||
mTokenToRecord,
|
||||
mWaitingToRecord);
|
||||
mWaitingForConsent);
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -551,10 +551,10 @@ public final class ContentRecordingSession implements Parcelable {
|
||||
}
|
||||
|
||||
@DataClass.Generated(
|
||||
time = 1679855157534L,
|
||||
time = 1683628463074L,
|
||||
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 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
|
||||
private void __metadata() {}
|
||||
|
||||
|
||||
@@ -1675,6 +1675,12 @@
|
||||
"group": "WM_DEBUG_CONFIGURATION",
|
||||
"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": {
|
||||
"message": "%s",
|
||||
"level": "INFO",
|
||||
@@ -2167,6 +2173,12 @@
|
||||
"group": "WM_DEBUG_BACK_PREVIEW",
|
||||
"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": {
|
||||
"message": "Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s",
|
||||
"level": "VERBOSE",
|
||||
|
||||
@@ -1560,7 +1560,7 @@ public final class DisplayManagerService extends SystemService {
|
||||
// VirtualDisplay has been successfully constructed.
|
||||
session.setVirtualDisplayId(displayId);
|
||||
// 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
|
||||
// a second AIDL call in MediaProjection. By ensuring that a virtual display has
|
||||
|
||||
@@ -406,7 +406,7 @@ public final class MediaProjectionManagerService extends SystemService
|
||||
return;
|
||||
}
|
||||
if (mProjectionGrant.mSession == null
|
||||
|| !mProjectionGrant.mSession.isWaitingToRecord()) {
|
||||
|| !mProjectionGrant.mSession.isWaitingForConsent()) {
|
||||
Slog.w(TAG, "Reusing token: Ignore consent result " + consentResult
|
||||
+ " if not waiting for the result.");
|
||||
return;
|
||||
@@ -445,7 +445,7 @@ public final class MediaProjectionManagerService extends SystemService
|
||||
*/
|
||||
private void setReviewedConsentSessionLocked(@Nullable ContentRecordingSession session) {
|
||||
if (session != null) {
|
||||
session.setWaitingToRecord(false);
|
||||
session.setWaitingForConsent(false);
|
||||
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
|
||||
// against the current projection token before re-using the current projection.
|
||||
if (mProjectionGrant == null || mProjectionGrant.mSession == null
|
||||
|| !mProjectionGrant.mSession.isWaitingToRecord()) {
|
||||
|| !mProjectionGrant.mSession.isWaitingForConsent()) {
|
||||
Slog.e(TAG, "Reusing token: Not possible to reuse the current projection "
|
||||
+ "instance");
|
||||
return null;
|
||||
|
||||
@@ -276,6 +276,12 @@ final class ContentRecorder implements WindowContainerListener {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mContentRecordingSession.isWaitingForConsent()) {
|
||||
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING, "Content Recording: waiting to record, so do "
|
||||
+ "nothing");
|
||||
return;
|
||||
}
|
||||
|
||||
mRecordedWindowContainer = retrieveRecordedWindowContainer();
|
||||
if (mRecordedWindowContainer == null) {
|
||||
// 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.
|
||||
* <p>Handles the following scenarios:
|
||||
* <ul>
|
||||
* <li>Invalid scenarios: The incoming session is malformed, or the incoming session is
|
||||
* identical to the current session</li>
|
||||
* <li>Invalid scenarios: The incoming session is malformed.</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>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
|
||||
@@ -66,6 +66,8 @@ final class ContentRecordingController {
|
||||
* begin.</li>
|
||||
* <li>Stopping scenario: The incoming session is null and there is currently an ongoing
|
||||
* 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>
|
||||
*
|
||||
* @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)) {
|
||||
return;
|
||||
}
|
||||
// Invalid scenario: ignore identical incoming session.
|
||||
final boolean hasSessionUpdatedWithConsent =
|
||||
mSession != null && incomingSession != null && mSession.isWaitingForConsent()
|
||||
&& !incomingSession.isWaitingForConsent();
|
||||
if (ContentRecordingSession.isProjectionOnSameDisplay(mSession, incomingSession)) {
|
||||
// TODO(242833866): if incoming session is no longer waiting to record, allow
|
||||
// the update through.
|
||||
|
||||
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
|
||||
"Content Recording: Ignoring session on same display %d, with an existing "
|
||||
+ "session %s",
|
||||
incomingSession.getVirtualDisplayId(), mSession.getVirtualDisplayId());
|
||||
return;
|
||||
if (hasSessionUpdatedWithConsent) {
|
||||
// Updating scenario: accept an incoming session updating the current display.
|
||||
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
|
||||
"Content Recording: Accept session updating same display %d with granted "
|
||||
+ "consent, with an existing session %s",
|
||||
incomingSession.getVirtualDisplayId(), mSession.getVirtualDisplayId());
|
||||
} else {
|
||||
// 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;
|
||||
// Start scenario: recording begins immediately.
|
||||
if (incomingSession != null) {
|
||||
// Start scenario: recording begins immediately.
|
||||
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
|
||||
"Content Recording: Handle incoming session on display %d, with a "
|
||||
+ "pre-existing session %s", incomingSession.getVirtualDisplayId(),
|
||||
@@ -106,11 +116,14 @@ final class ContentRecordingController {
|
||||
return;
|
||||
}
|
||||
incomingDisplayContent.setContentRecordingSession(incomingSession);
|
||||
// TODO(b/270118861): When user grants consent to re-use, explicitly ask ContentRecorder
|
||||
// to update, since no config/display change arrives. Mark recording as black.
|
||||
// Updating scenario: Explicitly ask ContentRecorder to update, since no config or
|
||||
// display change will trigger an update from the DisplayContent.
|
||||
if (hasSessionUpdatedWithConsent) {
|
||||
incomingDisplayContent.updateRecording();
|
||||
}
|
||||
}
|
||||
// Takeover and stopping scenario: stop recording on the pre-existing session.
|
||||
if (mSession != null) {
|
||||
if (mSession != null && !hasSessionUpdatedWithConsent) {
|
||||
ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
|
||||
"Content Recording: Pause the recording session on display %s",
|
||||
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
|
||||
* 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 (!setDisplayMirroring()) {
|
||||
return;
|
||||
|
||||
@@ -1079,7 +1079,7 @@ public class DisplayManagerServiceTest {
|
||||
verify(mMockProjectionService, atLeastOnce()).setContentRecordingSession(
|
||||
mContentRecordingSessionCaptor.capture(), nullable(IMediaProjection.class));
|
||||
ContentRecordingSession session = mContentRecordingSessionCaptor.getValue();
|
||||
assertThat(session.isWaitingToRecord()).isTrue();
|
||||
assertThat(session.isWaitingForConsent()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1114,7 +1114,7 @@ public class DisplayManagerServiceTest {
|
||||
assertThat(session.getContentToRecord()).isEqualTo(RECORD_CONTENT_DISPLAY);
|
||||
assertThat(session.getVirtualDisplayId()).isEqualTo(displayId);
|
||||
assertThat(session.getDisplayToRecord()).isEqualTo(displayToRecord);
|
||||
assertThat(session.isWaitingToRecord()).isFalse();
|
||||
assertThat(session.isWaitingForConsent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -139,7 +139,7 @@ public class MediaProjectionManagerServiceTest {
|
||||
doReturn(mPackageManager).when(mContext).getPackageManager();
|
||||
|
||||
mClock = new OffsettableClock.Stopped();
|
||||
mWaitingDisplaySession.setWaitingToRecord(true);
|
||||
mWaitingDisplaySession.setWaitingForConsent(true);
|
||||
mWaitingDisplaySession.setVirtualDisplayId(5);
|
||||
|
||||
mAppInfo.targetSdkVersion = 32;
|
||||
@@ -484,7 +484,7 @@ public class MediaProjectionManagerServiceTest {
|
||||
mSessionCaptor.capture());
|
||||
// Examine latest value.
|
||||
final ContentRecordingSession capturedSession = mSessionCaptor.getValue();
|
||||
assertThat(capturedSession.isWaitingToRecord()).isFalse();
|
||||
assertThat(capturedSession.isWaitingForConsent()).isFalse();
|
||||
assertThat(capturedSession.getVirtualDisplayId()).isEqualTo(INVALID_DISPLAY);
|
||||
}
|
||||
|
||||
|
||||
@@ -79,6 +79,8 @@ public class ContentRecorderTests extends WindowTestsBase {
|
||||
private Task mTask;
|
||||
private final ContentRecordingSession mDisplaySession =
|
||||
ContentRecordingSession.createDisplaySession(DEFAULT_DISPLAY);
|
||||
private final ContentRecordingSession mWaitingDisplaySession =
|
||||
ContentRecordingSession.createDisplaySession(DEFAULT_DISPLAY);
|
||||
private ContentRecordingSession mTaskSession;
|
||||
private static Point sSurfaceSize;
|
||||
private ContentRecorder mContentRecorder;
|
||||
@@ -120,6 +122,10 @@ public class ContentRecorderTests extends WindowTestsBase {
|
||||
mTaskSession = ContentRecordingSession.createTaskSession(sTaskWindowContainerToken);
|
||||
mTaskSession.setVirtualDisplayId(displayId);
|
||||
|
||||
// GIVEN a session is waiting for the user to review consent.
|
||||
mWaitingDisplaySession.setVirtualDisplayId(displayId);
|
||||
mWaitingDisplaySession.setWaitingForConsent(true);
|
||||
|
||||
mConfigListener = new ConfigListener();
|
||||
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
|
||||
mContext.getMainExecutor(), mConfigListener);
|
||||
@@ -220,6 +226,18 @@ public class ContentRecorderTests extends WindowTestsBase {
|
||||
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
|
||||
public void testOnConfigurationChanged_neverRecording() {
|
||||
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 org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
|
||||
import android.os.IBinder;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.view.ContentRecordingSession;
|
||||
|
||||
@@ -36,6 +34,8 @@ import androidx.test.filters.SmallTest;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
/**
|
||||
* Tests for the {@link ContentRecordingController} class.
|
||||
@@ -49,12 +49,20 @@ import org.junit.runner.RunWith;
|
||||
public class ContentRecordingControllerTests extends WindowTestsBase {
|
||||
private final ContentRecordingSession mDefaultSession =
|
||||
ContentRecordingSession.createDisplaySession(DEFAULT_DISPLAY);
|
||||
private final ContentRecordingSession mWaitingDisplaySession =
|
||||
ContentRecordingSession.createDisplaySession(DEFAULT_DISPLAY);
|
||||
|
||||
private int mVirtualDisplayId;
|
||||
private DisplayContent mVirtualDisplayContent;
|
||||
private WindowContainer.RemoteToken mRootTaskToken;
|
||||
|
||||
@Mock
|
||||
private WindowContainer mTaskWindowContainer;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
// GIVEN the VirtualDisplay associated with the session (so the display has state ON).
|
||||
mVirtualDisplayContent = new TestDisplayContent.Builder(mAtm, 500, 600).build();
|
||||
mVirtualDisplayId = mVirtualDisplayContent.getDisplayId();
|
||||
@@ -62,6 +70,11 @@ public class ContentRecordingControllerTests extends WindowTestsBase {
|
||||
spyOn(mVirtualDisplayContent);
|
||||
|
||||
mDefaultSession.setVirtualDisplayId(mVirtualDisplayId);
|
||||
mWaitingDisplaySession.setVirtualDisplayId(mVirtualDisplayId);
|
||||
mWaitingDisplaySession.setWaitingForConsent(true);
|
||||
|
||||
mRootTaskToken = new WindowContainer.RemoteToken(mTaskWindowContainer);
|
||||
mTaskWindowContainer.mRemoteToken = mRootTaskToken;
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -92,7 +105,7 @@ public class ContentRecordingControllerTests extends WindowTestsBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetContentRecordingSessionLocked_newDisplaySession_accepted() {
|
||||
public void testSetContentRecordingSessionLocked_newSession_accepted() {
|
||||
ContentRecordingController controller = new ContentRecordingController();
|
||||
// GIVEN a valid display session.
|
||||
// WHEN updating the session.
|
||||
@@ -104,15 +117,37 @@ public class ContentRecordingControllerTests extends WindowTestsBase {
|
||||
}
|
||||
|
||||
@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();
|
||||
// GIVEN a valid display session already in place.
|
||||
controller.setContentRecordingSessionLocked(mDefaultSession, mWm);
|
||||
verify(mVirtualDisplayContent, atLeastOnce()).setContentRecordingSession(mDefaultSession);
|
||||
|
||||
// WHEN updating the session on the same display.
|
||||
ContentRecordingSession sessionUpdate =
|
||||
ContentRecordingSession.createTaskSession(mock(IBinder.class));
|
||||
ContentRecordingSession sessionUpdate = ContentRecordingSession.createTaskSession(
|
||||
mRootTaskToken.toWindowContainerToken().asBinder());
|
||||
sessionUpdate.setVirtualDisplayId(mVirtualDisplayId);
|
||||
controller.setContentRecordingSessionLocked(sessionUpdate, mWm);
|
||||
|
||||
@@ -123,7 +158,7 @@ public class ContentRecordingControllerTests extends WindowTestsBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetContentRecordingSessionLocked_disableCurrentDisplaySession_accepted() {
|
||||
public void testSetContentRecordingSessionLocked_disableCurrentSession_accepted() {
|
||||
ContentRecordingController controller = new ContentRecordingController();
|
||||
// GIVEN a valid display session already in place.
|
||||
controller.setContentRecordingSessionLocked(mDefaultSession, mWm);
|
||||
@@ -141,7 +176,7 @@ public class ContentRecordingControllerTests extends WindowTestsBase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetContentRecordingSessionLocked_takeOverCurrentDisplaySession_accepted() {
|
||||
public void testSetContentRecordingSessionLocked_takeOverCurrentSession_accepted() {
|
||||
ContentRecordingController controller = new ContentRecordingController();
|
||||
// GIVEN a valid display session already in place.
|
||||
controller.setContentRecordingSessionLocked(mDefaultSession, mWm);
|
||||
|
||||
Reference in New Issue
Block a user