All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.android.server.display.LogicalDisplay Maven / Gradle / Ivy

/*
 * 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 com.android.server.display;

import static com.android.server.display.DisplayDeviceInfo.TOUCH_NONE;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManagerInternal;
import android.util.ArraySet;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayEventReceiver;
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.SurfaceControl;

import com.android.server.wm.utils.InsetUtils;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Objects;

/**
 * Describes how a logical display is configured.
 * 

* At this time, we only support logical displays that are coupled to a particular * primary display device from which the logical display derives its basic properties * such as its size, density and refresh rate. *

* A logical display may be mirrored onto multiple display devices in addition to its * primary display device. Note that the contents of a logical display may not * always be visible, even on its primary display device, such as in the case where * the primary display device is currently mirroring content from a different * logical display. *

* This object is designed to encapsulate as much of the policy of logical * displays as possible. The idea is to make it easy to implement new kinds of * logical displays mostly by making local changes to this class. *

* Note: The display manager architecture does not actually require logical displays * to be associated with any individual display device. Logical displays and * display devices are orthogonal concepts. Some mapping will exist between * logical displays and display devices but it can be many-to-many and * and some might have no relation at all. *

* Logical displays are guarded by the {@link DisplayManagerService.SyncRoot} lock. *

*/ final class LogicalDisplay { private static final String TAG = "LogicalDisplay"; /** * Phase indicating the logical display's existence is hidden from the rest of the framework. * This can happen if the current layout has specifically requested to keep this display * disabled. */ static final int DISPLAY_PHASE_DISABLED = -1; /** * Phase indicating that the logical display is going through a layout transition. * When in this phase, other systems can choose to special case power-state handling of a * display that might be in a transition. */ static final int DISPLAY_PHASE_LAYOUT_TRANSITION = 0; /** * The display is exposed to the rest of the system and its power state is determined by a * power-request from PowerManager. */ static final int DISPLAY_PHASE_ENABLED = 1; @IntDef(prefix = {"DISPLAY_PHASE" }, value = { DISPLAY_PHASE_DISABLED, DISPLAY_PHASE_LAYOUT_TRANSITION, DISPLAY_PHASE_ENABLED }) @interface DisplayPhase {} // The layer stack we use when the display has been blanked to prevent any // of its content from appearing. private static final int BLANK_LAYER_STACK = -1; private static final DisplayInfo EMPTY_DISPLAY_INFO = new DisplayInfo(); private final DisplayInfo mBaseDisplayInfo = new DisplayInfo(); private final int mDisplayId; private final int mLayerStack; private int mDisplayGroupId = Display.INVALID_DISPLAY_GROUP; /** * Override information set by the window manager. Will be reported instead of {@link #mInfo} * if not null. * @see #setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo) * @see #getDisplayInfoLocked() */ private DisplayInfo mOverrideDisplayInfo; /** * Current display info. Initialized with {@link #mBaseDisplayInfo}. Set to {@code null} if * needs to be updated. * @see #getDisplayInfoLocked() */ private final DisplayInfoProxy mInfo = new DisplayInfoProxy(null); // The display device that this logical display is based on and which // determines the base metrics that it uses. private DisplayDevice mPrimaryDisplayDevice; private DisplayDeviceInfo mPrimaryDisplayDeviceInfo; // True if the logical display has unique content. private boolean mHasContent; private int mRequestedColorMode; private boolean mRequestedMinimalPostProcessing; private int[] mUserDisabledHdrTypes = {}; private DisplayModeDirector.DesiredDisplayModeSpecs mDesiredDisplayModeSpecs = new DisplayModeDirector.DesiredDisplayModeSpecs(); // The display offsets to apply to the display projection. private int mDisplayOffsetX; private int mDisplayOffsetY; /** * The position of the display projection sent to SurfaceFlinger */ private final Point mDisplayPosition = new Point(); /** * {@code true} if display scaling is disabled, or {@code false} if the default scaling mode * is used. * @see #isDisplayScalingDisabled() * @see #setDisplayScalingDisabledLocked(boolean) */ private boolean mDisplayScalingDisabled; // Temporary rectangle used when needed. private final Rect mTempLayerStackRect = new Rect(); private final Rect mTempDisplayRect = new Rect(); /** * Indicates the current phase of the display. Generally, phases supersede any * requests from PowerManager in DPC's calculation for the display state. Only when the * phase is ENABLED does PowerManager's request for the display take effect. */ @DisplayPhase private int mPhase = DISPLAY_PHASE_ENABLED; /** * The UID mappings for refresh rate override */ private DisplayEventReceiver.FrameRateOverride[] mFrameRateOverrides; /** * Holds a set of UIDs that their frame rate override changed and needs to be notified */ private ArraySet mPendingFrameRateOverrideUids; /** * Temporary frame rate override list, used when needed. */ private final SparseArray mTempFrameRateOverride; public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) { mDisplayId = displayId; mLayerStack = layerStack; mPrimaryDisplayDevice = primaryDisplayDevice; mPendingFrameRateOverrideUids = new ArraySet<>(); mTempFrameRateOverride = new SparseArray<>(); } /** * Gets the logical display id of this logical display. * * @return The logical display id. */ public int getDisplayIdLocked() { return mDisplayId; } /** * Gets the primary display device associated with this logical display. * * @return The primary display device. */ public DisplayDevice getPrimaryDisplayDeviceLocked() { return mPrimaryDisplayDevice; } /** * Gets information about the logical display. * * @return The device info, which should be treated as immutable by the caller. * The logical display should allocate a new display info object whenever * the data changes. */ public DisplayInfo getDisplayInfoLocked() { if (mInfo.get() == null) { DisplayInfo info = new DisplayInfo(); info.copyFrom(mBaseDisplayInfo); if (mOverrideDisplayInfo != null) { info.appWidth = mOverrideDisplayInfo.appWidth; info.appHeight = mOverrideDisplayInfo.appHeight; info.smallestNominalAppWidth = mOverrideDisplayInfo.smallestNominalAppWidth; info.smallestNominalAppHeight = mOverrideDisplayInfo.smallestNominalAppHeight; info.largestNominalAppWidth = mOverrideDisplayInfo.largestNominalAppWidth; info.largestNominalAppHeight = mOverrideDisplayInfo.largestNominalAppHeight; info.logicalWidth = mOverrideDisplayInfo.logicalWidth; info.logicalHeight = mOverrideDisplayInfo.logicalHeight; info.physicalXDpi = mOverrideDisplayInfo.physicalXDpi; info.physicalYDpi = mOverrideDisplayInfo.physicalYDpi; info.rotation = mOverrideDisplayInfo.rotation; info.displayCutout = mOverrideDisplayInfo.displayCutout; info.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi; info.roundedCorners = mOverrideDisplayInfo.roundedCorners; } mInfo.set(info); } return mInfo.get(); } /** * Returns the frame rate overrides list */ public DisplayEventReceiver.FrameRateOverride[] getFrameRateOverrides() { return mFrameRateOverrides; } /** * Returns the list of uids that needs to be updated about their frame rate override */ public ArraySet getPendingFrameRateOverrideUids() { return mPendingFrameRateOverrideUids; } /** * Clears the list of uids that needs to be updated about their frame rate override */ public void clearPendingFrameRateOverrideUids() { mPendingFrameRateOverrideUids = new ArraySet<>(); } /** * @see DisplayManagerInternal#getNonOverrideDisplayInfo(int, DisplayInfo) */ void getNonOverrideDisplayInfoLocked(DisplayInfo outInfo) { outInfo.copyFrom(mBaseDisplayInfo); } /** * Sets overridden logical display information from the window manager. * This method can be used to adjust application insets, rotation, and other * properties that the window manager takes care of. * * @param info The logical display information, may be null. */ public boolean setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo info) { if (info != null) { if (mOverrideDisplayInfo == null) { mOverrideDisplayInfo = new DisplayInfo(info); mInfo.set(null); return true; } else if (!mOverrideDisplayInfo.equals(info)) { mOverrideDisplayInfo.copyFrom(info); mInfo.set(null); return true; } } else if (mOverrideDisplayInfo != null) { mOverrideDisplayInfo = null; mInfo.set(null); return true; } return false; } /** * Returns true if the logical display is in a valid state. * This method should be checked after calling {@link #updateLocked} to handle the * case where a logical display should be removed because all of its associated * display devices are gone or if it is otherwise no longer needed. * * @return True if the logical display is still valid. */ public boolean isValidLocked() { return mPrimaryDisplayDevice != null; } /** * Updates the {@link DisplayGroup} to which the logical display belongs. * * @param groupId Identifier for the {@link DisplayGroup}. */ public void updateDisplayGroupIdLocked(int groupId) { if (groupId != mDisplayGroupId) { mDisplayGroupId = groupId; mBaseDisplayInfo.displayGroupId = groupId; mInfo.set(null); } } /** * Updates the state of the logical display based on the available display devices. * The logical display might become invalid if it is attached to a display device * that no longer exists. * * @param deviceRepo Repository of active {@link DisplayDevice}s. */ public void updateLocked(DisplayDeviceRepository deviceRepo) { // Nothing to update if already invalid. if (mPrimaryDisplayDevice == null) { return; } // Check whether logical display has become invalid. if (!deviceRepo.containsLocked(mPrimaryDisplayDevice)) { setPrimaryDisplayDeviceLocked(null); return; } // Bootstrap the logical display using its associated primary physical display. // We might use more elaborate configurations later. It's possible that the // configuration of several physical displays might be used to determine the // logical display that they are sharing. (eg. Adjust size for pixel-perfect // mirroring over HDMI.) DisplayDeviceInfo deviceInfo = mPrimaryDisplayDevice.getDisplayDeviceInfoLocked(); if (!Objects.equals(mPrimaryDisplayDeviceInfo, deviceInfo)) { mBaseDisplayInfo.layerStack = mLayerStack; mBaseDisplayInfo.flags = 0; if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) { mBaseDisplayInfo.flags |= Display.FLAG_SUPPORTS_PROTECTED_BUFFERS; } if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_SECURE) != 0) { mBaseDisplayInfo.flags |= Display.FLAG_SECURE; } if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_PRIVATE) != 0) { mBaseDisplayInfo.flags |= Display.FLAG_PRIVATE; // For private displays by default content is destroyed on removal. mBaseDisplayInfo.removeMode = Display.REMOVE_MODE_DESTROY_CONTENT; } if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_DESTROY_CONTENT_ON_REMOVAL) != 0) { mBaseDisplayInfo.removeMode = Display.REMOVE_MODE_DESTROY_CONTENT; } if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_PRESENTATION) != 0) { mBaseDisplayInfo.flags |= Display.FLAG_PRESENTATION; } if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ROUND) != 0) { mBaseDisplayInfo.flags |= Display.FLAG_ROUND; } if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) { mBaseDisplayInfo.flags |= Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; } if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0) { mBaseDisplayInfo.flags |= Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; } if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_TRUSTED) != 0) { mBaseDisplayInfo.flags |= Display.FLAG_TRUSTED; } if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0) { mBaseDisplayInfo.flags |= Display.FLAG_OWN_DISPLAY_GROUP; } if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED) != 0) { mBaseDisplayInfo.flags |= Display.FLAG_ALWAYS_UNLOCKED; } if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) { mBaseDisplayInfo.flags |= Display.FLAG_TOUCH_FEEDBACK_DISABLED; } Rect maskingInsets = getMaskingInsets(deviceInfo); int maskedWidth = deviceInfo.width - maskingInsets.left - maskingInsets.right; int maskedHeight = deviceInfo.height - maskingInsets.top - maskingInsets.bottom; mBaseDisplayInfo.type = deviceInfo.type; mBaseDisplayInfo.address = deviceInfo.address; mBaseDisplayInfo.deviceProductInfo = deviceInfo.deviceProductInfo; mBaseDisplayInfo.name = deviceInfo.name; mBaseDisplayInfo.uniqueId = deviceInfo.uniqueId; mBaseDisplayInfo.appWidth = maskedWidth; mBaseDisplayInfo.appHeight = maskedHeight; mBaseDisplayInfo.logicalWidth = maskedWidth; mBaseDisplayInfo.logicalHeight = maskedHeight; mBaseDisplayInfo.rotation = Surface.ROTATION_0; mBaseDisplayInfo.modeId = deviceInfo.modeId; mBaseDisplayInfo.defaultModeId = deviceInfo.defaultModeId; mBaseDisplayInfo.supportedModes = Arrays.copyOf( deviceInfo.supportedModes, deviceInfo.supportedModes.length); mBaseDisplayInfo.colorMode = deviceInfo.colorMode; mBaseDisplayInfo.supportedColorModes = Arrays.copyOf( deviceInfo.supportedColorModes, deviceInfo.supportedColorModes.length); mBaseDisplayInfo.hdrCapabilities = deviceInfo.hdrCapabilities; mBaseDisplayInfo.userDisabledHdrTypes = mUserDisabledHdrTypes; mBaseDisplayInfo.minimalPostProcessingSupported = deviceInfo.allmSupported || deviceInfo.gameContentTypeSupported; mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi; mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi; mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi; mBaseDisplayInfo.appVsyncOffsetNanos = deviceInfo.appVsyncOffsetNanos; mBaseDisplayInfo.presentationDeadlineNanos = deviceInfo.presentationDeadlineNanos; mBaseDisplayInfo.state = deviceInfo.state; mBaseDisplayInfo.smallestNominalAppWidth = maskedWidth; mBaseDisplayInfo.smallestNominalAppHeight = maskedHeight; mBaseDisplayInfo.largestNominalAppWidth = maskedWidth; mBaseDisplayInfo.largestNominalAppHeight = maskedHeight; mBaseDisplayInfo.ownerUid = deviceInfo.ownerUid; mBaseDisplayInfo.ownerPackageName = deviceInfo.ownerPackageName; boolean maskCutout = (deviceInfo.flags & DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT) != 0; mBaseDisplayInfo.displayCutout = maskCutout ? null : deviceInfo.displayCutout; mBaseDisplayInfo.displayId = mDisplayId; mBaseDisplayInfo.displayGroupId = mDisplayGroupId; updateFrameRateOverrides(deviceInfo); mBaseDisplayInfo.brightnessMinimum = deviceInfo.brightnessMinimum; mBaseDisplayInfo.brightnessMaximum = deviceInfo.brightnessMaximum; mBaseDisplayInfo.brightnessDefault = deviceInfo.brightnessDefault; mBaseDisplayInfo.roundedCorners = deviceInfo.roundedCorners; mBaseDisplayInfo.installOrientation = deviceInfo.installOrientation; mPrimaryDisplayDeviceInfo = deviceInfo; mInfo.set(null); } } private void updateFrameRateOverrides(DisplayDeviceInfo deviceInfo) { mTempFrameRateOverride.clear(); if (mFrameRateOverrides != null) { for (DisplayEventReceiver.FrameRateOverride frameRateOverride : mFrameRateOverrides) { mTempFrameRateOverride.put(frameRateOverride.uid, frameRateOverride.frameRateHz); } } mFrameRateOverrides = deviceInfo.frameRateOverrides; if (mFrameRateOverrides != null) { for (DisplayEventReceiver.FrameRateOverride frameRateOverride : mFrameRateOverrides) { float refreshRate = mTempFrameRateOverride.get(frameRateOverride.uid, 0f); if (refreshRate == 0 || frameRateOverride.frameRateHz != refreshRate) { mTempFrameRateOverride.put(frameRateOverride.uid, frameRateOverride.frameRateHz); } else { mTempFrameRateOverride.delete(frameRateOverride.uid); } } } for (int i = 0; i < mTempFrameRateOverride.size(); i++) { mPendingFrameRateOverrideUids.add(mTempFrameRateOverride.keyAt(i)); } } /** * Return the insets currently applied to the display. * * Note that the base DisplayInfo already takes these insets into account, so if you want to * find out the true size of the display, you need to add them back to the logical * dimensions. */ public Rect getInsets() { return getMaskingInsets(mPrimaryDisplayDeviceInfo); } /** * Returns insets in ROTATION_0 for areas that are masked. */ private static Rect getMaskingInsets(DisplayDeviceInfo deviceInfo) { boolean maskCutout = (deviceInfo.flags & DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT) != 0; if (maskCutout && deviceInfo.displayCutout != null) { // getSafeInsets is fixed at creation time and cannot change return deviceInfo.displayCutout.getSafeInsets(); } else { return new Rect(); } } /** * Returns the position of the display's projection. * * @return The x, y coordinates of the display. The return object must be treated as immutable. */ Point getDisplayPosition() { // Allocate a new object to avoid a data race. return new Point(mDisplayPosition); } /** * Applies the layer stack and transformation to the given display device * so that it shows the contents of this logical display. * * We know that the given display device is only ever showing the contents of * a single logical display, so this method is expected to blow away all of its * transformation properties to make it happen regardless of what the * display device was previously showing. * * The caller must have an open Surface transaction. * * The display device may not be the primary display device, in the case * where the display is being mirrored. * * @param device The display device to modify. * @param isBlanked True if the device is being blanked. */ public void configureDisplayLocked(SurfaceControl.Transaction t, DisplayDevice device, boolean isBlanked) { // Set the layer stack. device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack); // Also inform whether the device is the same one sent to inputflinger for its layerstack. // TODO(b/188914255): Remove once input can dispatch against device vs layerstack. device.setDisplayFlagsLocked(t, device.getDisplayDeviceInfoLocked().touch != TOUCH_NONE ? SurfaceControl.DISPLAY_RECEIVES_INPUT : 0); // Set the color mode and allowed display mode. if (device == mPrimaryDisplayDevice) { device.setDesiredDisplayModeSpecsLocked(mDesiredDisplayModeSpecs); device.setRequestedColorModeLocked(mRequestedColorMode); } else { // Reset to default for non primary displays device.setDesiredDisplayModeSpecsLocked( new DisplayModeDirector.DesiredDisplayModeSpecs()); device.setRequestedColorModeLocked(0); } device.setAutoLowLatencyModeLocked(mRequestedMinimalPostProcessing); device.setGameContentTypeLocked(mRequestedMinimalPostProcessing); // Only grab the display info now as it may have been changed based on the requests above. final DisplayInfo displayInfo = getDisplayInfoLocked(); final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked(); // Set the viewport. // This is the area of the logical display that we intend to show on the // display device. For now, it is always the full size of the logical display. mTempLayerStackRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight); // Set the orientation. // The orientation specifies how the physical coordinate system of the display // is rotated when the contents of the logical display are rendered. int orientation = Surface.ROTATION_0; if ((displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0) { orientation = displayInfo.rotation; } // Apply the physical rotation of the display device itself. orientation = (orientation + displayDeviceInfo.rotation) % 4; // Set the frame. // The frame specifies the rotated physical coordinates into which the viewport // is mapped. We need to take care to preserve the aspect ratio of the viewport. // Currently we maximize the area to fill the display, but we could try to be // more clever and match resolutions. boolean rotated = (orientation == Surface.ROTATION_90 || orientation == Surface.ROTATION_270); int physWidth = rotated ? displayDeviceInfo.height : displayDeviceInfo.width; int physHeight = rotated ? displayDeviceInfo.width : displayDeviceInfo.height; Rect maskingInsets = getMaskingInsets(displayDeviceInfo); InsetUtils.rotateInsets(maskingInsets, orientation); // Don't consider the masked area as available when calculating the scaling below. physWidth -= maskingInsets.left + maskingInsets.right; physHeight -= maskingInsets.top + maskingInsets.bottom; // Determine whether the width or height is more constrained to be scaled. // physWidth / displayInfo.logicalWidth => letter box // or physHeight / displayInfo.logicalHeight => pillar box // // We avoid a division (and possible floating point imprecision) here by // multiplying the fractions by the product of their denominators before // comparing them. int displayRectWidth, displayRectHeight; if ((displayInfo.flags & Display.FLAG_SCALING_DISABLED) != 0 || mDisplayScalingDisabled) { displayRectWidth = displayInfo.logicalWidth; displayRectHeight = displayInfo.logicalHeight; } else if (physWidth * displayInfo.logicalHeight < physHeight * displayInfo.logicalWidth) { // Letter box. displayRectWidth = physWidth; displayRectHeight = displayInfo.logicalHeight * physWidth / displayInfo.logicalWidth; } else { // Pillar box. displayRectWidth = displayInfo.logicalWidth * physHeight / displayInfo.logicalHeight; displayRectHeight = physHeight; } int displayRectTop = (physHeight - displayRectHeight) / 2; int displayRectLeft = (physWidth - displayRectWidth) / 2; mTempDisplayRect.set(displayRectLeft, displayRectTop, displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight); // Now add back the offset for the masked area. mTempDisplayRect.offset(maskingInsets.left, maskingInsets.top); if (orientation == Surface.ROTATION_0) { mTempDisplayRect.offset(mDisplayOffsetX, mDisplayOffsetY); } else if (orientation == Surface.ROTATION_90) { mTempDisplayRect.offset(mDisplayOffsetY, -mDisplayOffsetX); } else if (orientation == Surface.ROTATION_180) { mTempDisplayRect.offset(-mDisplayOffsetX, -mDisplayOffsetY); } else { // Surface.ROTATION_270 mTempDisplayRect.offset(-mDisplayOffsetY, mDisplayOffsetX); } mDisplayPosition.set(mTempDisplayRect.left, mTempDisplayRect.top); device.setProjectionLocked(t, orientation, mTempLayerStackRect, mTempDisplayRect); } /** * Returns true if the logical display has unique content. *

* If the display has unique content then we will try to ensure that it is * visible on at least its primary display device. Otherwise we will ignore the * logical display and perhaps show mirrored content on the primary display device. *

* * @return True if the display has unique content. */ public boolean hasContentLocked() { return mHasContent; } /** * Sets whether the logical display has unique content. * * @param hasContent True if the display has unique content. */ public void setHasContentLocked(boolean hasContent) { mHasContent = hasContent; } /** * Sets the display configs the system can use. */ public void setDesiredDisplayModeSpecsLocked( DisplayModeDirector.DesiredDisplayModeSpecs specs) { mDesiredDisplayModeSpecs = specs; } /** * Returns the display configs the system can choose. */ public DisplayModeDirector.DesiredDisplayModeSpecs getDesiredDisplayModeSpecsLocked() { return mDesiredDisplayModeSpecs; } /** * Requests the given color mode. */ public void setRequestedColorModeLocked(int colorMode) { mRequestedColorMode = colorMode; } /** * Returns the last requested minimal post processing setting. */ public boolean getRequestedMinimalPostProcessingLocked() { return mRequestedMinimalPostProcessing; } /** * Instructs the connected display to do minimal post processing. This is implemented either * via HDMI 2.1 ALLM or HDMI 1.4 ContentType=Game. * * @param on Whether to set minimal post processing on/off on the connected display. */ public void setRequestedMinimalPostProcessingLocked(boolean on) { mRequestedMinimalPostProcessing = on; } /** Returns the pending requested color mode. */ public int getRequestedColorModeLocked() { return mRequestedColorMode; } /** * Gets the burn-in offset in X. */ public int getDisplayOffsetXLocked() { return mDisplayOffsetX; } /** * Gets the burn-in offset in Y. */ public int getDisplayOffsetYLocked() { return mDisplayOffsetY; } /** * Sets the burn-in offsets. */ public void setDisplayOffsetsLocked(int x, int y) { mDisplayOffsetX = x; mDisplayOffsetY = y; } /** * @return {@code true} if display scaling is disabled, or {@code false} if the default scaling * mode is used. */ public boolean isDisplayScalingDisabled() { return mDisplayScalingDisabled; } /** * Disables scaling for a display. * * @param disableScaling {@code true} to disable scaling, * {@code false} to use the default scaling behavior of the logical display. */ public void setDisplayScalingDisabledLocked(boolean disableScaling) { mDisplayScalingDisabled = disableScaling; } public void setUserDisabledHdrTypes(@NonNull int[] userDisabledHdrTypes) { if (mUserDisabledHdrTypes != userDisabledHdrTypes) { mUserDisabledHdrTypes = userDisabledHdrTypes; mBaseDisplayInfo.userDisabledHdrTypes = userDisabledHdrTypes; mInfo.set(null); } } /** * Swap the underlying {@link DisplayDevice} with the specified LogicalDisplay. * * @param targetDisplay The display with which to swap display-devices. * @return {@code true} if the displays were swapped, {@code false} otherwise. */ public void swapDisplaysLocked(@NonNull LogicalDisplay targetDisplay) { final DisplayDevice oldTargetDevice = targetDisplay.setPrimaryDisplayDeviceLocked(mPrimaryDisplayDevice); setPrimaryDisplayDeviceLocked(oldTargetDevice); } /** * Sets the primary display device to the specified device. * * @param device The new device to set. * @return The previously set display device. */ public DisplayDevice setPrimaryDisplayDeviceLocked(@Nullable DisplayDevice device) { final DisplayDevice old = mPrimaryDisplayDevice; mPrimaryDisplayDevice = device; // Reset all our display info data mPrimaryDisplayDeviceInfo = null; mBaseDisplayInfo.copyFrom(EMPTY_DISPLAY_INFO); mInfo.set(null); return old; } public void setPhase(@DisplayPhase int phase) { mPhase = phase; } /** * Returns the currently set phase for this LogicalDisplay. Phases are used when transitioning * from one device state to another. {@see LogicalDisplayMapper}. */ @DisplayPhase public int getPhase() { return mPhase; } /** * @return {@code true} if the LogicalDisplay is enabled or {@code false} * if disabled indicating that the display should be hidden from the rest of the apps and * framework. */ public boolean isEnabled() { // DISPLAY_PHASE_LAYOUT_TRANSITION is still considered an 'enabled' phase. return mPhase == DISPLAY_PHASE_ENABLED || mPhase == DISPLAY_PHASE_LAYOUT_TRANSITION; } public void dumpLocked(PrintWriter pw) { pw.println("mDisplayId=" + mDisplayId); pw.println("mPhase=" + mPhase); pw.println("mLayerStack=" + mLayerStack); pw.println("mHasContent=" + mHasContent); pw.println("mDesiredDisplayModeSpecs={" + mDesiredDisplayModeSpecs + "}"); pw.println("mRequestedColorMode=" + mRequestedColorMode); pw.println("mDisplayOffset=(" + mDisplayOffsetX + ", " + mDisplayOffsetY + ")"); pw.println("mDisplayScalingDisabled=" + mDisplayScalingDisabled); pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ? mPrimaryDisplayDevice.getNameLocked() : "null")); pw.println("mBaseDisplayInfo=" + mBaseDisplayInfo); pw.println("mOverrideDisplayInfo=" + mOverrideDisplayInfo); pw.println("mRequestedMinimalPostProcessing=" + mRequestedMinimalPostProcessing); pw.println("mFrameRateOverrides=" + Arrays.toString(mFrameRateOverrides)); pw.println("mPendingFrameRateOverrideUids=" + mPendingFrameRateOverrideUids); } @Override public String toString() { StringWriter sw = new StringWriter(); dumpLocked(new PrintWriter(sw)); return sw.toString(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy