Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a506a6ec authored by Jeff Brown's avatar Jeff Brown
Browse files

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
parent 012416fd
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -10548,6 +10548,7 @@ package android.hardware {
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.view.Display getDisplay(int);
    method public android.view.Display[] getDisplays();
    method public android.view.Display[] getDisplays(java.lang.String);
@@ -10562,6 +10563,11 @@ package android.hardware.display {
    method public abstract void onDisplayRemoved(int);
  }
  public final class VirtualDisplay {
    method public android.view.Display getDisplay();
    method public void release();
  }
}
package android.hardware.input {
@@ -25050,6 +25056,7 @@ package android.view {
    method public deprecated int getWidth();
    method public boolean isValid();
    field public static final int DEFAULT_DISPLAY = 0; // 0x0
    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
  }
+37 −0
Original line number Diff line number Diff line
@@ -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 {
@@ -274,6 +276,41 @@ public final class DisplayManager {
        return mGlobal.getWifiDisplayStatus();
    }

    /**
     * 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.
     */
+50 −0
Original line number Diff line number Diff line
@@ -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) {
+8 −0
Original line number Diff line number Diff line
@@ -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);
}
+62 −0
Original line number Diff line number Diff line
/*
 * 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 + "}";
    }
}
Loading