summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2013-06-04 00:02:38 -0700
committerJeff Brown <jeffbrown@google.com>2013-06-18 15:32:41 -0700
commita506a6ec94863a35acca9feb165db76ddac3892c (patch)
tree703825e9e8d3d4928b4d36185244c22b425be04c /core
parent012416fdbb279f291b43e9d6bf565750752e6a41 (diff)
downloadframeworks_base-a506a6ec94863a35acca9feb165db76ddac3892c.zip
frameworks_base-a506a6ec94863a35acca9feb165db76ddac3892c.tar.gz
frameworks_base-a506a6ec94863a35acca9feb165db76ddac3892c.tar.bz2
Add an API to allow for creating private virtual displays.
This change enables applications to create a private virtual display that renders its content to a surface of its own creation. The display is private in the sense that only the application that owns the display is allowed to place windows upon it. Mirroring and blanking is also disabled for these displays. Bug: 9192512 Change-Id: I852ea07f0c7df1d244e354e3daca3a6960285ca0
Diffstat (limited to 'core')
-rw-r--r--core/java/android/hardware/display/DisplayManager.java37
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java50
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl8
-rw-r--r--core/java/android/hardware/display/VirtualDisplay.java62
-rw-r--r--core/java/android/view/Display.java69
-rw-r--r--core/java/android/view/DisplayInfo.java47
6 files changed, 270 insertions, 3 deletions
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 0a7a2e7..dcf50cd 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.os.Handler;
import android.util.SparseArray;
import android.view.Display;
+import android.view.Surface;
import java.util.ArrayList;
@@ -134,6 +135,7 @@ public final class DisplayManager {
addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI);
addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_HDMI);
addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY);
+ addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL);
}
return mTempDisplays.toArray(new Display[mTempDisplays.size()]);
} finally {
@@ -275,6 +277,41 @@ public final class DisplayManager {
}
/**
+ * Creates a private virtual display.
+ * <p>
+ * The content of a virtual display is rendered to a {@link Surface} provided
+ * by the application that created the virtual display.
+ * </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
+ * provided by the application, it will be released automatically when the
+ * process terminates and all remaining windows on it will be forcibly removed.
+ * </p>
+ *
+ * @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.
+ * @param surface The surface to which the content of the virtual display should
+ * be rendered, must be non-null.
+ * @return The newly created virtual display, or null if the application could
+ * not create the virtual display.
+ */
+ public VirtualDisplay createPrivateVirtualDisplay(String name,
+ int width, int height, int densityDpi, Surface surface) {
+ return mGlobal.createPrivateVirtualDisplay(mContext,
+ name, width, height, densityDpi, surface);
+ }
+
+ /**
* Listens for changes in available display devices.
*/
public interface DisplayListener {
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index a858681..3ab882d 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -18,17 +18,20 @@ package android.hardware.display;
import android.content.Context;
import android.hardware.display.DisplayManager.DisplayListener;
+import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.CompatibilityInfoHolder;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.Surface;
import java.util.ArrayList;
@@ -315,6 +318,53 @@ public final class DisplayManagerGlobal {
}
}
+ public VirtualDisplay createPrivateVirtualDisplay(Context context, String name,
+ int width, int height, int densityDpi, Surface surface) {
+ 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 (surface == null) {
+ throw new IllegalArgumentException("surface must not be null");
+ }
+
+ Binder token = new Binder();
+ int displayId;
+ try {
+ displayId = mDm.createPrivateVirtualDisplay(token, context.getPackageName(),
+ name, width, height, densityDpi, surface);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Could not create private virtual display: " + name, ex);
+ return null;
+ }
+ if (displayId < 0) {
+ Log.e(TAG, "Could not create private 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);
+ try {
+ mDm.releaseVirtualDisplay(token);
+ } catch (RemoteException ex) {
+ }
+ return null;
+ }
+ return new VirtualDisplay(this, display, token);
+ }
+
+ public void releaseVirtualDisplay(IBinder token) {
+ try {
+ mDm.releaseVirtualDisplay(token);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Failed to release virtual display.", ex);
+ }
+ }
+
private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
@Override
public void onDisplayEvent(int displayId, int event) {
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 79aad78..cd4896a 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -20,6 +20,7 @@ import android.hardware.display.IDisplayManagerCallback;
import android.hardware.display.WifiDisplay;
import android.hardware.display.WifiDisplayStatus;
import android.view.DisplayInfo;
+import android.view.Surface;
/** @hide */
interface IDisplayManager {
@@ -46,4 +47,11 @@ interface IDisplayManager {
// 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);
+
+ // 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
new file mode 100644
index 0000000..145a217
--- /dev/null
+++ b/core/java/android/hardware/display/VirtualDisplay.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013 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 android.os.IBinder;
+import android.view.Display;
+
+/**
+ * Represents a virtual display.
+ *
+ * @see DisplayManager#createPrivateVirtualDisplay
+ */
+public final class VirtualDisplay {
+ private final DisplayManagerGlobal mGlobal;
+ private final Display mDisplay;
+ private IBinder mToken;
+
+ VirtualDisplay(DisplayManagerGlobal global, Display display, IBinder token) {
+ mGlobal = global;
+ mDisplay = display;
+ mToken = token;
+ }
+
+ /**
+ * Gets the virtual display.
+ */
+ public Display getDisplay() {
+ return mDisplay;
+ }
+
+ /**
+ * Releases the virtual display and destroys its underlying surface.
+ * <p>
+ * All remaining windows on the virtual display will be forcibly removed
+ * as part of releasing the virtual display.
+ * </p>
+ */
+ public void release() {
+ if (mToken != null) {
+ mGlobal.releaseVirtualDisplay(mToken);
+ mToken = null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "VirtualDisplay{display=" + mDisplay + ", token=" + mToken + "}";
+ }
+}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index e6a7950..4d984fd 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -20,6 +20,7 @@ import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerGlobal;
+import android.os.Process;
import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -57,6 +58,8 @@ public final class Display {
private final int mFlags;
private final int mType;
private final String mAddress;
+ private final int mOwnerUid;
+ private final String mOwnerPackageName;
private final CompatibilityInfoHolder mCompatibilityInfo;
private DisplayInfo mDisplayInfo; // never null
@@ -143,6 +146,18 @@ public final class Display {
public static final int FLAG_SECURE = 1 << 1;
/**
+ * 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 type: Unknown display type.
* @hide
*/
@@ -173,6 +188,12 @@ public final class Display {
public static final int TYPE_OVERLAY = 4;
/**
+ * Display type: Virtual display.
+ * @hide
+ */
+ public static final int TYPE_VIRTUAL = 5;
+
+ /**
* Internal method to create a display.
* Applications should use {@link android.view.WindowManager#getDefaultDisplay()}
* or {@link android.hardware.display.DisplayManager#getDisplay}
@@ -194,6 +215,8 @@ public final class Display {
mFlags = displayInfo.flags;
mType = displayInfo.type;
mAddress = displayInfo.address;
+ mOwnerUid = displayInfo.ownerUid;
+ mOwnerPackageName = displayInfo.ownerPackageName;
}
/**
@@ -262,6 +285,7 @@ public final class Display {
*
* @see #FLAG_SUPPORTS_PROTECTED_BUFFERS
* @see #FLAG_SECURE
+ * @see #FLAG_PRIVATE
*/
public int getFlags() {
return mFlags;
@@ -277,6 +301,7 @@ public final class Display {
* @see #TYPE_HDMI
* @see #TYPE_WIFI
* @see #TYPE_OVERLAY
+ * @see #TYPE_VIRTUAL
* @hide
*/
public int getType() {
@@ -295,6 +320,32 @@ public final class Display {
}
/**
+ * Gets the UID of the application that owns this display, or zero if it is
+ * owned by the system.
+ * <p>
+ * If the display is private, then only the owner can use it.
+ * </p>
+ *
+ * @hide
+ */
+ public int getOwnerUid() {
+ return mOwnerUid;
+ }
+
+ /**
+ * Gets the package name of the application that owns this display, or null if it is
+ * owned by the system.
+ * <p>
+ * If the display is private, then only the owner can use it.
+ * </p>
+ *
+ * @hide
+ */
+ public String getOwnerPackageName() {
+ return mOwnerPackageName;
+ }
+
+ /**
* Gets the compatibility info used by this display instance.
*
* @return The compatibility info holder, or null if none is required.
@@ -564,6 +615,22 @@ public final class Display {
}
}
+ /**
+ * Returns true if the specified UID has access to this display.
+ * @hide
+ */
+ public boolean hasAccess(int uid) {
+ return Display.hasAccess(uid, mFlags, mOwnerUid);
+ }
+
+ /** @hide */
+ public static boolean hasAccess(int uid, int flags, int ownerUid) {
+ return (flags & Display.FLAG_PRIVATE) == 0
+ || uid == ownerUid
+ || uid == Process.SYSTEM_UID
+ || uid == 0;
+ }
+
private void updateDisplayInfoLocked() {
// Note: The display manager caches display info objects on our behalf.
DisplayInfo newInfo = mGlobal.getDisplayInfo(mDisplayId);
@@ -624,6 +691,8 @@ public final class Display {
return "WIFI";
case TYPE_OVERLAY:
return "OVERLAY";
+ case TYPE_VIRTUAL:
+ return "VIRTUAL";
default:
return Integer.toString(type);
}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 9fcd9b1..1442cb7 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -19,6 +19,7 @@ package android.view;
import android.content.res.CompatibilityInfo;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Process;
import android.util.DisplayMetrics;
import libcore.util.Objects;
@@ -177,6 +178,23 @@ public final class DisplayInfo implements Parcelable {
*/
public float physicalYDpi;
+ /**
+ * The UID of the application that owns this display, or zero if it is owned by the system.
+ * <p>
+ * If the display is private, then only the owner can use it.
+ * </p>
+ */
+ public int ownerUid;
+
+ /**
+ * The package name of the application that owns this display, or null if it is
+ * owned by the system.
+ * <p>
+ * If the display is private, then only the owner can use it.
+ * </p>
+ */
+ public String ownerPackageName;
+
public static final Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
@Override
public DisplayInfo createFromParcel(Parcel source) {
@@ -228,7 +246,9 @@ public final class DisplayInfo implements Parcelable {
&& refreshRate == other.refreshRate
&& logicalDensityDpi == other.logicalDensityDpi
&& physicalXDpi == other.physicalXDpi
- && physicalYDpi == other.physicalYDpi;
+ && physicalYDpi == other.physicalYDpi
+ && ownerUid == other.ownerUid
+ && Objects.equal(ownerPackageName, other.ownerPackageName);
}
@Override
@@ -259,6 +279,8 @@ public final class DisplayInfo implements Parcelable {
logicalDensityDpi = other.logicalDensityDpi;
physicalXDpi = other.physicalXDpi;
physicalYDpi = other.physicalYDpi;
+ ownerUid = other.ownerUid;
+ ownerPackageName = other.ownerPackageName;
}
public void readFromParcel(Parcel source) {
@@ -284,6 +306,8 @@ public final class DisplayInfo implements Parcelable {
logicalDensityDpi = source.readInt();
physicalXDpi = source.readFloat();
physicalYDpi = source.readFloat();
+ ownerUid = source.readInt();
+ ownerPackageName = source.readString();
}
@Override
@@ -310,6 +334,8 @@ public final class DisplayInfo implements Parcelable {
dest.writeInt(logicalDensityDpi);
dest.writeFloat(physicalXDpi);
dest.writeFloat(physicalYDpi);
+ dest.writeInt(ownerUid);
+ dest.writeString(ownerPackageName);
}
@Override
@@ -335,6 +361,13 @@ public final class DisplayInfo implements Parcelable {
logicalHeight : logicalWidth;
}
+ /**
+ * Returns true if the specified UID has access to this display.
+ */
+ public boolean hasAccess(int uid) {
+ return Display.hasAccess(uid, flags, ownerUid);
+ }
+
private void getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfoHolder cih,
int width, int height) {
outMetrics.densityDpi = outMetrics.noncompatDensityDpi = logicalDensityDpi;
@@ -402,8 +435,13 @@ public final class DisplayInfo implements Parcelable {
sb.append(layerStack);
sb.append(", type ");
sb.append(Display.typeToString(type));
- sb.append(", address ");
- sb.append(address);
+ if (address != null) {
+ sb.append(", address ").append(address);
+ }
+ if (ownerUid != 0 || ownerPackageName != null) {
+ sb.append(", owner ").append(ownerPackageName);
+ sb.append(" (uid ").append(ownerUid).append(")");
+ }
sb.append(flagsToString(flags));
sb.append("}");
return sb.toString();
@@ -417,6 +455,9 @@ public final class DisplayInfo implements Parcelable {
if ((flags & Display.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) {
result.append(", FLAG_SUPPORTS_PROTECTED_BUFFERS");
}
+ if ((flags & Display.FLAG_PRIVATE) != 0) {
+ result.append(", FLAG_PRIVATE");
+ }
return result.toString();
}
}