Merge "Runtime resolution changes"

This commit is contained in:
Kriti Dang
2022-01-14 08:28:12 +00:00
committed by Android (Google) Code Review
12 changed files with 487 additions and 64 deletions

View File

@@ -1147,15 +1147,15 @@ package android.hardware.display {
public final class DisplayManager {
method public boolean areUserDisabledHdrTypesAllowed();
method @RequiresPermission(android.Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE) public void clearUserPreferredDisplayMode();
method @RequiresPermission(android.Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE) public void clearGlobalUserPreferredDisplayMode();
method @Nullable public android.view.Display.Mode getGlobalUserPreferredDisplayMode();
method @NonNull public int[] getUserDisabledHdrTypes();
method @Nullable public android.view.Display.Mode getUserPreferredDisplayMode();
method public boolean isMinimalPostProcessingRequested(int);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setAreUserDisabledHdrTypesAllowed(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE) public void setGlobalUserPreferredDisplayMode(@NonNull android.view.Display.Mode);
method @RequiresPermission(android.Manifest.permission.MODIFY_REFRESH_RATE_SWITCHING_TYPE) public void setRefreshRateSwitchingType(int);
method @RequiresPermission(android.Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS) public void setShouldAlwaysRespectAppRequestedMode(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setUserDisabledHdrTypes(@NonNull int[]);
method @RequiresPermission(android.Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE) public void setUserPreferredDisplayMode(@NonNull android.view.Display.Mode);
method @RequiresPermission(android.Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS) public boolean shouldAlwaysRespectAppRequestedMode();
field public static final int SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS = 2; // 0x2
field public static final int SWITCHING_TYPE_NONE = 0; // 0x0
@@ -2714,11 +2714,14 @@ package android.view {
}
public final class Display {
method @RequiresPermission(android.Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE) public void clearUserPreferredDisplayMode();
method @NonNull public android.view.Display.Mode getDefaultMode();
method @NonNull public int[] getReportedHdrTypes();
method @NonNull public android.graphics.ColorSpace[] getSupportedWideColorGamut();
method public int getType();
method @Nullable public android.view.Display.Mode getUserPreferredDisplayMode();
method public boolean hasAccess(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE) public void setUserPreferredDisplayMode(@NonNull android.view.Display.Mode);
field public static final int FLAG_TRUSTED = 128; // 0x80
field public static final int TYPE_EXTERNAL = 2; // 0x2
field public static final int TYPE_INTERNAL = 1; // 0x1
@@ -2733,6 +2736,13 @@ package android.view {
method public boolean matches(int, int, float);
}
public static final class Display.Mode.Builder {
ctor public Display.Mode.Builder();
method @NonNull public android.view.Display.Mode build();
method @NonNull public android.view.Display.Mode.Builder setRefreshRate(float);
method @NonNull public android.view.Display.Mode.Builder setResolution(int, int);
}
public class FocusFinder {
method public static void sort(android.view.View[], int, int, android.view.ViewGroup, boolean);
}

View File

@@ -737,6 +737,8 @@ MissingGetterMatchingBuilder: android.telephony.ims.stub.ImsFeatureConfiguration
MissingGetterMatchingBuilder: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String):
MissingGetterMatchingBuilder: android.view.Display.Mode.Builder#setResolution(int, int):
android.view.Display.Mode does not declare a `getResolution()` method matching method android.view.Display.Mode.Builder.setResolution(int,int)
MissingNullability: android.app.Activity#onMovedToDisplay(int, android.content.res.Configuration) parameter #1:

View File

@@ -1132,41 +1132,48 @@ public final class DisplayManager {
}
/**
* Sets the default display mode, according to the refresh rate and the resolution chosen by the
* user.
* Sets the global default {@link Display.Mode}. The display mode includes preference for
* resolution and refresh rate. The mode change is applied globally, i.e. to all the connected
* displays. If the mode specified is not supported by a connected display, then no mode change
* occurs for that display.
*
* @param mode The {@link Display.Mode} to set, which can include resolution and/or
* refresh-rate. It is created using {@link Display.Mode.Builder}.
*`
* @hide
*/
@TestApi
@RequiresPermission(Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE)
public void setUserPreferredDisplayMode(@NonNull Display.Mode mode) {
public void setGlobalUserPreferredDisplayMode(@NonNull Display.Mode mode) {
// Create a new object containing default values for the unused fields like mode ID and
// alternative refresh rates.
Display.Mode preferredMode = new Display.Mode(mode.getPhysicalWidth(),
mode.getPhysicalHeight(), mode.getRefreshRate());
mGlobal.setUserPreferredDisplayMode(preferredMode);
mGlobal.setUserPreferredDisplayMode(Display.INVALID_DISPLAY, preferredMode);
}
/**
* Removes the user preferred display mode.
* Removes the global user preferred display mode.
* User preferred display mode is cleared for all the connected displays.
*
* @hide
*/
@TestApi
@RequiresPermission(Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE)
public void clearUserPreferredDisplayMode() {
mGlobal.setUserPreferredDisplayMode(null);
public void clearGlobalUserPreferredDisplayMode() {
mGlobal.setUserPreferredDisplayMode(Display.INVALID_DISPLAY, null);
}
/**
* Returns the user preferred display mode.
* Returns the global user preferred display mode.
* If no user preferred mode has been set, or it has been cleared, this method returns null.
*
* @hide
*/
@TestApi
@Nullable
public Display.Mode getUserPreferredDisplayMode() {
return mGlobal.getUserPreferredDisplayMode();
public Display.Mode getGlobalUserPreferredDisplayMode() {
return mGlobal.getUserPreferredDisplayMode(Display.INVALID_DISPLAY);
}
/**

View File

@@ -896,9 +896,9 @@ public final class DisplayManagerGlobal {
* Sets the default display mode, according to the refresh rate and the resolution chosen by the
* user.
*/
public void setUserPreferredDisplayMode(Display.Mode mode) {
public void setUserPreferredDisplayMode(int displayId, Display.Mode mode) {
try {
mDm.setUserPreferredDisplayMode(mode);
mDm.setUserPreferredDisplayMode(displayId, mode);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -907,9 +907,9 @@ public final class DisplayManagerGlobal {
/**
* Returns the user preferred display mode.
*/
public Display.Mode getUserPreferredDisplayMode() {
public Display.Mode getUserPreferredDisplayMode(int displayId) {
try {
return mDm.getUserPreferredDisplayMode();
return mDm.getUserPreferredDisplayMode(displayId);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}

View File

@@ -166,8 +166,8 @@ interface IDisplayManager {
// Sets the user preferred display mode.
// Requires MODIFY_USER_PREFERRED_DISPLAY_MODE permission.
void setUserPreferredDisplayMode(in Mode mode);
Mode getUserPreferredDisplayMode();
void setUserPreferredDisplayMode(int displayId, in Mode mode);
Mode getUserPreferredDisplayMode(int displayId);
// When enabled the app requested display resolution and refresh rate is always selected
// in DisplayModeDirector regardless of user settings and policies for low brightness, low

View File

@@ -19,6 +19,7 @@ package android.view;
import static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_MODE;
import static android.Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS;
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -137,6 +138,24 @@ public final class Display {
*/
public static final int INVALID_DISPLAY = -1;
/**
* Invalid resolution width.
* @hide
*/
public static final int INVALID_DISPLAY_WIDTH = -1;
/**
* Invalid resolution height.
* @hide
*/
public static final int INVALID_DISPLAY_HEIGHT = -1;
/**
* Invalid refresh rate.
* @hide
*/
public static final float INVALID_DISPLAY_REFRESH_RATE = 0.0f;
/**
* The default display group id, which is the display group id of the primary display assuming
* there is one.
@@ -1169,6 +1188,49 @@ public final class Display {
}
}
/**
* Sets the default {@link Display.Mode} to use for the display. The display mode includes
* preference for resolution and refresh rate.
* If the mode specified is not supported by the display, then no mode change occurs.
*
* @param mode The {@link Display.Mode} to set, which can include resolution and/or
* refresh-rate. It is created using {@link Display.Mode.Builder}.
*`
* @hide
*/
@TestApi
@RequiresPermission(Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE)
public void setUserPreferredDisplayMode(@NonNull Display.Mode mode) {
// Create a new object containing default values for the unused fields like mode ID and
// alternative refresh rates.
Display.Mode preferredMode = new Display.Mode(mode.getPhysicalWidth(),
mode.getPhysicalHeight(), mode.getRefreshRate());
mGlobal.setUserPreferredDisplayMode(mDisplayId, preferredMode);
}
/**
* Removes the display's user preferred display mode.
*
* @hide
*/
@TestApi
@RequiresPermission(Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE)
public void clearUserPreferredDisplayMode() {
mGlobal.setUserPreferredDisplayMode(mDisplayId, null);
}
/**
* Returns the display's user preferred display mode.
*
* @hide
*/
@TestApi
@Nullable
public Display.Mode getUserPreferredDisplayMode() {
return mGlobal.getUserPreferredDisplayMode(mDisplayId);
}
/**
* Returns whether this display can be used to display wide color gamut content.
* This does not necessarily mean the device itself can render wide color gamut
@@ -1709,6 +1771,30 @@ public final class Display {
return state == STATE_ON || state == STATE_VR || state == STATE_ON_SUSPEND;
}
/**
* Returns true if the specified width is valid.
* @hide
*/
public static boolean isWidthValid(int width) {
return width > 0;
}
/**
* Returns true if the specified height is valid.
* @hide
*/
public static boolean isHeightValid(int height) {
return height > 0;
}
/**
* Returns true if the specified refresh-rate is valid.
* @hide
*/
public static boolean isRefreshRateValid(float refreshRate) {
return refreshRate > 0.0f;
}
/**
* A mode supported by a given display.
*
@@ -1845,6 +1931,30 @@ public final class Display {
Float.floatToIntBits(mRefreshRate) == Float.floatToIntBits(refreshRate);
}
/**
* Returns {@code true} if this mode matches the given parameters, if those parameters are
* valid.<p>
* If resolution (width and height) is valid and refresh-rate is not, the method matches
* only resolution.
* If refresh-rate is valid and resolution (width and height) is not, the method matches
* only refresh-rate.</p>
*
* @hide
*/
public boolean matchesIfValid(int width, int height, float refreshRate) {
if (!isWidthValid(width) && !isHeightValid(height)
&& !isRefreshRateValid(refreshRate)) {
return false;
}
if (isWidthValid(width) != isHeightValid(height)) {
return false;
}
return (!isWidthValid(width) || mWidth == width)
&& (!isHeightValid(height) || mHeight == height)
&& (!isRefreshRateValid(refreshRate)
|| Float.floatToIntBits(mRefreshRate) == Float.floatToIntBits(refreshRate));
}
/**
* Returns {@code true} if this mode equals to the other mode in all parameters except
* the refresh rate.
@@ -1855,6 +1965,24 @@ public final class Display {
return mWidth == other.mWidth && mHeight == other.mHeight;
}
/**
* Returns {@code true} if refresh-rate is set for a display mode
*
* @hide
*/
public boolean isRefreshRateSet() {
return mRefreshRate != INVALID_DISPLAY_REFRESH_RATE;
}
/**
* Returns {@code true} if refresh-rate is set for a display mode
*
* @hide
*/
public boolean isResolutionSet() {
return mWidth != INVALID_DISPLAY_WIDTH && mHeight != INVALID_DISPLAY_HEIGHT;
}
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
@@ -1923,6 +2051,80 @@ public final class Display {
return new Mode[size];
}
};
/**
* Builder is used to create {@link Display.Mode} objects
*
* @hide
*/
@TestApi
public static final class Builder {
private int mWidth;
private int mHeight;
private float mRefreshRate;
public Builder() {
mWidth = Display.INVALID_DISPLAY_WIDTH;
mHeight = Display.INVALID_DISPLAY_HEIGHT;
mRefreshRate = Display.INVALID_DISPLAY_REFRESH_RATE;
}
/**
* Sets the resolution (width and height) of a {@link Display.Mode}
*
* @return Instance of {@link Builder}
*/
@NonNull
public Builder setResolution(int width, int height) {
if (width > 0 && height > 0) {
mWidth = width;
mHeight = height;
}
return this;
}
/**
* Sets the refresh rate of a {@link Display.Mode}
*
* @return Instance of {@link Builder}
*/
@NonNull
public Builder setRefreshRate(float refreshRate) {
if (refreshRate > 0.0f) {
mRefreshRate = refreshRate;
}
return this;
}
/**
* Creates the {@link Display.Mode} object.
*
* <p>
* If resolution needs to be set, but refresh-rate doesn't matter, create a mode with
* Builder and call setResolution.
* {@code
* Display.Mode mode =
* new Display.Mode.Builder()
* .setResolution(width, height)
* .build();
* }
* </p><p>
* If refresh-rate needs to be set, but resolution doesn't matter, create a mode with
* Builder and call setRefreshRate.
* {@code
* Display.Mode mode =
* new Display.Mode.Builder()
* .setRefreshRate(refreshRate)
* .build();
* }
* </p>
*/
@NonNull
public Mode build() {
Display.Mode mode = new Mode(mWidth, mHeight, mRefreshRate);
return mode;
}
}
}
/**

View File

@@ -37,6 +37,8 @@ import java.io.PrintWriter;
* </p>
*/
abstract class DisplayDevice {
private static final Display.Mode EMPTY_DISPLAY_MODE = new Display.Mode.Builder().build();
private final DisplayAdapter mDisplayAdapter;
private final IBinder mDisplayToken;
private final String mUniqueId;
@@ -212,6 +214,13 @@ abstract class DisplayDevice {
*/
public void setUserPreferredDisplayModeLocked(Display.Mode mode) { }
/**
* Returns the user preferred display mode.
*/
public Display.Mode getUserPreferredDisplayModeLocked() {
return EMPTY_DISPLAY_MODE;
}
/**
* Sets the requested color mode.
*/

View File

@@ -873,11 +873,11 @@ public final class DisplayManagerService extends SystemService {
private void updateUserPreferredDisplayModeSettingsLocked() {
final float refreshRate = Settings.Global.getFloat(mContext.getContentResolver(),
Settings.Global.USER_PREFERRED_REFRESH_RATE, 0.0f);
Settings.Global.USER_PREFERRED_REFRESH_RATE, Display.INVALID_DISPLAY_REFRESH_RATE);
final int height = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.USER_PREFERRED_RESOLUTION_HEIGHT, -1);
Settings.Global.USER_PREFERRED_RESOLUTION_HEIGHT, Display.INVALID_DISPLAY_HEIGHT);
final int width = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.USER_PREFERRED_RESOLUTION_WIDTH, -1);
Settings.Global.USER_PREFERRED_RESOLUTION_WIDTH, Display.INVALID_DISPLAY_WIDTH);
Display.Mode mode = new Display.Mode(width, height, refreshRate);
mUserPreferredMode = isResolutionAndRefreshRateValid(mode) ? mode : null;
}
@@ -1560,8 +1560,11 @@ public final class DisplayManagerService extends SystemService {
}
if (mUserPreferredMode != null) {
device.setUserPreferredDisplayModeLocked(mUserPreferredMode);
} else {
configurePreferredDisplayModeLocked(display);
}
addDisplayPowerControllerLocked(display);
mDisplayStates.append(displayId, Display.STATE_UNKNOWN);
final float brightnessDefault = display.getDisplayInfoLocked().brightnessDefault;
@@ -1688,6 +1691,24 @@ public final class DisplayManagerService extends SystemService {
}
}
private void configurePreferredDisplayModeLocked(LogicalDisplay display) {
final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
final Point userPreferredResolution =
mPersistentDataStore.getUserPreferredResolution(device);
final float refreshRate = mPersistentDataStore.getUserPreferredRefreshRate(device);
if (userPreferredResolution == null && Float.isNaN(refreshRate)) {
return;
}
Display.Mode.Builder modeBuilder = new Display.Mode.Builder();
if (userPreferredResolution != null) {
modeBuilder.setResolution(userPreferredResolution.x, userPreferredResolution.y);
}
if (!Float.isNaN(refreshRate)) {
modeBuilder.setRefreshRate(refreshRate);
}
device.setUserPreferredDisplayModeLocked(modeBuilder.build());
}
// If we've never recorded stable device stats for this device before and they aren't
// explicitly configured, go ahead and record the stable device stats now based on the status
// of the default display at first boot.
@@ -1731,36 +1752,79 @@ public final class DisplayManagerService extends SystemService {
return mWideColorSpace.getId();
}
void setUserPreferredDisplayModeInternal(Display.Mode mode) {
void setUserPreferredDisplayModeInternal(int displayId, Display.Mode mode) {
synchronized (mSyncRoot) {
if (Objects.equals(mUserPreferredMode, mode)) {
if (Objects.equals(mUserPreferredMode, mode) && displayId == Display.INVALID_DISPLAY) {
return;
}
if (mode != null && !isResolutionAndRefreshRateValid(mode)) {
if (mode != null && !isResolutionAndRefreshRateValid(mode)
&& displayId == Display.INVALID_DISPLAY) {
throw new IllegalArgumentException("width, height and refresh rate of mode should "
+ "be greater than 0");
+ "be greater than 0 when setting the global user preferred display mode.");
}
mUserPreferredMode = mode;
final int resolutionHeight = mode == null ? -1 : mode.getPhysicalHeight();
final int resolutionWidth = mode == null ? -1 : mode.getPhysicalWidth();
final float refreshRate = mode == null ? 0.0f : mode.getRefreshRate();
Settings.Global.putFloat(mContext.getContentResolver(),
Settings.Global.USER_PREFERRED_REFRESH_RATE, refreshRate);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.USER_PREFERRED_RESOLUTION_HEIGHT, resolutionHeight);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.USER_PREFERRED_RESOLUTION_WIDTH, resolutionWidth);
mDisplayDeviceRepo.forEachLocked((DisplayDevice device) -> {
device.setUserPreferredDisplayModeLocked(mode);
});
final int resolutionHeight = mode == null ? Display.INVALID_DISPLAY_HEIGHT
: mode.getPhysicalHeight();
final int resolutionWidth = mode == null ? Display.INVALID_DISPLAY_WIDTH
: mode.getPhysicalWidth();
final float refreshRate = mode == null ? Display.INVALID_DISPLAY_REFRESH_RATE
: mode.getRefreshRate();
storeModeInPersistentDataStoreLocked(
displayId, resolutionWidth, resolutionHeight, refreshRate);
if (displayId != Display.INVALID_DISPLAY) {
setUserPreferredModeForDisplayLocked(displayId, mode);
} else {
mUserPreferredMode = mode;
storeModeInGlobalSettingsLocked(
resolutionWidth, resolutionHeight, refreshRate, mode);
}
}
}
private Display.Mode getUserPreferredDisplayModeInternal() {
private void storeModeInPersistentDataStoreLocked(int displayId, int resolutionWidth,
int resolutionHeight, float refreshRate) {
DisplayDevice displayDevice = getDeviceForDisplayLocked(displayId);
if (displayDevice == null) {
return;
}
mPersistentDataStore.setUserPreferredResolution(
displayDevice, resolutionWidth, resolutionHeight);
mPersistentDataStore.setUserPreferredRefreshRate(displayDevice, refreshRate);
}
private void setUserPreferredModeForDisplayLocked(int displayId, Display.Mode mode) {
DisplayDevice displayDevice = getDeviceForDisplayLocked(displayId);
if (displayDevice == null) {
return;
}
displayDevice.setUserPreferredDisplayModeLocked(mode);
}
private void storeModeInGlobalSettingsLocked(
int resolutionWidth, int resolutionHeight, float refreshRate, Display.Mode mode) {
Settings.Global.putFloat(mContext.getContentResolver(),
Settings.Global.USER_PREFERRED_REFRESH_RATE, refreshRate);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.USER_PREFERRED_RESOLUTION_HEIGHT, resolutionHeight);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.USER_PREFERRED_RESOLUTION_WIDTH, resolutionWidth);
mDisplayDeviceRepo.forEachLocked((DisplayDevice device) -> {
device.setUserPreferredDisplayModeLocked(mode);
});
}
Display.Mode getUserPreferredDisplayModeInternal(int displayId) {
synchronized (mSyncRoot) {
return mUserPreferredMode;
if (displayId == Display.INVALID_DISPLAY) {
return mUserPreferredMode;
}
DisplayDevice displayDevice = getDeviceForDisplayLocked(displayId);
if (displayDevice == null) {
return null;
}
return displayDevice.getUserPreferredDisplayModeLocked();
}
}
@@ -2373,7 +2437,7 @@ public final class DisplayManagerService extends SystemService {
pw.println(" mMinimumBrightnessCurve=" + mMinimumBrightnessCurve);
if (mUserPreferredMode != null) {
pw.println(mUserPreferredMode.toString());
pw.println(mUserPreferredMode);
}
pw.println();
@@ -3379,23 +3443,23 @@ public final class DisplayManagerService extends SystemService {
}
@Override // Binder call
public void setUserPreferredDisplayMode(Display.Mode mode) {
public void setUserPreferredDisplayMode(int displayId, Display.Mode mode) {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE,
"Permission required to set the user preferred display mode.");
final long token = Binder.clearCallingIdentity();
try {
setUserPreferredDisplayModeInternal(mode);
setUserPreferredDisplayModeInternal(displayId, mode);
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override // Binder call
public Display.Mode getUserPreferredDisplayMode() {
public Display.Mode getUserPreferredDisplayMode(int displayId) {
final long token = Binder.clearCallingIdentity();
try {
return getUserPreferredDisplayModeInternal();
return getUserPreferredDisplayModeInternal(displayId);
} finally {
Binder.restoreCallingIdentity(token);
}

View File

@@ -113,13 +113,18 @@ class DisplayManagerShellCommand extends ShellCommand {
pw.println(" constrain-launcher-metrics [true|false]");
pw.println(" Sets if Display#getRealSize and getRealMetrics should be constrained for ");
pw.println(" Launcher.");
pw.println(" set-user-preferred-display-mode WIDTH HEIGHT REFRESH-RATE");
pw.println(" set-user-preferred-display-mode WIDTH HEIGHT REFRESH-RATE "
+ "DISPLAY_ID (optional)");
pw.println(" Sets the user preferred display mode which has fields WIDTH, HEIGHT and "
+ "REFRESH-RATE");
pw.println(" clear-user-preferred-display-mode");
pw.println(" Clears the user preferred display mode");
pw.println(" get-user-preferred-display-mode");
pw.println(" Returns the user preferred display mode or null id no mode is set by user");
+ "REFRESH-RATE. If DISPLAY_ID is passed, the mode change is applied to display"
+ "with id = DISPLAY_ID, else mode change is applied globally.");
pw.println(" clear-user-preferred-display-mode DISPLAY_ID (optional)");
pw.println(" Clears the user preferred display mode. If DISPLAY_ID is passed, the mode"
+ " is cleared for display with id = DISPLAY_ID, else mode is cleared globally.");
pw.println(" get-user-preferred-display-mode DISPLAY_ID (optional)");
pw.println(" Returns the user preferred display mode or null if no mode is set by user."
+ "If DISPLAY_ID is passed, the mode for display with id = DISPLAY_ID is "
+ "returned, else global display mode is returned.");
pw.println(" set-match-content-frame-rate-pref PREFERENCE");
pw.println(" Sets the match content frame rate preference as PREFERENCE ");
pw.println(" get-match-content-frame-rate-pref");
@@ -235,28 +240,54 @@ class DisplayManagerShellCommand extends ShellCommand {
getErrPrintWriter().println("Error: invalid format of width, height or refresh rate");
return 1;
}
if (width < 0 || height < 0 || refreshRate <= 0.0f) {
getErrPrintWriter().println("Error: invalid value of width, height or refresh rate");
if ((width < 0 || height < 0) && refreshRate <= 0.0f) {
getErrPrintWriter().println("Error: invalid value of resolution (width, height)"
+ " and refresh rate");
return 1;
}
final Context context = mService.getContext();
final DisplayManager dm = context.getSystemService(DisplayManager.class);
dm.setUserPreferredDisplayMode(new Display.Mode(width, height, refreshRate));
final String displayIdText = getNextArg();
int displayId = Display.INVALID_DISPLAY;
if (displayIdText != null) {
try {
displayId = Integer.parseInt(displayIdText);
} catch (NumberFormatException e) {
getErrPrintWriter().println("Error: invalid format of display ID");
return 1;
}
}
mService.setUserPreferredDisplayModeInternal(
displayId, new Display.Mode(width, height, refreshRate));
return 0;
}
private int clearUserPreferredDisplayMode() {
final Context context = mService.getContext();
final DisplayManager dm = context.getSystemService(DisplayManager.class);
dm.clearUserPreferredDisplayMode();
final String displayIdText = getNextArg();
int displayId = Display.INVALID_DISPLAY;
if (displayIdText != null) {
try {
displayId = Integer.parseInt(displayIdText);
} catch (NumberFormatException e) {
getErrPrintWriter().println("Error: invalid format of display ID");
return 1;
}
}
mService.setUserPreferredDisplayModeInternal(displayId, null);
return 0;
}
private int getUserPreferredDisplayMode() {
final Context context = mService.getContext();
final DisplayManager dm = context.getSystemService(DisplayManager.class);
final Display.Mode mode = dm.getUserPreferredDisplayMode();
final String displayIdText = getNextArg();
int displayId = Display.INVALID_DISPLAY;
if (displayIdText != null) {
try {
displayId = Integer.parseInt(displayIdText);
} catch (NumberFormatException e) {
getErrPrintWriter().println("Error: invalid format of display ID");
return 1;
}
}
final Display.Mode mode = mService.getUserPreferredDisplayModeInternal(displayId);
if (mode == null) {
getOutPrintWriter().println("User preferred display mode: null");
return 0;

View File

@@ -847,6 +847,10 @@ final class LocalDisplayAdapter extends DisplayAdapter {
public void setUserPreferredDisplayModeLocked(Display.Mode mode) {
final int oldModeId = getPreferredModeId();
mUserPreferredMode = mode;
if (mode != null && (mode.isRefreshRateSet() ^ mode.isResolutionSet())) {
mUserPreferredMode = findMode(mode.getPhysicalWidth(),
mode.getPhysicalHeight(), mode.getRefreshRate());
}
mUserPreferredModeId = findUserPreferredModeIdLocked(mode);
if (oldModeId != getPreferredModeId()) {
@@ -854,6 +858,11 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
}
@Override
public Display.Mode getUserPreferredDisplayModeLocked() {
return mUserPreferredMode;
}
@Override
public void setRequestedColorModeLocked(int colorMode) {
requestColorModeLocked(colorMode);
@@ -1062,6 +1071,18 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return matchingModeId;
}
// Returns a mode with resolution (width, height) and/or refreshRate. If any one of the
// resolution or refresh-rate is valid, a mode having the valid parameters is returned.
private Display.Mode findMode(int width, int height, float refreshRate) {
for (int i = 0; i < mSupportedModes.size(); i++) {
Display.Mode supportedMode = mSupportedModes.valueAt(i).mMode;
if (supportedMode.matchesIfValid(width, height, refreshRate)) {
return supportedMode;
}
}
return null;
}
private int findUserPreferredModeIdLocked(Display.Mode userPreferredMode) {
if (userPreferredMode != null) {
for (int i = 0; i < mSupportedModes.size(); i++) {

View File

@@ -291,6 +291,54 @@ final class PersistentDataStore {
return false;
}
public boolean setUserPreferredRefreshRate(DisplayDevice displayDevice, float refreshRate) {
final String displayDeviceUniqueId = displayDevice.getUniqueId();
if (!displayDevice.hasStableUniqueId() || displayDeviceUniqueId == null) {
return false;
}
DisplayState state = getDisplayState(displayDevice.getUniqueId(), true);
if (state.setRefreshRate(refreshRate)) {
setDirty();
return true;
}
return false;
}
public float getUserPreferredRefreshRate(DisplayDevice device) {
if (device == null || !device.hasStableUniqueId()) {
return Float.NaN;
}
final DisplayState state = getDisplayState(device.getUniqueId(), false);
if (state == null) {
return Float.NaN;
}
return state.getRefreshRate();
}
public boolean setUserPreferredResolution(DisplayDevice displayDevice, int width, int height) {
final String displayDeviceUniqueId = displayDevice.getUniqueId();
if (!displayDevice.hasStableUniqueId() || displayDeviceUniqueId == null) {
return false;
}
DisplayState state = getDisplayState(displayDevice.getUniqueId(), true);
if (state.setResolution(width, height)) {
setDirty();
return true;
}
return false;
}
public Point getUserPreferredResolution(DisplayDevice displayDevice) {
if (displayDevice == null || !displayDevice.hasStableUniqueId()) {
return null;
}
final DisplayState state = getDisplayState(displayDevice.getUniqueId(), false);
if (state == null) {
return null;
}
return state.getResolution();
}
public Point getStableDisplaySize() {
loadIfNeeded();
return mStableDeviceValues.getDisplaySize();
@@ -536,6 +584,9 @@ final class PersistentDataStore {
private static final class DisplayState {
private int mColorMode;
private float mBrightness;
private int mWidth;
private int mHeight;
private float mRefreshRate;
// Brightness configuration by user
private BrightnessConfigurations mDisplayBrightnessConfigurations =
@@ -576,6 +627,31 @@ final class PersistentDataStore {
return mDisplayBrightnessConfigurations.mConfigurations.get(userSerial);
}
public boolean setResolution(int width, int height) {
if (width == mWidth && height == mHeight) {
return false;
}
mWidth = width;
mHeight = height;
return true;
}
public Point getResolution() {
return new Point(mWidth, mHeight);
}
public boolean setRefreshRate(float refreshRate) {
if (refreshRate == mRefreshRate) {
return false;
}
mRefreshRate = refreshRate;
return true;
}
public float getRefreshRate() {
return mRefreshRate;
}
public void loadFromXml(TypedXmlPullParser parser)
throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();

View File

@@ -4588,7 +4588,8 @@ public class StatsPullAtomService extends SystemService {
int matchContentFrameRateUserPreference =
displayManager.getMatchContentFrameRateUserPreference();
byte[] userDisabledHdrTypes = toBytes(displayManager.getUserDisabledHdrTypes());
Display.Mode userPreferredDisplayMode = displayManager.getUserPreferredDisplayMode();
Display.Mode userPreferredDisplayMode =
displayManager.getGlobalUserPreferredDisplayMode();
int userPreferredWidth = userPreferredDisplayMode != null
? userPreferredDisplayMode.getPhysicalWidth() : -1;
int userPreferredHeight = userPreferredDisplayMode != null