994 lines
37 KiB
Java
994 lines
37 KiB
Java
![]() |
/*
|
||
|
* 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.view;
|
||
|
|
||
|
import static android.view.Display.Mode.INVALID_MODE_ID;
|
||
|
import static android.view.DisplayInfoProto.APP_HEIGHT;
|
||
|
import static android.view.DisplayInfoProto.APP_WIDTH;
|
||
|
import static android.view.DisplayInfoProto.CUTOUT;
|
||
|
import static android.view.DisplayInfoProto.FLAGS;
|
||
|
import static android.view.DisplayInfoProto.LOGICAL_HEIGHT;
|
||
|
import static android.view.DisplayInfoProto.LOGICAL_WIDTH;
|
||
|
import static android.view.DisplayInfoProto.NAME;
|
||
|
|
||
|
import android.annotation.NonNull;
|
||
|
import android.annotation.Nullable;
|
||
|
import android.app.WindowConfiguration;
|
||
|
import android.compat.annotation.UnsupportedAppUsage;
|
||
|
import android.content.res.CompatibilityInfo;
|
||
|
import android.content.res.Configuration;
|
||
|
import android.graphics.Rect;
|
||
|
import android.hardware.display.DeviceProductInfo;
|
||
|
import android.os.Build;
|
||
|
import android.os.Parcel;
|
||
|
import android.os.Parcelable;
|
||
|
import android.os.Process;
|
||
|
import android.util.ArraySet;
|
||
|
import android.util.DisplayMetrics;
|
||
|
import android.util.SparseArray;
|
||
|
import android.util.proto.ProtoOutputStream;
|
||
|
|
||
|
import com.android.internal.display.BrightnessSynchronizer;
|
||
|
|
||
|
import java.util.Arrays;
|
||
|
import java.util.Objects;
|
||
|
|
||
|
/**
|
||
|
* Describes the characteristics of a particular logical display.
|
||
|
* @hide
|
||
|
*/
|
||
|
@android.ravenwood.annotation.RavenwoodKeepWholeClass
|
||
|
public final class DisplayInfo implements Parcelable {
|
||
|
/**
|
||
|
* The surface flinger layer stack associated with this logical display.
|
||
|
*/
|
||
|
public int layerStack;
|
||
|
|
||
|
/**
|
||
|
* Display flags.
|
||
|
*/
|
||
|
public int flags;
|
||
|
|
||
|
/**
|
||
|
* Display type.
|
||
|
*/
|
||
|
public int type;
|
||
|
|
||
|
/**
|
||
|
* Logical display identifier.
|
||
|
*/
|
||
|
public int displayId;
|
||
|
|
||
|
/**
|
||
|
* Display Group identifier.
|
||
|
*/
|
||
|
public int displayGroupId;
|
||
|
|
||
|
/**
|
||
|
* Display address, or null if none.
|
||
|
* Interpretation varies by display type.
|
||
|
*/
|
||
|
public DisplayAddress address;
|
||
|
|
||
|
/**
|
||
|
* Product-specific information about the display or the directly connected device on the
|
||
|
* display chain. For example, if the display is transitively connected, this field may contain
|
||
|
* product information about the intermediate device.
|
||
|
*/
|
||
|
public DeviceProductInfo deviceProductInfo;
|
||
|
|
||
|
/**
|
||
|
* The human-readable name of the display.
|
||
|
*/
|
||
|
public String name;
|
||
|
|
||
|
/**
|
||
|
* Unique identifier for the display. Shouldn't be displayed to the user.
|
||
|
*/
|
||
|
public String uniqueId;
|
||
|
|
||
|
/**
|
||
|
* The width of the portion of the display that is available to applications, in pixels.
|
||
|
* Represents the size of the display minus any system decorations.
|
||
|
*/
|
||
|
public int appWidth;
|
||
|
|
||
|
/**
|
||
|
* The height of the portion of the display that is available to applications, in pixels.
|
||
|
* Represents the size of the display minus any system decorations.
|
||
|
*/
|
||
|
public int appHeight;
|
||
|
|
||
|
/**
|
||
|
* The smallest value of {@link #appWidth} that an application is likely to encounter,
|
||
|
* in pixels, excepting cases where the width may be even smaller due to the presence
|
||
|
* of a soft keyboard, for example.
|
||
|
*/
|
||
|
public int smallestNominalAppWidth;
|
||
|
|
||
|
/**
|
||
|
* The smallest value of {@link #appHeight} that an application is likely to encounter,
|
||
|
* in pixels, excepting cases where the height may be even smaller due to the presence
|
||
|
* of a soft keyboard, for example.
|
||
|
*/
|
||
|
public int smallestNominalAppHeight;
|
||
|
|
||
|
/**
|
||
|
* The largest value of {@link #appWidth} that an application is likely to encounter,
|
||
|
* in pixels, excepting cases where the width may be even larger due to system decorations
|
||
|
* such as the status bar being hidden, for example.
|
||
|
*/
|
||
|
public int largestNominalAppWidth;
|
||
|
|
||
|
/**
|
||
|
* The largest value of {@link #appHeight} that an application is likely to encounter,
|
||
|
* in pixels, excepting cases where the height may be even larger due to system decorations
|
||
|
* such as the status bar being hidden, for example.
|
||
|
*/
|
||
|
public int largestNominalAppHeight;
|
||
|
|
||
|
/**
|
||
|
* The logical width of the display, in pixels.
|
||
|
* Represents the usable size of the display which may be smaller than the
|
||
|
* physical size when the system is emulating a smaller display.
|
||
|
*/
|
||
|
@UnsupportedAppUsage
|
||
|
public int logicalWidth;
|
||
|
|
||
|
/**
|
||
|
* The logical height of the display, in pixels.
|
||
|
* Represents the usable size of the display which may be smaller than the
|
||
|
* physical size when the system is emulating a smaller display.
|
||
|
*/
|
||
|
@UnsupportedAppUsage
|
||
|
public int logicalHeight;
|
||
|
|
||
|
/**
|
||
|
* The {@link DisplayCutout} if present, otherwise {@code null}.
|
||
|
*
|
||
|
* @hide
|
||
|
*/
|
||
|
// Remark on @UnsupportedAppUsage: Display.getCutout should be used instead
|
||
|
@Nullable
|
||
|
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
|
||
|
public DisplayCutout displayCutout;
|
||
|
|
||
|
/**
|
||
|
* The rotation of the display relative to its natural orientation.
|
||
|
* May be one of {@link android.view.Surface#ROTATION_0},
|
||
|
* {@link android.view.Surface#ROTATION_90}, {@link android.view.Surface#ROTATION_180},
|
||
|
* {@link android.view.Surface#ROTATION_270}.
|
||
|
* <p>
|
||
|
* The value of this field is indeterminate if the logical display is presented on
|
||
|
* more than one physical display.
|
||
|
* </p>
|
||
|
*/
|
||
|
@Surface.Rotation
|
||
|
@UnsupportedAppUsage
|
||
|
public int rotation;
|
||
|
|
||
|
/**
|
||
|
* The active display mode.
|
||
|
*/
|
||
|
public int modeId;
|
||
|
|
||
|
/**
|
||
|
* The render frame rate this display is scheduled at, which is a divisor of the active mode
|
||
|
* refresh rate. This is the rate SurfaceFlinger would consume frames and would be observable
|
||
|
* by applications via the cadence of {@link android.view.Choreographer} callbacks and
|
||
|
* by backpressure when submitting buffers as fast as possible.
|
||
|
* Apps can call {@link android.view.Display#getRefreshRate} to query this value.
|
||
|
*
|
||
|
*/
|
||
|
public float renderFrameRate;
|
||
|
|
||
|
/**
|
||
|
* The default display mode.
|
||
|
*/
|
||
|
public int defaultModeId;
|
||
|
|
||
|
/**
|
||
|
* The user preferred display mode.
|
||
|
*/
|
||
|
public int userPreferredModeId = INVALID_MODE_ID;
|
||
|
|
||
|
/**
|
||
|
* The supported modes of this display.
|
||
|
*/
|
||
|
public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY;
|
||
|
|
||
|
/** The active color mode. */
|
||
|
public int colorMode;
|
||
|
|
||
|
/** The list of supported color modes */
|
||
|
public int[] supportedColorModes = { Display.COLOR_MODE_DEFAULT };
|
||
|
|
||
|
/** The display's HDR capabilities */
|
||
|
public Display.HdrCapabilities hdrCapabilities;
|
||
|
|
||
|
/** The formats disabled by user **/
|
||
|
public int[] userDisabledHdrTypes = {};
|
||
|
|
||
|
/**
|
||
|
* Indicates whether the display can be switched into a mode with minimal post
|
||
|
* processing.
|
||
|
*
|
||
|
* @see android.view.Display#isMinimalPostProcessingSupported
|
||
|
*/
|
||
|
public boolean minimalPostProcessingSupported;
|
||
|
|
||
|
/**
|
||
|
* The logical display density which is the basis for density-independent
|
||
|
* pixels.
|
||
|
*/
|
||
|
public int logicalDensityDpi;
|
||
|
|
||
|
/**
|
||
|
* The exact physical pixels per inch of the screen in the X dimension.
|
||
|
* <p>
|
||
|
* The value of this field is indeterminate if the logical display is presented on
|
||
|
* more than one physical display.
|
||
|
* </p>
|
||
|
*/
|
||
|
public float physicalXDpi;
|
||
|
|
||
|
/**
|
||
|
* The exact physical pixels per inch of the screen in the Y dimension.
|
||
|
* <p>
|
||
|
* The value of this field is indeterminate if the logical display is presented on
|
||
|
* more than one physical display.
|
||
|
* </p>
|
||
|
*/
|
||
|
public float physicalYDpi;
|
||
|
|
||
|
/**
|
||
|
* This is a positive value indicating the phase offset of the VSYNC events provided by
|
||
|
* Choreographer relative to the display refresh. For example, if Choreographer reports
|
||
|
* that the refresh occurred at time N, it actually occurred at (N - appVsyncOffsetNanos).
|
||
|
*/
|
||
|
public long appVsyncOffsetNanos;
|
||
|
|
||
|
/**
|
||
|
* This is how far in advance a buffer must be queued for presentation at
|
||
|
* a given time. If you want a buffer to appear on the screen at
|
||
|
* time N, you must submit the buffer before (N - bufferDeadlineNanos).
|
||
|
*/
|
||
|
public long presentationDeadlineNanos;
|
||
|
|
||
|
/**
|
||
|
* The state of the display, such as {@link android.view.Display#STATE_ON}.
|
||
|
*/
|
||
|
public int state;
|
||
|
|
||
|
/**
|
||
|
* The current committed state of the display. For example, this becomes
|
||
|
* {@link android.view.Display#STATE_ON} only after the power state ON is fully committed.
|
||
|
*/
|
||
|
public int committedState;
|
||
|
|
||
|
/**
|
||
|
* The UID of the application that owns this display, or zero if it is owned by the system.
|
||
|
* <p>
|
||
|
* If the display is private, then only the owner can use it.
|
||
|
* </p>
|
||
|
*/
|
||
|
public int ownerUid;
|
||
|
|
||
|
/**
|
||
|
* The package name of the application that owns this display, or null if it is
|
||
|
* owned by the system.
|
||
|
* <p>
|
||
|
* If the display is private, then only the owner can use it.
|
||
|
* </p>
|
||
|
*/
|
||
|
public String ownerPackageName;
|
||
|
|
||
|
/**
|
||
|
* The refresh rate override for this app. 0 means no override.
|
||
|
*/
|
||
|
public float refreshRateOverride;
|
||
|
|
||
|
/**
|
||
|
* @hide
|
||
|
* Get current remove mode of the display - what actions should be performed with the display's
|
||
|
* content when it is removed.
|
||
|
*
|
||
|
* @see Display#getRemoveMode()
|
||
|
*/
|
||
|
// TODO (b/114338689): Remove the flag and use IWindowManager#getRemoveContentMode
|
||
|
public int removeMode = Display.REMOVE_MODE_MOVE_CONTENT_TO_PRIMARY;
|
||
|
|
||
|
/**
|
||
|
* @hide
|
||
|
* The current minimum brightness constraint of the display. Value between 0.0 and 1.0,
|
||
|
* derived from the config constraints of the display device of this logical display.
|
||
|
*/
|
||
|
public float brightnessMinimum;
|
||
|
|
||
|
/**
|
||
|
* @hide
|
||
|
* The current maximum brightness constraint of the display. Value between 0.0 and 1.0,
|
||
|
* derived from the config constraints of the display device of this logical display.
|
||
|
*/
|
||
|
public float brightnessMaximum;
|
||
|
|
||
|
/**
|
||
|
* @hide
|
||
|
* The current default brightness of the display. Value between 0.0 and 1.0,
|
||
|
* derived from the configuration of the display device of this logical display.
|
||
|
*/
|
||
|
public float brightnessDefault;
|
||
|
|
||
|
/**
|
||
|
* The {@link RoundedCorners} if present, otherwise {@code null}.
|
||
|
*/
|
||
|
@Nullable
|
||
|
public RoundedCorners roundedCorners;
|
||
|
|
||
|
/**
|
||
|
* Install orientation of the display relative to its natural orientation.
|
||
|
*/
|
||
|
@Surface.Rotation
|
||
|
public int installOrientation;
|
||
|
|
||
|
@Nullable
|
||
|
public DisplayShape displayShape;
|
||
|
|
||
|
/**
|
||
|
* Refresh rate range limitation based on the current device layout
|
||
|
*/
|
||
|
@Nullable
|
||
|
public SurfaceControl.RefreshRateRange layoutLimitedRefreshRate;
|
||
|
|
||
|
/**
|
||
|
* The current hdr/sdr ratio for the display. If the display doesn't support hdr/sdr ratio
|
||
|
* queries then this is NaN
|
||
|
*/
|
||
|
public float hdrSdrRatio = Float.NaN;
|
||
|
|
||
|
/**
|
||
|
* RefreshRateRange limitation for @Temperature.ThrottlingStatus
|
||
|
*/
|
||
|
@NonNull
|
||
|
public SparseArray<SurfaceControl.RefreshRateRange> thermalRefreshRateThrottling =
|
||
|
new SparseArray<>();
|
||
|
|
||
|
/**
|
||
|
* The ID of the brightness throttling data that should be used. This can change e.g. in
|
||
|
* concurrent displays mode in which a stricter brightness throttling policy might need to be
|
||
|
* used.
|
||
|
*/
|
||
|
@Nullable
|
||
|
public String thermalBrightnessThrottlingDataId;
|
||
|
|
||
|
public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
|
||
|
@Override
|
||
|
public DisplayInfo createFromParcel(Parcel source) {
|
||
|
return new DisplayInfo(source);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public DisplayInfo[] newArray(int size) {
|
||
|
return new DisplayInfo[size];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769467)
|
||
|
public DisplayInfo() {
|
||
|
}
|
||
|
|
||
|
public DisplayInfo(DisplayInfo other) {
|
||
|
copyFrom(other);
|
||
|
}
|
||
|
|
||
|
private DisplayInfo(Parcel source) {
|
||
|
readFromParcel(source);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean equals(@Nullable Object o) {
|
||
|
return o instanceof DisplayInfo && equals((DisplayInfo)o);
|
||
|
}
|
||
|
|
||
|
public boolean equals(DisplayInfo other) {
|
||
|
return other != null
|
||
|
&& layerStack == other.layerStack
|
||
|
&& flags == other.flags
|
||
|
&& type == other.type
|
||
|
&& displayId == other.displayId
|
||
|
&& displayGroupId == other.displayGroupId
|
||
|
&& Objects.equals(address, other.address)
|
||
|
&& Objects.equals(deviceProductInfo, other.deviceProductInfo)
|
||
|
&& Objects.equals(uniqueId, other.uniqueId)
|
||
|
&& appWidth == other.appWidth
|
||
|
&& appHeight == other.appHeight
|
||
|
&& smallestNominalAppWidth == other.smallestNominalAppWidth
|
||
|
&& smallestNominalAppHeight == other.smallestNominalAppHeight
|
||
|
&& largestNominalAppWidth == other.largestNominalAppWidth
|
||
|
&& largestNominalAppHeight == other.largestNominalAppHeight
|
||
|
&& logicalWidth == other.logicalWidth
|
||
|
&& logicalHeight == other.logicalHeight
|
||
|
&& Objects.equals(displayCutout, other.displayCutout)
|
||
|
&& rotation == other.rotation
|
||
|
&& modeId == other.modeId
|
||
|
&& renderFrameRate == other.renderFrameRate
|
||
|
&& defaultModeId == other.defaultModeId
|
||
|
&& userPreferredModeId == other.userPreferredModeId
|
||
|
&& Arrays.equals(supportedModes, other.supportedModes)
|
||
|
&& colorMode == other.colorMode
|
||
|
&& Arrays.equals(supportedColorModes, other.supportedColorModes)
|
||
|
&& Objects.equals(hdrCapabilities, other.hdrCapabilities)
|
||
|
&& Arrays.equals(userDisabledHdrTypes, other.userDisabledHdrTypes)
|
||
|
&& minimalPostProcessingSupported == other.minimalPostProcessingSupported
|
||
|
&& logicalDensityDpi == other.logicalDensityDpi
|
||
|
&& physicalXDpi == other.physicalXDpi
|
||
|
&& physicalYDpi == other.physicalYDpi
|
||
|
&& appVsyncOffsetNanos == other.appVsyncOffsetNanos
|
||
|
&& presentationDeadlineNanos == other.presentationDeadlineNanos
|
||
|
&& state == other.state
|
||
|
&& committedState == other.committedState
|
||
|
&& ownerUid == other.ownerUid
|
||
|
&& Objects.equals(ownerPackageName, other.ownerPackageName)
|
||
|
&& removeMode == other.removeMode
|
||
|
&& getRefreshRate() == other.getRefreshRate()
|
||
|
&& brightnessMinimum == other.brightnessMinimum
|
||
|
&& brightnessMaximum == other.brightnessMaximum
|
||
|
&& brightnessDefault == other.brightnessDefault
|
||
|
&& Objects.equals(roundedCorners, other.roundedCorners)
|
||
|
&& installOrientation == other.installOrientation
|
||
|
&& Objects.equals(displayShape, other.displayShape)
|
||
|
&& Objects.equals(layoutLimitedRefreshRate, other.layoutLimitedRefreshRate)
|
||
|
&& BrightnessSynchronizer.floatEquals(hdrSdrRatio, other.hdrSdrRatio)
|
||
|
&& thermalRefreshRateThrottling.contentEquals(other.thermalRefreshRateThrottling)
|
||
|
&& Objects.equals(
|
||
|
thermalBrightnessThrottlingDataId, other.thermalBrightnessThrottlingDataId);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int hashCode() {
|
||
|
return 0; // don't care
|
||
|
}
|
||
|
|
||
|
public void copyFrom(DisplayInfo other) {
|
||
|
layerStack = other.layerStack;
|
||
|
flags = other.flags;
|
||
|
type = other.type;
|
||
|
displayId = other.displayId;
|
||
|
displayGroupId = other.displayGroupId;
|
||
|
address = other.address;
|
||
|
deviceProductInfo = other.deviceProductInfo;
|
||
|
name = other.name;
|
||
|
uniqueId = other.uniqueId;
|
||
|
appWidth = other.appWidth;
|
||
|
appHeight = other.appHeight;
|
||
|
smallestNominalAppWidth = other.smallestNominalAppWidth;
|
||
|
smallestNominalAppHeight = other.smallestNominalAppHeight;
|
||
|
largestNominalAppWidth = other.largestNominalAppWidth;
|
||
|
largestNominalAppHeight = other.largestNominalAppHeight;
|
||
|
logicalWidth = other.logicalWidth;
|
||
|
logicalHeight = other.logicalHeight;
|
||
|
displayCutout = other.displayCutout;
|
||
|
rotation = other.rotation;
|
||
|
modeId = other.modeId;
|
||
|
renderFrameRate = other.renderFrameRate;
|
||
|
defaultModeId = other.defaultModeId;
|
||
|
userPreferredModeId = other.userPreferredModeId;
|
||
|
supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length);
|
||
|
colorMode = other.colorMode;
|
||
|
supportedColorModes = Arrays.copyOf(
|
||
|
other.supportedColorModes, other.supportedColorModes.length);
|
||
|
hdrCapabilities = other.hdrCapabilities;
|
||
|
userDisabledHdrTypes = other.userDisabledHdrTypes;
|
||
|
minimalPostProcessingSupported = other.minimalPostProcessingSupported;
|
||
|
logicalDensityDpi = other.logicalDensityDpi;
|
||
|
physicalXDpi = other.physicalXDpi;
|
||
|
physicalYDpi = other.physicalYDpi;
|
||
|
appVsyncOffsetNanos = other.appVsyncOffsetNanos;
|
||
|
presentationDeadlineNanos = other.presentationDeadlineNanos;
|
||
|
state = other.state;
|
||
|
committedState = other.committedState;
|
||
|
ownerUid = other.ownerUid;
|
||
|
ownerPackageName = other.ownerPackageName;
|
||
|
removeMode = other.removeMode;
|
||
|
refreshRateOverride = other.refreshRateOverride;
|
||
|
brightnessMinimum = other.brightnessMinimum;
|
||
|
brightnessMaximum = other.brightnessMaximum;
|
||
|
brightnessDefault = other.brightnessDefault;
|
||
|
roundedCorners = other.roundedCorners;
|
||
|
installOrientation = other.installOrientation;
|
||
|
displayShape = other.displayShape;
|
||
|
layoutLimitedRefreshRate = other.layoutLimitedRefreshRate;
|
||
|
hdrSdrRatio = other.hdrSdrRatio;
|
||
|
thermalRefreshRateThrottling = other.thermalRefreshRateThrottling;
|
||
|
thermalBrightnessThrottlingDataId = other.thermalBrightnessThrottlingDataId;
|
||
|
}
|
||
|
|
||
|
public void readFromParcel(Parcel source) {
|
||
|
layerStack = source.readInt();
|
||
|
flags = source.readInt();
|
||
|
type = source.readInt();
|
||
|
displayId = source.readInt();
|
||
|
displayGroupId = source.readInt();
|
||
|
address = source.readParcelable(null, android.view.DisplayAddress.class);
|
||
|
deviceProductInfo = source.readParcelable(null, android.hardware.display.DeviceProductInfo.class);
|
||
|
name = source.readString8();
|
||
|
appWidth = source.readInt();
|
||
|
appHeight = source.readInt();
|
||
|
smallestNominalAppWidth = source.readInt();
|
||
|
smallestNominalAppHeight = source.readInt();
|
||
|
largestNominalAppWidth = source.readInt();
|
||
|
largestNominalAppHeight = source.readInt();
|
||
|
logicalWidth = source.readInt();
|
||
|
logicalHeight = source.readInt();
|
||
|
displayCutout = DisplayCutout.ParcelableWrapper.readCutoutFromParcel(source);
|
||
|
rotation = source.readInt();
|
||
|
modeId = source.readInt();
|
||
|
renderFrameRate = source.readFloat();
|
||
|
defaultModeId = source.readInt();
|
||
|
userPreferredModeId = source.readInt();
|
||
|
int nModes = source.readInt();
|
||
|
supportedModes = new Display.Mode[nModes];
|
||
|
for (int i = 0; i < nModes; i++) {
|
||
|
supportedModes[i] = Display.Mode.CREATOR.createFromParcel(source);
|
||
|
}
|
||
|
colorMode = source.readInt();
|
||
|
int nColorModes = source.readInt();
|
||
|
supportedColorModes = new int[nColorModes];
|
||
|
for (int i = 0; i < nColorModes; i++) {
|
||
|
supportedColorModes[i] = source.readInt();
|
||
|
}
|
||
|
hdrCapabilities = source.readParcelable(null, android.view.Display.HdrCapabilities.class);
|
||
|
minimalPostProcessingSupported = source.readBoolean();
|
||
|
logicalDensityDpi = source.readInt();
|
||
|
physicalXDpi = source.readFloat();
|
||
|
physicalYDpi = source.readFloat();
|
||
|
appVsyncOffsetNanos = source.readLong();
|
||
|
presentationDeadlineNanos = source.readLong();
|
||
|
state = source.readInt();
|
||
|
committedState = source.readInt();
|
||
|
ownerUid = source.readInt();
|
||
|
ownerPackageName = source.readString8();
|
||
|
uniqueId = source.readString8();
|
||
|
removeMode = source.readInt();
|
||
|
refreshRateOverride = source.readFloat();
|
||
|
brightnessMinimum = source.readFloat();
|
||
|
brightnessMaximum = source.readFloat();
|
||
|
brightnessDefault = source.readFloat();
|
||
|
roundedCorners = source.readTypedObject(RoundedCorners.CREATOR);
|
||
|
int numUserDisabledFormats = source.readInt();
|
||
|
userDisabledHdrTypes = new int[numUserDisabledFormats];
|
||
|
for (int i = 0; i < numUserDisabledFormats; i++) {
|
||
|
userDisabledHdrTypes[i] = source.readInt();
|
||
|
}
|
||
|
installOrientation = source.readInt();
|
||
|
displayShape = source.readTypedObject(DisplayShape.CREATOR);
|
||
|
layoutLimitedRefreshRate = source.readTypedObject(SurfaceControl.RefreshRateRange.CREATOR);
|
||
|
hdrSdrRatio = source.readFloat();
|
||
|
thermalRefreshRateThrottling = source.readSparseArray(null,
|
||
|
SurfaceControl.RefreshRateRange.class);
|
||
|
thermalBrightnessThrottlingDataId = source.readString8();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void writeToParcel(Parcel dest, int flags) {
|
||
|
dest.writeInt(layerStack);
|
||
|
dest.writeInt(this.flags);
|
||
|
dest.writeInt(type);
|
||
|
dest.writeInt(displayId);
|
||
|
dest.writeInt(displayGroupId);
|
||
|
dest.writeParcelable(address, flags);
|
||
|
dest.writeParcelable(deviceProductInfo, flags);
|
||
|
dest.writeString8(name);
|
||
|
dest.writeInt(appWidth);
|
||
|
dest.writeInt(appHeight);
|
||
|
dest.writeInt(smallestNominalAppWidth);
|
||
|
dest.writeInt(smallestNominalAppHeight);
|
||
|
dest.writeInt(largestNominalAppWidth);
|
||
|
dest.writeInt(largestNominalAppHeight);
|
||
|
dest.writeInt(logicalWidth);
|
||
|
dest.writeInt(logicalHeight);
|
||
|
DisplayCutout.ParcelableWrapper.writeCutoutToParcel(displayCutout, dest, flags);
|
||
|
dest.writeInt(rotation);
|
||
|
dest.writeInt(modeId);
|
||
|
dest.writeFloat(renderFrameRate);
|
||
|
dest.writeInt(defaultModeId);
|
||
|
dest.writeInt(userPreferredModeId);
|
||
|
dest.writeInt(supportedModes.length);
|
||
|
for (int i = 0; i < supportedModes.length; i++) {
|
||
|
supportedModes[i].writeToParcel(dest, flags);
|
||
|
}
|
||
|
dest.writeInt(colorMode);
|
||
|
dest.writeInt(supportedColorModes.length);
|
||
|
for (int i = 0; i < supportedColorModes.length; i++) {
|
||
|
dest.writeInt(supportedColorModes[i]);
|
||
|
}
|
||
|
dest.writeParcelable(hdrCapabilities, flags);
|
||
|
dest.writeBoolean(minimalPostProcessingSupported);
|
||
|
dest.writeInt(logicalDensityDpi);
|
||
|
dest.writeFloat(physicalXDpi);
|
||
|
dest.writeFloat(physicalYDpi);
|
||
|
dest.writeLong(appVsyncOffsetNanos);
|
||
|
dest.writeLong(presentationDeadlineNanos);
|
||
|
dest.writeInt(state);
|
||
|
dest.writeInt(committedState);
|
||
|
dest.writeInt(ownerUid);
|
||
|
dest.writeString8(ownerPackageName);
|
||
|
dest.writeString8(uniqueId);
|
||
|
dest.writeInt(removeMode);
|
||
|
dest.writeFloat(refreshRateOverride);
|
||
|
dest.writeFloat(brightnessMinimum);
|
||
|
dest.writeFloat(brightnessMaximum);
|
||
|
dest.writeFloat(brightnessDefault);
|
||
|
dest.writeTypedObject(roundedCorners, flags);
|
||
|
dest.writeInt(userDisabledHdrTypes.length);
|
||
|
for (int i = 0; i < userDisabledHdrTypes.length; i++) {
|
||
|
dest.writeInt(userDisabledHdrTypes[i]);
|
||
|
}
|
||
|
dest.writeInt(installOrientation);
|
||
|
dest.writeTypedObject(displayShape, flags);
|
||
|
dest.writeTypedObject(layoutLimitedRefreshRate, flags);
|
||
|
dest.writeFloat(hdrSdrRatio);
|
||
|
dest.writeSparseArray(thermalRefreshRateThrottling);
|
||
|
dest.writeString8(thermalBrightnessThrottlingDataId);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int describeContents() {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the refresh rate the application would experience.
|
||
|
*/
|
||
|
public float getRefreshRate() {
|
||
|
if (refreshRateOverride > 0) {
|
||
|
return refreshRateOverride;
|
||
|
}
|
||
|
if (supportedModes.length == 0) {
|
||
|
return 0;
|
||
|
}
|
||
|
return getMode().getRefreshRate();
|
||
|
}
|
||
|
|
||
|
public Display.Mode getMode() {
|
||
|
return findMode(modeId);
|
||
|
}
|
||
|
|
||
|
public Display.Mode getDefaultMode() {
|
||
|
return findMode(defaultModeId);
|
||
|
}
|
||
|
|
||
|
private Display.Mode findMode(int id) {
|
||
|
for (int i = 0; i < supportedModes.length; i++) {
|
||
|
if (supportedModes[i].getModeId() == id) {
|
||
|
return supportedModes[i];
|
||
|
}
|
||
|
}
|
||
|
throw new IllegalStateException(
|
||
|
"Unable to locate mode id=" + id + ",supportedModes=" + Arrays.toString(
|
||
|
supportedModes));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the id of the "default" mode with the given refresh rate, or {@code 0} if no suitable
|
||
|
* mode could be found.
|
||
|
*/
|
||
|
@Nullable
|
||
|
public Display.Mode findDefaultModeByRefreshRate(float refreshRate) {
|
||
|
Display.Mode[] modes = supportedModes;
|
||
|
Display.Mode defaultMode = getDefaultMode();
|
||
|
for (int i = 0; i < modes.length; i++) {
|
||
|
if (modes[i].matches(
|
||
|
defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), refreshRate)) {
|
||
|
return modes[i];
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the list of supported refresh rates in the default mode.
|
||
|
*/
|
||
|
public float[] getDefaultRefreshRates() {
|
||
|
Display.Mode[] modes = supportedModes;
|
||
|
ArraySet<Float> rates = new ArraySet<>();
|
||
|
Display.Mode defaultMode = getDefaultMode();
|
||
|
for (int i = 0; i < modes.length; i++) {
|
||
|
Display.Mode mode = modes[i];
|
||
|
if (mode.getPhysicalWidth() == defaultMode.getPhysicalWidth()
|
||
|
&& mode.getPhysicalHeight() == defaultMode.getPhysicalHeight()) {
|
||
|
rates.add(mode.getRefreshRate());
|
||
|
}
|
||
|
}
|
||
|
float[] result = new float[rates.size()];
|
||
|
int i = 0;
|
||
|
for (Float rate : rates) {
|
||
|
result[i++] = rate;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
public void getAppMetrics(DisplayMetrics outMetrics) {
|
||
|
getAppMetrics(outMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
|
||
|
}
|
||
|
|
||
|
public void getAppMetrics(DisplayMetrics outMetrics, DisplayAdjustments displayAdjustments) {
|
||
|
getMetricsWithSize(outMetrics, displayAdjustments.getCompatibilityInfo(),
|
||
|
displayAdjustments.getConfiguration(), appWidth, appHeight);
|
||
|
}
|
||
|
|
||
|
public void getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfo ci,
|
||
|
Configuration configuration) {
|
||
|
getMetricsWithSize(outMetrics, ci, configuration, appWidth, appHeight);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Populates {@code outMetrics} with details of the logical display. Bounds are limited
|
||
|
* by the logical size of the display.
|
||
|
*
|
||
|
* @param outMetrics the {@link DisplayMetrics} to be populated
|
||
|
* @param compatInfo the {@link CompatibilityInfo} to be applied
|
||
|
* @param configuration the {@link Configuration}
|
||
|
*/
|
||
|
public void getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
|
||
|
Configuration configuration) {
|
||
|
getMetricsWithSize(outMetrics, compatInfo, configuration, logicalWidth, logicalHeight);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Similar to {@link #getLogicalMetrics}, but the limiting bounds are determined from
|
||
|
* {@link WindowConfiguration#getMaxBounds()}
|
||
|
*/
|
||
|
public void getMaxBoundsMetrics(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
|
||
|
Configuration configuration) {
|
||
|
Rect bounds = configuration.windowConfiguration.getMaxBounds();
|
||
|
// Pass in null configuration to ensure width and height are not overridden to app bounds.
|
||
|
getMetricsWithSize(outMetrics, compatInfo, /* configuration= */ null,
|
||
|
bounds.width(), bounds.height());
|
||
|
}
|
||
|
|
||
|
public int getNaturalWidth() {
|
||
|
return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ?
|
||
|
logicalWidth : logicalHeight;
|
||
|
}
|
||
|
|
||
|
public int getNaturalHeight() {
|
||
|
return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 ?
|
||
|
logicalHeight : logicalWidth;
|
||
|
}
|
||
|
|
||
|
public boolean isHdr() {
|
||
|
int[] types = hdrCapabilities != null ? hdrCapabilities.getSupportedHdrTypes() : null;
|
||
|
return types != null && types.length > 0;
|
||
|
}
|
||
|
|
||
|
public boolean isWideColorGamut() {
|
||
|
for (int colorMode : supportedColorModes) {
|
||
|
if (colorMode == Display.COLOR_MODE_DCI_P3 || colorMode > Display.COLOR_MODE_SRGB) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the specified UID has access to this display.
|
||
|
*/
|
||
|
public boolean hasAccess(int uid) {
|
||
|
return Display.hasAccess(uid, flags, ownerUid, displayId);
|
||
|
}
|
||
|
|
||
|
private void getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfo compatInfo,
|
||
|
Configuration configuration, int width, int height) {
|
||
|
outMetrics.densityDpi = outMetrics.noncompatDensityDpi = logicalDensityDpi;
|
||
|
outMetrics.density = outMetrics.noncompatDensity =
|
||
|
logicalDensityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
|
||
|
outMetrics.scaledDensity = outMetrics.noncompatScaledDensity = outMetrics.density;
|
||
|
outMetrics.xdpi = outMetrics.noncompatXdpi = physicalXDpi;
|
||
|
outMetrics.ydpi = outMetrics.noncompatYdpi = physicalYDpi;
|
||
|
|
||
|
final Rect appBounds = configuration != null
|
||
|
? configuration.windowConfiguration.getAppBounds() : null;
|
||
|
width = appBounds != null ? appBounds.width() : width;
|
||
|
height = appBounds != null ? appBounds.height() : height;
|
||
|
|
||
|
outMetrics.noncompatWidthPixels = outMetrics.widthPixels = width;
|
||
|
outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;
|
||
|
|
||
|
// Apply to size if the configuration is EMPTY because the size is from real display info.
|
||
|
final boolean applyToSize = configuration != null && appBounds == null;
|
||
|
compatInfo.applyDisplayMetricsIfNeeded(outMetrics, applyToSize);
|
||
|
}
|
||
|
|
||
|
// For debugging purposes
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
StringBuilder sb = new StringBuilder();
|
||
|
sb.append("DisplayInfo{\"");
|
||
|
sb.append(name);
|
||
|
sb.append("\", displayId ");
|
||
|
sb.append(displayId);
|
||
|
sb.append(", displayGroupId ");
|
||
|
sb.append(displayGroupId);
|
||
|
sb.append(flagsToString(flags));
|
||
|
sb.append(", real ");
|
||
|
sb.append(logicalWidth);
|
||
|
sb.append(" x ");
|
||
|
sb.append(logicalHeight);
|
||
|
sb.append(", largest app ");
|
||
|
sb.append(largestNominalAppWidth);
|
||
|
sb.append(" x ");
|
||
|
sb.append(largestNominalAppHeight);
|
||
|
sb.append(", smallest app ");
|
||
|
sb.append(smallestNominalAppWidth);
|
||
|
sb.append(" x ");
|
||
|
sb.append(smallestNominalAppHeight);
|
||
|
sb.append(", appVsyncOff ");
|
||
|
sb.append(appVsyncOffsetNanos);
|
||
|
sb.append(", presDeadline ");
|
||
|
sb.append(presentationDeadlineNanos);
|
||
|
sb.append(", mode ");
|
||
|
sb.append(modeId);
|
||
|
sb.append(", renderFrameRate ");
|
||
|
sb.append(renderFrameRate);
|
||
|
sb.append(", defaultMode ");
|
||
|
sb.append(defaultModeId);
|
||
|
sb.append(", userPreferredModeId ");
|
||
|
sb.append(userPreferredModeId);
|
||
|
sb.append(", modes ");
|
||
|
sb.append(Arrays.toString(supportedModes));
|
||
|
sb.append(", hdrCapabilities ");
|
||
|
sb.append(hdrCapabilities);
|
||
|
sb.append(", userDisabledHdrTypes ");
|
||
|
sb.append(Arrays.toString(userDisabledHdrTypes));
|
||
|
sb.append(", minimalPostProcessingSupported ");
|
||
|
sb.append(minimalPostProcessingSupported);
|
||
|
sb.append(", rotation ");
|
||
|
sb.append(rotation);
|
||
|
sb.append(", state ");
|
||
|
sb.append(Display.stateToString(state));
|
||
|
sb.append(", committedState ");
|
||
|
sb.append(Display.stateToString(committedState));
|
||
|
|
||
|
if (Process.myUid() != Process.SYSTEM_UID) {
|
||
|
sb.append("}");
|
||
|
return sb.toString();
|
||
|
}
|
||
|
|
||
|
sb.append(", type ");
|
||
|
sb.append(Display.typeToString(type));
|
||
|
sb.append(", uniqueId \"");
|
||
|
sb.append(uniqueId);
|
||
|
sb.append("\", app ");
|
||
|
sb.append(appWidth);
|
||
|
sb.append(" x ");
|
||
|
sb.append(appHeight);
|
||
|
sb.append(", density ");
|
||
|
sb.append(logicalDensityDpi);
|
||
|
sb.append(" (");
|
||
|
sb.append(physicalXDpi);
|
||
|
sb.append(" x ");
|
||
|
sb.append(physicalYDpi);
|
||
|
sb.append(") dpi, layerStack ");
|
||
|
sb.append(layerStack);
|
||
|
sb.append(", colorMode ");
|
||
|
sb.append(colorMode);
|
||
|
sb.append(", supportedColorModes ");
|
||
|
sb.append(Arrays.toString(supportedColorModes));
|
||
|
if (address != null) {
|
||
|
sb.append(", address ").append(address);
|
||
|
}
|
||
|
sb.append(", deviceProductInfo ");
|
||
|
sb.append(deviceProductInfo);
|
||
|
if (ownerUid != 0 || ownerPackageName != null) {
|
||
|
sb.append(", owner ").append(ownerPackageName);
|
||
|
sb.append(" (uid ").append(ownerUid).append(")");
|
||
|
}
|
||
|
sb.append(", removeMode ");
|
||
|
sb.append(removeMode);
|
||
|
sb.append(", refreshRateOverride ");
|
||
|
sb.append(refreshRateOverride);
|
||
|
sb.append(", brightnessMinimum ");
|
||
|
sb.append(brightnessMinimum);
|
||
|
sb.append(", brightnessMaximum ");
|
||
|
sb.append(brightnessMaximum);
|
||
|
sb.append(", brightnessDefault ");
|
||
|
sb.append(brightnessDefault);
|
||
|
sb.append(", installOrientation ");
|
||
|
sb.append(Surface.rotationToString(installOrientation));
|
||
|
sb.append(", layoutLimitedRefreshRate ");
|
||
|
sb.append(layoutLimitedRefreshRate);
|
||
|
sb.append(", hdrSdrRatio ");
|
||
|
if (Float.isNaN(hdrSdrRatio)) {
|
||
|
sb.append("not_available");
|
||
|
} else {
|
||
|
sb.append(hdrSdrRatio);
|
||
|
}
|
||
|
sb.append(", thermalRefreshRateThrottling ");
|
||
|
sb.append(thermalRefreshRateThrottling);
|
||
|
sb.append(", thermalBrightnessThrottlingDataId ");
|
||
|
sb.append(thermalBrightnessThrottlingDataId);
|
||
|
sb.append("}");
|
||
|
return sb.toString();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Write to a protocol buffer output stream.
|
||
|
* Protocol buffer message definition at {@link android.view.DisplayInfoProto}
|
||
|
*
|
||
|
* @param protoOutputStream Stream to write the Rect object to.
|
||
|
* @param fieldId Field Id of the DisplayInfoProto as defined in the parent message
|
||
|
*/
|
||
|
public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId) {
|
||
|
final long token = protoOutputStream.start(fieldId);
|
||
|
protoOutputStream.write(LOGICAL_WIDTH, logicalWidth);
|
||
|
protoOutputStream.write(LOGICAL_HEIGHT, logicalHeight);
|
||
|
protoOutputStream.write(APP_WIDTH, appWidth);
|
||
|
protoOutputStream.write(APP_HEIGHT, appHeight);
|
||
|
protoOutputStream.write(NAME, name);
|
||
|
protoOutputStream.write(FLAGS, flags);
|
||
|
if (displayCutout != null) {
|
||
|
displayCutout.dumpDebug(protoOutputStream, CUTOUT);
|
||
|
}
|
||
|
protoOutputStream.end(token);
|
||
|
}
|
||
|
|
||
|
private static String flagsToString(int flags) {
|
||
|
StringBuilder result = new StringBuilder();
|
||
|
if ((flags & Display.FLAG_SECURE) != 0) {
|
||
|
result.append(", FLAG_SECURE");
|
||
|
}
|
||
|
if ((flags & Display.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) {
|
||
|
result.append(", FLAG_SUPPORTS_PROTECTED_BUFFERS");
|
||
|
}
|
||
|
if ((flags & Display.FLAG_PRIVATE) != 0) {
|
||
|
result.append(", FLAG_PRIVATE");
|
||
|
}
|
||
|
if ((flags & Display.FLAG_PRESENTATION) != 0) {
|
||
|
result.append(", FLAG_PRESENTATION");
|
||
|
}
|
||
|
if ((flags & Display.FLAG_SCALING_DISABLED) != 0) {
|
||
|
result.append(", FLAG_SCALING_DISABLED");
|
||
|
}
|
||
|
if ((flags & Display.FLAG_ROUND) != 0) {
|
||
|
result.append(", FLAG_ROUND");
|
||
|
}
|
||
|
if ((flags & Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
|
||
|
result.append(", FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD");
|
||
|
}
|
||
|
if ((flags & Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0) {
|
||
|
result.append(", FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS");
|
||
|
}
|
||
|
if ((flags & Display.FLAG_TRUSTED) != 0) {
|
||
|
result.append(", FLAG_TRUSTED");
|
||
|
}
|
||
|
if ((flags & Display.FLAG_OWN_DISPLAY_GROUP) != 0) {
|
||
|
result.append(", FLAG_OWN_DISPLAY_GROUP");
|
||
|
}
|
||
|
if ((flags & Display.FLAG_ALWAYS_UNLOCKED) != 0) {
|
||
|
result.append(", FLAG_ALWAYS_UNLOCKED");
|
||
|
}
|
||
|
if ((flags & Display.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
|
||
|
result.append(", FLAG_TOUCH_FEEDBACK_DISABLED");
|
||
|
}
|
||
|
if ((flags & Display.FLAG_REAR) != 0) {
|
||
|
result.append(", FLAG_REAR_DISPLAY");
|
||
|
}
|
||
|
return result.toString();
|
||
|
}
|
||
|
}
|