Support public virtual displays.

Refactor the new private virtual display API to also support
creating public virtual displays with various characteristics.
This feature requires special permissions and is only intended
for use by the system.

Change-Id: I44dd19f37cf76ea6d6e313afe42f4a412bd96663
diff --git a/api/current.txt b/api/current.txt
index 429caa5a..7d83fcf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -40,6 +40,9 @@
     field public static final java.lang.String CALL_PHONE = "android.permission.CALL_PHONE";
     field public static final java.lang.String CALL_PRIVILEGED = "android.permission.CALL_PRIVILEGED";
     field public static final java.lang.String CAMERA = "android.permission.CAMERA";
+    field public static final java.lang.String CAPTURE_AUDIO_OUTPUT = "android.permission.CAPTURE_AUDIO_OUTPUT";
+    field public static final java.lang.String CAPTURE_SECURE_VIDEO_OUTPUT = "android.permission.CAPTURE_SECURE_VIDEO_OUTPUT";
+    field public static final java.lang.String CAPTURE_VIDEO_OUTPUT = "android.permission.CAPTURE_VIDEO_OUTPUT";
     field public static final java.lang.String CHANGE_COMPONENT_ENABLED_STATE = "android.permission.CHANGE_COMPONENT_ENABLED_STATE";
     field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
     field public static final java.lang.String CHANGE_NETWORK_STATE = "android.permission.CHANGE_NETWORK_STATE";
@@ -10798,13 +10801,16 @@
 package android.hardware.display {
 
   public final class DisplayManager {
-    method public android.hardware.display.VirtualDisplay createPrivateVirtualDisplay(java.lang.String, int, int, int, android.view.Surface);
+    method public android.hardware.display.VirtualDisplay createVirtualDisplay(java.lang.String, int, int, int, android.view.Surface, int);
     method public android.view.Display getDisplay(int);
     method public android.view.Display[] getDisplays();
     method public android.view.Display[] getDisplays(java.lang.String);
     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_PRESENTATION = 2; // 0x2
+    field public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1; // 0x1
+    field public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 4; // 0x4
   }
 
   public static abstract interface DisplayManager.DisplayListener {
@@ -25610,6 +25616,7 @@
     method public deprecated int getWidth();
     method public boolean isValid();
     field public static final int DEFAULT_DISPLAY = 0; // 0x0
+    field public static final int FLAG_PRESENTATION = 8; // 0x8
     field public static final int FLAG_PRIVATE = 4; // 0x4
     field public static final int FLAG_SECURE = 2; // 0x2
     field public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 1; // 0x1
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 9e2e4ba..7d65736 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -69,16 +69,110 @@
      * Display category: Presentation displays.
      * <p>
      * This category can be used to identify secondary displays that are suitable for
-     * use as presentation displays.
+     * use as presentation displays such as HDMI or Wireless displays.  Applications
+     * may automatically project their content to presentation displays to provide
+     * richer second screen experiences.
      * </p>
      *
      * @see android.app.Presentation for information about presenting content
      * on secondary displays.
+     * @see Display#FLAG_PRESENTATION
      * @see #getDisplays(String)
      */
     public static final String DISPLAY_CATEGORY_PRESENTATION =
             "android.hardware.display.category.PRESENTATION";
 
+    /**
+     * Virtual display flag: Create a public display.
+     *
+     * <h3>Public virtual displays</h3>
+     * <p>
+     * When this flag is set, the virtual display is public.
+     * </p><p>
+     * A public virtual display behaves just like most any other display that is connected
+     * to the system such as an HDMI or Wireless display.  Applications can open
+     * 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.
+     * </p>
+     *
+     * <h3>Private virtual displays</h3>
+     * <p>
+     * When this flag is not set, the virtual display is private as defined by the
+     * {@link Display#FLAG_PRIVATE} display flag.
+     * </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
+     * neither receive mirrored content from another display nor allow its own content to
+     * 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>
+     *
+     * @see #createVirtualDisplay
+     */
+    public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1 << 0;
+
+    /**
+     * Virtual display flag: Create a presentation display.
+     *
+     * <h3>Presentation virtual displays</h3>
+     * <p>
+     * When this flag is set, the virtual display is registered as a presentation
+     * display in the {@link #DISPLAY_CATEGORY_PRESENTATION presentation display category}.
+     * Applications may automatically project their content to presentation displays
+     * to provide richer second screen experiences.
+     * </p>
+     *
+     * <h3>Non-presentation virtual displays</h3>
+     * <p>
+     * When this flag is not set, the virtual display is not registered as a presentation
+     * display.  Applications can still project their content on the display but they
+     * will typically not do so automatically.  This option is appropriate for
+     * more special-purpose displays.
+     * </p>
+     *
+     * @see android.app.Presentation for information about presenting content
+     * on secondary displays.
+     * @see #createVirtualDisplay
+     * @see #DISPLAY_CATEGORY_PRESENTATION
+     * @see Display#FLAG_PRESENTATION
+     */
+    public static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = 1 << 1;
+
+    /**
+     * Virtual display flag: Create a secure display.
+     *
+     * <h3>Secure virtual displays</h3>
+     * <p>
+     * When this flag is set, the virtual display is considered secure as defined
+     * by the {@link Display#FLAG_SECURE} display flag.  The caller promises to take
+     * reasonable measures, such as over-the-air encryption, to prevent the contents
+     * of the display from being intercepted or recorded on a persistent medium.
+     * </p><p>
+     * Creating a secure virtual display requires the
+     * {@link android.Manifest.permission#CAPTURE_SECURE_VIDEO_OUTPUT} permission.
+     * This permission is reserved for use by system components and is not available to
+     * third-party applications.
+     * </p>
+     *
+     * <h3>Non-secure virtual displays</h3>
+     * <p>
+     * When this flag is not set, the virtual display is considered unsecure.
+     * The content of secure windows will be blanked if shown on this display.
+     * </p>
+     *
+     * @see Display#FLAG_SECURE for information about secure displays.
+     * @see #createVirtualDisplay
+     */
+    public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 1 << 2;
+
     /** @hide */
     public DisplayManager(Context context) {
         mContext = context;
@@ -130,12 +224,12 @@
         synchronized (mLock) {
             try {
                 if (category == null) {
-                    addMatchingDisplaysLocked(mTempDisplays, displayIds, -1);
+                    addAllDisplaysLocked(mTempDisplays, displayIds);
                 } else if (category.equals(DISPLAY_CATEGORY_PRESENTATION)) {
-                    addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI);
-                    addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_HDMI);
-                    addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY);
-                    addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL);
+                    addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI);
+                    addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_HDMI);
+                    addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY);
+                    addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL);
                 }
                 return mTempDisplays.toArray(new Display[mTempDisplays.size()]);
             } finally {
@@ -144,12 +238,22 @@
         }
     }
 
-    private void addMatchingDisplaysLocked(
+    private void addAllDisplaysLocked(ArrayList<Display> displays, int[] displayIds) {
+        for (int i = 0; i < displayIds.length; i++) {
+            Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
+            if (display != null) {
+                displays.add(display);
+            }
+        }
+    }
+
+    private void addPresentationDisplaysLocked(
             ArrayList<Display> displays, int[] displayIds, int matchType) {
         for (int i = 0; i < displayIds.length; i++) {
             Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
             if (display != null
-                    && (matchType < 0 || display.getType() == matchType)) {
+                    && (display.getFlags() & Display.FLAG_PRESENTATION) != 0
+                    && display.getType() == matchType) {
                 displays.add(display);
             }
         }
@@ -277,23 +381,19 @@
     }
 
     /**
-     * Creates a private virtual display.
+     * Creates a virtual display.
      * <p>
      * The content of a virtual display is rendered to a {@link Surface} provided
-     * by the application that created the virtual display.
+     * by the application.
      * </p><p>
-     * Only the application that created a private virtual display is allowed to
-     * place windows upon it.  The private virtual display also does not participate
-     * in display mirroring: it will neither receive mirrored content from another
-     * display nor allow its own content to be mirrored elsewhere.  More precisely,
-     * the only processes that are allowed to enumerate or interact with a private
-     * display are those that have the same UID as the application that originally
-     * created the private virtual display.
-     * </p><p>
-     * The private virtual display should be {@link VirtualDisplay#release released}
-     * when no longer needed.  Because a private virtual display renders to a surface
+     * The virtual display should be {@link VirtualDisplay#release released}
+     * when no longer needed.  Because a virtual display renders to a surface
      * provided by the application, it will be released automatically when the
      * process terminates and all remaining windows on it will be forcibly removed.
+     * </p><p>
+     * The behavior of the virtual display depends on the flags that are provided
+     * to this method.  By default, virtual displays are created to be private,
+     * non-presentation and unsecure.  Permissions may be required to use certain flags.
      * </p>
      *
      * @param name The name of the virtual display, must be non-empty.
@@ -302,13 +402,19 @@
      * @param densityDpi The density of the virtual display in dpi, must be greater than 0.
      * @param surface The surface to which the content of the virtual display should
      * be rendered, must be non-null.
+     * @param flags A combination of virtual display flags:
+     * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION}
+     * or {@link #VIRTUAL_DISPLAY_FLAG_SECURE}.
      * @return The newly created virtual display, or null if the application could
      * not create the virtual display.
+     *
+     * @throws SecurityException if the caller does not have permission to create
+     * a virtual display with the specified flags.
      */
-    public VirtualDisplay createPrivateVirtualDisplay(String name,
-            int width, int height, int densityDpi, Surface surface) {
-        return mGlobal.createPrivateVirtualDisplay(mContext,
-                name, width, height, densityDpi, surface);
+    public VirtualDisplay createVirtualDisplay(String name,
+            int width, int height, int densityDpi, Surface surface, int flags) {
+        return mGlobal.createVirtualDisplay(mContext,
+                name, width, height, densityDpi, surface, flags);
     }
 
     /**
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 320185d..10c14ff 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -329,8 +329,8 @@
         }
     }
 
-    public VirtualDisplay createPrivateVirtualDisplay(Context context, String name,
-            int width, int height, int densityDpi, Surface surface) {
+    public VirtualDisplay createVirtualDisplay(Context context, String name,
+            int width, int height, int densityDpi, Surface surface, int flags) {
         if (TextUtils.isEmpty(name)) {
             throw new IllegalArgumentException("name must be non-null and non-empty");
         }
@@ -345,20 +345,20 @@
         Binder token = new Binder();
         int displayId;
         try {
-            displayId = mDm.createPrivateVirtualDisplay(token, context.getPackageName(),
-                    name, width, height, densityDpi, surface);
+            displayId = mDm.createVirtualDisplay(token, context.getPackageName(),
+                    name, width, height, densityDpi, surface, flags);
         } catch (RemoteException ex) {
-            Log.e(TAG, "Could not create private virtual display: " + name, ex);
+            Log.e(TAG, "Could not create virtual display: " + name, ex);
             return null;
         }
         if (displayId < 0) {
-            Log.e(TAG, "Could not create private virtual display: " + name);
+            Log.e(TAG, "Could not create virtual display: " + name);
             return null;
         }
         Display display = getRealDisplay(displayId);
         if (display == null) {
             Log.wtf(TAG, "Could not obtain display info for newly created "
-                    + "private virtual display: " + name);
+                    + "virtual display: " + name);
             try {
                 mDm.releaseVirtualDisplay(token);
             } catch (RemoteException ex) {
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index cd4896a..afaf436 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -48,9 +48,10 @@
     // No permissions required.
     WifiDisplayStatus getWifiDisplayStatus();
 
-    // No permissions required.
-    int createPrivateVirtualDisplay(IBinder token, String packageName,
-            String name, int width, int height, int densityDpi, in Surface surface);
+    // Requires CAPTURE_VIDEO_OUTPUT or CAPTURE_SECURE_VIDEO_OUTPUT for certain
+    // combinations of flags.
+    int createVirtualDisplay(IBinder token, String packageName,
+            String name, int width, int height, int densityDpi, in Surface surface, int flags);
 
     // No permissions required but must be same Uid as the creator.
     void releaseVirtualDisplay(in IBinder token);
diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java
index 145a217..908aadd 100644
--- a/core/java/android/hardware/display/VirtualDisplay.java
+++ b/core/java/android/hardware/display/VirtualDisplay.java
@@ -21,7 +21,7 @@
 /**
  * Represents a virtual display.
  *
- * @see DisplayManager#createPrivateVirtualDisplay
+ * @see DisplayManager#createVirtualDisplay
  */
 public final class VirtualDisplay {
     private final DisplayManagerGlobal mGlobal;
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 5f614b1..354ea66 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -149,16 +149,25 @@
     /**
      * Display flag: Indicates that the display is private.  Only the application that
      * owns the display can create windows on it.
-     * <p>
-     * This flag is associated with displays that were created using
-     * {@link android.hardware.display.DisplayManager#createPrivateVirtualDisplay}.
-     * </p>
      *
      * @see #getFlags
      */
     public static final int FLAG_PRIVATE = 1 << 2;
 
     /**
+     * Display flag: Indicates that the display is a presentation display.
+     * <p>
+     * This flag identifies secondary displays that are suitable for
+     * use as presentation displays such as HDMI or Wireless displays.  Applications
+     * may automatically project their content to presentation displays to provide
+     * richer second screen experiences.
+     * </p>
+     *
+     * @see #getFlags
+     */
+    public static final int FLAG_PRESENTATION = 1 << 3;
+
+    /**
      * Display type: Unknown display type.
      * @hide
      */
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 9a9c4cd..8944207 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -466,6 +466,9 @@
         if ((flags & Display.FLAG_PRIVATE) != 0) {
             result.append(", FLAG_PRIVATE");
         }
+        if ((flags & Display.FLAG_PRESENTATION) != 0) {
+            result.append(", FLAG_PRESENTATION");
+        }
         return result.toString();
     }
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 74d383f..a9a14ad 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2026,6 +2026,27 @@
         android:description="@string/permdesc_controlWifiDisplay"
         android:protectionLevel="signature" />
 
+    <!-- Allows an application to capture audio output.
+         <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"
+        android:label="@string/permlab_captureAudioOutput"
+        android:description="@string/permdesc_captureAudioOutput"
+        android:protectionLevel="signature|system" />
+
+    <!-- Allows an application to capture video output.
+         <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"
+        android:label="@string/permlab_captureVideoOutput"
+        android:description="@string/permdesc_captureVideoOutput"
+        android:protectionLevel="signature|system" />
+
+    <!-- Allows an application to capture secure video output.
+         <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT"
+        android:label="@string/permlab_captureSecureVideoOutput"
+        android:description="@string/permdesc_captureSecureVideoOutput"
+        android:protectionLevel="signature|system" />
+
     <!-- Required to be able to disable the device (very dangerous!).
     <p>Not for use by third-party applications.. -->
     <permission android:name="android.permission.BRICK"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a9d1c86..4830a19 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1394,9 +1394,19 @@
     <string name="permdesc_configureWifiDisplay">Allows the app to configure and connect to Wifi displays.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_controlWifiDisplay">control Wifi displays</string>
+    <string name="permlab_captureAudioOutput">capture audio output</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_controlWifiDisplay">Allows the app to control low-level features of Wifi displays.</string>
+    <string name="permdesc_captureAudioOutput">Allows the app to capture and redirect audio output.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_captureVideoOutput">capture video output</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_captureVideoOutput">Allows the app to capture and redirect video output.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_captureSecureVideoOutput">capture secure video output</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_captureSecureVideoOutput">Allows the app to capture and redirect secure video output.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_modifyAudioSettings">change your audio settings</string>
diff --git a/services/java/com/android/server/display/DisplayDeviceInfo.java b/services/java/com/android/server/display/DisplayDeviceInfo.java
index 11f8d6a..11c5d87 100644
--- a/services/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/java/com/android/server/display/DisplayDeviceInfo.java
@@ -73,6 +73,11 @@
     public static final int FLAG_NEVER_BLANK = 1 << 5;
 
     /**
+     * Flag: Indicates that the display is suitable for presentations.
+     */
+    public static final int FLAG_PRESENTATION = 1 << 6;
+
+    /**
      * Touch attachment: Display does not receive touch.
      */
     public static final int TOUCH_NONE = 0;
@@ -289,6 +294,9 @@
         if ((flags & FLAG_NEVER_BLANK) != 0) {
             msg.append(", FLAG_NEVER_BLANK");
         }
+        if ((flags & FLAG_PRESENTATION) != 0) {
+            msg.append(", FLAG_PRESENTATION");
+        }
         return msg.toString();
     }
 }
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index c339c26..19a11c0 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -21,6 +21,7 @@
 import android.Manifest;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerGlobal;
 import android.hardware.display.IDisplayManager;
 import android.hardware.display.IDisplayManagerCallback;
