Merge "[wm] VirtualDisplayConfig to mirror the non-default display" into rvc-dev

This commit is contained in:
TreeHugger Robot
2020-04-03 18:59:27 +00:00
committed by Android (Google) Code Review
11 changed files with 777 additions and 72 deletions

View File

@@ -634,17 +634,39 @@ public final class DisplayManager {
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int densityDpi, @Nullable Surface surface, int flags,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
return createVirtualDisplay(null /* projection */, name, width, height, densityDpi, surface,
flags, callback, handler, null /* uniqueId */);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
height, densityDpi);
builder.setFlags(flags);
if (surface != null) {
builder.setSurface(surface);
}
return createVirtualDisplay(null /* projection */, builder.build(), callback, handler);
}
// TODO : Remove this hidden API after remove all callers. (Refer to MultiDisplayService)
/** @hide */
public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
@NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface,
int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler,
@Nullable String uniqueId) {
return mGlobal.createVirtualDisplay(mContext, projection,
name, width, height, densityDpi, surface, flags, callback, handler, uniqueId);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
height, densityDpi);
builder.setFlags(flags);
if (uniqueId != null) {
builder.setUniqueId(uniqueId);
}
if (surface != null) {
builder.setSurface(surface);
}
return createVirtualDisplay(projection, builder.build(), callback, handler);
}
/** @hide */
public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
@NonNull VirtualDisplayConfig virtualDisplayConfig,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
return mGlobal.createVirtualDisplay(mContext, projection, virtualDisplayConfig, callback,
handler);
}
/**

View File

@@ -451,35 +451,26 @@ public final class DisplayManagerGlobal {
}
}
public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection,
String name, int width, int height, int densityDpi, Surface surface, int flags,
VirtualDisplay.Callback callback, Handler handler, String uniqueId) {
if (TextUtils.isEmpty(name)) {
throw new IllegalArgumentException("name must be non-null and non-empty");
}
if (width <= 0 || height <= 0 || densityDpi <= 0) {
throw new IllegalArgumentException("width, height, and densityDpi must be "
+ "greater than 0");
}
public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection,
@NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback,
Handler handler) {
VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler);
IMediaProjection projectionToken = projection != null ? projection.getProjection() : null;
int displayId;
try {
displayId = mDm.createVirtualDisplay(callbackWrapper, projectionToken,
context.getPackageName(), name, width, height, densityDpi, surface, flags,
uniqueId);
displayId = mDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper,
projectionToken, context.getPackageName());
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
if (displayId < 0) {
Log.e(TAG, "Could not create virtual display: " + name);
Log.e(TAG, "Could not create virtual display: " + virtualDisplayConfig.getName());
return null;
}
Display display = getRealDisplay(displayId);
if (display == null) {
Log.wtf(TAG, "Could not obtain display info for newly created "
+ "virtual display: " + name);
+ "virtual display: " + virtualDisplayConfig.getName());
try {
mDm.releaseVirtualDisplay(callbackWrapper);
} catch (RemoteException ex) {
@@ -487,7 +478,8 @@ public final class DisplayManagerGlobal {
}
return null;
}
return new VirtualDisplay(this, display, callbackWrapper, surface);
return new VirtualDisplay(this, display, callbackWrapper,
virtualDisplayConfig.getSurface());
}
public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) {

View File

@@ -22,6 +22,7 @@ import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.Curve;
import android.hardware.display.IDisplayManagerCallback;
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig;
import android.hardware.display.WifiDisplay;
import android.hardware.display.WifiDisplayStatus;
import android.media.projection.IMediaProjection;
@@ -71,9 +72,9 @@ interface IDisplayManager {
// Requires CAPTURE_VIDEO_OUTPUT, CAPTURE_SECURE_VIDEO_OUTPUT, or an appropriate
// MediaProjection token for certain combinations of flags.
int createVirtualDisplay(in IVirtualDisplayCallback callback,
in IMediaProjection projectionToken, String packageName, String name,
int width, int height, int densityDpi, in Surface surface, int flags, String uniqueId);
int createVirtualDisplay(in VirtualDisplayConfig virtualDisplayConfig,
in IVirtualDisplayCallback callback, in IMediaProjection projectionToken,
String packageName);
// No permissions required, but must be same Uid as the creator.
void resizeVirtualDisplay(in IVirtualDisplayCallback token,

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2020 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.hardware.display;
parcelable VirtualDisplayConfig;

View File

@@ -0,0 +1,491 @@
/*
* Copyright (C) 2020 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.hardware.display;
import static android.view.Display.DEFAULT_DISPLAY;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.media.projection.MediaProjection;
import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.Surface;
import com.android.internal.util.DataClass;
/**
* Holds configuration used to create {@link VirtualDisplay} instances. See
* {@link MediaProjection#createVirtualDisplay(VirtualDisplayConfig, VirtualDisplay.Callback, Handler)}.
*
* @hide
*/
@DataClass(genParcelable = true, genAidl = true, genBuilder = true)
public final class VirtualDisplayConfig implements Parcelable {
/**
* The name of the virtual display, must be non-empty.
*/
@NonNull
private String mName;
/**
* The width of the virtual display in pixels. Must be greater than 0.
*/
@IntRange(from = 1)
private int mWidth;
/**
* The height of the virtual display in pixels. Must be greater than 0.
*/
@IntRange(from = 1)
private int mHeight;
/**
* The density of the virtual display in dpi. Must be greater than 0.
*/
@IntRange(from = 1)
private int mDensityDpi;
/**
* A combination of virtual display flags.
* {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PUBLIC},
* {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PRESENTATION},
* {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_SECURE},
* {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY},
* or {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}.
*/
private int mFlags = 0;
/**
* The surface to which the content of the virtual display should be rendered, or null if
* there is none initially.
*/
@Nullable
private Surface mSurface = null;
/**
* The unique identifier for the display. Shouldn't be displayed to the user.
* @hide
*/
@Nullable
private String mUniqueId = null;
/**
* The id of the display that the virtual display should mirror, or
* {@link android.view.Display#DEFAULT_DISPLAY} if there is none initially.
*/
private int mDisplayIdToMirror = DEFAULT_DISPLAY;
// Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/hardware/display/VirtualDisplayConfig.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
//@formatter:off
@DataClass.Generated.Member
/* package-private */ VirtualDisplayConfig(
@NonNull String name,
@IntRange(from = 1) int width,
@IntRange(from = 1) int height,
@IntRange(from = 1) int densityDpi,
int flags,
@Nullable Surface surface,
@Nullable String uniqueId,
int displayIdToMirror) {
this.mName = name;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mName);
this.mWidth = width;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mWidth,
"from", 1);
this.mHeight = height;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mHeight,
"from", 1);
this.mDensityDpi = densityDpi;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mDensityDpi,
"from", 1);
this.mFlags = flags;
this.mSurface = surface;
this.mUniqueId = uniqueId;
this.mDisplayIdToMirror = displayIdToMirror;
// onConstructed(); // You can define this method to get a callback
}
/**
* The name of the virtual display, must be non-empty.
*/
@DataClass.Generated.Member
public @NonNull String getName() {
return mName;
}
/**
* The width of the virtual display in pixels. Must be greater than 0.
*/
@DataClass.Generated.Member
public @IntRange(from = 1) int getWidth() {
return mWidth;
}
/**
* The height of the virtual display in pixels. Must be greater than 0.
*/
@DataClass.Generated.Member
public @IntRange(from = 1) int getHeight() {
return mHeight;
}
/**
* The density of the virtual display in dpi. Must be greater than 0.
*/
@DataClass.Generated.Member
public @IntRange(from = 1) int getDensityDpi() {
return mDensityDpi;
}
/**
* A combination of virtual display flags.
* {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PUBLIC},
* {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PRESENTATION},
* {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_SECURE},
* {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY},
* or {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}.
*/
@DataClass.Generated.Member
public int getFlags() {
return mFlags;
}
/**
* The surface to which the content of the virtual display should be rendered, or null if
* there is none initially.
*/
@DataClass.Generated.Member
public @Nullable Surface getSurface() {
return mSurface;
}
/**
* The unique identifier for the display. Shouldn't be displayed to the user.
*
* @hide
*/
@DataClass.Generated.Member
public @Nullable String getUniqueId() {
return mUniqueId;
}
/**
* The id of the display that the virtual display should mirror, or
* {@link android.view.Display#DEFAULT_DISPLAY} if there is none initially.
*/
@DataClass.Generated.Member
public int getDisplayIdToMirror() {
return mDisplayIdToMirror;
}
@Override
@DataClass.Generated.Member
public void writeToParcel(@NonNull Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
int flg = 0;
if (mSurface != null) flg |= 0x20;
if (mUniqueId != null) flg |= 0x40;
dest.writeInt(flg);
dest.writeString(mName);
dest.writeInt(mWidth);
dest.writeInt(mHeight);
dest.writeInt(mDensityDpi);
dest.writeInt(mFlags);
if (mSurface != null) dest.writeTypedObject(mSurface, flags);
if (mUniqueId != null) dest.writeString(mUniqueId);
dest.writeInt(mDisplayIdToMirror);
}
@Override
@DataClass.Generated.Member
public int describeContents() { return 0; }
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
/* package-private */ VirtualDisplayConfig(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
int flg = in.readInt();
String name = in.readString();
int width = in.readInt();
int height = in.readInt();
int densityDpi = in.readInt();
int flags = in.readInt();
Surface surface = (flg & 0x20) == 0 ? null : (Surface) in.readTypedObject(Surface.CREATOR);
String uniqueId = (flg & 0x40) == 0 ? null : in.readString();
int displayIdToMirror = in.readInt();
this.mName = name;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mName);
this.mWidth = width;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mWidth,
"from", 1);
this.mHeight = height;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mHeight,
"from", 1);
this.mDensityDpi = densityDpi;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mDensityDpi,
"from", 1);
this.mFlags = flags;
this.mSurface = surface;
this.mUniqueId = uniqueId;
this.mDisplayIdToMirror = displayIdToMirror;
// onConstructed(); // You can define this method to get a callback
}
@DataClass.Generated.Member
public static final @NonNull Parcelable.Creator<VirtualDisplayConfig> CREATOR
= new Parcelable.Creator<VirtualDisplayConfig>() {
@Override
public VirtualDisplayConfig[] newArray(int size) {
return new VirtualDisplayConfig[size];
}
@Override
public VirtualDisplayConfig createFromParcel(@NonNull Parcel in) {
return new VirtualDisplayConfig(in);
}
};
/**
* A builder for {@link VirtualDisplayConfig}
*/
@SuppressWarnings("WeakerAccess")
@DataClass.Generated.Member
public static final class Builder {
private @NonNull String mName;
private @IntRange(from = 1) int mWidth;
private @IntRange(from = 1) int mHeight;
private @IntRange(from = 1) int mDensityDpi;
private int mFlags;
private @Nullable Surface mSurface;
private @Nullable String mUniqueId;
private int mDisplayIdToMirror;
private long mBuilderFieldsSet = 0L;
/**
* Creates a new Builder.
*
* @param name
* The name of the virtual display, must be non-empty.
* @param width
* The width of the virtual display in pixels. Must be greater than 0.
* @param height
* The height of the virtual display in pixels. Must be greater than 0.
* @param densityDpi
* The density of the virtual display in dpi. Must be greater than 0.
*/
public Builder(
@NonNull String name,
@IntRange(from = 1) int width,
@IntRange(from = 1) int height,
@IntRange(from = 1) int densityDpi) {
mName = name;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mName);
mWidth = width;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mWidth,
"from", 1);
mHeight = height;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mHeight,
"from", 1);
mDensityDpi = densityDpi;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mDensityDpi,
"from", 1);
}
/**
* The name of the virtual display, must be non-empty.
*/
@DataClass.Generated.Member
public @NonNull Builder setName(@NonNull String value) {
checkNotUsed();
mBuilderFieldsSet |= 0x1;
mName = value;
return this;
}
/**
* The width of the virtual display in pixels. Must be greater than 0.
*/
@DataClass.Generated.Member
public @NonNull Builder setWidth(@IntRange(from = 1) int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x2;
mWidth = value;
return this;
}
/**
* The height of the virtual display in pixels. Must be greater than 0.
*/
@DataClass.Generated.Member
public @NonNull Builder setHeight(@IntRange(from = 1) int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x4;
mHeight = value;
return this;
}
/**
* The density of the virtual display in dpi. Must be greater than 0.
*/
@DataClass.Generated.Member
public @NonNull Builder setDensityDpi(@IntRange(from = 1) int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x8;
mDensityDpi = value;
return this;
}
/**
* A combination of virtual display flags.
* {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PUBLIC},
* {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PRESENTATION},
* {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_SECURE},
* {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY},
* or {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}.
*/
@DataClass.Generated.Member
public @NonNull Builder setFlags(int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x10;
mFlags = value;
return this;
}
/**
* The surface to which the content of the virtual display should be rendered, or null if
* there is none initially.
*/
@DataClass.Generated.Member
public @NonNull Builder setSurface(@NonNull Surface value) {
checkNotUsed();
mBuilderFieldsSet |= 0x20;
mSurface = value;
return this;
}
/**
* The unique identifier for the display. Shouldn't be displayed to the user.
*
* @hide
*/
@DataClass.Generated.Member
public @NonNull Builder setUniqueId(@NonNull String value) {
checkNotUsed();
mBuilderFieldsSet |= 0x40;
mUniqueId = value;
return this;
}
/**
* The id of the display that the virtual display should mirror, or
* {@link android.view.Display#DEFAULT_DISPLAY} if there is none initially.
*/
@DataClass.Generated.Member
public @NonNull Builder setDisplayIdToMirror(int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x80;
mDisplayIdToMirror = value;
return this;
}
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull VirtualDisplayConfig build() {
checkNotUsed();
mBuilderFieldsSet |= 0x100; // Mark builder used
if ((mBuilderFieldsSet & 0x10) == 0) {
mFlags = 0;
}
if ((mBuilderFieldsSet & 0x20) == 0) {
mSurface = null;
}
if ((mBuilderFieldsSet & 0x40) == 0) {
mUniqueId = null;
}
if ((mBuilderFieldsSet & 0x80) == 0) {
mDisplayIdToMirror = DEFAULT_DISPLAY;
}
VirtualDisplayConfig o = new VirtualDisplayConfig(
mName,
mWidth,
mHeight,
mDensityDpi,
mFlags,
mSurface,
mUniqueId,
mDisplayIdToMirror);
return o;
}
private void checkNotUsed() {
if ((mBuilderFieldsSet & 0x100) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
}
}
@DataClass.Generated(
time = 1585179350902L,
codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/hardware/display/VirtualDisplayConfig.java",
inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange(from=1L) int mWidth\nprivate @android.annotation.IntRange(from=1L) int mHeight\nprivate @android.annotation.IntRange(from=1L) int mDensityDpi\nprivate int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)")
@Deprecated
private void __metadata() {}
//@formatter:on
// End of generated code
}

