/* * Copyright (C) 2012 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 static android.view.Display.HdrCapabilities.HdrType; import android.Manifest; import android.annotation.FlaggedApi; import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.LongDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.app.ActivityThread; import android.app.KeyguardManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.IPackageManager; import android.content.res.Resources; import android.graphics.Point; import android.media.projection.MediaProjection; import android.os.Build; import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.view.Display; import android.view.Surface; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; import java.util.function.Predicate; /** * Manages the properties of attached displays. */ @SystemService(Context.DISPLAY_SERVICE) public final class DisplayManager { private static final String TAG = "DisplayManager"; // To enable these logs, run: // 'adb shell setprop persist.log.tag.DisplayManager DEBUG && adb reboot' static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG) || Log.isLoggable("DisplayManager_All", Log.DEBUG); private static final boolean ENABLE_VIRTUAL_DISPLAY_REFRESH_RATE = true; /** * The hdr output control feature flag, the value should be read via * {@link android.provider.DeviceConfig#getBoolean(String, String, boolean)} with * {@link android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER} as the namespace. * @hide */ @TestApi public static final String HDR_OUTPUT_CONTROL_FLAG = "enable_hdr_output_control"; private final Context mContext; private final DisplayManagerGlobal mGlobal; private final Object mLock = new Object(); @GuardedBy("mLock") private final WeakDisplayCache mDisplayCache = new WeakDisplayCache(); /** * Broadcast receiver that indicates when the Wifi display status changes. *
* The status is provided as a {@link WifiDisplayStatus} object in the * {@link #EXTRA_WIFI_DISPLAY_STATUS} extra. *
* This broadcast is only sent to registered receivers and can only be sent by the system. *
* @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static final String ACTION_WIFI_DISPLAY_STATUS_CHANGED = "android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED"; /** * Contains a {@link WifiDisplayStatus} object. * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static final String EXTRA_WIFI_DISPLAY_STATUS = "android.hardware.display.extra.WIFI_DISPLAY_STATUS"; /** * Display category: Presentation displays. ** This category can be used to identify secondary displays that are suitable for * use as presentation displays such as external or wireless displays. Applications * may automatically project their content to presentation displays to provide * richer second screen experiences. *
* * @see android.app.Presentation * @see Display#FLAG_PRESENTATION * @see #getDisplays(String) */ public static final String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION"; /** * Display category: Rear displays. ** This category can be used to identify complementary internal displays that are facing away * from the user. * Certain applications may present to this display. * Similar to presentation displays. *
* * @see android.app.Presentation * @see Display#FLAG_PRESENTATION * @see #getDisplays(String) * @hide */ @TestApi public static final String DISPLAY_CATEGORY_REAR = "android.hardware.display.category.REAR"; /** * Display category: All displays, including disabled displays. ** This returns all displays, including currently disabled and inaccessible displays. * * @see #getDisplays(String) * @hide */ public static final String DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED = "android.hardware.display.category.ALL_INCLUDING_DISABLED"; /** @hide **/ @IntDef(prefix = "VIRTUAL_DISPLAY_FLAG_", flag = true, value = { VIRTUAL_DISPLAY_FLAG_PUBLIC, VIRTUAL_DISPLAY_FLAG_PRESENTATION, VIRTUAL_DISPLAY_FLAG_SECURE, VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY, VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD, VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH, VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT, VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL, VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS, VIRTUAL_DISPLAY_FLAG_TRUSTED, VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP, VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED, VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED, VIRTUAL_DISPLAY_FLAG_OWN_FOCUS, VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED, }) @Retention(RetentionPolicy.SOURCE) public @interface VirtualDisplayFlag {} /** * Virtual display flag: Create a public display. * *
* When this flag is set, the virtual display is public. *
* A public virtual display behaves just like most any other display that is connected * to the system such as an external or wireless display. Applications can open * windows on the display and the system may mirror the contents of other displays * onto it. *
* 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. *
* ** When this flag is not set, the virtual display is private as defined by the * {@link Display#FLAG_PRIVATE} display flag. *
* ** A private virtual display belongs to the application that created it. Only the a owner of a * private virtual display and the apps that are already on that display are 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 or as the activities that are already on that * display. *
* * @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; /** * Virtual display flag: Create a presentation display. * ** 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. *
* ** 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. *
* * @see android.app.Presentation * @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. * ** 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. *
* Creating a secure virtual display requires the CAPTURE_SECURE_VIDEO_OUTPUT permission. * This permission is reserved for use by system components and is not available to * third-party applications. *
* ** 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. *
* * @see Display#FLAG_SECURE * @see #createVirtualDisplay */ public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 1 << 2; /** * Virtual display flag: Only show this display's own content; do not mirror * the content of another display. * ** This flag is used in conjunction with {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}. * Ordinarily public virtual displays will automatically mirror the content of the * default display if they have no windows of their own. When this flag is * specified, the virtual display will only ever show its own content and * will be blanked instead if it has no windows. *
* ** 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. *
* ** 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. *
* * @see #createVirtualDisplay */ public static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 1 << 3; /** * Virtual display flag: Allows content to be mirrored on private displays when no content is * being shown. * ** 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. *
* ** 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. *
* ** Creating an auto-mirroing virtual display requires the CAPTURE_VIDEO_OUTPUT * or 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. *
* * @see #createVirtualDisplay */ public static final int VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR = 1 << 4; /** * Virtual display flag: Allows content to be displayed on private virtual displays when * keyguard is shown but is insecure. * ** This might be used in a case when the content of a virtual display is captured and sent to an * external hardware display that is not visible to the system directly. This flag will allow * the continued display of content while other displays will be covered by a keyguard which * doesn't require providing credentials to unlock. This means that there is either no password * or other authentication method set, or the device is in a trusted state - * {@link android.service.trust.TrustAgentService} has available and active trust agent. *
* This flag can only be applied to private displays as defined by the * {@link Display#FLAG_PRIVATE} display flag. It is mutually exclusive with * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}. If both flags are specified then this flag's behavior * will not be applied. *
* * @see #createVirtualDisplay * @see KeyguardManager#isDeviceSecure() * @see KeyguardManager#isDeviceLocked() * @hide */ // TODO (b/114338689): Remove the flag and use IWindowManager#shouldShowWithInsecureKeyguard // TODO: Update name and documentation and un-hide the flag. Don't change the value before that. public static final int VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 1 << 5; /** * Virtual display flag: Specifies that the virtual display can be associated with a * touchpad device that matches its uniqueId. * * @see #createVirtualDisplay * @hide */ @SuppressLint("UnflaggedApi") // @TestApi without associated feature. @TestApi public static final int VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH = 1 << 6; /** * Virtual display flag: Indicates that the orientation of this display device is coupled to * the orientation of its associated logical display. ** The flag should not be set when the physical display is mounted in a fixed orientation * such as on a desk. Without this flag, display manager will apply a coordinate transformation * such as a scale and translation to letterbox or pillarbox format under the assumption that * the physical orientation of the display is invariant. With this flag set, the content will * rotate to fill in the space of the display, as it does on the internal device display. *
* * @see #createVirtualDisplay * @hide */ @FlaggedApi(android.companion.virtual.flags.Flags.FLAG_VDM_PUBLIC_APIS) @SystemApi public static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 1 << 7; /** * Virtual display flag: Indicates that the contents will be destroyed once * the display is removed. * * Public virtual displays without this flag will move their content to main display * stack once they're removed. Private vistual displays will always destroy their * content on removal even without this flag. * * @see #createVirtualDisplay * @hide */ // TODO (b/114338689): Remove the flag and use WindowManager#REMOVE_CONTENT_MODE_DESTROY public static final int VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL = 1 << 8; /** * Virtual display flag: Indicates that the display should support system decorations. Virtual * displays without this flag shouldn't show home, navigation bar or wallpaper. *This flag doesn't work without {@link #VIRTUAL_DISPLAY_FLAG_TRUSTED}
* * @see #createVirtualDisplay * @see #VIRTUAL_DISPLAY_FLAG_TRUSTED * @hide */ @TestApi public static final int VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 1 << 9; /** * Virtual display flags: Indicates that the display is trusted to show system decorations and * receive inputs without users' touch. * * @see #createVirtualDisplay * @see #VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS * @hide */ @SystemApi public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1 << 10; /** * Virtual display flags: Indicates that the display should not be a part of the default * DisplayGroup and instead be part of a new DisplayGroup. * * @see #createVirtualDisplay * @hide */ public static final int VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP = 1 << 11; /** * Virtual display flags: Indicates that the virtual display should always be unlocked and not * have keyguard displayed on it. Only valid for virtual displays that aren't in the default * display group. * * @see #createVirtualDisplay * @see #VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP * @hide */ public static final int VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED = 1 << 12; /** * Virtual display flags: Indicates that the display should not play sound effects or perform * haptic feedback when the user touches the screen. * * @see #createVirtualDisplay * @hide */ public static final int VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED = 1 << 13; /** * Virtual display flags: Indicates that the display maintains its own focus and touch mode. * * This flag is similar to {@link com.android.internal.R.bool.config_perDisplayFocusEnabled} in * behavior, but only applies to the specific display instead of system-wide to all displays. * * Note: The display must be trusted in order to have its own focus. * * @see #createVirtualDisplay * @see #VIRTUAL_DISPLAY_FLAG_TRUSTED * @hide */ @TestApi public static final int VIRTUAL_DISPLAY_FLAG_OWN_FOCUS = 1 << 14; /** * Virtual display flags: Indicates that the display should not be a part of the default * DisplayGroup and instead be part of a DisplayGroup associated with its virtual device. * * @see #createVirtualDisplay * @hide */ public static final int VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP = 1 << 15; /** * Virtual display flags: Indicates that the display should not become the top focused display * by stealing the top focus from another display. * * @see Display#FLAG_STEAL_TOP_FOCUS_DISABLED * @see #createVirtualDisplay * @see #VIRTUAL_DISPLAY_FLAG_OWN_FOCUS * @hide */ @SystemApi public static final int VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED = 1 << 16; /** @hide */ @IntDef(prefix = {"MATCH_CONTENT_FRAMERATE_"}, value = { MATCH_CONTENT_FRAMERATE_UNKNOWN, MATCH_CONTENT_FRAMERATE_NEVER, MATCH_CONTENT_FRAMERATE_SEAMLESSS_ONLY, MATCH_CONTENT_FRAMERATE_ALWAYS, }) @Retention(RetentionPolicy.SOURCE) public @interface MatchContentFrameRateType {} /** * Match content frame rate user preference is unknown. */ public static final int MATCH_CONTENT_FRAMERATE_UNKNOWN = -1; /** * No mode switching is allowed. */ public static final int MATCH_CONTENT_FRAMERATE_NEVER = 0; /** * Only refresh rate switches without visual interruptions are allowed. */ public static final int MATCH_CONTENT_FRAMERATE_SEAMLESSS_ONLY = 1; /** * Refresh rate switches between all refresh rates are allowed even if they have visual * interruptions for the user. */ public static final int MATCH_CONTENT_FRAMERATE_ALWAYS = 2; /** @hide */ @IntDef(prefix = {"SWITCHING_TYPE_"}, value = { SWITCHING_TYPE_NONE, SWITCHING_TYPE_WITHIN_GROUPS, SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS, SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY, }) @Retention(RetentionPolicy.SOURCE) public @interface SwitchingType {} /** * No display mode switching will happen. * @hide */ @TestApi public static final int SWITCHING_TYPE_NONE = 0; /** * Allow only refresh rate switching between modes in the same configuration group. This way * only switches without visual interruptions for the user will be allowed. * @hide */ @TestApi public static final int SWITCHING_TYPE_WITHIN_GROUPS = 1; /** * Allow refresh rate switching between all refresh rates even if the switch with have visual * interruptions for the user. * @hide */ @TestApi public static final int SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS = 2; /** * Allow render frame rate switches, but not physical modes. * @hide */ @TestApi public static final int SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY = 3; /** * @hide */ @LongDef(flag = true, prefix = {"EVENT_FLAG_"}, value = { EVENT_FLAG_DISPLAY_ADDED, EVENT_FLAG_DISPLAY_CHANGED, EVENT_FLAG_DISPLAY_REMOVED, EVENT_FLAG_DISPLAY_BRIGHTNESS, EVENT_FLAG_HDR_SDR_RATIO_CHANGED, EVENT_FLAG_DISPLAY_CONNECTION_CHANGED, }) @Retention(RetentionPolicy.SOURCE) public @interface EventsMask {} /** * Event type for when a new display is added. * * @see #registerDisplayListener(DisplayListener, Handler, long) * * @hide */ public static final long EVENT_FLAG_DISPLAY_ADDED = 1L << 0; /** * Event type for when a display is removed. * * @see #registerDisplayListener(DisplayListener, Handler, long) * * @hide */ public static final long EVENT_FLAG_DISPLAY_REMOVED = 1L << 1; /** * Event type for when a display is changed. * * @see #registerDisplayListener(DisplayListener, Handler, long) * * @hide */ public static final long EVENT_FLAG_DISPLAY_CHANGED = 1L << 2; /** * Event flag to register for a display's brightness changes. This notification is sent * through the {@link DisplayListener#onDisplayChanged} callback method. New brightness * values can be retrieved via {@link android.view.Display#getBrightnessInfo()}. * * @see #registerDisplayListener(DisplayListener, Handler, long) * * @hide */ public static final long EVENT_FLAG_DISPLAY_BRIGHTNESS = 1L << 3; /** * Event flag to register for a display's hdr/sdr ratio changes. This notification is sent * through the {@link DisplayListener#onDisplayChanged} callback method. New hdr/sdr * values can be retrieved via {@link Display#getHdrSdrRatio()}. * * Requires that {@link Display#isHdrSdrRatioAvailable()} is true. * * @see #registerDisplayListener(DisplayListener, Handler, long) * * @hide */ public static final long EVENT_FLAG_HDR_SDR_RATIO_CHANGED = 1L << 4; /** * Event flag to register for a display's connection changed. * * @hide */ public static final long EVENT_FLAG_DISPLAY_CONNECTION_CHANGED = 1L << 5; /** @hide */ public DisplayManager(Context context) { mContext = context; mGlobal = DisplayManagerGlobal.getInstance(); } /** * Gets information about a logical display. * * The display metrics may be adjusted to provide compatibility * for legacy applications. * * @param displayId The logical display id. * @return The display object, or null if there is no valid display with the given id. */ public Display getDisplay(int displayId) { return getOrCreateDisplay(displayId, false /*assumeValid*/); } /** * Gets all currently valid logical displays. * * @return An array containing all displays. */ public Display[] getDisplays() { return getDisplays(null); } /** * Gets all currently valid logical displays of the specified category. ** When there are multiple displays in a category the returned displays are sorted * of preference. For example, if the requested category is * {@link #DISPLAY_CATEGORY_PRESENTATION} and there are multiple presentation displays * then the displays are sorted so that the first display in the returned array * is the most preferred presentation display. The application may simply * use the first display or allow the user to choose. *
* * @param category The requested display category or null to return all displays. * @return An array containing all displays sorted by order of preference. * * @see #DISPLAY_CATEGORY_PRESENTATION */ public Display[] getDisplays(String category) { boolean includeDisabled = (category != null && category.equals(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)); final int[] displayIds = mGlobal.getDisplayIds(includeDisabled); if (DISPLAY_CATEGORY_PRESENTATION.equals(category)) { return getDisplays(displayIds, DisplayManager::isPresentationDisplay); } else if (DISPLAY_CATEGORY_REAR.equals(category)) { return getDisplays(displayIds, DisplayManager::isRearDisplay); } else if (category == null || DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED.equals(category)) { return getDisplays(displayIds, Objects::nonNull); } return new Display[0]; } private Display[] getDisplays(int[] displayIds, Predicate* Calls to this method nest and must be matched by an equal number of calls to * {@link #stopWifiDisplayScan()}. *
* Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. *
* * @hide */ @UnsupportedAppUsage public void startWifiDisplayScan() { mGlobal.startWifiDisplayScan(); } /** * Stops scanning for available Wifi displays. ** Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. *
* * @hide */ @UnsupportedAppUsage public void stopWifiDisplayScan() { mGlobal.stopWifiDisplayScan(); } /** * Connects to a Wifi display. * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast. ** Automatically remembers the display after a successful connection, if not * already remembered. *
* Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. *
* * @param deviceAddress The MAC address of the device to which we should connect. * @hide */ @UnsupportedAppUsage public void connectWifiDisplay(String deviceAddress) { mGlobal.connectWifiDisplay(deviceAddress); } /** @hide */ @UnsupportedAppUsage public void pauseWifiDisplay() { mGlobal.pauseWifiDisplay(); } /** @hide */ @UnsupportedAppUsage public void resumeWifiDisplay() { mGlobal.resumeWifiDisplay(); } /** * Disconnects from the current Wifi display. * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast. * @hide */ @UnsupportedAppUsage public void disconnectWifiDisplay() { mGlobal.disconnectWifiDisplay(); } /** * Renames a Wifi display. ** The display must already be remembered for this call to succeed. In other words, * we must already have successfully connected to the display at least once and then * not forgotten it. *
* Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. *
* * @param deviceAddress The MAC address of the device to rename. * @param alias The alias name by which to remember the device, or null * or empty if no alias should be used. * @hide */ @UnsupportedAppUsage public void renameWifiDisplay(String deviceAddress, String alias) { mGlobal.renameWifiDisplay(deviceAddress, alias); } /** * Forgets a previously remembered Wifi display. ** Automatically disconnects from the display if currently connected to it. *
* Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. *
* * @param deviceAddress The MAC address of the device to forget. * @hide */ @UnsupportedAppUsage public void forgetWifiDisplay(String deviceAddress) { mGlobal.forgetWifiDisplay(deviceAddress); } /** * Gets the current Wifi display status. * Watch for changes in the status by registering a broadcast receiver for * {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED}. * * @return The current Wifi display status. * @hide */ @UnsupportedAppUsage public WifiDisplayStatus getWifiDisplayStatus() { return mGlobal.getWifiDisplayStatus(); } /** * Enable a connected display that is currently disabled. * @hide */ @RequiresPermission("android.permission.MANAGE_DISPLAYS") public void enableConnectedDisplay(int displayId) { mGlobal.enableConnectedDisplay(displayId); } /** * Disable a connected display that is currently enabled. * @hide */ @RequiresPermission("android.permission.MANAGE_DISPLAYS") public void disableConnectedDisplay(int displayId) { mGlobal.disableConnectedDisplay(displayId); } /** * Set the level of color saturation to apply to the display. * @param level The amount of saturation to apply, between 0 and 1 inclusive. * 0 produces a grayscale image, 1 is normal. * * @hide * @deprecated use {@link ColorDisplayManager#setSaturationLevel(int)} instead. The level passed * as a parameter here will be rounded to the nearest hundredth. */ @SystemApi @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION) public void setSaturationLevel(float level) { if (level < 0f || level > 1f) { throw new IllegalArgumentException("Saturation level must be between 0 and 1"); } final ColorDisplayManager cdm = mContext.getSystemService(ColorDisplayManager.class); cdm.setSaturationLevel(Math.round(level * 100f)); } /** * Sets the HDR types that have been disabled by user. * @param userDisabledTypes the HDR types to disable. * @hide */ @TestApi @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) public void setUserDisabledHdrTypes(@NonNull @HdrType int[] userDisabledTypes) { mGlobal.setUserDisabledHdrTypes(userDisabledTypes); } /** * Sets whether or not the user disabled HDR types are returned from * {@link Display#getHdrCapabilities}. * * @param areUserDisabledHdrTypesAllowed If true, the user-disabled types * are ignored and returned, if the display supports them. If false, the * user-disabled types are taken into consideration and are never returned, * even if the display supports them. * @hide */ @TestApi @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) public void setAreUserDisabledHdrTypesAllowed(boolean areUserDisabledHdrTypesAllowed) { mGlobal.setAreUserDisabledHdrTypesAllowed(areUserDisabledHdrTypesAllowed); } /** * Returns whether or not the user-disabled HDR types are returned from * {@link Display#getHdrCapabilities}. * * @hide */ @TestApi public boolean areUserDisabledHdrTypesAllowed() { return mGlobal.areUserDisabledHdrTypesAllowed(); } /** * Returns the HDR formats disabled by the user. * * @hide */ @TestApi public @NonNull int[] getUserDisabledHdrTypes() { return mGlobal.getUserDisabledHdrTypes(); } /** * Overrides HDR modes for a display device. * * @hide */ @RequiresPermission(Manifest.permission.ACCESS_SURFACE_FLINGER) @TestApi public void overrideHdrTypes(int displayId, @NonNull int[] modes) { mGlobal.overrideHdrTypes(displayId, modes); } /** * Creates a virtual display. * * @see #createVirtualDisplay(String, int, int, int, Surface, int, * VirtualDisplay.Callback, Handler) */ public VirtualDisplay createVirtualDisplay(@NonNull String name, @IntRange(from = 1) int width, @IntRange(from = 1) int height, @IntRange(from = 1) int densityDpi, @Nullable Surface surface, @VirtualDisplayFlag int flags) { return createVirtualDisplay(name, width, height, densityDpi, surface, flags, null, null); } /** * Creates a virtual display. ** The content of a virtual display is rendered to a {@link Surface} provided * by the application. *
* 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. *
* 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. *
* As of {@link android.os.Build.VERSION_CODES#KITKAT_WATCH}, the surface may * be attached or detached dynamically using {@link VirtualDisplay#setSurface}. * Previously, the surface had to be non-null when {@link #createVirtualDisplay} * was called and could not be changed for the lifetime of the display. *
* Detaching the surface that backs a virtual display has a similar effect to * turning off the screen. *
* * @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, or null if there is none initially. * @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_AUTO_MIRROR}. * @param callback Callback 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. * @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 createVirtualDisplay(@NonNull String name, @IntRange(from = 1) int width, @IntRange(from = 1) int height, @IntRange(from = 1) int densityDpi, @Nullable Surface surface, @VirtualDisplayFlag int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) { final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width, height, densityDpi); builder.setFlags(flags); if (surface != null) { builder.setSurface(surface); } return createVirtualDisplay(builder.build(), handler, callback); } /** * Creates a virtual display. * * @see #createVirtualDisplay(VirtualDisplayConfig, Handler, VirtualDisplay.Callback) */ @Nullable public VirtualDisplay createVirtualDisplay(@NonNull VirtualDisplayConfig config) { return createVirtualDisplay(config, /*handler=*/null, /*callback=*/null); } /** * Creates a virtual display. ** The content of a virtual display is rendered to a {@link Surface} provided * by the application. *
* 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. *
* 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. *
* As of {@link android.os.Build.VERSION_CODES#KITKAT_WATCH}, the surface may * be attached or detached dynamically using {@link VirtualDisplay#setSurface}. * Previously, the surface had to be non-null when {@link #createVirtualDisplay} * was called and could not be changed for the lifetime of the display. *
* Detaching the surface that backs a virtual display has a similar effect to * turning off the screen. *
* * @param config The configuration of the virtual display, must be non-null. * @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. * @param callback Callback to call when the state of the {@link VirtualDisplay} changes * @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 flags specified in the configuration. */ @Nullable public VirtualDisplay createVirtualDisplay( @NonNull VirtualDisplayConfig config, @Nullable Handler handler, @Nullable VirtualDisplay.Callback callback) { return createVirtualDisplay(null /* projection */, config, callback, handler); } // TODO : Remove this hidden API after remove all callers. (Refer to MultiDisplayService) /** @hide */ public VirtualDisplay createVirtualDisplay( @Nullable MediaProjection projection, @NonNull String name, @IntRange(from = 1) int width, @IntRange(from = 1) int height, @IntRange(from = 1) int densityDpi, @Nullable Surface surface, @VirtualDisplayFlag int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler, @Nullable String uniqueId) { final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width, height, densityDpi); builder.setFlags(flags); if (uniqueId != null) { builder.setUniqueId(uniqueId); } if (surface != null) { builder.setSurface(surface); } return createVirtualDisplay(projection, builder.build(), callback, handler); } /** @hide */ public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection, @NonNull VirtualDisplayConfig virtualDisplayConfig, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) { Executor executor = null; // If callback is null, the executor will not be used. Avoid creating the handler and the // handler executor. if (callback != null) { executor = new HandlerExecutor( Handler.createAsync(handler != null ? handler.getLooper() : Looper.myLooper())); } return mGlobal.createVirtualDisplay(mContext, projection, virtualDisplayConfig, callback, executor); } /** * Gets the stable device display size, in pixels. * * This should really only be used for things like server-side filtering of available * applications. Most applications don't need the level of stability guaranteed by this and * should instead query either the size of the display they're currently running on or the * size of the default display. * @hide */ @SystemApi public Point getStableDisplaySize() { return mGlobal.getStableDisplaySize(); } /** * Fetch {@link BrightnessChangeEvent}s. * @hide until we make it a system api. */ @SystemApi @RequiresPermission(Manifest.permission.BRIGHTNESS_SLIDER_USAGE) public List* Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission. *
* * @param brightness The brightness value from 0.0f to 1.0f. * * @hide Requires signature permission. */ public void setTemporaryBrightness(int displayId, float brightness) { mGlobal.setTemporaryBrightness(displayId, brightness); } /** * Sets the brightness of the specified display. ** Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} * permission. *
* * @param displayId the logical display id * @param brightness The brightness value from 0.0f to 1.0f. * * @hide */ @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS) public void setBrightness(int displayId, @FloatRange(from = 0f, to = 1f) float brightness) { mGlobal.setBrightness(displayId, brightness); } /** * Gets the brightness of the specified display. ** Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} * permission. *
* * @param displayId The display of which brightness value to get from. * * @hide */ @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS) @FloatRange(from = 0f, to = 1f) public float getBrightness(int displayId) { return mGlobal.getBrightness(displayId); } /** * Temporarily sets the auto brightness adjustment factor. ** Requires the {@link android.Manifest.permission#CONTROL_DISPLAY_BRIGHTNESS} permission. *
* * @param adjustment The adjustment factor from -1.0 to 1.0. * * @hide Requires signature permission. */ public void setTemporaryAutoBrightnessAdjustment(float adjustment) { mGlobal.setTemporaryAutoBrightnessAdjustment(adjustment); } /** * Returns the minimum brightness curve, which guarantess that any brightness curve that dips * below it is rejected by the system. * This prevent auto-brightness from setting the screen so dark as to prevent the user from * resetting or disabling it, and maps lux to the absolute minimum nits that are still readable * in that ambient brightness. * * @return The minimum brightness curve (as lux values and their corresponding nits values). * * @hide */ @SystemApi public Pair* Never: Even if the app requests it, the device will never try to match its output to the * original frame rate of the content. *
* Seamless: If the app requests it, the device will match its output to the original frame * rate of the content, ONLY if the display can transition seamlessly. *
* Always: If the app requests it, the device will match its output to the original * frame rate of the content. This may cause the screen to go blank for a * second when exiting or entering a video playback. *
*/ @MatchContentFrameRateType public int getMatchContentFrameRateUserPreference() { return toMatchContentFrameRateSetting(mGlobal.getRefreshRateSwitchingType()); } @MatchContentFrameRateType private int toMatchContentFrameRateSetting(@SwitchingType int switchingType) { switch (switchingType) { case SWITCHING_TYPE_NONE: return MATCH_CONTENT_FRAMERATE_NEVER; case SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY: case SWITCHING_TYPE_WITHIN_GROUPS: return MATCH_CONTENT_FRAMERATE_SEAMLESSS_ONLY; case SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS: return MATCH_CONTENT_FRAMERATE_ALWAYS; default: Slog.e(TAG, switchingType + " is not a valid value of switching type."); return MATCH_CONTENT_FRAMERATE_UNKNOWN; } } /** * Creates a VirtualDisplay that will mirror the content of displayIdToMirror * @param name The name for the virtual display * @param width The initial width for the virtual display * @param height The initial height for the virtual display * @param displayIdToMirror The displayId that will be mirrored into the virtual display. * @return VirtualDisplay that can be used to update properties. * * @hide */ @RequiresPermission(Manifest.permission.CAPTURE_VIDEO_OUTPUT) @Nullable @SystemApi public static VirtualDisplay createVirtualDisplay(@NonNull String name, int width, int height, int displayIdToMirror, @Nullable Surface surface) { IDisplayManager sDm = IDisplayManager.Stub.asInterface( ServiceManager.getService(Context.DISPLAY_SERVICE)); IPackageManager sPackageManager = IPackageManager.Stub.asInterface( ServiceManager.getService("package")); // Density doesn't matter since this virtual display is only used for mirroring. VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width, height, 1 /* densityDpi */) .setFlags(VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) .setDisplayIdToMirror(displayIdToMirror); if (surface != null) { builder.setSurface(surface); } VirtualDisplayConfig virtualDisplayConfig = builder.build(); String[] packages; try { packages = sPackageManager.getPackagesForUid(Process.myUid()); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } // Just use the first one since it just needs to match the package when looking it up by // calling UID in system server. // The call may come from a rooted device, in that case the requesting uid will be root so // it will not have any package name String packageName = packages == null ? null : packages[0]; DisplayManagerGlobal.VirtualDisplayCallback callbackWrapper = new DisplayManagerGlobal.VirtualDisplayCallback(null, null); int displayId; try { displayId = sDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper, null, packageName); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } return DisplayManagerGlobal.getInstance().createVirtualDisplayWrapper(virtualDisplayConfig, callbackWrapper, displayId); } /** * Allows internal application to restrict display modes to specified modeIds * * @param displayId display that restrictions will be applied to * @param modeIds allowed mode ids * * @hide */ @RequiresPermission("android.permission.RESTRICT_DISPLAY_MODES") public void requestDisplayModes(int displayId, @Nullable int[] modeIds) { if (modeIds != null && modeIds.length == 0) { throw new IllegalArgumentException("requestDisplayModes: modesIds can't be empty"); } mGlobal.requestDisplayModes(displayId, modeIds); } /** * Listens for changes in available display devices. */ public interface DisplayListener { /** * Called whenever a logical display has been added to the system. * Use {@link DisplayManager#getDisplay} to get more information about * the display. * * @param displayId The id of the logical display that was added. */ void onDisplayAdded(int displayId); /** * Called whenever a logical display has been removed from the system. * * @param displayId The id of the logical display that was removed. */ void onDisplayRemoved(int displayId); /** * Called whenever the properties of a logical {@link android.view.Display}, * such as size and density, have changed. * * @param displayId The id of the logical display that changed. */ void onDisplayChanged(int displayId); /** * Called when a display is connected, but not necessarily used. * * A display is always connected before being added. * @hide */ default void onDisplayConnected(int displayId) { } /** * Called when a display is disconnected. * * If a display was added, a display is only disconnected after it has been removed. Note, * however, that the display may have been disconnected by the time the removed event is * received by the listener. * @hide */ default void onDisplayDisconnected(int displayId) { } } /** * Interface for accessing keys belonging to {@link * android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER}. * @hide */ public interface DeviceConfig { /** * Key for refresh rate in the low zone defined by thresholds. * * Note that the name and value don't match because they were added before we had a high * zone to consider. * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.integer#config_defaultZoneBehavior */ String KEY_REFRESH_RATE_IN_LOW_ZONE = "refresh_rate_in_zone"; /** * Key for accessing the low display brightness thresholds for the configured refresh * rate zone. * The value will be a pair of comma separated integers representing the minimum and maximum * thresholds of the zone, respectively, in display backlight units (i.e. [0, 255]). * * Note that the name and value don't match because they were added before we had a high * zone to consider. * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.array#config_brightnessThresholdsOfPeakRefreshRate * @hide */ String KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS = "peak_refresh_rate_brightness_thresholds"; /** * Key for accessing the low ambient brightness thresholds for the configured refresh * rate zone. The value will be a pair of comma separated integers representing the minimum * and maximum thresholds of the zone, respectively, in lux. * * Note that the name and value don't match because they were added before we had a high * zone to consider. * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.array#config_ambientThresholdsOfPeakRefreshRate * @hide */ String KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS = "peak_refresh_rate_ambient_thresholds"; /** * Key for refresh rate in the high zone defined by thresholds. * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.integer#config_fixedRefreshRateInHighZone */ String KEY_REFRESH_RATE_IN_HIGH_ZONE = "refresh_rate_in_high_zone"; /** * Key for accessing the display brightness thresholds for the configured refresh rate zone. * The value will be a pair of comma separated integers representing the minimum and maximum * thresholds of the zone, respectively, in display backlight units (i.e. [0, 255]). * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.array#config_brightnessHighThresholdsOfFixedRefreshRate * @hide */ String KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS = "fixed_refresh_rate_high_display_brightness_thresholds"; /** * Key for accessing the ambient brightness thresholds for the configured refresh rate zone. * The value will be a pair of comma separated integers representing the minimum and maximum * thresholds of the zone, respectively, in lux. * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.array#config_ambientHighThresholdsOfFixedRefreshRate * @hide */ String KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS = "fixed_refresh_rate_high_ambient_brightness_thresholds"; /** * Key for refresh rate when the device is in high brightness mode for sunlight visility. * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.integer#config_defaultRefreshRateInHbmSunlight */ String KEY_REFRESH_RATE_IN_HBM_SUNLIGHT = "refresh_rate_in_hbm_sunlight"; /** * Key for refresh rate when the device is in high brightness mode for HDR. * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.integer#config_defaultRefreshRateInHbmHdr */ String KEY_REFRESH_RATE_IN_HBM_HDR = "refresh_rate_in_hbm_hdr"; /** * Key for default peak refresh rate * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.integer#config_defaultPeakRefreshRate * @hide */ String KEY_PEAK_REFRESH_RATE_DEFAULT = "peak_refresh_rate_default"; // TODO(b/162536543): rename it once it is proved not harmful for users. /** * Key for controlling which packages are explicitly blocked from running at refresh rates * higher than 60hz. An app may be added to this list if they exhibit performance issues at * higher refresh rates. * * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER * @see android.R.array#config_highRefreshRateBlacklist * @hide */ String KEY_HIGH_REFRESH_RATE_BLACKLIST = "high_refresh_rate_blacklist"; /** * Key for the brightness throttling data as a String formatted: *