@@ -589,8 +590,8 @@
     }
 
     @Override // Binder call
-    public int createPrivateVirtualDisplay(IBinder appToken, String packageName,
-            String name, int width, int height, int densityDpi, Surface surface) {
+    public int createVirtualDisplay(IBinder appToken, String packageName,
+            String name, int width, int height, int densityDpi, Surface surface, int flags) {
         final int callingUid = Binder.getCallingUid();
         if (!validatePackageName(callingUid, packageName)) {
             throw new SecurityException("packageName must match the calling uid");
@@ -608,6 +609,25 @@
         if (surface == null) {
             throw new IllegalArgumentException("surface must not be null");
         }
+        if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
+            if (mContext.checkCallingPermission(android.Manifest.permission.CAPTURE_VIDEO_OUTPUT)
+                    != PackageManager.PERMISSION_GRANTED
+                    && mContext.checkCallingPermission(
+                            android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT)
+                            != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
+                        + "CAPTURE_SECURE_VIDEO_OUTPUT permission to create a "
+                        + "public virtual display.");
+            }
+        }
+        if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
+            if (mContext.checkCallingPermission(
+                    android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT)
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT "
+                        + "to create a secure virtual display.");
+            }
+        }
 
         final long token = Binder.clearCallingIdentity();
         try {
@@ -618,9 +638,9 @@
                     return -1;
                 }
 
