blob: d966a8c07d92a5f5b704c1e600fb414470181d98 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.virtualdevice.cts;
import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY;
import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
import static android.Manifest.permission.CREATE_VIRTUAL_DEVICE;
import static android.Manifest.permission.WAKE_LOCK;
import static android.virtualdevice.cts.common.util.VirtualDeviceTestUtils.createDefaultVirtualDisplayConfigBuilder;
import static android.virtualdevice.cts.common.util.VirtualDeviceTestUtils.isVirtualDeviceManagerConfigEnabled;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertThrows;
import static org.junit.Assume.assumeTrue;
import android.annotation.Nullable;
import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceManager.VirtualDevice;
import android.companion.virtual.VirtualDeviceParams;
import android.companion.virtual.flags.Flags;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.view.Display;
import android.virtualdevice.cts.common.FakeAssociationRule;
import android.virtualdevice.cts.common.util.VirtualDeviceTestUtils;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.compatibility.common.util.AdoptShellPermissionsRule;
import com.google.common.base.Objects;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@RunWith(AndroidJUnit4.class)
@AppModeFull(reason = " cannot be accessed by instant apps")
public class VirtualDisplayTest {
private static final int DISPLAY_WIDTH = 640;
private static final int DISPLAY_HEIGHT = 480;
private static final int DISPLAY_DPI = 420;
private static final String DISPLAY_NAME = "TestVirtualDisplay";
private static final int TIMEOUT_MILLIS = 1000;
private static final VirtualDeviceParams DEFAULT_VIRTUAL_DEVICE_PARAMS =
new VirtualDeviceParams.Builder().build();
private static final VirtualDisplayConfig DEFAULT_VIRTUAL_DISPLAY_CONFIG =
createDefaultVirtualDisplayConfigBuilder().build();
@Rule
public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule(
InstrumentationRegistry.getInstrumentation().getUiAutomation(),
ADD_ALWAYS_UNLOCKED_DISPLAY,
ADD_TRUSTED_DISPLAY,
CREATE_VIRTUAL_DEVICE,
WAKE_LOCK);
@Rule
public FakeAssociationRule mFakeAssociationRule = new FakeAssociationRule();
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private VirtualDeviceManager mVirtualDeviceManager;
private DisplayManager mDisplayManager;
private VirtualDeviceTestUtils.DisplayListenerForTest mDisplayListener;
@Nullable
private VirtualDevice mVirtualDevice;
@Mock
private VirtualDisplay.Callback mVirtualDisplayCallback;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
Context context = getApplicationContext();
final PackageManager packageManager = context.getPackageManager();
assumeTrue(isVirtualDeviceManagerConfigEnabled(context));
assumeTrue(packageManager.hasSystemFeature(
PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS));
mVirtualDeviceManager = context.getSystemService(VirtualDeviceManager.class);
mDisplayManager = context.getSystemService(DisplayManager.class);
mDisplayListener = new VirtualDeviceTestUtils.DisplayListenerForTest();
mDisplayManager.registerDisplayListener(mDisplayListener, /*handler=*/null);
}
@After
public void tearDown() {
if (mVirtualDevice != null) {
mVirtualDevice.close();
}
if (mDisplayManager != null && mDisplayListener != null) {
mDisplayManager.unregisterDisplayListener(mDisplayListener);
}
}
@Test
public void createVirtualDisplay_shouldSucceed() {
mVirtualDevice =
mVirtualDeviceManager.createVirtualDevice(
mFakeAssociationRule.getAssociationInfo().getId(),
DEFAULT_VIRTUAL_DEVICE_PARAMS);
VirtualDisplay virtualDisplay = mVirtualDevice.createVirtualDisplay(
DEFAULT_VIRTUAL_DISPLAY_CONFIG, Runnable::run, mVirtualDisplayCallback);
assertThat(mDisplayListener.waitForOnDisplayAddedCallback()).isTrue();
assertThat(virtualDisplay).isNotNull();
Display display = virtualDisplay.getDisplay();
assertThat(display.isValid()).isTrue();
assertThat(display.getWidth()).isEqualTo(DEFAULT_VIRTUAL_DISPLAY_CONFIG.getWidth());
assertThat(display.getHeight()).isEqualTo(DEFAULT_VIRTUAL_DISPLAY_CONFIG.getHeight());
assertThat(mDisplayListener.getObservedAddedDisplays()).containsExactly(
Integer.valueOf(display.getDisplayId()));
}
@Test
public void createVirtualDisplay_deprecatedOverload_shouldSucceed() {
mVirtualDevice =
mVirtualDeviceManager.createVirtualDevice(
mFakeAssociationRule.getAssociationInfo().getId(),
DEFAULT_VIRTUAL_DEVICE_PARAMS);
VirtualDisplay virtualDisplay = mVirtualDevice.createVirtualDisplay(
/* width= */ DISPLAY_WIDTH,
/* height= */ DISPLAY_HEIGHT,
/* densityDpi= */ DISPLAY_DPI,
/* surface= */ null,
/* flags= */ 0,
Runnable::run,
mVirtualDisplayCallback);
assertThat(mDisplayListener.waitForOnDisplayAddedCallback()).isTrue();
assertThat(virtualDisplay).isNotNull();
Display display = virtualDisplay.getDisplay();
assertThat(display.isValid()).isTrue();
assertThat(display.getWidth()).isEqualTo(DISPLAY_WIDTH);
assertThat(display.getHeight()).isEqualTo(DISPLAY_HEIGHT);
assertThat(mDisplayListener.getObservedAddedDisplays()).containsExactly(
Integer.valueOf(display.getDisplayId()));
}
@Test
public void createVirtualDisplay_defaultVirtualDisplayFlags() {
mVirtualDevice =
mVirtualDeviceManager.createVirtualDevice(
mFakeAssociationRule.getAssociationInfo().getId(),
DEFAULT_VIRTUAL_DEVICE_PARAMS);
VirtualDisplay virtualDisplay = mVirtualDevice.createVirtualDisplay(
DEFAULT_VIRTUAL_DISPLAY_CONFIG, Runnable::run, mVirtualDisplayCallback);
assertThat(mDisplayListener.waitForOnDisplayAddedCallback()).isTrue();
Display display = virtualDisplay.getDisplay();
assertThat(display.isValid()).isTrue();
assertThat(display.getFlags()).isEqualTo(
Display.FLAG_PRIVATE | Display.FLAG_TOUCH_FEEDBACK_DISABLED);
// Private displays always destroy their content on removal
assertThat(display.getRemoveMode()).isEqualTo(Display.REMOVE_MODE_DESTROY_CONTENT);
assertThat(mDisplayListener.getObservedAddedDisplays()).containsExactly(
display.getDisplayId());
}
/**
* Tests that a virtual device is not allowed create a virtual display with just
* VIRTUAL_DISPLAY_FLAG_PUBLIC flag if screen mirroring is disabled, as DisplayManagerService
* tries to create an auto-mirror display by default for public virtual displays.
*/
@RequiresFlagsDisabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void createVirtualDisplay_public_throwsException() {
assertThrows(SecurityException.class,
() -> createVirtualDisplayForVirtualDevice(
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
DEFAULT_VIRTUAL_DEVICE_PARAMS));
}
/**
* Tests that a virtual device is not allowed create a virtual display with
* VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR flag if screen mirroring is disabled.
*/
@RequiresFlagsDisabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void createVirtualDisplay_autoMirror_throwsException() {
assertThrows(SecurityException.class,
() -> createVirtualDisplayForVirtualDevice(
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
DEFAULT_VIRTUAL_DEVICE_PARAMS));
}
/**
* Tests that a virtual device is not allowed create a virtual display with
* VIRTUAL_DISPLAY_FLAG_PUBLIC or VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR flags if screen mirroring is
* disabled.
*/
@RequiresFlagsDisabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void createVirtualDisplay_publicAutoMirror_throwsException() {
assertThrows(SecurityException.class,
() -> createVirtualDisplayForVirtualDevice(
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
| DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
DEFAULT_VIRTUAL_DEVICE_PARAMS));
}
@RequiresFlagsEnabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void createVirtualDisplay_public_createsMirrorDisplay() {
VirtualDisplay virtualDisplay = createVirtualDisplayForVirtualDevice(
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
DEFAULT_VIRTUAL_DEVICE_PARAMS);
assertThat(virtualDisplay).isNotNull();
Display display = virtualDisplay.getDisplay();
assertThat(display.isValid()).isTrue();
assertThat(mVirtualDeviceManager.isVirtualDeviceOwnedMirrorDisplay(display.getDisplayId()))
.isTrue();
}
@RequiresFlagsEnabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void createVirtualDisplay_autoMirror_createsMirrorDisplay() {
VirtualDisplay virtualDisplay = createVirtualDisplayForVirtualDevice(
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
DEFAULT_VIRTUAL_DEVICE_PARAMS);
assertThat(virtualDisplay).isNotNull();
Display display = virtualDisplay.getDisplay();
assertThat(display.isValid()).isTrue();
assertThat(mVirtualDeviceManager.isVirtualDeviceOwnedMirrorDisplay(display.getDisplayId()))
.isTrue();
}
@RequiresFlagsEnabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void createVirtualDisplay_publicAutoMirror_createsMirrorDisplay() {
VirtualDisplay virtualDisplay = createVirtualDisplayForVirtualDevice(
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
| DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
DEFAULT_VIRTUAL_DEVICE_PARAMS);
assertThat(virtualDisplay).isNotNull();
Display display = virtualDisplay.getDisplay();
assertThat(display.isValid()).isTrue();
assertThat(mVirtualDeviceManager.isVirtualDeviceOwnedMirrorDisplay(display.getDisplayId()))
.isTrue();
}
@RequiresFlagsEnabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void createVirtualDisplay_ownContentOnly_doesNotCreateMirrorDisplay() {
VirtualDisplay virtualDisplay = createVirtualDisplayForVirtualDevice(
DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY,
DEFAULT_VIRTUAL_DEVICE_PARAMS);
assertThat(virtualDisplay).isNotNull();
Display display = virtualDisplay.getDisplay();
assertThat(display.isValid()).isTrue();
assertThat(mVirtualDeviceManager.isVirtualDeviceOwnedMirrorDisplay(display.getDisplayId()))
.isFalse();
}
@RequiresFlagsEnabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void createVirtualDisplay_autoMirrorAndOwnContentOnly_doesNotCreateMirrorDisplay() {
VirtualDisplay virtualDisplay = createVirtualDisplayForVirtualDevice(
DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
| DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
DEFAULT_VIRTUAL_DEVICE_PARAMS);
assertThat(virtualDisplay).isNotNull();
Display display = virtualDisplay.getDisplay();
assertThat(display.isValid()).isTrue();
assertThat(mVirtualDeviceManager.isVirtualDeviceOwnedMirrorDisplay(display.getDisplayId()))
.isFalse();
}
@RequiresFlagsEnabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void createVirtualDisplay_autoMirror_flagAlwaysUnlockedNotSet() {
VirtualDeviceParams params = new VirtualDeviceParams.Builder()
.setLockState(VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED)
.build();
VirtualDisplay virtualDisplay = createVirtualDisplayForVirtualDevice(
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, params);
assertThat(virtualDisplay).isNotNull();
Display display = virtualDisplay.getDisplay();
assertThat(display.getFlags() & Display.FLAG_ALWAYS_UNLOCKED).isEqualTo(0);
}
@RequiresFlagsEnabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void createVirtualDisplay_public_flagAlwaysUnlockedNotSet() {
VirtualDeviceParams params = new VirtualDeviceParams.Builder()
.setLockState(VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED)
.build();
VirtualDisplay virtualDisplay = createVirtualDisplayForVirtualDevice(
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, params);
assertThat(virtualDisplay).isNotNull();
Display display = virtualDisplay.getDisplay();
assertThat(display.getFlags() & Display.FLAG_ALWAYS_UNLOCKED).isEqualTo(0);
}
@RequiresFlagsEnabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void createVirtualDisplay_autoMirror_flagPresentationNotSet() {
VirtualDisplay virtualDisplay = createVirtualDisplayForVirtualDevice(
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
| DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION,
DEFAULT_VIRTUAL_DEVICE_PARAMS);
assertThat(virtualDisplay).isNotNull();
Display display = virtualDisplay.getDisplay();
assertThat(display.getFlags() & Display.FLAG_PRESENTATION).isEqualTo(0);
}
@RequiresFlagsEnabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void createVirtualDisplay_public_flagPresentationNotSet() {
VirtualDisplay virtualDisplay = createVirtualDisplayForVirtualDevice(
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
| DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION,
DEFAULT_VIRTUAL_DEVICE_PARAMS);
assertThat(virtualDisplay).isNotNull();
Display display = virtualDisplay.getDisplay();
assertThat(display.getFlags() & Display.FLAG_PRESENTATION).isEqualTo(0);
}
@RequiresFlagsEnabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void isVirtualDeviceOwnedMirrorDisplay_invalidDisplay_returnsFalse() {
assertThat(mVirtualDeviceManager.isVirtualDeviceOwnedMirrorDisplay(Display.INVALID_DISPLAY))
.isFalse();
}
@RequiresFlagsEnabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void isVirtualDeviceOwnedMirrorDisplay_defaultDisplay_returnsFalse() {
assertThat(mVirtualDeviceManager.isVirtualDeviceOwnedMirrorDisplay(Display.DEFAULT_DISPLAY))
.isFalse();
}
@RequiresFlagsEnabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void isVirtualDeviceOwnedMirrorDisplay_unownedAutoMirrorDisplay_returnsFalse() {
VirtualDisplay virtualDisplay = createUnownedVirtualDisplay(
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
Display display = virtualDisplay.getDisplay();
assertThat(mVirtualDeviceManager.isVirtualDeviceOwnedMirrorDisplay(display.getDisplayId()))
.isFalse();
}
@RequiresFlagsEnabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void isVirtualDeviceOwnedMirrorDisplay_unownedPublicDisplay_returnsFalse() {
VirtualDisplay virtualDisplay = createUnownedVirtualDisplay(
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC);
Display display = virtualDisplay.getDisplay();
assertThat(mVirtualDeviceManager.isVirtualDeviceOwnedMirrorDisplay(display.getDisplayId()))
.isFalse();
}
@RequiresFlagsEnabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void isVirtualDeviceOwnedMirrorDisplay_unownedPublicAutoMirrorDisplay_returnsFalse() {
VirtualDisplay virtualDisplay = createUnownedVirtualDisplay(
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
| DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
Display display = virtualDisplay.getDisplay();
assertThat(mVirtualDeviceManager.isVirtualDeviceOwnedMirrorDisplay(display.getDisplayId()))
.isFalse();
}
@RequiresFlagsEnabled(Flags.FLAG_INTERACTIVE_SCREEN_MIRROR)
@Test
public void isVirtualDeviceOwnedMirrorDisplay_unownedDisplay_returnsFalse() {
VirtualDisplay virtualDisplay = createUnownedVirtualDisplay();
Display display = virtualDisplay.getDisplay();
assertThat(mVirtualDeviceManager.isVirtualDeviceOwnedMirrorDisplay(display.getDisplayId()))
.isFalse();
}
@Test
public void createVirtualDisplay_trustedDisplay_shouldSpecifyOwnFocusFlag() {
mVirtualDevice =
mVirtualDeviceManager.createVirtualDevice(
mFakeAssociationRule.getAssociationInfo().getId(),
new VirtualDeviceParams.Builder()
.setDevicePolicy(VirtualDeviceParams.POLICY_TYPE_RECENTS,
VirtualDeviceParams.DEVICE_POLICY_CUSTOM)
.build());
VirtualDisplayConfig config = createDefaultVirtualDisplayConfigBuilder()
.setFlags(DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED)
.build();
VirtualDisplay virtualDisplay = mVirtualDevice.createVirtualDisplay(
config, Runnable::run, mVirtualDisplayCallback);
assertThat(mDisplayListener.waitForOnDisplayAddedCallback()).isTrue();
assertThat(virtualDisplay).isNotNull();
Display display = virtualDisplay.getDisplay();
assertThat(display.isValid()).isTrue();
assertThat(display.getFlags()).isEqualTo(Display.FLAG_TOUCH_FEEDBACK_DISABLED
| Display.FLAG_TRUSTED
| Display.FLAG_PRIVATE
| Display.FLAG_OWN_FOCUS);
assertThat(mDisplayListener.getObservedAddedDisplays()).containsExactly(
display.getDisplayId());
}
@Test
public void createVirtualDisplay_alwaysUnlocked_shouldSpecifyAlwaysUnlockedFlag() {
mVirtualDevice =
mVirtualDeviceManager.createVirtualDevice(
mFakeAssociationRule.getAssociationInfo().getId(),
new VirtualDeviceParams.Builder()
.setLockState(VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED)
.build());
VirtualDisplay virtualDisplay = mVirtualDevice.createVirtualDisplay(
DEFAULT_VIRTUAL_DISPLAY_CONFIG, Runnable::run, mVirtualDisplayCallback);
assertThat(mDisplayListener.waitForOnDisplayAddedCallback()).isTrue();
assertThat(virtualDisplay).isNotNull();
Display display = virtualDisplay.getDisplay();
assertThat(display.isValid()).isTrue();
int displayFlags = display.getFlags();
assertWithMessage(
String.format(
"Virtual display flags (0x%x) should contain FLAG_ALWAYS_UNLOCKED",
displayFlags))
.that(displayFlags & Display.FLAG_ALWAYS_UNLOCKED)
.isNotEqualTo(0);
assertThat(mDisplayListener.getObservedAddedDisplays()).containsExactly(
display.getDisplayId());
}
@Test
public void createVirtualDisplay_nullExecutorAndCallback_shouldSucceed() {
mVirtualDevice =
mVirtualDeviceManager.createVirtualDevice(
mFakeAssociationRule.getAssociationInfo().getId(),
DEFAULT_VIRTUAL_DEVICE_PARAMS);
VirtualDisplay virtualDisplay = mVirtualDevice.createVirtualDisplay(
DEFAULT_VIRTUAL_DISPLAY_CONFIG, /* executor= */ null, /* callback= */ null);
assertThat(mDisplayListener.waitForOnDisplayAddedCallback()).isTrue();
assertThat(virtualDisplay).isNotNull();
Display display = virtualDisplay.getDisplay();
assertThat(display.isValid()).isTrue();
assertThat(mDisplayListener.getObservedAddedDisplays()).containsExactly(
Integer.valueOf(display.getDisplayId()));
}
@Test
public void createVirtualDisplay_nullExecutorButNonNullCallback_shouldThrow() {
mVirtualDevice =
mVirtualDeviceManager.createVirtualDevice(
mFakeAssociationRule.getAssociationInfo().getId(),
DEFAULT_VIRTUAL_DEVICE_PARAMS);
assertThrows(NullPointerException.class,
() -> mVirtualDevice.createVirtualDisplay(
DEFAULT_VIRTUAL_DISPLAY_CONFIG, /*executor=*/ null,
mVirtualDisplayCallback));
}
@Test
public void virtualDisplay_createAndRemoveSeveralDisplays() {
mVirtualDevice =
mVirtualDeviceManager.createVirtualDevice(
mFakeAssociationRule.getAssociationInfo().getId(),
DEFAULT_VIRTUAL_DEVICE_PARAMS);
ArrayList<VirtualDisplay> displays = new ArrayList<>();
for (int i = 0; i < 5; i++) {
displays.add(mVirtualDevice.createVirtualDisplay(
DEFAULT_VIRTUAL_DISPLAY_CONFIG, Runnable::run, mVirtualDisplayCallback));
}
// Releasing several displays in quick succession should not cause deadlock
displays.forEach(VirtualDisplay::release);
assertThat(mDisplayListener.waitForOnDisplayRemovedCallback(/*numDisplays=*/5)).isTrue();
assertThat(mDisplayListener.getObservedRemovedDisplays()).containsExactlyElementsIn(
getDisplayIds(displays));
}
@Test
public void virtualDisplay_releasedWhenDeviceIsClosed() {
mVirtualDevice =
mVirtualDeviceManager.createVirtualDevice(
mFakeAssociationRule.getAssociationInfo().getId(),
DEFAULT_VIRTUAL_DEVICE_PARAMS);
ArrayList<VirtualDisplay> displays = new ArrayList<>();
for (int i = 0; i < 5; i++) {
displays.add(mVirtualDevice.createVirtualDisplay(
DEFAULT_VIRTUAL_DISPLAY_CONFIG, Runnable::run, mVirtualDisplayCallback));
}
// Closing the virtual device should automatically release displays.
mVirtualDevice.close();
assertThat(mDisplayListener.waitForOnDisplayRemovedCallback(/*numDisplays=*/5)).isTrue();
assertThat(mDisplayListener.getObservedRemovedDisplays()).containsExactlyElementsIn(
getDisplayIds(displays));
displays.forEach(display -> assertThat(display.getDisplay().isValid()).isFalse());
}
@Test
public void virtualDisplay_releaseDisplaysAndCloseDevice() {
mVirtualDevice =
mVirtualDeviceManager.createVirtualDevice(
mFakeAssociationRule.getAssociationInfo().getId(),
DEFAULT_VIRTUAL_DEVICE_PARAMS);
ArrayList<VirtualDisplay> displays = new ArrayList<>();
for (int i = 0; i < 5; i++) {
displays.add(mVirtualDevice.createVirtualDisplay(
DEFAULT_VIRTUAL_DISPLAY_CONFIG, Runnable::run, mVirtualDisplayCallback));
}
// Releasing and closing the device should result in each display being released only once.
displays.forEach(VirtualDisplay::release);
mVirtualDevice.close();
assertThat(mDisplayListener.waitForOnDisplayRemovedCallback(/*numDisplays=*/5)).isTrue();
assertThat(mDisplayListener.getObservedRemovedDisplays()).containsExactlyElementsIn(
getDisplayIds(displays));
}
@Test
public void getDeviceIdForDisplayId_returnsCorrectId() {
mVirtualDevice =
mVirtualDeviceManager.createVirtualDevice(
mFakeAssociationRule.getAssociationInfo().getId(),
DEFAULT_VIRTUAL_DEVICE_PARAMS);
VirtualDisplay virtualDisplay = mVirtualDevice.createVirtualDisplay(
DEFAULT_VIRTUAL_DISPLAY_CONFIG, Runnable::run, mVirtualDisplayCallback);
assertThat(mVirtualDeviceManager.getDeviceIdForDisplayId(
virtualDisplay.getDisplay().getDisplayId())).isEqualTo(
mVirtualDevice.getDeviceId());
}
@Test
public void getDeviceIdForDisplayId_returnsDefaultIdForReleasedDisplay() {
mVirtualDevice =
mVirtualDeviceManager.createVirtualDevice(
mFakeAssociationRule.getAssociationInfo().getId(),
DEFAULT_VIRTUAL_DEVICE_PARAMS);
VirtualDisplay virtualDisplay = mVirtualDevice.createVirtualDisplay(
DEFAULT_VIRTUAL_DISPLAY_CONFIG, Runnable::run, mVirtualDisplayCallback);
virtualDisplay.release();
assertThat(mDisplayListener.waitForOnDisplayRemovedCallback()).isTrue();
// When virtual display is released, the callback from display manager service to VDM
// is dispatched asynchronously and after display listener callbacks are dispatched.
// Therefore, even receiving onDisplayRemoved callback from display manager doesn't
// guarantee that the display removal was already processed by VDM.
// To test the proper removal but avoid flakiness, the assertion below polls for result
// until it returns DEVICE_ID_DEFAULT (meaning the display was properly disposed of).
// In case the display is not released within the polling timeout, the pollForResult returns
// last value from getDeviceIdForDisplayId call and the test will fail.
assertThat(pollForResult(() -> mVirtualDeviceManager.getDeviceIdForDisplayId(
virtualDisplay.getDisplay().getDisplayId()),
Context.DEVICE_ID_DEFAULT)).isEqualTo(
Context.DEVICE_ID_DEFAULT);
}
@Test
public void createAndRelease_isInvalidForReleasedDisplay() {
mVirtualDevice =
mVirtualDeviceManager.createVirtualDevice(
mFakeAssociationRule.getAssociationInfo().getId(),
DEFAULT_VIRTUAL_DEVICE_PARAMS);
VirtualDisplay virtualDisplay = mVirtualDevice.createVirtualDisplay(
DEFAULT_VIRTUAL_DISPLAY_CONFIG, Runnable::run, mVirtualDisplayCallback);
mVirtualDevice.close();
assertThat(mDisplayListener.waitForOnDisplayRemovedCallback()).isTrue();
// Check whether display associated with virtual device is valid.
Display display = virtualDisplay.getDisplay();
assertThat(display.isValid()).isFalse();
}
private VirtualDisplay createVirtualDisplayForVirtualDevice(int displayFlags,
VirtualDeviceParams deviceParams) {
mVirtualDevice =
mVirtualDeviceManager.createVirtualDevice(
mFakeAssociationRule.getAssociationInfo().getId(),
deviceParams);
VirtualDisplayConfig config = createDefaultVirtualDisplayConfigBuilder()
.setFlags(displayFlags)
.build();
return mVirtualDevice.createVirtualDisplay(
config, Runnable::run, mVirtualDisplayCallback);
}
private VirtualDisplay createUnownedVirtualDisplay() {
VirtualDisplayConfig config = createDefaultVirtualDisplayConfigBuilder().build();
return mDisplayManager.createVirtualDisplay(config);
}
private VirtualDisplay createUnownedVirtualDisplay(int displayFlags) {
VirtualDisplayConfig config = createDefaultVirtualDisplayConfigBuilder()
.setFlags(displayFlags)
.build();
return mDisplayManager.createVirtualDisplay(config);
}
private static List<Integer> getDisplayIds(Collection<VirtualDisplay> displays) {
return displays.stream().map((display) -> display.getDisplay().getDisplayId()).collect(
Collectors.toList());
}
/**
* Polls for result of supplier until the returned value equals expected
* value, or the timeout expires.
*
* @param supplier Supplier to poll from
* @param expectedResult expected result, when this result is returned, polling stops.
* @param <T> return type of supplier
* @return last return value from supplier.
*/
private static <T> T pollForResult(Supplier<T> supplier, T expectedResult) {
final long pollingStartedTime = System.currentTimeMillis();
T lastResult = supplier.get();
while (!Objects.equal(lastResult, expectedResult)
&& (System.currentTimeMillis() - pollingStartedTime < TIMEOUT_MILLIS)) {
try {
Thread.sleep(1);
} catch (InterruptedException ie) {
continue;
}
lastResult = supplier.get();
}
return lastResult;
}
}