Merge "VirtualDisplay: Merge AIDL calls to stop race condition" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c722618ac8
@@ -28,6 +28,7 @@ import android.os.Handler;
|
|||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
|
import android.view.ContentRecordingSession;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
|
||||||
@@ -53,6 +54,8 @@ public final class VirtualDisplayConfig implements Parcelable {
|
|||||||
private final int mDisplayIdToMirror;
|
private final int mDisplayIdToMirror;
|
||||||
private final boolean mWindowManagerMirroringEnabled;
|
private final boolean mWindowManagerMirroringEnabled;
|
||||||
private ArraySet<String> mDisplayCategories = null;
|
private ArraySet<String> mDisplayCategories = null;
|
||||||
|
@Nullable
|
||||||
|
private ContentRecordingSession mContentRecordingSession;
|
||||||
private final float mRequestedRefreshRate;
|
private final float mRequestedRefreshRate;
|
||||||
|
|
||||||
private VirtualDisplayConfig(
|
private VirtualDisplayConfig(
|
||||||
@@ -65,6 +68,7 @@ public final class VirtualDisplayConfig implements Parcelable {
|
|||||||
@Nullable String uniqueId,
|
@Nullable String uniqueId,
|
||||||
int displayIdToMirror,
|
int displayIdToMirror,
|
||||||
boolean windowManagerMirroringEnabled,
|
boolean windowManagerMirroringEnabled,
|
||||||
|
ContentRecordingSession session,
|
||||||
@NonNull ArraySet<String> displayCategories,
|
@NonNull ArraySet<String> displayCategories,
|
||||||
float requestedRefreshRate) {
|
float requestedRefreshRate) {
|
||||||
mName = name;
|
mName = name;
|
||||||
@@ -76,6 +80,7 @@ public final class VirtualDisplayConfig implements Parcelable {
|
|||||||
mUniqueId = uniqueId;
|
mUniqueId = uniqueId;
|
||||||
mDisplayIdToMirror = displayIdToMirror;
|
mDisplayIdToMirror = displayIdToMirror;
|
||||||
mWindowManagerMirroringEnabled = windowManagerMirroringEnabled;
|
mWindowManagerMirroringEnabled = windowManagerMirroringEnabled;
|
||||||
|
mContentRecordingSession = session;
|
||||||
mDisplayCategories = displayCategories;
|
mDisplayCategories = displayCategories;
|
||||||
mRequestedRefreshRate = requestedRefreshRate;
|
mRequestedRefreshRate = requestedRefreshRate;
|
||||||
}
|
}
|
||||||
@@ -155,6 +160,17 @@ public final class VirtualDisplayConfig implements Parcelable {
|
|||||||
return mWindowManagerMirroringEnabled;
|
return mWindowManagerMirroringEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the recording session associated with this VirtualDisplay. Only used for
|
||||||
|
* recording via {@link MediaProjection}.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public ContentRecordingSession getContentRecordingSession() {
|
||||||
|
return mContentRecordingSession;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the display categories.
|
* Returns the display categories.
|
||||||
*
|
*
|
||||||
@@ -186,6 +202,7 @@ public final class VirtualDisplayConfig implements Parcelable {
|
|||||||
dest.writeString8(mUniqueId);
|
dest.writeString8(mUniqueId);
|
||||||
dest.writeInt(mDisplayIdToMirror);
|
dest.writeInt(mDisplayIdToMirror);
|
||||||
dest.writeBoolean(mWindowManagerMirroringEnabled);
|
dest.writeBoolean(mWindowManagerMirroringEnabled);
|
||||||
|
dest.writeTypedObject(mContentRecordingSession, flags);
|
||||||
dest.writeArraySet(mDisplayCategories);
|
dest.writeArraySet(mDisplayCategories);
|
||||||
dest.writeFloat(mRequestedRefreshRate);
|
dest.writeFloat(mRequestedRefreshRate);
|
||||||
}
|
}
|
||||||
@@ -211,6 +228,7 @@ public final class VirtualDisplayConfig implements Parcelable {
|
|||||||
&& Objects.equals(mUniqueId, that.mUniqueId)
|
&& Objects.equals(mUniqueId, that.mUniqueId)
|
||||||
&& mDisplayIdToMirror == that.mDisplayIdToMirror
|
&& mDisplayIdToMirror == that.mDisplayIdToMirror
|
||||||
&& mWindowManagerMirroringEnabled == that.mWindowManagerMirroringEnabled
|
&& mWindowManagerMirroringEnabled == that.mWindowManagerMirroringEnabled
|
||||||
|
&& Objects.equals(mContentRecordingSession, that.mContentRecordingSession)
|
||||||
&& Objects.equals(mDisplayCategories, that.mDisplayCategories)
|
&& Objects.equals(mDisplayCategories, that.mDisplayCategories)
|
||||||
&& mRequestedRefreshRate == that.mRequestedRefreshRate;
|
&& mRequestedRefreshRate == that.mRequestedRefreshRate;
|
||||||
}
|
}
|
||||||
@@ -219,8 +237,8 @@ public final class VirtualDisplayConfig implements Parcelable {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int hashCode = Objects.hash(
|
int hashCode = Objects.hash(
|
||||||
mName, mWidth, mHeight, mDensityDpi, mFlags, mSurface, mUniqueId,
|
mName, mWidth, mHeight, mDensityDpi, mFlags, mSurface, mUniqueId,
|
||||||
mDisplayIdToMirror, mWindowManagerMirroringEnabled, mDisplayCategories,
|
mDisplayIdToMirror, mWindowManagerMirroringEnabled, mContentRecordingSession,
|
||||||
mRequestedRefreshRate);
|
mDisplayCategories, mRequestedRefreshRate);
|
||||||
return hashCode;
|
return hashCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,6 +255,7 @@ public final class VirtualDisplayConfig implements Parcelable {
|
|||||||
+ " mUniqueId=" + mUniqueId
|
+ " mUniqueId=" + mUniqueId
|
||||||
+ " mDisplayIdToMirror=" + mDisplayIdToMirror
|
+ " mDisplayIdToMirror=" + mDisplayIdToMirror
|
||||||
+ " mWindowManagerMirroringEnabled=" + mWindowManagerMirroringEnabled
|
+ " mWindowManagerMirroringEnabled=" + mWindowManagerMirroringEnabled
|
||||||
|
+ " mContentRecordingSession=" + mContentRecordingSession
|
||||||
+ " mDisplayCategories=" + mDisplayCategories
|
+ " mDisplayCategories=" + mDisplayCategories
|
||||||
+ " mRequestedRefreshRate=" + mRequestedRefreshRate
|
+ " mRequestedRefreshRate=" + mRequestedRefreshRate
|
||||||
+ ")";
|
+ ")";
|
||||||
@@ -252,6 +271,7 @@ public final class VirtualDisplayConfig implements Parcelable {
|
|||||||
mUniqueId = in.readString8();
|
mUniqueId = in.readString8();
|
||||||
mDisplayIdToMirror = in.readInt();
|
mDisplayIdToMirror = in.readInt();
|
||||||
mWindowManagerMirroringEnabled = in.readBoolean();
|
mWindowManagerMirroringEnabled = in.readBoolean();
|
||||||
|
mContentRecordingSession = in.readTypedObject(ContentRecordingSession.CREATOR);
|
||||||
mDisplayCategories = (ArraySet<String>) in.readArraySet(null);
|
mDisplayCategories = (ArraySet<String>) in.readArraySet(null);
|
||||||
mRequestedRefreshRate = in.readFloat();
|
mRequestedRefreshRate = in.readFloat();
|
||||||
}
|
}
|
||||||
@@ -283,6 +303,8 @@ public final class VirtualDisplayConfig implements Parcelable {
|
|||||||
private String mUniqueId = null;
|
private String mUniqueId = null;
|
||||||
private int mDisplayIdToMirror = DEFAULT_DISPLAY;
|
private int mDisplayIdToMirror = DEFAULT_DISPLAY;
|
||||||
private boolean mWindowManagerMirroringEnabled = false;
|
private boolean mWindowManagerMirroringEnabled = false;
|
||||||
|
@Nullable
|
||||||
|
private ContentRecordingSession mContentRecordingSession;
|
||||||
private ArraySet<String> mDisplayCategories = new ArraySet<>();
|
private ArraySet<String> mDisplayCategories = new ArraySet<>();
|
||||||
private float mRequestedRefreshRate = 0.0f;
|
private float mRequestedRefreshRate = 0.0f;
|
||||||
|
|
||||||
@@ -374,6 +396,18 @@ public final class VirtualDisplayConfig implements Parcelable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the recording session associated with this {@link VirtualDisplay}. Only used for
|
||||||
|
* recording via {@link MediaProjection}.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public Builder setContentRecordingSession(@Nullable ContentRecordingSession session) {
|
||||||
|
mContentRecordingSession = session;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the display categories.
|
* Sets the display categories.
|
||||||
*
|
*
|
||||||
@@ -435,6 +469,7 @@ public final class VirtualDisplayConfig implements Parcelable {
|
|||||||
mUniqueId,
|
mUniqueId,
|
||||||
mDisplayIdToMirror,
|
mDisplayIdToMirror,
|
||||||
mWindowManagerMirroringEnabled,
|
mWindowManagerMirroringEnabled,
|
||||||
|
mContentRecordingSession,
|
||||||
mDisplayCategories,
|
mDisplayCategories,
|
||||||
mRequestedRefreshRate);
|
mRequestedRefreshRate);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,20 +191,13 @@ public final class MediaProjection {
|
|||||||
} else {
|
} else {
|
||||||
session = ContentRecordingSession.createTaskSession(launchCookie);
|
session = ContentRecordingSession.createTaskSession(launchCookie);
|
||||||
}
|
}
|
||||||
|
// Pass in the current session details, so they are guaranteed to only be set in WMS
|
||||||
|
// AFTER a VirtualDisplay is constructed (assuming there are no errors during set-up).
|
||||||
|
virtualDisplayConfig.setContentRecordingSession(session);
|
||||||
virtualDisplayConfig.setWindowManagerMirroringEnabled(true);
|
virtualDisplayConfig.setWindowManagerMirroringEnabled(true);
|
||||||
final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
|
final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
|
||||||
final VirtualDisplay virtualDisplay = dm.createVirtualDisplay(this,
|
final VirtualDisplay virtualDisplay = dm.createVirtualDisplay(this,
|
||||||
virtualDisplayConfig.build(), callback, handler, windowContext);
|
virtualDisplayConfig.build(), callback, handler, windowContext);
|
||||||
if (virtualDisplay == null) {
|
|
||||||
// Since WM handling a new display and DM creating a new VirtualDisplay is async,
|
|
||||||
// WM may have tried to start task recording and encountered an error that required
|
|
||||||
// stopping recording entirely. The VirtualDisplay would then be null when the
|
|
||||||
// MediaProjection is no longer active.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
session.setDisplayId(virtualDisplay.getDisplay().getDisplayId());
|
|
||||||
// Successfully set up, so save the current session details.
|
|
||||||
getProjectionService().setContentRecordingSession(session, mImpl);
|
|
||||||
return virtualDisplay;
|
return virtualDisplay;
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
// Can not capture if WMS is not accessible, so bail out.
|
// Can not capture if WMS is not accessible, so bail out.
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ import android.util.Slog;
|
|||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
import android.util.Spline;
|
import android.util.Spline;
|
||||||
|
import android.view.ContentRecordingSession;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
import android.view.DisplayEventReceiver;
|
import android.view.DisplayEventReceiver;
|
||||||
import android.view.DisplayInfo;
|
import android.view.DisplayInfo;
|
||||||
@@ -250,6 +251,7 @@ public final class DisplayManagerService extends SystemService {
|
|||||||
private ActivityManagerInternal mActivityManagerInternal;
|
private ActivityManagerInternal mActivityManagerInternal;
|
||||||
private ActivityManager mActivityManager;
|
private ActivityManager mActivityManager;
|
||||||
private UidImportanceListener mUidImportanceListener = new UidImportanceListener();
|
private UidImportanceListener mUidImportanceListener = new UidImportanceListener();
|
||||||
|
@Nullable
|
||||||
private IMediaProjectionManager mProjectionService;
|
private IMediaProjectionManager mProjectionService;
|
||||||
private DeviceStateManagerInternal mDeviceStateManager;
|
private DeviceStateManagerInternal mDeviceStateManager;
|
||||||
@GuardedBy("mSyncRoot")
|
@GuardedBy("mSyncRoot")
|
||||||
@@ -1494,8 +1496,9 @@ public final class DisplayManagerService extends SystemService {
|
|||||||
|
|
||||||
final long token = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
|
final int displayId;
|
||||||
synchronized (mSyncRoot) {
|
synchronized (mSyncRoot) {
|
||||||
final int displayId =
|
displayId =
|
||||||
createVirtualDisplayLocked(
|
createVirtualDisplayLocked(
|
||||||
callback,
|
callback,
|
||||||
projection,
|
projection,
|
||||||
@@ -1509,8 +1512,39 @@ public final class DisplayManagerService extends SystemService {
|
|||||||
mDisplayWindowPolicyControllers.put(
|
mDisplayWindowPolicyControllers.put(
|
||||||
displayId, Pair.create(virtualDevice, dwpc));
|
displayId, Pair.create(virtualDevice, dwpc));
|
||||||
}
|
}
|
||||||
return displayId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When calling setContentRecordingSession into the WindowManagerService, the WMS
|
||||||
|
// attempts to acquire a lock before executing its main body. Due to this, we need
|
||||||
|
// to be sure that it isn't called while the DisplayManagerService is also holding
|
||||||
|
// a lock, to avoid a deadlock scenario.
|
||||||
|
final ContentRecordingSession session =
|
||||||
|
virtualDisplayConfig.getContentRecordingSession();
|
||||||
|
|
||||||
|
if (displayId != Display.INVALID_DISPLAY && session != null) {
|
||||||
|
// Only attempt to set content recording session if there are details to set and a
|
||||||
|
// VirtualDisplay has been successfully constructed.
|
||||||
|
session.setDisplayId(displayId);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// been constructed before calling setContentRecordingSession, we avoid a race
|
||||||
|
// condition between the DMS & WMS which could lead to the MediaProjection
|
||||||
|
// being pre-emptively torn down.
|
||||||
|
if (!mWindowManagerInternal.setContentRecordingSession(session)) {
|
||||||
|
// Unable to start mirroring, so tear down projection & release VirtualDisplay.
|
||||||
|
try {
|
||||||
|
getProjectionService().stopActiveProjection();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Slog.e(TAG, "Unable to tell MediaProjectionManagerService to stop the "
|
||||||
|
+ "active projection", e);
|
||||||
|
}
|
||||||
|
releaseVirtualDisplayInternal(callback.asBinder());
|
||||||
|
return Display.INVALID_DISPLAY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return displayId;
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(token);
|
Binder.restoreCallingIdentity(token);
|
||||||
}
|
}
|
||||||
@@ -2804,8 +2838,7 @@ public final class DisplayManagerService extends SystemService {
|
|||||||
|
|
||||||
private IMediaProjectionManager getProjectionService() {
|
private IMediaProjectionManager getProjectionService() {
|
||||||
if (mProjectionService == null) {
|
if (mProjectionService == null) {
|
||||||
IBinder b = ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE);
|
mProjectionService = mInjector.getProjectionService();
|
||||||
mProjectionService = IMediaProjectionManager.Stub.asInterface(b);
|
|
||||||
}
|
}
|
||||||
return mProjectionService;
|
return mProjectionService;
|
||||||
}
|
}
|
||||||
@@ -2964,6 +2997,11 @@ public final class DisplayManagerService extends SystemService {
|
|||||||
boolean getHdrOutputConversionSupport() {
|
boolean getHdrOutputConversionSupport() {
|
||||||
return DisplayControl.getHdrOutputConversionSupport();
|
return DisplayControl.getHdrOutputConversionSupport();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IMediaProjectionManager getProjectionService() {
|
||||||
|
IBinder b = ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE);
|
||||||
|
return IMediaProjectionManager.Stub.asInterface(b);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
|||||||
@@ -88,7 +88,17 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
|
|||||||
// Called with SyncRoot lock held.
|
// Called with SyncRoot lock held.
|
||||||
public VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
|
public VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
|
||||||
Context context, Handler handler, Listener listener) {
|
Context context, Handler handler, Listener listener) {
|
||||||
this(syncRoot, context, handler, listener, DisplayControl::createDisplay);
|
this(syncRoot, context, handler, listener, new SurfaceControlDisplayFactory() {
|
||||||
|
@Override
|
||||||
|
public IBinder createDisplay(String name, boolean secure, float requestedRefreshRate) {
|
||||||
|
return DisplayControl.createDisplay(name, secure, requestedRefreshRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroyDisplay(IBinder displayToken) {
|
||||||
|
DisplayControl.destroyDisplay(displayToken);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -311,7 +321,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
|
|||||||
mSurface.release();
|
mSurface.release();
|
||||||
mSurface = null;
|
mSurface = null;
|
||||||
}
|
}
|
||||||
DisplayControl.destroyDisplay(getDisplayTokenLocked());
|
mSurfaceControlDisplayFactory.destroyDisplay(getDisplayTokenLocked());
|
||||||
if (mProjection != null && mMediaProjectionCallback != null) {
|
if (mProjection != null && mMediaProjectionCallback != null) {
|
||||||
try {
|
try {
|
||||||
mProjection.unregisterCallback(mMediaProjectionCallback);
|
mProjection.unregisterCallback(mMediaProjectionCallback);
|
||||||
@@ -653,5 +663,12 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
|
|||||||
* @return The token reference for the display in SurfaceFlinger.
|
* @return The token reference for the display in SurfaceFlinger.
|
||||||
*/
|
*/
|
||||||
IBinder createDisplay(String name, boolean secure, float requestedRefreshRate);
|
IBinder createDisplay(String name, boolean secure, float requestedRefreshRate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a display in SurfaceFlinger.
|
||||||
|
*
|
||||||
|
* @param displayToken The display token for the display to be destroyed.
|
||||||
|
*/
|
||||||
|
void destroyDisplay(IBinder displayToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
<uses-permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES" />
|
<uses-permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_CONTEXT_HUB" />
|
<uses-permission android:name="android.permission.ACCESS_CONTEXT_HUB" />
|
||||||
<uses-permission android:name="android.permission.USE_BIOMETRIC_INTERNAL" />
|
<uses-permission android:name="android.permission.USE_BIOMETRIC_INTERNAL" />
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
|
||||||
|
|
||||||
<queries>
|
<queries>
|
||||||
<package android:name="com.android.servicestests.apps.suspendtestapp" />
|
<package android:name="com.android.servicestests.apps.suspendtestapp" />
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_D
|
|||||||
|
|
||||||
import static com.android.server.display.VirtualDisplayAdapter.UNIQUE_ID_PREFIX;
|
import static com.android.server.display.VirtualDisplayAdapter.UNIQUE_ID_PREFIX;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotEquals;
|
import static org.junit.Assert.assertNotEquals;
|
||||||
@@ -32,8 +34,10 @@ import static org.junit.Assert.assertThrows;
|
|||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
|
import static org.mockito.Mockito.any;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@@ -61,10 +65,13 @@ import android.hardware.display.HdrConversionMode;
|
|||||||
import android.hardware.display.IDisplayManagerCallback;
|
import android.hardware.display.IDisplayManagerCallback;
|
||||||
import android.hardware.display.IVirtualDisplayCallback;
|
import android.hardware.display.IVirtualDisplayCallback;
|
||||||
import android.hardware.display.VirtualDisplayConfig;
|
import android.hardware.display.VirtualDisplayConfig;
|
||||||
|
import android.media.projection.IMediaProjectionManager;
|
||||||
|
import android.os.Binder;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.MessageQueue;
|
import android.os.MessageQueue;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
|
import android.view.ContentRecordingSession;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
import android.view.DisplayCutout;
|
import android.view.DisplayCutout;
|
||||||
import android.view.DisplayEventReceiver;
|
import android.view.DisplayEventReceiver;
|
||||||
@@ -158,25 +165,40 @@ public class DisplayManagerServiceTest {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class BasicInjector extends DisplayManagerService.Injector {
|
class BasicInjector extends DisplayManagerService.Injector {
|
||||||
@Override
|
@Override
|
||||||
VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, Context context,
|
IMediaProjectionManager getProjectionService() {
|
||||||
Handler handler, DisplayAdapter.Listener displayAdapterListener) {
|
return mMockProjectionService;
|
||||||
return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener,
|
}
|
||||||
(String name, boolean secure, float refreshRate) -> mMockDisplayToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
LocalDisplayAdapter getLocalDisplayAdapter(SyncRoot syncRoot, Context context,
|
VirtualDisplayAdapter getVirtualDisplayAdapter(SyncRoot syncRoot, Context context,
|
||||||
Handler handler, DisplayAdapter.Listener displayAdapterListener) {
|
Handler handler, DisplayAdapter.Listener displayAdapterListener) {
|
||||||
return new LocalDisplayAdapter(syncRoot, context, handler,
|
return new VirtualDisplayAdapter(syncRoot, context, handler, displayAdapterListener,
|
||||||
displayAdapterListener, new LocalDisplayAdapter.Injector() {
|
new VirtualDisplayAdapter.SurfaceControlDisplayFactory() {
|
||||||
@Override
|
@Override
|
||||||
public LocalDisplayAdapter.SurfaceControlProxy getSurfaceControlProxy() {
|
public IBinder createDisplay(String name, boolean secure,
|
||||||
return mSurfaceControlProxy;
|
float requestedRefreshRate) {
|
||||||
}
|
return mMockDisplayToken;
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public void destroyDisplay(IBinder displayToken) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
LocalDisplayAdapter getLocalDisplayAdapter(SyncRoot syncRoot, Context context,
|
||||||
|
Handler handler, DisplayAdapter.Listener displayAdapterListener) {
|
||||||
|
return new LocalDisplayAdapter(syncRoot, context, handler,
|
||||||
|
displayAdapterListener, new LocalDisplayAdapter.Injector() {
|
||||||
|
@Override
|
||||||
|
public LocalDisplayAdapter.SurfaceControlProxy getSurfaceControlProxy() {
|
||||||
|
return mSurfaceControlProxy;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int setHdrConversionMode(int conversionMode, int preferredHdrOutputType,
|
int setHdrConversionMode(int conversionMode, int preferredHdrOutputType,
|
||||||
@@ -198,6 +220,7 @@ public class DisplayManagerServiceTest {
|
|||||||
|
|
||||||
private final DisplayManagerService.Injector mBasicInjector = new BasicInjector();
|
private final DisplayManagerService.Injector mBasicInjector = new BasicInjector();
|
||||||
|
|
||||||
|
@Mock IMediaProjectionManager mMockProjectionService;
|
||||||
@Mock IVirtualDeviceManager mIVirtualDeviceManager;
|
@Mock IVirtualDeviceManager mIVirtualDeviceManager;
|
||||||
@Mock InputManagerInternal mMockInputManagerInternal;
|
@Mock InputManagerInternal mMockInputManagerInternal;
|
||||||
@Mock VirtualDeviceManagerInternal mMockVirtualDeviceManagerInternal;
|
@Mock VirtualDeviceManagerInternal mMockVirtualDeviceManagerInternal;
|
||||||
@@ -285,6 +308,7 @@ public class DisplayManagerServiceTest {
|
|||||||
builder.setFlags(flags);
|
builder.setFlags(flags);
|
||||||
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
|
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
|
||||||
null /* projection */, PACKAGE_NAME);
|
null /* projection */, PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
|
|
||||||
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
||||||
|
|
||||||
@@ -410,6 +434,7 @@ public class DisplayManagerServiceTest {
|
|||||||
builder.setUniqueId(uniqueId);
|
builder.setUniqueId(uniqueId);
|
||||||
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
|
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
|
||||||
null /* projection */, PACKAGE_NAME);
|
null /* projection */, PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
|
|
||||||
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
||||||
|
|
||||||
@@ -446,6 +471,7 @@ public class DisplayManagerServiceTest {
|
|||||||
builder.setUniqueId(uniqueId);
|
builder.setUniqueId(uniqueId);
|
||||||
int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken,
|
int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken,
|
||||||
/* projection= */ null, PACKAGE_NAME);
|
/* projection= */ null, PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
|
|
||||||
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
||||||
|
|
||||||
@@ -479,6 +505,7 @@ public class DisplayManagerServiceTest {
|
|||||||
builder.setUniqueId(uniqueId);
|
builder.setUniqueId(uniqueId);
|
||||||
int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken,
|
int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken,
|
||||||
/* projection= */ null, PACKAGE_NAME);
|
/* projection= */ null, PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
|
|
||||||
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
||||||
|
|
||||||
@@ -720,6 +747,7 @@ public class DisplayManagerServiceTest {
|
|||||||
builder.setUniqueId(uniqueId);
|
builder.setUniqueId(uniqueId);
|
||||||
final int firstDisplayId = binderService.createVirtualDisplay(builder.build(),
|
final int firstDisplayId = binderService.createVirtualDisplay(builder.build(),
|
||||||
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
|
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
|
|
||||||
// The second virtual display requests to mirror the first virtual display.
|
// The second virtual display requests to mirror the first virtual display.
|
||||||
final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2";
|
final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2";
|
||||||
@@ -731,6 +759,7 @@ public class DisplayManagerServiceTest {
|
|||||||
final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(),
|
final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(),
|
||||||
mMockAppToken2 /* callback */, null /* projection */,
|
mMockAppToken2 /* callback */, null /* projection */,
|
||||||
PACKAGE_NAME);
|
PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
||||||
|
|
||||||
// flush the handler
|
// flush the handler
|
||||||
@@ -768,6 +797,7 @@ public class DisplayManagerServiceTest {
|
|||||||
virtualDevice /* virtualDeviceToken */,
|
virtualDevice /* virtualDeviceToken */,
|
||||||
mock(DisplayWindowPolicyController.class),
|
mock(DisplayWindowPolicyController.class),
|
||||||
PACKAGE_NAME);
|
PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId;
|
int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId;
|
||||||
|
|
||||||
// Create a second virtual display. This should be added to the previously created display
|
// Create a second virtual display. This should be added to the previously created display
|
||||||
@@ -783,6 +813,7 @@ public class DisplayManagerServiceTest {
|
|||||||
virtualDevice /* virtualDeviceToken */,
|
virtualDevice /* virtualDeviceToken */,
|
||||||
mock(DisplayWindowPolicyController.class),
|
mock(DisplayWindowPolicyController.class),
|
||||||
PACKAGE_NAME);
|
PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId;
|
int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId;
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@@ -820,6 +851,7 @@ public class DisplayManagerServiceTest {
|
|||||||
virtualDevice /* virtualDeviceToken */,
|
virtualDevice /* virtualDeviceToken */,
|
||||||
mock(DisplayWindowPolicyController.class),
|
mock(DisplayWindowPolicyController.class),
|
||||||
PACKAGE_NAME);
|
PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId;
|
int displayGroupId1 = localService.getDisplayInfo(displayId1).displayGroupId;
|
||||||
|
|
||||||
// Create a second virtual display. With the flag VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP,
|
// Create a second virtual display. With the flag VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP,
|
||||||
@@ -838,6 +870,7 @@ public class DisplayManagerServiceTest {
|
|||||||
virtualDevice /* virtualDeviceToken */,
|
virtualDevice /* virtualDeviceToken */,
|
||||||
mock(DisplayWindowPolicyController.class),
|
mock(DisplayWindowPolicyController.class),
|
||||||
PACKAGE_NAME);
|
PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId;
|
int displayGroupId2 = localService.getDisplayInfo(displayId2).displayGroupId;
|
||||||
|
|
||||||
assertNotEquals(
|
assertNotEquals(
|
||||||
@@ -881,6 +914,7 @@ public class DisplayManagerServiceTest {
|
|||||||
virtualDevice /* virtualDeviceToken */,
|
virtualDevice /* virtualDeviceToken */,
|
||||||
mock(DisplayWindowPolicyController.class),
|
mock(DisplayWindowPolicyController.class),
|
||||||
PACKAGE_NAME);
|
PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
|
|
||||||
// Check that FLAG_ALWAYS_UNLOCKED is set.
|
// Check that FLAG_ALWAYS_UNLOCKED is set.
|
||||||
assertNotEquals(
|
assertNotEquals(
|
||||||
@@ -906,6 +940,7 @@ public class DisplayManagerServiceTest {
|
|||||||
virtualDevice /* virtualDeviceToken */,
|
virtualDevice /* virtualDeviceToken */,
|
||||||
mock(DisplayWindowPolicyController.class),
|
mock(DisplayWindowPolicyController.class),
|
||||||
PACKAGE_NAME);
|
PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
|
|
||||||
// Check that FLAG_ALWAYS_UNLOCKED is set.
|
// Check that FLAG_ALWAYS_UNLOCKED is set.
|
||||||
assertNotEquals(
|
assertNotEquals(
|
||||||
@@ -929,6 +964,7 @@ public class DisplayManagerServiceTest {
|
|||||||
null /* virtualDeviceToken */,
|
null /* virtualDeviceToken */,
|
||||||
mock(DisplayWindowPolicyController.class),
|
mock(DisplayWindowPolicyController.class),
|
||||||
PACKAGE_NAME);
|
PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
|
|
||||||
// Check that FLAG_ALWAYS_UNLOCKED is not set.
|
// Check that FLAG_ALWAYS_UNLOCKED is not set.
|
||||||
assertEquals(
|
assertEquals(
|
||||||
@@ -960,6 +996,7 @@ public class DisplayManagerServiceTest {
|
|||||||
.setFlags(VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
|
.setFlags(VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
|
||||||
final int firstDisplayId = binderService.createVirtualDisplay(builder.build(),
|
final int firstDisplayId = binderService.createVirtualDisplay(builder.build(),
|
||||||
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
|
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
|
|
||||||
// The second virtual display requests to mirror the first virtual display.
|
// The second virtual display requests to mirror the first virtual display.
|
||||||
final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2";
|
final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2";
|
||||||
@@ -971,6 +1008,7 @@ public class DisplayManagerServiceTest {
|
|||||||
final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(),
|
final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(),
|
||||||
mMockAppToken2 /* callback */, null /* projection */,
|
mMockAppToken2 /* callback */, null /* projection */,
|
||||||
PACKAGE_NAME);
|
PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
||||||
|
|
||||||
// flush the handler
|
// flush the handler
|
||||||
@@ -985,6 +1023,54 @@ public class DisplayManagerServiceTest {
|
|||||||
Display.INVALID_DISPLAY);
|
Display.INVALID_DISPLAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateVirtualDisplay_setContentRecordingSessionSuccess() throws Exception {
|
||||||
|
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
|
||||||
|
when(mMockWindowManagerInternal
|
||||||
|
.setContentRecordingSession(any(ContentRecordingSession.class)))
|
||||||
|
.thenReturn(true);
|
||||||
|
|
||||||
|
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
|
||||||
|
VIRTUAL_DISPLAY_NAME, 600, 800, 320);
|
||||||
|
builder.setUniqueId("uniqueId --- setContentRecordingSession true");
|
||||||
|
builder.setContentRecordingSession(
|
||||||
|
ContentRecordingSession.createDisplaySession(new Binder("")));
|
||||||
|
|
||||||
|
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
|
||||||
|
registerDefaultDisplays(displayManager);
|
||||||
|
displayManager.windowManagerAndInputReady();
|
||||||
|
|
||||||
|
DisplayManagerService.BinderService binderService = displayManager.new BinderService();
|
||||||
|
final int displayId = binderService.createVirtualDisplay(builder.build(),
|
||||||
|
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
|
||||||
|
|
||||||
|
assertThat(displayId).isNotEqualTo(Display.INVALID_DISPLAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateVirtualDisplay_setContentRecordingSessionFail() throws Exception {
|
||||||
|
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
|
||||||
|
when(mMockWindowManagerInternal
|
||||||
|
.setContentRecordingSession(any(ContentRecordingSession.class)))
|
||||||
|
.thenReturn(false);
|
||||||
|
|
||||||
|
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
|
||||||
|
VIRTUAL_DISPLAY_NAME, 600, 800, 320);
|
||||||
|
builder.setUniqueId("uniqueId --- setContentRecordingSession false");
|
||||||
|
builder.setContentRecordingSession(
|
||||||
|
ContentRecordingSession.createDisplaySession(new Binder("")));
|
||||||
|
|
||||||
|
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
|
||||||
|
registerDefaultDisplays(displayManager);
|
||||||
|
displayManager.windowManagerAndInputReady();
|
||||||
|
|
||||||
|
DisplayManagerService.BinderService binderService = displayManager.new BinderService();
|
||||||
|
final int displayId = binderService.createVirtualDisplay(builder.build(),
|
||||||
|
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
|
||||||
|
|
||||||
|
assertThat(displayId).isEqualTo(Display.INVALID_DISPLAY);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that the virtual display is created with
|
* Tests that the virtual display is created with
|
||||||
* {@link VirtualDisplayConfig.Builder#setSurface(Surface)}
|
* {@link VirtualDisplayConfig.Builder#setSurface(Surface)}
|
||||||
@@ -1011,6 +1097,7 @@ public class DisplayManagerServiceTest {
|
|||||||
builder.setUniqueId(uniqueId);
|
builder.setUniqueId(uniqueId);
|
||||||
final int displayId = binderService.createVirtualDisplay(builder.build(),
|
final int displayId = binderService.createVirtualDisplay(builder.build(),
|
||||||
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
|
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
|
|
||||||
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
||||||
|
|
||||||
@@ -1043,6 +1130,7 @@ public class DisplayManagerServiceTest {
|
|||||||
|
|
||||||
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
|
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
|
||||||
null /* projection */, PACKAGE_NAME);
|
null /* projection */, PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
||||||
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
|
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
|
||||||
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
|
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
|
||||||
@@ -1093,7 +1181,6 @@ public class DisplayManagerServiceTest {
|
|||||||
|
|
||||||
registerDefaultDisplays(displayManager);
|
registerDefaultDisplays(displayManager);
|
||||||
|
|
||||||
DisplayManagerService.BinderService bs = displayManager.new BinderService();
|
|
||||||
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
|
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
|
||||||
|
|
||||||
when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn(
|
when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn(
|
||||||
@@ -1111,6 +1198,7 @@ public class DisplayManagerServiceTest {
|
|||||||
int displayId = localService.createVirtualDisplay(builder.build(),
|
int displayId = localService.createVirtualDisplay(builder.build(),
|
||||||
mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */,
|
mMockAppToken /* callback */, virtualDevice /* virtualDeviceToken */,
|
||||||
mock(DisplayWindowPolicyController.class), PACKAGE_NAME);
|
mock(DisplayWindowPolicyController.class), PACKAGE_NAME);
|
||||||
|
verify(mMockWindowManagerInternal, never()).setContentRecordingSession(Mockito.any());
|
||||||
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
|
||||||
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
|
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
|
||||||
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
|
DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
|
||||||
|
|||||||
Reference in New Issue
Block a user