-                DisplayDevice device = mVirtualDisplayAdapter.createPrivateVirtualDisplayLocked(
+                DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
                         appToken, callingUid, packageName, name, width, height, densityDpi,
-                        surface);
+                        surface, flags);
                 if (device == null) {
                     return -1;
                 }
@@ -632,7 +652,7 @@
                 }
 
                 // Something weird happened and the logical display was not created.
-                Slog.w(TAG, "Rejecting request to create private virtual display "
+                Slog.w(TAG, "Rejecting request to create virtual display "
                         + "because the logical display was not created.");
                 mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
                 handleDisplayDeviceRemovedLocked(device);
diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/java/com/android/server/display/LocalDisplayAdapter.java
index 475f27b..cb8f3e2 100644
--- a/services/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/java/com/android/server/display/LocalDisplayAdapter.java
@@ -155,6 +155,7 @@
                     mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
                 } else {
                     mInfo.type = Display.TYPE_HDMI;
+                    mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
                     mInfo.name = getContext().getResources().getString(
                             com.android.internal.R.string.display_manager_hdmi_display_name);
                     mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
diff --git a/services/java/com/android/server/display/LogicalDisplay.java b/services/java/com/android/server/display/LogicalDisplay.java
index 775ebb2..b9839c2 100644
--- a/services/java/com/android/server/display/LogicalDisplay.java
+++ b/services/java/com/android/server/display/LogicalDisplay.java
@@ -205,6 +205,9 @@
             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_PRIVATE) != 0) {
                 mBaseDisplayInfo.flags |= Display.FLAG_PRIVATE;
             }
