Allow media projections to create public presentations.
Change-Id: I3b6e0b54d658352942a38be6a24486bdfc179efd
diff --git a/api/current.txt b/api/current.txt
index 93360c1..5cafd6c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -13236,10 +13236,10 @@
method public void registerDisplayListener(android.hardware.display.DisplayManager.DisplayListener, android.os.Handler);
method public void unregisterDisplayListener(android.hardware.display.DisplayManager.DisplayListener);
field public static final java.lang.String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+ field public static final int VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR = 16; // 0x10
field public static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 8; // 0x8
field public static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = 2; // 0x2
field public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1; // 0x1
- field public static final int VIRTUAL_DISPLAY_FLAG_SCREEN_SHARE = 16; // 0x10
field public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 4; // 0x4
}
@@ -16401,7 +16401,7 @@
public final class MediaProjection {
method public void addCallback(android.media.projection.MediaProjection.Callback, android.os.Handler);
method public android.media.AudioRecord createAudioRecord(int, int, int, int);
- method public android.hardware.display.VirtualDisplay createVirtualDisplay(java.lang.String, int, int, int, boolean, android.view.Surface, android.hardware.display.VirtualDisplay.Callbacks, android.os.Handler);
+ method public android.hardware.display.VirtualDisplay createVirtualDisplay(java.lang.String, int, int, int, int, android.view.Surface, android.hardware.display.VirtualDisplay.Callbacks, android.os.Handler);
method public void removeCallback(android.media.projection.MediaProjection.Callback);
method public void stop();
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index d4e6df5..51b7229 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -96,11 +96,9 @@
* windows on the display and the system may mirror the contents of other displays
* onto it.
* </p><p>
- * Creating a public virtual display requires the
- * {@link android.Manifest.permission#CAPTURE_VIDEO_OUTPUT}
- * or {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission.
- * These permissions are reserved for use by system components and are not available to
- * third-party applications.
+ * Creating a public virtual display that isn't restricted to own-content only implicitly
+ * creates an auto-mirroring display. See {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR} for
+ * restrictions on who is allowed to create an auto-mirroring display.
* </p>
*
* <h3>Private virtual displays</h3>
@@ -108,6 +106,8 @@
* When this flag is not set, the virtual display is private as defined by the
* {@link Display#FLAG_PRIVATE} display flag.
* </p>
+ *
+ * <p>
* A private virtual display belongs to the application that created it.
* Only the a owner of a private virtual display is allowed to place windows upon it.
* The private virtual display also does not participate in display mirroring: it will
@@ -115,10 +115,11 @@
* be mirrored elsewhere. More precisely, the only processes that are allowed to
* enumerate or interact with the private display are those that have the same UID as the
* application that originally created the private virtual display.
- * </p>
+ * </p>
*
* @see #createVirtualDisplay
* @see #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
+ * @see #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
*/
public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1 << 0;
@@ -187,29 +188,51 @@
* will be blanked instead if it has no windows.
* </p>
*
+ * <p>
+ * This flag is mutually exclusive with {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}. If both
+ * flags are specified then the own-content only behavior will be applied.
+ * </p>
+ *
+ * <p>
+ * This behavior of this flag is implied whenever neither {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}
+ * nor {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR} have been set. This flag is only required to
+ * override the default behavior when creating a public display.
+ * </p>
+ *
* @see #createVirtualDisplay
*/
public static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 1 << 3;
/**
- * Virtual display flag: Indicates that the display is being created for
- * the purpose of screen sharing. This implies
- * VIRTUAL_DISPLAY_FLAG_PRIVATE. Other flags are not allowed (especially
- * not VIRTUAL_DISPLAY_FLAG_PUBLIC or PRESENTATION).
+ * Virtual display flag: Allows content to be mirrored on private displays when no content is
+ * being shown.
*
* <p>
- * Requires screen share permission for use.
+ * This flag is mutually exclusive with {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}.
+ * If both flags are specified then the own-content only behavior will be applied.
* </p>
*
* <p>
- * While a display of this type exists, the system will show some sort of
- * notification to the user indicating that the screen is being shared.
+ * The behavior of this flag is implied whenever {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC} is set
+ * and {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY} has not been set. This flag is only
+ * required to override the default behavior when creating a private display.
+ * </p>
+ *
+ * <p>
+ * Creating an auto-mirroing virtual display requires the
+ * {@link android.Manifest.permission#CAPTURE_VIDEO_OUTPUT}
+ * or {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission.
+ * These permissions are reserved for use by system components and are not available to
+ * third-party applications.
+ *
+ * Alternatively, an appropriate {@link MediaProjection} may be used to create an
+ * auto-mirroring virtual display.
* </p>
*
* @see #createVirtualDisplay
*/
- public static final int VIRTUAL_DISPLAY_FLAG_SCREEN_SHARE = 1 << 4;
+ public static final int VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR = 1 << 4;
/** @hide */
public DisplayManager(Context context) {
@@ -489,7 +512,7 @@
* @param flags A combination of virtual display flags:
* {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION},
* {@link #VIRTUAL_DISPLAY_FLAG_SECURE}, {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY},
- * or {@link #VIRTUAL_DISPLAY_FLAG_SCREEN_SHARE}.
+ * or {@link #VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR}.
* @param callbacks Callbacks to call when the state of the {@link VirtualDisplay} changes
* @param handler The handler on which the listener should be invoked, or null
* if the listener should be invoked on the calling thread's looper.
diff --git a/media/java/android/media/projection/IMediaProjection.aidl b/media/java/android/media/projection/IMediaProjection.aidl
index dd84ad32..3d25aa6 100644
--- a/media/java/android/media/projection/IMediaProjection.aidl
+++ b/media/java/android/media/projection/IMediaProjection.aidl
@@ -25,7 +25,7 @@
boolean canProjectAudio();
boolean canProjectVideo();
boolean canProjectSecureVideo();
- int getVirtualDisplayFlags();
+ int applyVirtualDisplayFlags(int flags);
void addCallback(IMediaProjectionCallback callback);
void removeCallback(IMediaProjectionCallback callback);
}
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 7c03171..861039d 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -93,6 +93,19 @@
}
/**
+ * @hide
+ */
+ public VirtualDisplay createVirtualDisplay(@NonNull String name,
+ int width, int height, int dpi, boolean isSecure, @Nullable Surface surface,
+ @Nullable VirtualDisplay.Callbacks callbacks, @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, callbacks, handler);
+ }
+
+ /**
* Creates a {@link android.hardware.display.VirtualDisplay} to capture the
* contents of the screen.
*
@@ -105,9 +118,8 @@
* than 0.
* @param surface The surface to which the content of the virtual display
* should be rendered, or null if there is none initially.
- * @param isSecure Whether the display should be considered a secure
- * display. This typically requires special permissions not available to
- * third party applications.
+ * @param flags A combination of virtual display flags. See {@link DisplayManager} for the full
+ * list of flags.
* @param callbacks Callbacks 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
@@ -118,10 +130,9 @@
* String, int, int, int, int, Surface, VirtualDisplay.Callbacks, Handler)
*/
public VirtualDisplay createVirtualDisplay(@NonNull String name,
- int width, int height, int dpi, boolean isSecure, @Nullable Surface surface,
+ int width, int height, int dpi, int flags, @Nullable Surface surface,
@Nullable VirtualDisplay.Callbacks callbacks, @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, callbacks, handler);
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 2dd150a..e31f177 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1269,28 +1269,26 @@
+ "greater than 0");
}
+ if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
+ flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
+ }
+ if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) {
+ flags &= ~DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
+ }
+
if (projection != null) {
try {
if (!getProjectionService().isValidMediaProjection(projection)) {
throw new SecurityException("Invalid media projection");
}
+ flags = projection.applyVirtualDisplayFlags(flags);
} catch (RemoteException e) {
- throw new SecurityException("unable to validate media projection");
- }
- flags &= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
- try {
- flags |= projection.getVirtualDisplayFlags();
- } catch (RemoteException e) {
- throw new RuntimeException("unable to retrieve media projection flags");
+ throw new SecurityException("unable to validate media projection or flags");
}
}
- if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SCREEN_SHARE) != 0) {
- if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0 ||
- (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION) != 0) {
- throw new IllegalArgumentException("screen sharing virtual displays must not "
- + "be public or presentation displays");
- }
+ if (callingUid != Process.SYSTEM_UID &&
+ (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
if (!canProjectVideo(projection)) {
throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
+ "CAPTURE_SECURE_VIDEO_OUTPUT permission, or an appropriate "
@@ -1298,16 +1296,6 @@
+ "display.");
}
}
-
-
- if (callingUid != Process.SYSTEM_UID &&
- (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
- if (!canProjectVideo(projection)) {
- throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
- + "CAPTURE_SECURE_VIDEO_OUTPUT permission, or an appropriate "
- + "MediaProjection token to create a public virtual display.");
- }
- }
if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
if (!canProjectSecureVideo(projection)) {
throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT "
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 0ebd2de..72ac29a 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -262,14 +262,15 @@
mInfo.presentationDeadlineNanos = 1000000000L / (int) mInfo.refreshRate; // 1 frame
mInfo.flags = 0;
if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
- mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE;
- if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SCREEN_SHARE) == 0) {
- mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY
- | DisplayDeviceInfo.FLAG_NEVER_BLANK;
- }
- } else if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) {
+ mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE
+ | DisplayDeviceInfo.FLAG_NEVER_BLANK;
+ }
+ if ((mInfo.flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
+ mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK;
+ } else {
mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
}
+
if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE;
}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 7b28699..289b5aa 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -103,7 +103,7 @@
try {
hasPermission |= checkPermission(packageName,
android.Manifest.permission.CAPTURE_VIDEO_OUTPUT)
- || mAppOps.checkOpNoThrow(
+ || mAppOps.noteOpNoThrow(
AppOpsManager.OP_PROJECT_MEDIA, uid, packageName)
== AppOpsManager.MODE_ALLOWED;
} finally {
@@ -196,18 +196,27 @@
}
@Override // Binder call
- public int getVirtualDisplayFlags() {
- switch (mType) {
- case MediaProjectionManager.TYPE_SCREEN_CAPTURE:
- return DisplayManager.VIRTUAL_DISPLAY_FLAG_SCREEN_SHARE;
- case MediaProjectionManager.TYPE_MIRRORING:
- return DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
- DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
- case MediaProjectionManager.TYPE_PRESENTATION:
- return DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION |
- DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+ public int applyVirtualDisplayFlags(int flags) {
+ if (mType == MediaProjectionManager.TYPE_SCREEN_CAPTURE) {
+ flags &= ~DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+ flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
+ | DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
+ return flags;
+ } else if (mType == MediaProjectionManager.TYPE_MIRRORING) {
+ flags &= ~(DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
+ flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY |
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
+ return flags;
+ } else if (mType == MediaProjectionManager.TYPE_PRESENTATION) {
+ flags &= ~DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+ flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION |
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
+ return flags;
+ } else {
+ throw new RuntimeException("Unknown MediaProjection type");
}
- throw new RuntimeException("Unknown MediaProjection type");
}
@Override // Binder call