/* * 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.FlaggedApi; import android.annotation.FloatRange; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.hardware.display.DisplayManager.VirtualDisplayFlag; import android.media.projection.MediaProjection; import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; import android.util.ArraySet; import android.view.Display; import android.view.Surface; import java.util.Collections; import java.util.Objects; import java.util.Set; /** * Holds configuration used to create {@link VirtualDisplay} instances. * * @see DisplayManager#createVirtualDisplay(VirtualDisplayConfig, Handler, VirtualDisplay.Callback) * @see MediaProjection#createVirtualDisplay(String, int, int, int, int, Surface, * VirtualDisplay.Callback, Handler) */ public final class VirtualDisplayConfig implements Parcelable { private final String mName; private final int mWidth; private final int mHeight; private final int mDensityDpi; private final int mFlags; private final Surface mSurface; private final String mUniqueId; private final int mDisplayIdToMirror; private final boolean mWindowManagerMirroringEnabled; private ArraySet mDisplayCategories = null; private final float mRequestedRefreshRate; private final boolean mIsHomeSupported; private VirtualDisplayConfig( @NonNull String name, @IntRange(from = 1) int width, @IntRange(from = 1) int height, @IntRange(from = 1) int densityDpi, @VirtualDisplayFlag int flags, @Nullable Surface surface, @Nullable String uniqueId, int displayIdToMirror, boolean windowManagerMirroringEnabled, @NonNull ArraySet displayCategories, float requestedRefreshRate, boolean isHomeSupported) { mName = name; mWidth = width; mHeight = height; mDensityDpi = densityDpi; mFlags = flags; mSurface = surface; mUniqueId = uniqueId; mDisplayIdToMirror = displayIdToMirror; mWindowManagerMirroringEnabled = windowManagerMirroringEnabled; mDisplayCategories = displayCategories; mRequestedRefreshRate = requestedRefreshRate; mIsHomeSupported = isHomeSupported; } /** * Returns the name of the virtual display. */ @NonNull public String getName() { return mName; } /** * Returns the width of the virtual display in pixels. */ public int getWidth() { return mWidth; } /** * Returns the height of the virtual display in pixels. */ public int getHeight() { return mHeight; } /** * Returns the density of the virtual display in dpi. */ public int getDensityDpi() { return mDensityDpi; } /** * Returns the virtual display flags. * * @see Builder#setFlags */ public int getFlags() { return mFlags; } /** * Returns the surface to which the content of the virtual display should be rendered, if any. * * @see Builder#setSurface */ @Nullable public Surface getSurface() { return mSurface; } /** * Returns the unique identifier for the display. Shouldn't be displayed to the user. * @hide */ @Nullable public String getUniqueId() { return mUniqueId; } /** * Returns the id of the display that the virtual display should mirror, or * {@link android.view.Display#DEFAULT_DISPLAY} if there is none. * @hide */ public int getDisplayIdToMirror() { return mDisplayIdToMirror; } /** * Whether if WindowManager is responsible for mirroring content to this VirtualDisplay, or * if DisplayManager should record contents instead. * @hide */ public boolean isWindowManagerMirroringEnabled() { return mWindowManagerMirroringEnabled; } /** * Whether this virtual display supports showing home activity and wallpaper. * * @see Builder#setHomeSupported * @hide */ @FlaggedApi(android.companion.virtual.flags.Flags.FLAG_VDM_CUSTOM_HOME) @SystemApi public boolean isHomeSupported() { return android.companion.virtual.flags.Flags.vdmCustomHome() && mIsHomeSupported; } /** * Returns the display categories. * * @see Builder#setDisplayCategories */ @NonNull public Set getDisplayCategories() { return Collections.unmodifiableSet(mDisplayCategories); } /** * Returns the refresh rate of a virtual display in frames per second, or zero if it is using a * default refresh rate chosen by the system. * * @see Builder#setRequestedRefreshRate */ public float getRequestedRefreshRate() { return mRequestedRefreshRate; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString8(mName); dest.writeInt(mWidth); dest.writeInt(mHeight); dest.writeInt(mDensityDpi); dest.writeInt(mFlags); dest.writeTypedObject(mSurface, flags); dest.writeString8(mUniqueId); dest.writeInt(mDisplayIdToMirror); dest.writeBoolean(mWindowManagerMirroringEnabled); dest.writeArraySet(mDisplayCategories); dest.writeFloat(mRequestedRefreshRate); dest.writeBoolean(mIsHomeSupported); } @Override public int describeContents() { return 0; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof VirtualDisplayConfig)) { return false; } VirtualDisplayConfig that = (VirtualDisplayConfig) o; return Objects.equals(mName, that.mName) && mWidth == that.mWidth && mHeight == that.mHeight && mDensityDpi == that.mDensityDpi && mFlags == that.mFlags && Objects.equals(mSurface, that.mSurface) && Objects.equals(mUniqueId, that.mUniqueId) && mDisplayIdToMirror == that.mDisplayIdToMirror && mWindowManagerMirroringEnabled == that.mWindowManagerMirroringEnabled && Objects.equals(mDisplayCategories, that.mDisplayCategories) && mRequestedRefreshRate == that.mRequestedRefreshRate && mIsHomeSupported == that.mIsHomeSupported; } @Override public int hashCode() { int hashCode = Objects.hash( mName, mWidth, mHeight, mDensityDpi, mFlags, mSurface, mUniqueId, mDisplayIdToMirror, mWindowManagerMirroringEnabled, mDisplayCategories, mRequestedRefreshRate, mIsHomeSupported); return hashCode; } @Override @NonNull public String toString() { return "VirtualDisplayConfig(" + " mName=" + mName + " mHeight=" + mHeight + " mWidth=" + mWidth + " mDensityDpi=" + mDensityDpi + " mFlags=" + mFlags + " mSurface=" + mSurface + " mUniqueId=" + mUniqueId + " mDisplayIdToMirror=" + mDisplayIdToMirror + " mWindowManagerMirroringEnabled=" + mWindowManagerMirroringEnabled + " mDisplayCategories=" + mDisplayCategories + " mRequestedRefreshRate=" + mRequestedRefreshRate + " mIsHomeSupported=" + mIsHomeSupported + ")"; } private VirtualDisplayConfig(@NonNull Parcel in) { mName = in.readString8(); mWidth = in.readInt(); mHeight = in.readInt(); mDensityDpi = in.readInt(); mFlags = in.readInt(); mSurface = in.readTypedObject(Surface.CREATOR); mUniqueId = in.readString8(); mDisplayIdToMirror = in.readInt(); mWindowManagerMirroringEnabled = in.readBoolean(); mDisplayCategories = (ArraySet) in.readArraySet(null); mRequestedRefreshRate = in.readFloat(); mIsHomeSupported = in.readBoolean(); } @NonNull public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @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}. */ public static final class Builder { private final String mName; private final int mWidth; private final int mHeight; private final int mDensityDpi; private int mFlags = 0; private Surface mSurface = null; private String mUniqueId = null; private int mDisplayIdToMirror = DEFAULT_DISPLAY; private boolean mWindowManagerMirroringEnabled = false; private ArraySet mDisplayCategories = new ArraySet<>(); private float mRequestedRefreshRate = 0.0f; private boolean mIsHomeSupported = false; /** * 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) { if (name == null) { throw new IllegalArgumentException("Virtual display name is required"); } if (width <= 0) { throw new IllegalArgumentException("Virtual display width must be positive"); } if (height <= 0) { throw new IllegalArgumentException("Virtual display height must be positive"); } if (densityDpi <= 0) { throw new IllegalArgumentException("Virtual display density must be positive"); } mName = name; mWidth = width; mHeight = height; mDensityDpi = densityDpi; } /** * Sets the virtual display flags, a combination of * {@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}. */ @NonNull public Builder setFlags(@VirtualDisplayFlag int flags) { mFlags = flags; return this; } /** * Sets the surface to which the content of the virtual display should be rendered. * *

The surface can also be set after the display creation using * {@link VirtualDisplay#setSurface(Surface)}. */ @NonNull public Builder setSurface(@Nullable Surface surface) { mSurface = surface; return this; } /** * Sets the unique identifier for the display. * @hide */ @NonNull public Builder setUniqueId(@Nullable String uniqueId) { mUniqueId = uniqueId; return this; } /** * Sets the id of the display that the virtual display should mirror. * @hide */ @NonNull public Builder setDisplayIdToMirror(int displayIdToMirror) { mDisplayIdToMirror = displayIdToMirror; return this; } /** * Sets whether WindowManager is responsible for mirroring content to this VirtualDisplay. * If unset or false, DisplayManager should record contents instead. * @hide */ @NonNull public Builder setWindowManagerMirroringEnabled(boolean windowManagerMirroringEnabled) { mWindowManagerMirroringEnabled = windowManagerMirroringEnabled; return this; } /** * Sets the display categories. * *

The categories of the display indicate the type of activities allowed to run on that * display. Activities can declare a display category using * {@link android.content.pm.ActivityInfo#requiredDisplayCategory}. */ @NonNull public Builder setDisplayCategories(@NonNull Set displayCategories) { mDisplayCategories.clear(); mDisplayCategories.addAll(Objects.requireNonNull(displayCategories)); return this; } /** * Adds a display category. * * @see #setDisplayCategories */ @NonNull public Builder addDisplayCategory(@NonNull String displayCategory) { mDisplayCategories.add(Objects.requireNonNull(displayCategory)); return this; } /** * Sets the refresh rate of a virtual display in frames per second. * *

For best results, specify a divisor of the physical refresh rate, e.g., 30 or 60 on * a 120hz display. If an arbitrary refresh rate is specified, the rate will be rounded up * to a divisor of the physical display. If unset or zero, the virtual display will be * refreshed at the physical display refresh rate. * * @see Display#getRefreshRate() */ @NonNull public Builder setRequestedRefreshRate( @FloatRange(from = 0.0f) float requestedRefreshRate) { if (requestedRefreshRate < 0.0f) { throw new IllegalArgumentException( "Virtual display requested refresh rate must be non-negative"); } mRequestedRefreshRate = requestedRefreshRate; return this; } /** * Sets whether this display supports showing home activities and wallpaper. * *

If set to {@code true}, then the home activity relevant to this display will be * automatically launched upon the display creation. If unset or set to {@code false}, the * display will not host any activities upon creation.

* *

Note: setting to {@code true} requires the display to be trusted and to not mirror * content of other displays. If the display is not trusted, or if it mirrors content of * other displays, this property is ignored.

* * @param isHomeSupported whether home activities are supported on the display * @see DisplayManager#VIRTUAL_DISPLAY_FLAG_TRUSTED * @see DisplayManager#VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR * @see DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY * @hide */ @FlaggedApi(android.companion.virtual.flags.Flags.FLAG_VDM_CUSTOM_HOME) @SystemApi @NonNull public Builder setHomeSupported(boolean isHomeSupported) { mIsHomeSupported = isHomeSupported; return this; } /** * Builds the {@link VirtualDisplayConfig} instance. */ @NonNull public VirtualDisplayConfig build() { return new VirtualDisplayConfig( mName, mWidth, mHeight, mDensityDpi, mFlags, mSurface, mUniqueId, mDisplayIdToMirror, mWindowManagerMirroringEnabled, mDisplayCategories, mRequestedRefreshRate, mIsHomeSupported); } } }