+            if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_PRESENTATION) != 0) {
+                mBaseDisplayInfo.flags |= Display.FLAG_PRESENTATION;
+            }
             mBaseDisplayInfo.type = deviceInfo.type;
             mBaseDisplayInfo.address = deviceInfo.address;
             mBaseDisplayInfo.name = deviceInfo.name;
diff --git a/services/java/com/android/server/display/OverlayDisplayAdapter.java b/services/java/com/android/server/display/OverlayDisplayAdapter.java
index 3152897..ce402a5 100644
--- a/services/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -245,7 +245,7 @@
                 mInfo.densityDpi = mDensityDpi;
                 mInfo.xDpi = mDensityDpi;
                 mInfo.yDpi = mDensityDpi;
-                mInfo.flags = 0;
+                mInfo.flags = DisplayDeviceInfo.FLAG_PRESENTATION;
                 if (mSecure) {
                     mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE;
                 }
diff --git a/services/java/com/android/server/display/VirtualDisplayAdapter.java b/services/java/com/android/server/display/VirtualDisplayAdapter.java
index 634fba7..3a71361 100644
--- a/services/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -17,6 +17,7 @@
 package com.android.server.display;
 
 import android.content.Context;
+import android.hardware.display.DisplayManager;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
@@ -46,12 +47,13 @@
         super(syncRoot, context, handler, listener, TAG);
     }
 