View File

@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.content.Context;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionCallback;
import android.os.Handler;
@@ -100,11 +101,18 @@ public final class MediaProjection {
int width, int height, int dpi, boolean isSecure, @Nullable Surface surface,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
int flags = isSecure ? DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE : 0;
return dm.createVirtualDisplay(this, name, width, height, dpi, surface,
flags | DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR |
DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION, callback, handler,
null /* uniqueId */);
int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
| DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
if (isSecure) {
flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
}
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
height, dpi);
builder.setFlags(flags);
if (surface != null) {
builder.setSurface(surface);
}
return dm.createVirtualDisplay(this, builder.build(), callback, handler);
}
/**
@@ -133,9 +141,35 @@ public final class MediaProjection {
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int dpi, int flags, @Nullable Surface surface,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
return dm.createVirtualDisplay(this, name, width, height, dpi, surface, flags, callback,
handler, null /* uniqueId */);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
height, dpi);
builder.setFlags(flags);
if (surface != null) {
builder.setSurface(surface);
}
return createVirtualDisplay(builder.build(), callback, handler);
}
/**
* Creates a {@link android.hardware.display.VirtualDisplay} to capture the
* contents of the screen.
*
* @param virtualDisplayConfig The arguments for the virtual display configuration. See
* {@link VirtualDisplayConfig} for using it.
* @param callback Callback to call when the virtual display's state
* changes, or null if none.
* @param handler The {@link android.os.Handler} on which the callback should be
* invoked, or null if the callback should be invoked on the calling
* thread's main {@link android.os.Looper}.
*
* @see android.hardware.display.VirtualDisplay
* @hide
*/
@Nullable
public VirtualDisplay createVirtualDisplay(@NonNull VirtualDisplayConfig virtualDisplayConfig,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
DisplayManager dm = mContext.getSystemService(DisplayManager.class);
return dm.createVirtualDisplay(this, virtualDisplayConfig, callback, handler);
}
/**

View File

@@ -19,6 +19,7 @@ package com.android.server.display;
import android.graphics.Rect;
import android.hardware.display.DisplayViewport;
import android.os.IBinder;
import android.view.Display;
import android.view.DisplayAddress;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -77,6 +78,13 @@ abstract class DisplayDevice {
return mDisplayToken;
}
/**
* Gets the id of the display to mirror.
*/
public int getDisplayIdToMirrorLocked() {
return Display.DEFAULT_DISPLAY;
}
/**
* Gets the name of the display device.
*

View File

@@ -57,6 +57,7 @@ import android.hardware.display.DisplayedContentSamplingAttributes;
import android.hardware.display.IDisplayManager;
import android.hardware.display.IDisplayManagerCallback;
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig;
import android.hardware.display.WifiDisplayStatus;
import android.hardware.input.InputManagerInternal;
import android.media.projection.IMediaProjection;
@@ -794,8 +795,8 @@ public final class DisplayManagerService extends SystemService {
}
private int createVirtualDisplayInternal(IVirtualDisplayCallback callback,
IMediaProjection projection, int callingUid, String packageName, String name, int width,
int height, int densityDpi, Surface surface, int flags, String uniqueId) {
IMediaProjection projection, int callingUid, String packageName, Surface surface,
int flags, VirtualDisplayConfig virtualDisplayConfig) {
synchronized (mSyncRoot) {
if (mVirtualDisplayAdapter == null) {
Slog.w(TAG, "Rejecting request to create private virtual display "
@@ -804,8 +805,8 @@ public final class DisplayManagerService extends SystemService {
}
DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
callback, projection, callingUid, packageName, name, width, height, densityDpi,
surface, flags, uniqueId);
callback, projection, callingUid, packageName, surface, flags,
virtualDisplayConfig);
if (device == null) {
return -1;
}
@@ -1480,8 +1481,8 @@ public final class DisplayManagerService extends SystemService {
if (!ownContent) {
if (display != null && !display.hasContentLocked()) {
// If the display does not have any content of its own, then
// automatically mirror the default logical display contents.
display = null;
// automatically mirror the requested logical display contents if possible.
display = mLogicalDisplays.get(device.getDisplayIdToMirrorLocked());
}
if (display == null) {
display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
@@ -1729,6 +1730,28 @@ public final class DisplayManagerService extends SystemService {
}
}
@VisibleForTesting
int getDisplayIdToMirrorInternal(int displayId) {
synchronized (mSyncRoot) {
LogicalDisplay display = mLogicalDisplays.get(displayId);
if (display != null) {
DisplayDevice displayDevice = display.getPrimaryDisplayDeviceLocked();
return displayDevice.getDisplayIdToMirrorLocked();
}
return Display.INVALID_DISPLAY;
}
}
@VisibleForTesting
Surface getVirtualDisplaySurfaceInternal(IBinder appToken) {
synchronized (mSyncRoot) {
if (mVirtualDisplayAdapter == null) {
return null;
}
return mVirtualDisplayAdapter.getVirtualDisplaySurfaceLocked(appToken);
}
}
private final class DisplayManagerHandler extends Handler {
public DisplayManagerHandler(Looper looper) {
super(looper, null, true /*async*/);
@@ -2050,10 +2073,8 @@ public final class DisplayManagerService extends SystemService {
}
@Override // Binder call
public int createVirtualDisplay(IVirtualDisplayCallback callback,
IMediaProjection projection, String packageName, String name,
int width, int height, int densityDpi, Surface surface, int flags,
String uniqueId) {
public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
IVirtualDisplayCallback callback, IMediaProjection projection, String packageName) {
final int callingUid = Binder.getCallingUid();
if (!validatePackageName(callingUid, packageName)) {
throw new SecurityException("packageName must match the calling uid");
@@ -2061,13 +2082,12 @@ public final class DisplayManagerService extends SystemService {
if (callback == null) {
throw new IllegalArgumentException("appToken must not be null");
}
if (TextUtils.isEmpty(name)) {
throw new IllegalArgumentException("name must be non-null and non-empty");
}
if (width <= 0 || height <= 0 || densityDpi <= 0) {
throw new IllegalArgumentException("width, height, and densityDpi must be "
+ "greater than 0");
if (virtualDisplayConfig == null) {
throw new IllegalArgumentException("virtualDisplayConfig must not be null");
}
final Surface surface = virtualDisplayConfig.getSurface();
int flags = virtualDisplayConfig.getFlags();
if (surface != null && surface.isSingleBuffered()) {
throw new IllegalArgumentException("Surface can't be single-buffered");
}
@@ -2128,7 +2148,7 @@ public final class DisplayManagerService extends SystemService {
final long token = Binder.clearCallingIdentity();
try {
return createVirtualDisplayInternal(callback, projection, callingUid, packageName,
name, width, height, densityDpi, surface, flags, uniqueId);
surface, flags, virtualDisplayConfig);
} finally {
Binder.restoreCallingIdentity(token);
}

View File

@@ -28,6 +28,7 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPO
import android.content.Context;
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionCallback;
import android.os.Handler;
@@ -84,22 +85,24 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
}
public DisplayDevice createVirtualDisplayLocked(IVirtualDisplayCallback callback,
IMediaProjection projection, int ownerUid, String ownerPackageName, String name,
int width, int height, int densityDpi, Surface surface, int flags, String uniqueId) {
IMediaProjection projection, int ownerUid, String ownerPackageName, Surface surface,
int flags, VirtualDisplayConfig virtualDisplayConfig) {
String name = virtualDisplayConfig.getName();
boolean secure = (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
IBinder appToken = callback.asBinder();
IBinder displayToken = mSurfaceControlDisplayFactory.createDisplay(name, secure);
final String baseUniqueId =
UNIQUE_ID_PREFIX + ownerPackageName + "," + ownerUid + "," + name + ",";
final int uniqueIndex = getNextUniqueIndex(baseUniqueId);
String uniqueId = virtualDisplayConfig.getUniqueId();
if (uniqueId == null) {
uniqueId = baseUniqueId + uniqueIndex;
} else {
uniqueId = UNIQUE_ID_PREFIX + ownerPackageName + ":" + uniqueId;
}
VirtualDisplayDevice device = new VirtualDisplayDevice(displayToken, appToken,
ownerUid, ownerPackageName, name, width, height, densityDpi, surface, flags,
new Callback(callback, mHandler), uniqueId, uniqueIndex);
ownerUid, ownerPackageName, surface, flags, new Callback(callback, mHandler),
uniqueId, uniqueIndex, virtualDisplayConfig);
mVirtualDisplayDevices.put(appToken, device);
@@ -127,6 +130,14 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
}
}
@VisibleForTesting
Surface getVirtualDisplaySurfaceLocked(IBinder appToken) {
VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
if (device != null) {
return device.getSurfaceLocked();
}
return null;
}
public void setVirtualDisplaySurfaceLocked(IBinder appToken, Surface surface) {
VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
@@ -214,20 +225,21 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
private int mUniqueIndex;
private Display.Mode mMode;
private boolean mIsDisplayOn;
private int mDisplayIdToMirror;
public VirtualDisplayDevice(IBinder displayToken, IBinder appToken,
int ownerUid, String ownerPackageName,
String name, int width, int height, int densityDpi, Surface surface, int flags,
Callback callback, String uniqueId, int uniqueIndex) {
int ownerUid, String ownerPackageName, Surface surface, int flags,
Callback callback, String uniqueId, int uniqueIndex,
VirtualDisplayConfig virtualDisplayConfig) {
super(VirtualDisplayAdapter.this, displayToken, uniqueId);
mAppToken = appToken;
mOwnerUid = ownerUid;
mOwnerPackageName = ownerPackageName;
mName = name;
mWidth = width;
mHeight = height;
mMode = createMode(width, height, REFRESH_RATE);
mDensityDpi = densityDpi;
mName = virtualDisplayConfig.getName();
mWidth = virtualDisplayConfig.getWidth();
mHeight = virtualDisplayConfig.getHeight();
mMode = createMode(mWidth, mHeight, REFRESH_RATE);
mDensityDpi = virtualDisplayConfig.getDensityDpi();
mSurface = surface;
mFlags = flags;
mCallback = callback;
@@ -235,6 +247,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
mPendingChanges |= PENDING_SURFACE_CHANGE;
mUniqueIndex = uniqueIndex;
mIsDisplayOn = surface != null;
mDisplayIdToMirror = virtualDisplayConfig.getDisplayIdToMirror();
}
@Override
@@ -259,6 +272,16 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
}
}
@Override
public int getDisplayIdToMirrorLocked() {
return mDisplayIdToMirror;
}
@VisibleForTesting
Surface getSurfaceLocked() {
return mSurface;
}
@Override
public boolean hasStableUniqueId() {
return false;
@@ -332,6 +355,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
pw.println("mFlags=" + mFlags);
pw.println("mDisplayState=" + Display.stateToString(mDisplayState));
pw.println("mStopped=" + mStopped);
pw.println("mDisplayIdToMirror=" + mDisplayIdToMirror);
}

View File

@@ -11,6 +11,7 @@ import android.content.IntentFilter;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
import android.media.ImageReader;
import android.os.Handler;
import android.os.RemoteException;
@@ -295,10 +296,12 @@ class Vr2dDisplay {
flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
DISPLAY_NAME, mVirtualDisplayWidth, mVirtualDisplayHeight, mVirtualDisplayDpi);
builder.setUniqueId(UNIQUE_DISPLAY_ID);
builder.setFlags(flags);
mVirtualDisplay = mDisplayManager.createVirtualDisplay(null /* projection */,
DISPLAY_NAME, mVirtualDisplayWidth, mVirtualDisplayHeight, mVirtualDisplayDpi,
null /* surface */, flags, null /* callback */, null /* handler */,
UNIQUE_DISPLAY_ID);
builder.build(), null /* callback */, null /* handler */);
if (mVirtualDisplay != null) {
updateDisplayId(mVirtualDisplay.getDisplay().getDisplayId());

View File

@@ -34,14 +34,17 @@ import android.hardware.display.DisplayViewport;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplayConfig;
import android.hardware.input.InputManagerInternal;
import android.os.Handler;
import android.os.IBinder;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.SurfaceControl;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -67,6 +70,8 @@ import java.util.stream.LongStream;
public class DisplayManagerServiceTest {
private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS = 1;
private static final long SHORT_DEFAULT_DISPLAY_TIMEOUT_MILLIS = 10;
private static final String VIRTUAL_DISPLAY_NAME = "Test Virtual Display";
private static final String PACKAGE_NAME = "com.android.frameworks.servicestests";
private Context mContext;
@@ -97,6 +102,7 @@ public class DisplayManagerServiceTest {
@Mock InputManagerInternal mMockInputManagerInternal;
@Mock IVirtualDisplayCallback.Stub mMockAppToken;
@Mock IVirtualDisplayCallback.Stub mMockAppToken2;
@Mock WindowManagerInternal mMockWindowManagerInternal;
@Mock LightsManager mMockLightsManager;
@Mock VirtualDisplayAdapter mMockVirtualDisplayAdapter;
@@ -135,10 +141,12 @@ public class DisplayManagerServiceTest {
int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH;
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
int displayId = bs.createVirtualDisplay(mMockAppToken /* callback */,
null /* projection */, "com.android.frameworks.servicestests",
"Test Virtual Display", width, height, dpi, null /* surface */, flags /* flags */,
uniqueId);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, width, height, dpi);
builder.setUniqueId(uniqueId);
builder.setFlags(flags);
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
null /* projection */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -241,10 +249,12 @@ public class DisplayManagerServiceTest {
int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT;
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
int displayId = bs.createVirtualDisplay(mMockAppToken /* callback */,
null /* projection */, "com.android.frameworks.servicestests",
"Test Virtual Display", width, height, dpi, null /* surface */, flags /* flags */,
uniqueId);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, width, height, dpi);
builder.setFlags(flags);
builder.setUniqueId(uniqueId);
int displayId = bs.createVirtualDisplay(builder.build(), mMockAppToken /* callback */,
null /* projection */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
@@ -409,6 +419,87 @@ public class DisplayManagerServiceTest {
assertTrue(samples.length == 0 || LongStream.of(samples).sum() == numPixels);
}
/**
* Tests that the virtual display is created with
* {@link VirtualDisplayConfig.Builder#setDisplayIdToMirror(int)}
*/
@Test
@FlakyTest(bugId = 127687569)
public void testCreateVirtualDisplay_displayIdToMirror() throws Exception {
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
// This is effectively the DisplayManager service published to ServiceManager.
DisplayManagerService.BinderService binderService = displayManager.new BinderService();
final String uniqueId = "uniqueId --- displayIdToMirrorTest";
final int width = 600;
final int height = 800;
final int dpi = 320;
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, width, height, dpi);
builder.setUniqueId(uniqueId);
final int firstDisplayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
// The second virtual display requests to mirror the first virtual display.
final String uniqueId2 = "uniqueId --- displayIdToMirrorTest #2";
when(mMockAppToken2.asBinder()).thenReturn(mMockAppToken2);
final VirtualDisplayConfig.Builder builder2 = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, width, height, dpi).setUniqueId(uniqueId2);
builder2.setUniqueId(uniqueId2);
builder2.setDisplayIdToMirror(firstDisplayId);
final int secondDisplayId = binderService.createVirtualDisplay(builder2.build(),
mMockAppToken2 /* callback */, null /* projection */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
// The displayId to mirror should be a default display if there is none initially.
assertEquals(displayManager.getDisplayIdToMirrorInternal(firstDisplayId),
Display.DEFAULT_DISPLAY);
assertEquals(displayManager.getDisplayIdToMirrorInternal(secondDisplayId),
firstDisplayId);
}
/**
* Tests that the virtual display is created with
* {@link VirtualDisplayConfig.Builder#setSurface(Surface)}
*/
@Test
@FlakyTest(bugId = 127687569)
public void testCreateVirtualDisplay_setSurface() throws Exception {
DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
registerDefaultDisplays(displayManager);
// This is effectively the DisplayManager service published to ServiceManager.
DisplayManagerService.BinderService binderService = displayManager.new BinderService();
final String uniqueId = "uniqueId --- setSurface";
final int width = 600;
final int height = 800;
final int dpi = 320;
final Surface surface = new Surface();
when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
VIRTUAL_DISPLAY_NAME, width, height, dpi);
builder.setSurface(surface);
builder.setUniqueId(uniqueId);
final int displayId = binderService.createVirtualDisplay(builder.build(),
mMockAppToken /* callback */, null /* projection */, PACKAGE_NAME);
displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
// flush the handler
displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
assertEquals(displayManager.getVirtualDisplaySurfaceInternal(mMockAppToken), surface);
}
private void registerDefaultDisplays(DisplayManagerService displayManager) {
Handler handler = displayManager.getDisplayHandler();
// Would prefer to call displayManager.onStart() directly here but it performs binderService