-    public DisplayDevice createPrivateVirtualDisplayLocked(IBinder appToken,
+    public DisplayDevice createVirtualDisplayLocked(IBinder appToken,
             int ownerUid, String ownerPackageName,
-            String name, int width, int height, int densityDpi, Surface surface) {
-        IBinder displayToken = SurfaceControl.createDisplay(name, false /*secure*/);
+            String name, int width, int height, int densityDpi, Surface surface, int flags) {
+        boolean secure = (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
+        IBinder displayToken = SurfaceControl.createDisplay(name, secure);
         VirtualDisplayDevice device = new VirtualDisplayDevice(displayToken, appToken,
-                ownerUid, ownerPackageName, name, width, height, densityDpi, surface);
+                ownerUid, ownerPackageName, name, width, height, densityDpi, surface, flags);
 
         try {
             appToken.linkToDeath(device, 0);
@@ -96,6 +98,7 @@
         private final int mWidth;
         private final int mHeight;
         private final int mDensityDpi;
+        private final int mFlags;
 
         private boolean mReleased;
         private Surface mSurface;
@@ -103,7 +106,7 @@
 
         public VirtualDisplayDevice(IBinder displayToken,
                 IBinder appToken, int ownerUid, String ownerPackageName,
-                String name, int width, int height, int densityDpi, Surface surface) {
+                String name, int width, int height, int densityDpi, Surface surface, int flags) {
             super(VirtualDisplayAdapter.this, displayToken);
             mAppToken = appToken;
             mOwnerUid = ownerUid;
@@ -113,6 +116,7 @@
             mHeight = height;
             mDensityDpi = densityDpi;
             mSurface = surface;
+            mFlags = flags;
         }
 
         @Override
@@ -149,7 +153,17 @@
                 mInfo.densityDpi = mDensityDpi;
                 mInfo.xDpi = mDensityDpi;
                 mInfo.yDpi = mDensityDpi;
-                mInfo.flags = DisplayDeviceInfo.FLAG_PRIVATE | DisplayDeviceInfo.FLAG_NEVER_BLANK;
+                mInfo.flags = 0;
+                if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
+                    mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE |
+                            DisplayDeviceInfo.FLAG_NEVER_BLANK;
+                }
+                if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
+                    mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE;
+                }
+                if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION) != 0) {
+                    mInfo.flags |= DisplayDeviceInfo.FLAG_PRESENTATION;
+                }
                 mInfo.type = Display.TYPE_VIRTUAL;
                 mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
                 mInfo.ownerUid = mOwnerUid;
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index 4c80cf5..11d3819 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -352,7 +352,7 @@
         }
 
         boolean secure = (flags & RemoteDisplay.DISPLAY_FLAG_SECURE) != 0;
-        int deviceFlags = 0;
+        int deviceFlags = DisplayDeviceInfo.FLAG_PRESENTATION;
         if (secure) {
             deviceFlags |= DisplayDeviceInfo.FLAG_SECURE;
             if (mSupportsProtectedBuffers) {
diff --git a/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/DisplaySourceService.java b/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/DisplaySourceService.java
index ccead44..256f900 100644
--- a/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/DisplaySourceService.java
+++ b/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/DisplaySourceService.java
@@ -197,8 +197,8 @@
             Surface surface = codec.createInputSurface();
             codec.start();
 
-            VirtualDisplay virtualDisplay = mDisplayManager.createPrivateVirtualDisplay(
-                    DISPLAY_NAME, mWidth, mHeight, mDensityDpi, surface);
+            VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(
+                    DISPLAY_NAME, mWidth, mHeight, mDensityDpi, surface, 0);
             if (virtualDisplay != null) {
                 mHandler.obtainMessage(MSG_DISPATCH_DISPLAY_ADDED,
                         virtualDisplay.getDisplay()).sendToTarget();