Merge changes from topic "preferredDisplayModeId60120" into sc-dev
* changes:
Enable preferredDisplayModeId for frame rate override
Add preferredMaxDisplayRefreshRate
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 2d58520..dce3fef 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -190,6 +190,8 @@
* has a preference.
* @param requestedModeId The preferred mode id for the top-most visible window that has a
* preference.
+ * @param requestedMaxRefreshRate The preferred highest refresh rate for the top-most visible
+ * window that has a preference.
* @param requestedMinimalPostProcessing The preferred minimal post processing setting for the
* display. This is true when there is at least one visible window that wants minimal post
* processng on.
@@ -197,8 +199,8 @@
* prior to call to performTraversalInTransactionFromWindowManager.
*/
public abstract void setDisplayProperties(int displayId, boolean hasContent,
- float requestedRefreshRate, int requestedModeId, boolean requestedMinimalPostProcessing,
- boolean inTraversal);
+ float requestedRefreshRate, int requestedModeId, float requestedMaxRefreshRate,
+ boolean requestedMinimalPostProcessing, boolean inTraversal);
/**
* Applies an offset to the contents of a display, for example to avoid burn-in.
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c32ab3a..c1e394d 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -3010,6 +3010,14 @@
public int preferredDisplayModeId;
/**
+ * The max display refresh rate while the window is in focus.
+ *
+ * This value is ignored if {@link #preferredDisplayModeId} is set.
+ * @hide
+ */
+ public float preferredMaxDisplayRefreshRate;
+
+ /**
* An internal annotation for flags that can be specified to {@link #systemUiVisibility}
* and {@link #subtreeSystemUiVisibility}.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index 388d72d..ae018ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -61,7 +61,6 @@
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
@@ -85,7 +84,7 @@
private final LayoutParams mLpChanged;
private final boolean mKeyguardScreenRotation;
private final long mLockScreenDisplayTimeout;
- private final Display.Mode mKeyguardDisplayMode;
+ private final float mKeyguardRefreshRate;
private final KeyguardViewMediator mKeyguardViewMediator;
private final KeyguardBypassController mKeyguardBypassController;
private ViewGroup mNotificationShadeView;
@@ -135,14 +134,8 @@
// Running on the highest frame rate available can be expensive.
// Let's specify a preferred refresh rate, and allow higher FPS only when we
// know that we're not falsing (because we unlocked.)
- int keyguardRefreshRate = context.getResources()
+ mKeyguardRefreshRate = context.getResources()
.getInteger(R.integer.config_keyguardRefreshRate);
- // Find supported display mode with the same resolution and requested refresh rate.
- mKeyguardDisplayMode = Arrays.stream(supportedModes).filter(mode ->
- (int) mode.getRefreshRate() == keyguardRefreshRate
- && mode.getPhysicalWidth() == currentMode.getPhysicalWidth()
- && mode.getPhysicalHeight() == currentMode.getPhysicalHeight())
- .findFirst().orElse(null);
}
/**
@@ -273,16 +266,17 @@
mLpChanged.privateFlags &= ~LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
}
- if (mKeyguardDisplayMode != null) {
+ if (mKeyguardRefreshRate > 0) {
boolean bypassOnKeyguard = mKeyguardBypassController.getBypassEnabled()
&& state.mStatusBarState == StatusBarState.KEYGUARD
&& !state.mKeyguardFadingAway && !state.mKeyguardGoingAway;
if (state.mDozing || bypassOnKeyguard) {
- mLpChanged.preferredDisplayModeId = mKeyguardDisplayMode.getModeId();
+ mLpChanged.preferredMaxDisplayRefreshRate = mKeyguardRefreshRate;
} else {
- mLpChanged.preferredDisplayModeId = 0;
+ mLpChanged.preferredMaxDisplayRefreshRate = 0;
}
- Trace.setCounter("display_mode_id", mLpChanged.preferredDisplayModeId);
+ Trace.setCounter("display_max_refresh_rate",
+ (long) mLpChanged.preferredMaxDisplayRefreshRate);
}
}
@@ -669,7 +663,7 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(TAG + ":");
- pw.println(" mKeyguardDisplayMode=" + mKeyguardDisplayMode);
+ pw.println(" mKeyguardRefreshRate=" + mKeyguardRefreshRate);
pw.println(mCurrentState);
if (mNotificationShadeView != null && mNotificationShadeView.getViewRootImpl() != null) {
mNotificationShadeView.getViewRootImpl().dump(" ", pw);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index f75f3e1..d4920f5 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1498,8 +1498,8 @@
}
private void setDisplayPropertiesInternal(int displayId, boolean hasContent,
- float requestedRefreshRate, int requestedModeId, boolean preferMinimalPostProcessing,
- boolean inTraversal) {
+ float requestedRefreshRate, int requestedModeId, float requestedMaxRefreshRate,
+ boolean preferMinimalPostProcessing, boolean inTraversal) {
synchronized (mSyncRoot) {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
if (display == null) {
@@ -1523,8 +1523,8 @@
requestedModeId = display.getDisplayInfoLocked().findDefaultModeByRefreshRate(
requestedRefreshRate).getModeId();
}
- mDisplayModeDirector.getAppRequestObserver().setAppRequestedMode(
- displayId, requestedModeId);
+ mDisplayModeDirector.getAppRequestObserver().setAppRequest(
+ displayId, requestedModeId, requestedMaxRefreshRate);
if (display.getDisplayInfoLocked().minimalPostProcessingSupported) {
boolean mppRequest = mMinimalPostProcessingAllowed && preferMinimalPostProcessing;
@@ -3189,10 +3189,11 @@
@Override
public void setDisplayProperties(int displayId, boolean hasContent,
- float requestedRefreshRate, int requestedMode,
+ float requestedRefreshRate, int requestedMode, float requestedMaxRefreshRate,
boolean requestedMinimalPostProcessing, boolean inTraversal) {
setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate,
- requestedMode, requestedMinimalPostProcessing, inTraversal);
+ requestedMode, requestedMaxRefreshRate, requestedMinimalPostProcessing,
+ inTraversal);
}
@Override
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 67779a2..997f0e5 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -198,6 +198,8 @@
public float maxRefreshRate;
public int width;
public int height;
+ public boolean disableRefreshRateSwitching;
+ public float baseModeRefreshRate;
VoteSummary() {
reset();
@@ -208,6 +210,8 @@
maxRefreshRate = Float.POSITIVE_INFINITY;
width = Vote.INVALID_SIZE;
height = Vote.INVALID_SIZE;
+ disableRefreshRateSwitching = false;
+ baseModeRefreshRate = 0f;
}
}
@@ -229,13 +233,20 @@
// For refresh rates, just use the tightest bounds of all the votes
summary.minRefreshRate = Math.max(summary.minRefreshRate, vote.refreshRateRange.min);
summary.maxRefreshRate = Math.min(summary.maxRefreshRate, vote.refreshRateRange.max);
- // For display size, use only the first vote we come across (i.e. the highest
- // priority vote that includes the width / height).
+ // For display size, disable refresh rate switching and base mode refresh rate use only
+ // the first vote we come across (i.e. the highest priority vote that includes the
+ // attribute).
if (summary.height == Vote.INVALID_SIZE && summary.width == Vote.INVALID_SIZE
&& vote.height > 0 && vote.width > 0) {
summary.width = vote.width;
summary.height = vote.height;
}
+ if (!summary.disableRefreshRateSwitching && vote.disableRefreshRateSwitching) {
+ summary.disableRefreshRateSwitching = true;
+ }
+ if (summary.baseModeRefreshRate == 0f && vote.baseModeRefreshRate > 0f) {
+ summary.baseModeRefreshRate = vote.baseModeRefreshRate;
+ }
}
}
@@ -260,13 +271,14 @@
return new DesiredDisplayModeSpecs();
}
- int[] availableModes = new int[]{defaultMode.getModeId()};
+ ArrayList<Display.Mode> availableModes = new ArrayList<>();
+ availableModes.add(defaultMode);
VoteSummary primarySummary = new VoteSummary();
int lowestConsideredPriority = Vote.MIN_PRIORITY;
int highestConsideredPriority = Vote.MAX_PRIORITY;
if (mAlwaysRespectAppRequest) {
- lowestConsideredPriority = Vote.PRIORITY_APP_REQUEST_REFRESH_RATE;
+ lowestConsideredPriority = Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE;
highestConsideredPriority = Vote.PRIORITY_APP_REQUEST_SIZE;
}
@@ -286,16 +298,19 @@
}
availableModes = filterModes(modes, primarySummary);
- if (availableModes.length > 0) {
+ if (!availableModes.isEmpty()) {
if (mLoggingEnabled) {
- Slog.w(TAG, "Found available modes=" + Arrays.toString(availableModes)
+ Slog.w(TAG, "Found available modes=" + availableModes
+ " with lowest priority considered "
+ Vote.priorityToString(lowestConsideredPriority)
+ " and constraints: "
+ "width=" + primarySummary.width
+ ", height=" + primarySummary.height
+ ", minRefreshRate=" + primarySummary.minRefreshRate
- + ", maxRefreshRate=" + primarySummary.maxRefreshRate);
+ + ", maxRefreshRate=" + primarySummary.maxRefreshRate
+ + ", disableRefreshRateSwitching="
+ + primarySummary.disableRefreshRateSwitching
+ + ", baseModeRefreshRate=" + primarySummary.baseModeRefreshRate);
}
break;
}
@@ -307,7 +322,10 @@
+ "width=" + primarySummary.width
+ ", height=" + primarySummary.height
+ ", minRefreshRate=" + primarySummary.minRefreshRate
- + ", maxRefreshRate=" + primarySummary.maxRefreshRate);
+ + ", maxRefreshRate=" + primarySummary.maxRefreshRate
+ + ", disableRefreshRateSwitching="
+ + primarySummary.disableRefreshRateSwitching
+ + ", baseModeRefreshRate=" + primarySummary.baseModeRefreshRate);
}
// If we haven't found anything with the current set of votes, drop the
@@ -332,26 +350,38 @@
appRequestSummary.maxRefreshRate));
}
- int baseModeId = INVALID_DISPLAY_MODE_ID;
+ // Select the base mode id based on the base mode refresh rate, if available, since this
+ // will be the mode id the app voted for.
+ Display.Mode baseMode = null;
+ for (Display.Mode availableMode : availableModes) {
+ if (primarySummary.baseModeRefreshRate
+ >= availableMode.getRefreshRate() - FLOAT_TOLERANCE
+ && primarySummary.baseModeRefreshRate
+ <= availableMode.getRefreshRate() + FLOAT_TOLERANCE) {
+ baseMode = availableMode;
+ }
+ }
// Select the default mode if available. This is important because SurfaceFlinger
// can do only seamless switches by default. Some devices (e.g. TV) don't support
// seamless switching so the mode we select here won't be changed.
- for (int availableMode : availableModes) {
- if (availableMode == defaultMode.getModeId()) {
- baseModeId = defaultMode.getModeId();
- break;
+ if (baseMode == null) {
+ for (Display.Mode availableMode : availableModes) {
+ if (availableMode.getModeId() == defaultMode.getModeId()) {
+ baseMode = defaultMode;
+ break;
+ }
}
}
// If the application requests a display mode by setting
// LayoutParams.preferredDisplayModeId, it will be the only available mode and it'll
// be stored as baseModeId.
- if (baseModeId == INVALID_DISPLAY_MODE_ID && availableModes.length > 0) {
- baseModeId = availableModes[0];
+ if (baseMode == null && !availableModes.isEmpty()) {
+ baseMode = availableModes.get(0);
}
- if (baseModeId == INVALID_DISPLAY_MODE_ID) {
+ if (baseMode == null) {
Slog.w(TAG, "Can't find a set of allowed modes which satisfies the votes. Falling"
+ " back to the default mode. Display = " + displayId + ", votes = " + votes
+ ", supported modes = " + Arrays.toString(modes));
@@ -363,31 +393,19 @@
new RefreshRateRange(fps, fps));
}
- if (mModeSwitchingType == DisplayManager.SWITCHING_TYPE_NONE) {
- Display.Mode baseMode = null;
- for (Display.Mode mode : modes) {
- if (mode.getModeId() == baseModeId) {
- baseMode = mode;
- break;
- }
- }
- if (baseMode == null) {
- // This should never happen.
- throw new IllegalStateException(
- "The base mode with id " + baseModeId
- + " is not in the list of supported modes.");
- }
+ if (mModeSwitchingType == DisplayManager.SWITCHING_TYPE_NONE
+ || primarySummary.disableRefreshRateSwitching) {
float fps = baseMode.getRefreshRate();
- return new DesiredDisplayModeSpecs(baseModeId,
- /*allowGroupSwitching */ false,
- new RefreshRateRange(fps, fps),
- new RefreshRateRange(fps, fps));
+ primarySummary.minRefreshRate = primarySummary.maxRefreshRate = fps;
+ if (mModeSwitchingType == DisplayManager.SWITCHING_TYPE_NONE) {
+ appRequestSummary.minRefreshRate = appRequestSummary.maxRefreshRate = fps;
+ }
}
boolean allowGroupSwitching =
mModeSwitchingType == DisplayManager.SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS;
- return new DesiredDisplayModeSpecs(baseModeId,
+ return new DesiredDisplayModeSpecs(baseMode.getModeId(),
allowGroupSwitching,
new RefreshRateRange(
primarySummary.minRefreshRate, primarySummary.maxRefreshRate),
@@ -396,8 +414,10 @@
}
}
- private int[] filterModes(Display.Mode[] supportedModes, VoteSummary summary) {
+ private ArrayList<Display.Mode> filterModes(Display.Mode[] supportedModes,
+ VoteSummary summary) {
ArrayList<Display.Mode> availableModes = new ArrayList<>();
+ boolean missingBaseModeRefreshRate = summary.baseModeRefreshRate > 0f;
for (Display.Mode mode : supportedModes) {
if (mode.getPhysicalWidth() != summary.width
|| mode.getPhysicalHeight() != summary.height) {
@@ -426,13 +446,16 @@
continue;
}
availableModes.add(mode);
+ if (mode.getRefreshRate() >= summary.baseModeRefreshRate - FLOAT_TOLERANCE
+ && mode.getRefreshRate() <= summary.baseModeRefreshRate + FLOAT_TOLERANCE) {
+ missingBaseModeRefreshRate = false;
+ }
}
- final int size = availableModes.size();
- int[] availableModeIds = new int[size];
- for (int i = 0; i < size; i++) {
- availableModeIds[i] = availableModes.get(i).getModeId();
+ if (missingBaseModeRefreshRate) {
+ return new ArrayList<>();
}
- return availableModeIds;
+
+ return availableModes;
}
/**
@@ -912,37 +935,52 @@
// by all other considerations. It acts to set a default frame rate for a device.
public static final int PRIORITY_DEFAULT_REFRESH_RATE = 0;
- // FLICKER votes for a single refresh rate like [60,60], [90,90] or null.
- // If the higher voters result is a range, it will fix the rate to a single choice.
- // It's used to avoid refresh rate switches in certain conditions which may result in the
- // user seeing the display flickering when the switches occur.
- public static final int PRIORITY_FLICKER = 1;
+ // PRIORITY_FLICKER_REFRESH_RATE votes for a single refresh rate like [60,60], [90,90] or
+ // null. It is used to set a preferred refresh rate value in case the higher priority votes
+ // result is a range.
+ public static final int PRIORITY_FLICKER_REFRESH_RATE = 1;
// SETTING_MIN_REFRESH_RATE is used to propose a lower bound of display refresh rate.
// It votes [MIN_REFRESH_RATE, Float.POSITIVE_INFINITY]
public static final int PRIORITY_USER_SETTING_MIN_REFRESH_RATE = 2;
+ // APP_REQUEST_MAX_REFRESH_RATE is used to for internal apps to limit the refresh
+ // rate in certain cases, mostly to preserve power.
+ // It votes to [0, APP_REQUEST_MAX_REFRESH_RATE].
+ public static final int PRIORITY_APP_REQUEST_MAX_REFRESH_RATE = 3;
+
// We split the app request into different priorities in case we can satisfy one desire
// without the other.
// Application can specify preferred refresh rate with below attrs.
// @see android.view.WindowManager.LayoutParams#preferredRefreshRate
// @see android.view.WindowManager.LayoutParams#preferredDisplayModeId
- // System also forces some apps like denylisted app to run at a lower refresh rate.
+ // These translates into votes for the base mode refresh rate and resolution to be
+ // used by SurfaceFlinger as the policy of choosing the display mode. The system also
+ // forces some apps like denylisted app to run at a lower refresh rate.
// @see android.R.array#config_highRefreshRateBlacklist
- public static final int PRIORITY_APP_REQUEST_REFRESH_RATE = 3;
- public static final int PRIORITY_APP_REQUEST_SIZE = 4;
+ // The preferred refresh rate is set on the main surface of the app outside of
+ // DisplayModeDirector.
+ // @see com.android.server.wm.WindowState#updateFrameRateSelectionPriorityIfNeeded
+ public static final int PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE = 4;
+ public static final int PRIORITY_APP_REQUEST_SIZE = 5;
// SETTING_PEAK_REFRESH_RATE has a high priority and will restrict the bounds of the rest
// of low priority voters. It votes [0, max(PEAK, MIN)]
- public static final int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 5;
+ public static final int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 6;
// LOW_POWER_MODE force display to [0, 60HZ] if Settings.Global.LOW_POWER_MODE is on.
- public static final int PRIORITY_LOW_POWER_MODE = 6;
+ public static final int PRIORITY_LOW_POWER_MODE = 7;
+
+ // PRIORITY_FLICKER_REFRESH_RATE_SWITCH votes for disabling refresh rate switching. If the
+ // higher priority voters' result is a range, it will fix the rate to a single choice.
+ // It's used to avoid refresh rate switches in certain conditions which may result in the
+ // user seeing the display flickering when the switches occur.
+ public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8;
// The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
// to function, so this needs to be the highest priority of all votes.
- public static final int PRIORITY_UDFPS = 7;
+ public static final int PRIORITY_UDFPS = 9;
// Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
// APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
@@ -953,7 +991,7 @@
// The cutoff for the app request refresh rate range. Votes with priorities lower than this
// value will not be considered when constructing the app request refresh rate range.
public static final int APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF =
- PRIORITY_APP_REQUEST_REFRESH_RATE;
+ PRIORITY_APP_REQUEST_MAX_REFRESH_RATE;
/**
* A value signifying an invalid width or height in a vote.
@@ -973,32 +1011,64 @@
*/
public final RefreshRateRange refreshRateRange;
+ /**
+ * Whether refresh rate switching should be disabled (i.e. the refresh rate range is
+ * a single value).
+ */
+ public final boolean disableRefreshRateSwitching;
+
+ /**
+ * The base mode refresh rate to be used for this display. This would be used when deciding
+ * the base mode id.
+ */
+ public final float baseModeRefreshRate;
+
public static Vote forRefreshRates(float minRefreshRate, float maxRefreshRate) {
- return new Vote(INVALID_SIZE, INVALID_SIZE, minRefreshRate, maxRefreshRate);
+ return new Vote(INVALID_SIZE, INVALID_SIZE, minRefreshRate, maxRefreshRate,
+ minRefreshRate == maxRefreshRate, 0f);
}
public static Vote forSize(int width, int height) {
- return new Vote(width, height, 0f, Float.POSITIVE_INFINITY);
+ return new Vote(width, height, 0f, Float.POSITIVE_INFINITY, false,
+ 0f);
+ }
+
+ public static Vote forDisableRefreshRateSwitching() {
+ return new Vote(INVALID_SIZE, INVALID_SIZE, 0f, Float.POSITIVE_INFINITY, true,
+ 0f);
+ }
+
+ public static Vote forBaseModeRefreshRate(float baseModeRefreshRate) {
+ return new Vote(INVALID_SIZE, INVALID_SIZE, 0f, Float.POSITIVE_INFINITY, false,
+ baseModeRefreshRate);
}
private Vote(int width, int height,
- float minRefreshRate, float maxRefreshRate) {
+ float minRefreshRate, float maxRefreshRate,
+ boolean disableRefreshRateSwitching,
+ float baseModeRefreshRate) {
this.width = width;
this.height = height;
this.refreshRateRange =
new RefreshRateRange(minRefreshRate, maxRefreshRate);
+ this.disableRefreshRateSwitching = disableRefreshRateSwitching;
+ this.baseModeRefreshRate = baseModeRefreshRate;
}
public static String priorityToString(int priority) {
switch (priority) {
case PRIORITY_DEFAULT_REFRESH_RATE:
return "PRIORITY_DEFAULT_REFRESH_RATE";
- case PRIORITY_FLICKER:
- return "PRIORITY_FLICKER";
+ case PRIORITY_FLICKER_REFRESH_RATE:
+ return "PRIORITY_FLICKER_REFRESH_RATE";
+ case PRIORITY_FLICKER_REFRESH_RATE_SWITCH:
+ return "PRIORITY_FLICKER_REFRESH_RATE_SWITCH";
case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE";
- case PRIORITY_APP_REQUEST_REFRESH_RATE:
- return "PRIORITY_APP_REQUEST_REFRESH_RATE";
+ case PRIORITY_APP_REQUEST_MAX_REFRESH_RATE:
+ return "PRIORITY_APP_REQUEST_MAX_REFRESH_RATE";
+ case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE:
+ return "PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE";
case PRIORITY_APP_REQUEST_SIZE:
return "PRIORITY_APP_REQUEST_SIZE";
case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE:
@@ -1018,7 +1088,9 @@
return "Vote{"
+ "width=" + width + ", height=" + height
+ ", minRefreshRate=" + refreshRateRange.min
- + ", maxRefreshRate=" + refreshRateRange.max + "}";
+ + ", maxRefreshRate=" + refreshRateRange.max
+ + ", disableRefreshRateSwitching=" + disableRefreshRateSwitching
+ + ", baseModeRefreshRate=" + baseModeRefreshRate + "}";
}
}
@@ -1182,14 +1254,17 @@
final class AppRequestObserver {
private final SparseArray<Display.Mode> mAppRequestedModeByDisplay;
+ private final SparseArray<Float> mAppPreferredMaxRefreshRateByDisplay;
AppRequestObserver() {
mAppRequestedModeByDisplay = new SparseArray<>();
+ mAppPreferredMaxRefreshRateByDisplay = new SparseArray<>();
}
- public void setAppRequestedMode(int displayId, int modeId) {
+ public void setAppRequest(int displayId, int modeId, float requestedMaxRefreshRate) {
synchronized (mLock) {
setAppRequestedModeLocked(displayId, modeId);
+ setAppPreferredMaxRefreshRateLocked(displayId, requestedMaxRefreshRate);
}
}
@@ -1199,24 +1274,48 @@
return;
}
- final Vote refreshRateVote;
+ final Vote baseModeRefreshRateVote;
final Vote sizeVote;
if (requestedMode != null) {
mAppRequestedModeByDisplay.put(displayId, requestedMode);
- float refreshRate = requestedMode.getRefreshRate();
- refreshRateVote = Vote.forRefreshRates(refreshRate, refreshRate);
+ baseModeRefreshRateVote =
+ Vote.forBaseModeRefreshRate(requestedMode.getRefreshRate());
sizeVote = Vote.forSize(requestedMode.getPhysicalWidth(),
requestedMode.getPhysicalHeight());
} else {
mAppRequestedModeByDisplay.remove(displayId);
- refreshRateVote = null;
+ baseModeRefreshRateVote = null;
sizeVote = null;
}
- updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, refreshRateVote);
+ updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ baseModeRefreshRateVote);
updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_SIZE, sizeVote);
}
+ private void setAppPreferredMaxRefreshRateLocked(int displayId,
+ float requestedMaxRefreshRate) {
+ final Vote vote;
+ final Float requestedMaxRefreshRateVote =
+ requestedMaxRefreshRate > 0
+ ? new Float(requestedMaxRefreshRate) : null;
+ if (Objects.equals(requestedMaxRefreshRateVote,
+ mAppPreferredMaxRefreshRateByDisplay.get(displayId))) {
+ return;
+ }
+
+ if (requestedMaxRefreshRate > 0) {
+ mAppPreferredMaxRefreshRateByDisplay.put(displayId, requestedMaxRefreshRateVote);
+ vote = Vote.forRefreshRates(0, requestedMaxRefreshRate);
+ } else {
+ mAppPreferredMaxRefreshRateByDisplay.remove(displayId);
+ vote = null;
+ }
+ synchronized (mLock) {
+ updateVoteLocked(displayId, Vote.PRIORITY_APP_REQUEST_MAX_REFRESH_RATE, vote);
+ }
+ }
+
private Display.Mode findModeByIdLocked(int displayId, int modeId) {
Display.Mode[] modes = mSupportedModesByDisplay.get(displayId);
if (modes == null) {
@@ -1238,6 +1337,12 @@
final Display.Mode mode = mAppRequestedModeByDisplay.valueAt(i);
pw.println(" " + id + " -> " + mode);
}
+ pw.println(" mAppPreferredMaxRefreshRateByDisplay:");
+ for (int i = 0; i < mAppPreferredMaxRefreshRateByDisplay.size(); i++) {
+ final int id = mAppPreferredMaxRefreshRateByDisplay.keyAt(i);
+ final Float refreshRate = mAppPreferredMaxRefreshRateByDisplay.valueAt(i);
+ pw.println(" " + id + " -> " + refreshRate);
+ }
}
}
@@ -1486,7 +1591,8 @@
updateSensorStatus();
if (!changeable) {
// Revoke previous vote from BrightnessObserver
- updateVoteLocked(Vote.PRIORITY_FLICKER, null);
+ updateVoteLocked(Vote.PRIORITY_FLICKER_REFRESH_RATE, null);
+ updateVoteLocked(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, null);
}
}
}
@@ -1734,7 +1840,8 @@
return false;
}
private void onBrightnessChangedLocked() {
- Vote vote = null;
+ Vote refreshRateVote = null;
+ Vote refreshRateSwitchingVote = null;
if (mBrightness < 0) {
// Either the setting isn't available or we shouldn't be observing yet anyways.
@@ -1744,20 +1851,25 @@
boolean insideLowZone = hasValidLowZone() && isInsideLowZone(mBrightness, mAmbientLux);
if (insideLowZone) {
- vote = Vote.forRefreshRates(mRefreshRateInLowZone, mRefreshRateInLowZone);
+ refreshRateVote =
+ Vote.forRefreshRates(mRefreshRateInLowZone, mRefreshRateInLowZone);
+ refreshRateSwitchingVote = Vote.forDisableRefreshRateSwitching();
}
boolean insideHighZone = hasValidHighZone()
&& isInsideHighZone(mBrightness, mAmbientLux);
if (insideHighZone) {
- vote = Vote.forRefreshRates(mRefreshRateInHighZone, mRefreshRateInHighZone);
+ refreshRateVote =
+ Vote.forRefreshRates(mRefreshRateInHighZone, mRefreshRateInHighZone);
+ refreshRateSwitchingVote = Vote.forDisableRefreshRateSwitching();
}
if (mLoggingEnabled) {
Slog.d(TAG, "Display brightness " + mBrightness + ", ambient lux " + mAmbientLux
- + ", Vote " + vote);
+ + ", Vote " + refreshRateVote);
}
- updateVoteLocked(Vote.PRIORITY_FLICKER, vote);
+ updateVoteLocked(Vote.PRIORITY_FLICKER_REFRESH_RATE, refreshRateVote);
+ updateVoteLocked(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, refreshRateSwitchingVote);
}
private boolean hasValidLowZone() {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 8800a9e..91f75e5 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -901,6 +901,14 @@
&& preferredModeId != 0) {
mTmpApplySurfaceChangesTransactionState.preferredModeId = preferredModeId;
}
+
+ final float preferredMaxRefreshRate = getDisplayPolicy().getRefreshRatePolicy()
+ .getPreferredMaxRefreshRate(w);
+ if (mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate == 0
+ && preferredMaxRefreshRate != 0) {
+ mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate =
+ preferredMaxRefreshRate;
+ }
}
}
@@ -4230,6 +4238,7 @@
mLastHasContent,
mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,
mTmpApplySurfaceChangesTransactionState.preferredModeId,
+ mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate,
mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
true /* inTraversal, must call performTraversalInTrans... below */);
}
@@ -4513,12 +4522,13 @@
}
private static final class ApplySurfaceChangesTransactionState {
- boolean displayHasContent;
- boolean obscured;
- boolean syswin;
- boolean preferMinimalPostProcessing;
- float preferredRefreshRate;
- int preferredModeId;
+ public boolean displayHasContent;
+ public boolean obscured;
+ public boolean syswin;
+ public boolean preferMinimalPostProcessing;
+ public float preferredRefreshRate;
+ public int preferredModeId;
+ public float preferredMaxRefreshRate;
void reset() {
displayHasContent = false;
@@ -4527,6 +4537,7 @@
preferMinimalPostProcessing = false;
preferredRefreshRate = 0;
preferredModeId = 0;
+ preferredMaxRefreshRate = 0;
}
}
diff --git a/services/core/java/com/android/server/wm/RefreshRatePolicy.java b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
index 26871d1..deaf611 100644
--- a/services/core/java/com/android/server/wm/RefreshRatePolicy.java
+++ b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
@@ -20,6 +20,7 @@
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import android.util.ArraySet;
+import android.view.Display;
import android.view.Display.Mode;
import android.view.DisplayInfo;
@@ -95,18 +96,10 @@
return 0;
}
- // If app requests a certain refresh rate or mode, don't override it.
if (w.mAttrs.preferredRefreshRate != 0 || w.mAttrs.preferredDisplayModeId != 0) {
return w.mAttrs.preferredDisplayModeId;
}
- final String packageName = w.getOwningPackage();
-
- // If app is using Camera, force it to default (lower) refresh rate.
- if (mNonHighRefreshRatePackages.contains(packageName)) {
- return mLowRefreshRateMode.getModeId();
- }
-
return 0;
}
@@ -145,6 +138,44 @@
if (mHighRefreshRateDenylist.isDenylisted(packageName)) {
return mLowRefreshRateMode.getRefreshRate();
}
+
+ final int preferredModeId = getPreferredModeId(w);
+ if (preferredModeId > 0) {
+ DisplayInfo info = w.getDisplayInfo();
+ if (info != null) {
+ for (Display.Mode mode : info.supportedModes) {
+ if (preferredModeId == mode.getModeId()) {
+ return mode.getRefreshRate();
+ }
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ float getPreferredMaxRefreshRate(WindowState w) {
+ // If app is animating, it's not able to control refresh rate because we want the animation
+ // to run in default refresh rate.
+ if (w.isAnimating(TRANSITION | PARENTS)) {
+ return 0;
+ }
+
+ // If app requests a certain refresh rate or mode, don't override it.
+ if (w.mAttrs.preferredDisplayModeId != 0) {
+ return 0;
+ }
+
+ if (w.mAttrs.preferredMaxDisplayRefreshRate > 0) {
+ return w.mAttrs.preferredMaxDisplayRefreshRate;
+ }
+
+ final String packageName = w.getOwningPackage();
+ // If app is using Camera, force it to default (lower) refresh rate.
+ if (mNonHighRefreshRatePackages.contains(packageName)) {
+ return mLowRefreshRateMode.getRefreshRate();
+ }
+
return 0;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b121bfc..4eff18c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -751,11 +751,11 @@
int mFrameRateSelectionPriority = RefreshRatePolicy.LAYER_PRIORITY_UNSET;
/**
- * This is the frame rate which is passed to SurfaceFlinger if the window is part of the
- * high refresh rate deny list. The variable is cached, so we do not send too many updates to
- * SF.
+ * This is the frame rate which is passed to SurfaceFlinger if the window set a
+ * preferredDisplayModeId or is part of the high refresh rate deny list.
+ * The variable is cached, so we do not send too many updates to SF.
*/
- float mDenyListFrameRate = 0f;
+ float mAppPreferredFrameRate = 0f;
static final int BLAST_TIMEOUT_DURATION = 5000; /* milliseconds */
@@ -5416,10 +5416,11 @@
}
final float refreshRate = refreshRatePolicy.getPreferredRefreshRate(this);
- if (mDenyListFrameRate != refreshRate) {
- mDenyListFrameRate = refreshRate;
+ if (mAppPreferredFrameRate != refreshRate) {
+ mAppPreferredFrameRate = refreshRate;
getPendingTransaction().setFrameRate(
- mSurfaceControl, mDenyListFrameRate, Surface.FRAME_RATE_COMPATIBILITY_EXACT);
+ mSurfaceControl, mAppPreferredFrameRate,
+ Surface.FRAME_RATE_COMPATIBILITY_EXACT, Surface.CHANGE_FRAME_RATE_ALWAYS);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index cda659f..fb2db22 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -23,10 +23,11 @@
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE;
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE;
-import static com.android.server.display.DisplayModeDirector.Vote.PRIORITY_FLICKER;
+import static com.android.server.display.DisplayModeDirector.Vote.INVALID_SIZE;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -137,7 +138,14 @@
}
}
assertThat(defaultMode).isNotNull();
+ return createDirectorFromModeArray(modes, defaultMode);
+ }
+ private DisplayModeDirector createDirectorFromModeArray(Display.Mode[] modes,
+ Display.Mode defaultMode) {
+ DisplayModeDirector director =
+ new DisplayModeDirector(mContext, mHandler, mInjector);
+ director.setLoggingEnabled(true);
SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>();
supportedModesByDisplay.put(DISPLAY_ID, modes);
director.injectSupportedModesByDisplay(supportedModesByDisplay);
@@ -218,8 +226,9 @@
votesByDisplay.put(DISPLAY_ID, votes);
float error = FLOAT_TOLERANCE / 4;
votes.put(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, Vote.forRefreshRates(0, 60));
- votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forRefreshRates(60 + error, 60 + error));
- votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE,
+ votes.put(Vote.PRIORITY_APP_REQUEST_SIZE,
+ Vote.forRefreshRates(60 + error, 60 + error));
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
Vote.forRefreshRates(60 - error, 60 - error));
director.injectVotesByDisplay(votesByDisplay);
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
@@ -230,44 +239,159 @@
}
@Test
- public void testFlickerHasLowerPriorityThanUser() {
- assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_REFRESH_RATE);
- assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_SIZE);
+ public void testFlickerHasLowerPriorityThanUserAndRangeIsSingle() {
+ assertTrue(Vote.PRIORITY_FLICKER_REFRESH_RATE
+ < Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE);
+ assertTrue(Vote.PRIORITY_FLICKER_REFRESH_RATE
+ < Vote.PRIORITY_APP_REQUEST_SIZE);
- DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
+ assertTrue(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH
+ > Vote.PRIORITY_LOW_POWER_MODE);
+
+ Display.Mode[] modes = new Display.Mode[4];
+ modes[0] = new Display.Mode(
+ /*modeId=*/1, /*width=*/1000, /*height=*/1000, 60);
+ modes[1] = new Display.Mode(
+ /*modeId=*/2, /*width=*/2000, /*height=*/2000, 60);
+ modes[2] = new Display.Mode(
+ /*modeId=*/3, /*width=*/1000, /*height=*/1000, 90);
+ modes[3] = new Display.Mode(
+ /*modeId=*/4, /*width=*/2000, /*height=*/2000, 90);
+
+ DisplayModeDirector director = createDirectorFromModeArray(modes, modes[0]);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(DISPLAY_ID, votes);
- votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
- votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
+ Display.Mode appRequestedMode = modes[1];
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(appRequestedMode.getRefreshRate()));
+ votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forSize(appRequestedMode.getPhysicalWidth(),
+ appRequestedMode.getPhysicalHeight()));
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE, Vote.forRefreshRates(60, 60));
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, Vote.forDisableRefreshRateSwitching());
director.injectVotesByDisplay(votesByDisplay);
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(2);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max)
+ .isWithin(FLOAT_TOLERANCE).of(desiredSpecs.primaryRefreshRateRange.min);
+
+ votes.clear();
+ appRequestedMode = modes[3];
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(appRequestedMode.getRefreshRate()));
+ votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forSize(appRequestedMode.getPhysicalWidth(),
+ appRequestedMode.getPhysicalHeight()));
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE, Vote.forRefreshRates(90, 90));
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, Vote.forDisableRefreshRateSwitching());
+ director.injectVotesByDisplay(votesByDisplay);
+ desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(4);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max)
+ .isWithin(FLOAT_TOLERANCE).of(desiredSpecs.primaryRefreshRateRange.min);
+
+ votes.clear();
+ appRequestedMode = modes[3];
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(appRequestedMode.getRefreshRate()));
+ votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forSize(appRequestedMode.getPhysicalWidth(),
+ appRequestedMode.getPhysicalHeight()));
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE, Vote.forRefreshRates(60, 60));
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, Vote.forDisableRefreshRateSwitching());
+ director.injectVotesByDisplay(votesByDisplay);
+ desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(4);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max)
+ .isWithin(FLOAT_TOLERANCE).of(desiredSpecs.primaryRefreshRateRange.min);
+
+ votes.clear();
+ appRequestedMode = modes[1];
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(appRequestedMode.getRefreshRate()));
+ votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forSize(appRequestedMode.getPhysicalWidth(),
+ appRequestedMode.getPhysicalHeight()));
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE, Vote.forRefreshRates(90, 90));
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, Vote.forDisableRefreshRateSwitching());
+ director.injectVotesByDisplay(votesByDisplay);
+ desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(2);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max)
+ .isWithin(FLOAT_TOLERANCE).of(desiredSpecs.primaryRefreshRateRange.min);
+ }
+
+ @Test
+ public void testLPMHasHigherPriorityThanUser() {
+ assertTrue(Vote.PRIORITY_LOW_POWER_MODE > Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE);
+ assertTrue(Vote.PRIORITY_LOW_POWER_MODE > Vote.PRIORITY_APP_REQUEST_SIZE);
+
+
+ Display.Mode[] modes = new Display.Mode[4];
+ modes[0] = new Display.Mode(
+ /*modeId=*/1, /*width=*/1000, /*height=*/1000, 60);
+ modes[1] = new Display.Mode(
+ /*modeId=*/2, /*width=*/2000, /*height=*/2000, 60);
+ modes[2] = new Display.Mode(
+ /*modeId=*/3, /*width=*/1000, /*height=*/1000, 90);
+ modes[3] = new Display.Mode(
+ /*modeId=*/4, /*width=*/2000, /*height=*/2000, 90);
+
+ DisplayModeDirector director = createDirectorFromModeArray(modes, modes[0]);
+ SparseArray<Vote> votes = new SparseArray<>();
+ SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
+ votesByDisplay.put(DISPLAY_ID, votes);
+ Display.Mode appRequestedMode = modes[1];
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(appRequestedMode.getRefreshRate()));
+ votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forSize(appRequestedMode.getPhysicalWidth(),
+ appRequestedMode.getPhysicalHeight()));
+ votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRefreshRates(60, 60));
+ director.injectVotesByDisplay(votesByDisplay);
+ DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(2);
assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
votes.clear();
- votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
- votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90));
+ appRequestedMode = modes[3];
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(appRequestedMode.getRefreshRate()));
+ votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forSize(appRequestedMode.getPhysicalWidth(),
+ appRequestedMode.getPhysicalHeight()));
+ votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRefreshRates(90, 90));
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(4);
assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
votes.clear();
- votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90));
- votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
+ appRequestedMode = modes[3];
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(appRequestedMode.getRefreshRate()));
+ votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forSize(appRequestedMode.getPhysicalWidth(),
+ appRequestedMode.getPhysicalHeight()));
+ votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRefreshRates(60, 60));
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
- assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
- assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
-
- votes.clear();
- votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 60));
- votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90));
- director.injectVotesByDisplay(votesByDisplay);
- desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(2);
assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+
+ votes.clear();
+ appRequestedMode = modes[1];
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(appRequestedMode.getRefreshRate()));
+ votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forSize(appRequestedMode.getPhysicalWidth(),
+ appRequestedMode.getPhysicalHeight()));
+ votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRefreshRates(90, 90));
+ director.injectVotesByDisplay(votesByDisplay);
+ desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(4);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
}
@Test
@@ -275,19 +399,30 @@
// Confirm that the app request range doesn't include flicker or min refresh rate settings,
// but does include everything else.
assertTrue(
- PRIORITY_FLICKER < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
+ Vote.PRIORITY_FLICKER_REFRESH_RATE
+ < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
assertTrue(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE
< Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
- assertTrue(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE
+ assertTrue(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE
>= Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
- DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
+ Display.Mode[] modes = new Display.Mode[3];
+ modes[0] = new Display.Mode(
+ /*modeId=*/60, /*width=*/1000, /*height=*/1000, 60);
+ modes[1] = new Display.Mode(
+ /*modeId=*/75, /*width=*/2000, /*height=*/2000, 75);
+ modes[2] = new Display.Mode(
+ /*modeId=*/90, /*width=*/1000, /*height=*/1000, 90);
+
+ DisplayModeDirector director = createDirectorFromModeArray(modes, modes[0]);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(DISPLAY_ID, votes);
- votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE, Vote.forRefreshRates(60, 60));
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, Vote.forDisableRefreshRateSwitching());
director.injectVotesByDisplay(votesByDisplay);
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(60);
assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(desiredSpecs.appRequestRefreshRateRange.min).isAtMost(60f);
@@ -297,22 +432,24 @@
Vote.forRefreshRates(90, Float.POSITIVE_INFINITY));
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(90);
assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
assertThat(desiredSpecs.primaryRefreshRateRange.max).isAtLeast(90f);
assertThat(desiredSpecs.appRequestRefreshRateRange.min).isAtMost(60f);
assertThat(desiredSpecs.appRequestRefreshRateRange.max).isAtLeast(90f);
- votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(75, 75));
+ Display.Mode appRequestedMode = modes[1];
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(appRequestedMode.getRefreshRate()));
+ votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forSize(appRequestedMode.getPhysicalWidth(),
+ appRequestedMode.getPhysicalHeight()));
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(75);
assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(75);
assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(75);
- assertThat(desiredSpecs.appRequestRefreshRateRange.min)
- .isWithin(FLOAT_TOLERANCE)
- .of(75);
- assertThat(desiredSpecs.appRequestRefreshRateRange.max)
- .isWithin(FLOAT_TOLERANCE)
- .of(75);
+ assertThat(desiredSpecs.appRequestRefreshRateRange.min).isAtMost(60f);
+ assertThat(desiredSpecs.appRequestRefreshRateRange.max).isAtLeast(90f);
}
void verifySpecsWithRefreshRateSettings(DisplayModeDirector director, float minFps,
@@ -374,18 +511,29 @@
@Test
public void testVotingWithAlwaysRespectAppRequest() {
- DisplayModeDirector director = createDirectorFromFpsRange(50, 90);
+ Display.Mode[] modes = new Display.Mode[3];
+ modes[0] = new Display.Mode(
+ /*modeId=*/50, /*width=*/1000, /*height=*/1000, 50);
+ modes[1] = new Display.Mode(
+ /*modeId=*/60, /*width=*/1000, /*height=*/1000, 60);
+ modes[2] = new Display.Mode(
+ /*modeId=*/90, /*width=*/1000, /*height=*/1000, 90);
+
+ DisplayModeDirector director = createDirectorFromModeArray(modes, modes[0]);
+
+
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(DISPLAY_ID, votes);
- votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(0, 60));
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE, Vote.forRefreshRates(0, 60));
votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE, Vote.forRefreshRates(60, 90));
- votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90));
+ Display.Mode appRequestedMode = modes[2];
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(appRequestedMode.getRefreshRate()));
votes.put(Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, Vote.forRefreshRates(60, 60));
votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRefreshRates(0, 60));
-
-
director.injectVotesByDisplay(votesByDisplay);
+
assertThat(director.shouldAlwaysRespectAppRequestedMode()).isFalse();
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
@@ -396,8 +544,8 @@
director.setShouldAlwaysRespectAppRequestedMode(true);
assertThat(director.shouldAlwaysRespectAppRequestedMode()).isTrue();
desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
- assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
- assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isAtMost(50);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max).isAtLeast(90);
assertThat(desiredSpecs.baseModeId).isEqualTo(90);
director.setShouldAlwaysRespectAppRequestedMode(false);
@@ -497,7 +645,8 @@
// Inject votes
SparseArray<Vote> votes = new SparseArray<>();
votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forSize(1920, 1080));
- votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(50, 50));
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(60));
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(DISPLAY_ID, votes);
director.injectVotesByDisplay(votesByDisplay);
@@ -592,14 +741,19 @@
// Sensor reads 20 lux,
listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 20 /*lux*/));
- Vote vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
+ Vote vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE);
assertVoteForRefreshRate(vote, 90 /*fps*/);
+ vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH);
+ assertThat(vote).isNotNull();
+ assertThat(vote.disableRefreshRateSwitching).isTrue();
setBrightness(125);
// Sensor reads 1000 lux,
listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 1000 /*lux*/));
- vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
+ vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE);
+ assertThat(vote).isNull();
+ vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH);
assertThat(vote).isNull();
}
@@ -635,15 +789,20 @@
// Sensor reads 2000 lux,
listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 2000));
- Vote vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
+ Vote vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE);
+ assertThat(vote).isNull();
+ vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH);
assertThat(vote).isNull();
setBrightness(255);
// Sensor reads 9000 lux,
listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 9000));
- vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
+ vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE);
assertVoteForRefreshRate(vote, 60 /*fps*/);
+ vote = director.getVote(Display.DEFAULT_DISPLAY, Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH);
+ assertThat(vote).isNotNull();
+ assertThat(vote.disableRefreshRateSwitching).isTrue();
}
@Test
@@ -724,6 +883,336 @@
assertNull(vote);
}
+ @Test
+ public void testAppRequestMaxRefreshRate() {
+ // Confirm that the app max request range doesn't include flicker or min refresh rate
+ // settings but does include everything else.
+ assertTrue(Vote.PRIORITY_APP_REQUEST_MAX_REFRESH_RATE
+ >= Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
+
+ Display.Mode[] modes = new Display.Mode[3];
+ modes[0] = new Display.Mode(
+ /*modeId=*/60, /*width=*/1000, /*height=*/1000, 60);
+ modes[1] = new Display.Mode(
+ /*modeId=*/75, /*width=*/1000, /*height=*/1000, 75);
+ modes[2] = new Display.Mode(
+ /*modeId=*/90, /*width=*/1000, /*height=*/1000, 90);
+
+ DisplayModeDirector director = createDirectorFromModeArray(modes, modes[1]);
+ SparseArray<Vote> votes = new SparseArray<>();
+ SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
+ votesByDisplay.put(DISPLAY_ID, votes);
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, Vote.forDisableRefreshRateSwitching());
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE, Vote.forRefreshRates(60, 60));
+ director.injectVotesByDisplay(votesByDisplay);
+ DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ assertThat(desiredSpecs.appRequestRefreshRateRange.min).isAtMost(60f);
+ assertThat(desiredSpecs.appRequestRefreshRateRange.max).isAtLeast(90f);
+
+ votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE,
+ Vote.forRefreshRates(90, Float.POSITIVE_INFINITY));
+ director.injectVotesByDisplay(votesByDisplay);
+ desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max).isAtLeast(90f);
+ assertThat(desiredSpecs.appRequestRefreshRateRange.min).isAtMost(60f);
+ assertThat(desiredSpecs.appRequestRefreshRateRange.max).isAtLeast(90f);
+
+ votes.put(Vote.PRIORITY_APP_REQUEST_MAX_REFRESH_RATE, Vote.forRefreshRates(0, 75));
+ director.injectVotesByDisplay(votesByDisplay);
+ desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(75);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(75);
+ assertThat(desiredSpecs.appRequestRefreshRateRange.min).isZero();
+ assertThat(desiredSpecs.appRequestRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(75);
+ }
+
+ @Test
+ public void testAppRequestObserver_modeId() {
+ DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
+ director.getAppRequestObserver().setAppRequest(DISPLAY_ID, 60, 0);
+
+ Vote appRequestRefreshRate =
+ director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE);
+ assertNotNull(appRequestRefreshRate);
+ assertThat(appRequestRefreshRate.refreshRateRange.min).isZero();
+ assertThat(appRequestRefreshRate.refreshRateRange.max).isPositiveInfinity();
+ assertThat(appRequestRefreshRate.disableRefreshRateSwitching).isFalse();
+ assertThat(appRequestRefreshRate.baseModeRefreshRate).isWithin(FLOAT_TOLERANCE).of(60);
+ assertThat(appRequestRefreshRate.height).isEqualTo(INVALID_SIZE);
+ assertThat(appRequestRefreshRate.width).isEqualTo(INVALID_SIZE);
+
+ Vote appRequestSize = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_SIZE);
+ assertNotNull(appRequestSize);
+ assertThat(appRequestSize.refreshRateRange.min).isZero();
+ assertThat(appRequestSize.refreshRateRange.max).isPositiveInfinity();
+ assertThat(appRequestSize.disableRefreshRateSwitching).isFalse();
+ assertThat(appRequestSize.baseModeRefreshRate).isZero();
+ assertThat(appRequestSize.height).isEqualTo(1000);
+ assertThat(appRequestSize.width).isEqualTo(1000);
+
+ Vote appRequestMaxRefreshRate =
+ director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_MAX_REFRESH_RATE);
+ assertNull(appRequestMaxRefreshRate);
+
+ director.getAppRequestObserver().setAppRequest(DISPLAY_ID, 90, 0);
+
+ appRequestRefreshRate =
+ director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE);
+ assertNotNull(appRequestRefreshRate);
+ assertThat(appRequestRefreshRate.refreshRateRange.min).isZero();
+ assertThat(appRequestRefreshRate.refreshRateRange.max).isPositiveInfinity();
+ assertThat(appRequestRefreshRate.disableRefreshRateSwitching).isFalse();
+ assertThat(appRequestRefreshRate.baseModeRefreshRate).isWithin(FLOAT_TOLERANCE).of(90);
+ assertThat(appRequestRefreshRate.height).isEqualTo(INVALID_SIZE);
+ assertThat(appRequestRefreshRate.width).isEqualTo(INVALID_SIZE);
+
+ appRequestSize = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_SIZE);
+ assertNotNull(appRequestSize);
+ assertThat(appRequestSize.refreshRateRange.min).isZero();
+ assertThat(appRequestSize.refreshRateRange.max).isPositiveInfinity();
+ assertThat(appRequestSize.height).isEqualTo(1000);
+ assertThat(appRequestSize.width).isEqualTo(1000);
+
+ appRequestMaxRefreshRate =
+ director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_MAX_REFRESH_RATE);
+ assertNull(appRequestMaxRefreshRate);
+ }
+
+ @Test
+ public void testAppRequestObserver_maxRefreshRate() {
+ DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
+ director.getAppRequestObserver().setAppRequest(DISPLAY_ID, -1, 90);
+ Vote appRequestRefreshRate =
+ director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE);
+ assertNull(appRequestRefreshRate);
+
+ Vote appRequestSize = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_SIZE);
+ assertNull(appRequestSize);
+
+ Vote appRequestMaxRefreshRate =
+ director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_MAX_REFRESH_RATE);
+ assertNotNull(appRequestMaxRefreshRate);
+ assertThat(appRequestMaxRefreshRate.refreshRateRange.min).isZero();
+ assertThat(appRequestMaxRefreshRate.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
+ assertThat(appRequestMaxRefreshRate.height).isEqualTo(INVALID_SIZE);
+ assertThat(appRequestMaxRefreshRate.width).isEqualTo(INVALID_SIZE);
+
+ director.getAppRequestObserver().setAppRequest(DISPLAY_ID, -1, 60);
+ appRequestRefreshRate =
+ director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE);
+ assertNull(appRequestRefreshRate);
+
+ appRequestSize = director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_SIZE);
+ assertNull(appRequestSize);
+
+ appRequestMaxRefreshRate =
+ director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_MAX_REFRESH_RATE);
+ assertNotNull(appRequestMaxRefreshRate);
+ assertThat(appRequestMaxRefreshRate.refreshRateRange.min).isZero();
+ assertThat(appRequestMaxRefreshRate.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ assertThat(appRequestMaxRefreshRate.height).isEqualTo(INVALID_SIZE);
+ assertThat(appRequestMaxRefreshRate.width).isEqualTo(INVALID_SIZE);
+ }
+
+ @Test
+ public void testAppRequestObserver_modeIdAndMaxRefreshRate() {
+ DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
+ director.getAppRequestObserver().setAppRequest(DISPLAY_ID, 60, 90);
+
+ Vote appRequestRefreshRate =
+ director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE);
+ assertNotNull(appRequestRefreshRate);
+ assertThat(appRequestRefreshRate.refreshRateRange.min).isZero();
+ assertThat(appRequestRefreshRate.refreshRateRange.max).isPositiveInfinity();
+ assertThat(appRequestRefreshRate.disableRefreshRateSwitching).isFalse();
+ assertThat(appRequestRefreshRate.baseModeRefreshRate).isWithin(FLOAT_TOLERANCE).of(60);
+ assertThat(appRequestRefreshRate.height).isEqualTo(INVALID_SIZE);
+ assertThat(appRequestRefreshRate.width).isEqualTo(INVALID_SIZE);
+
+ Vote appRequestSize =
+ director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_SIZE);
+ assertNotNull(appRequestSize);
+ assertThat(appRequestSize.refreshRateRange.min).isZero();
+ assertThat(appRequestSize.refreshRateRange.max).isPositiveInfinity();
+ assertThat(appRequestSize.height).isEqualTo(1000);
+ assertThat(appRequestSize.width).isEqualTo(1000);
+
+ Vote appRequestMaxRefreshRate =
+ director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_MAX_REFRESH_RATE);
+ assertNotNull(appRequestMaxRefreshRate);
+ assertThat(appRequestMaxRefreshRate.refreshRateRange.min).isZero();
+ assertThat(appRequestMaxRefreshRate.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
+ assertThat(appRequestMaxRefreshRate.height).isEqualTo(INVALID_SIZE);
+ assertThat(appRequestMaxRefreshRate.width).isEqualTo(INVALID_SIZE);
+ }
+
+ @Test
+ public void testAppRequestsIsTheDefaultMode() {
+ Display.Mode[] modes = new Display.Mode[2];
+ modes[0] = new Display.Mode(
+ /*modeId=*/1, /*width=*/1000, /*height=*/1000, 60);
+ modes[1] = new Display.Mode(
+ /*modeId=*/2, /*width=*/1000, /*height=*/1000, 90);
+
+ DisplayModeDirector director = createDirectorFromModeArray(modes, modes[0]);
+ DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(1);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isAtMost(60);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max).isAtLeast(90);
+
+ SparseArray<Vote> votes = new SparseArray<>();
+ SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
+ votesByDisplay.put(DISPLAY_ID, votes);
+ Display.Mode appRequestedMode = modes[1];
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(appRequestedMode.getRefreshRate()));
+ votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forSize(appRequestedMode.getPhysicalWidth(),
+ appRequestedMode.getPhysicalHeight()));
+ director.injectVotesByDisplay(votesByDisplay);
+ desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(2);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isAtMost(60);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max).isAtLeast(90);
+ }
+
+ @Test
+ public void testDisableRefreshRateSwitchingVote() {
+ DisplayModeDirector director = createDirectorFromFpsRange(50, 90);
+ SparseArray<Vote> votes = new SparseArray<>();
+ SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
+ votesByDisplay.put(DISPLAY_ID, votes);
+ votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE,
+ Vote.forRefreshRates(90, Float.POSITIVE_INFINITY));
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, Vote.forDisableRefreshRateSwitching());
+ votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRefreshRates(0, 60));
+ director.injectVotesByDisplay(votesByDisplay);
+ DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(50);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(50);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(50);
+
+ votes.clear();
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE,
+ Vote.forRefreshRates(70, Float.POSITIVE_INFINITY));
+ votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE,
+ Vote.forRefreshRates(80, Float.POSITIVE_INFINITY));
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, Vote.forDisableRefreshRateSwitching());
+ votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRefreshRates(0, 90));
+ desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(80);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(80);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(80);
+
+ votes.clear();
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE,
+ Vote.forRefreshRates(90, Float.POSITIVE_INFINITY));
+ votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE,
+ Vote.forRefreshRates(80, Float.POSITIVE_INFINITY));
+ votes.put(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH, Vote.forDisableRefreshRateSwitching());
+ votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRefreshRates(0, 90));
+ desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(90);
+ }
+
+ @Test
+ public void testBaseModeIdInPrimaryRange() {
+ DisplayModeDirector director = createDirectorFromFpsRange(50, 90);
+ SparseArray<Vote> votes = new SparseArray<>();
+ SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
+ votesByDisplay.put(DISPLAY_ID, votes);
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(70));
+ votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRefreshRates(0, 60));
+ director.injectVotesByDisplay(votesByDisplay);
+ DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(0);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(50);
+
+ votes.clear();
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(55));
+ votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRefreshRates(0, 60));
+ director.injectVotesByDisplay(votesByDisplay);
+ desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(0);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(55);
+
+ votes.clear();
+ votes.put(Vote.PRIORITY_APP_REQUEST_MAX_REFRESH_RATE, Vote.forRefreshRates(0, 52));
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(55));
+ votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRefreshRates(0, 60));
+ director.injectVotesByDisplay(votesByDisplay);
+ desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(0);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(55);
+
+ votes.clear();
+ votes.put(Vote.PRIORITY_APP_REQUEST_MAX_REFRESH_RATE, Vote.forRefreshRates(0, 58));
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(55));
+ votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRefreshRates(0, 60));
+ director.injectVotesByDisplay(votesByDisplay);
+ desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(0);
+ assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(58);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(55);
+ }
+
+ @Test
+ public void testStaleAppVote() {
+ Display.Mode[] modes = new Display.Mode[4];
+ modes[0] = new Display.Mode(
+ /*modeId=*/1, /*width=*/1000, /*height=*/1000, 60);
+ modes[1] = new Display.Mode(
+ /*modeId=*/2, /*width=*/2000, /*height=*/2000, 60);
+ modes[2] = new Display.Mode(
+ /*modeId=*/3, /*width=*/1000, /*height=*/1000, 90);
+ modes[3] = new Display.Mode(
+ /*modeId=*/4, /*width=*/2000, /*height=*/2000, 90);
+
+ DisplayModeDirector director = createDirectorFromModeArray(modes, modes[0]);
+ SparseArray<Vote> votes = new SparseArray<>();
+ SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
+ votesByDisplay.put(DISPLAY_ID, votes);
+ Display.Mode appRequestedMode = modes[3];
+ votes.put(Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(appRequestedMode.getRefreshRate()));
+ votes.put(Vote.PRIORITY_APP_REQUEST_SIZE, Vote.forSize(appRequestedMode.getPhysicalWidth(),
+ appRequestedMode.getPhysicalHeight()));
+ director.injectVotesByDisplay(votesByDisplay);
+ DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(4);
+
+ // Change mode Id's to simulate that a hotplug has occurred.
+ Display.Mode[] newModes = new Display.Mode[4];
+ newModes[0] = new Display.Mode(
+ /*modeId=*/5, /*width=*/1000, /*height=*/1000, 60);
+ newModes[1] = new Display.Mode(
+ /*modeId=*/6, /*width=*/2000, /*height=*/2000, 60);
+ newModes[2] = new Display.Mode(
+ /*modeId=*/7, /*width=*/1000, /*height=*/1000, 90);
+ newModes[3] = new Display.Mode(
+ /*modeId=*/8, /*width=*/2000, /*height=*/2000, 90);
+
+ SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>();
+ supportedModesByDisplay.put(DISPLAY_ID, newModes);
+ director.injectSupportedModesByDisplay(supportedModesByDisplay);
+ SparseArray<Display.Mode> defaultModesByDisplay = new SparseArray<>();
+ defaultModesByDisplay.put(DISPLAY_ID, newModes[0]);
+ director.injectDefaultModeByDisplay(defaultModesByDisplay);
+ desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(8);
+ }
+
private void assertVoteForRefreshRate(Vote vote, float refreshRate) {
assertThat(vote).isNotNull();
final DisplayModeDirector.RefreshRateRange expectedRange =
diff --git a/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java b/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java
index 325bca4..1ee646c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java
@@ -77,12 +77,12 @@
assertNotNull("Window state is created", appWindow);
assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
- assertEquals(appWindow.mDenyListFrameRate, 0, FLOAT_TOLERANCE);
+ assertEquals(appWindow.mAppPreferredFrameRate, 0, FLOAT_TOLERANCE);
appWindow.updateFrameRateSelectionPriorityIfNeeded();
// Priority doesn't change.
assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
- assertEquals(appWindow.mDenyListFrameRate, 0, FLOAT_TOLERANCE);
+ assertEquals(appWindow.mAppPreferredFrameRate, 0, FLOAT_TOLERANCE);
// Call the function a few times.
appWindow.updateFrameRateSelectionPriorityIfNeeded();
@@ -92,7 +92,7 @@
verify(appWindow.getPendingTransaction(), never()).setFrameRateSelectionPriority(
any(SurfaceControl.class), anyInt());
verify(appWindow.getPendingTransaction(), never()).setFrameRate(
- any(SurfaceControl.class), anyInt(), anyInt());
+ any(SurfaceControl.class), anyInt(), anyInt(), anyInt());
}
@Test
@@ -101,16 +101,16 @@
assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
assertEquals(appWindow.getDisplayContent().getDisplayPolicy().getRefreshRatePolicy()
.getPreferredModeId(appWindow), 0);
- assertEquals(appWindow.mDenyListFrameRate, 0, FLOAT_TOLERANCE);
+ assertEquals(appWindow.mAppPreferredFrameRate, 0, FLOAT_TOLERANCE);
assertEquals(appWindow.getDisplayContent().getDisplayPolicy().getRefreshRatePolicy()
.getPreferredRefreshRate(appWindow), 0, FLOAT_TOLERANCE);
- assertEquals(appWindow.mDenyListFrameRate, 0, FLOAT_TOLERANCE);
+ assertEquals(appWindow.mAppPreferredFrameRate, 0, FLOAT_TOLERANCE);
appWindow.updateFrameRateSelectionPriorityIfNeeded();
// Priority stays MAX_VALUE.
assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
- assertEquals(appWindow.mDenyListFrameRate, 0, FLOAT_TOLERANCE);
+ assertEquals(appWindow.mAppPreferredFrameRate, 0, FLOAT_TOLERANCE);
verify(appWindow.getPendingTransaction(), never()).setFrameRateSelectionPriority(
appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET);
@@ -119,38 +119,38 @@
appWindow.updateFrameRateSelectionPriorityIfNeeded();
// Priority changes to 1.
assertEquals(appWindow.mFrameRateSelectionPriority, 1);
- assertEquals(appWindow.mDenyListFrameRate, 0, FLOAT_TOLERANCE);
+ assertEquals(appWindow.mAppPreferredFrameRate, 0, FLOAT_TOLERANCE);
verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority(
appWindow.getSurfaceControl(), 1);
verify(appWindow.getPendingTransaction(), never()).setFrameRate(
- any(SurfaceControl.class), anyInt(), anyInt());
+ any(SurfaceControl.class), anyInt(), anyInt(), anyInt());
}
@Test
public void testApplicationInFocusWithModeId() {
final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
- assertEquals(appWindow.mDenyListFrameRate, 0, FLOAT_TOLERANCE);
+ assertEquals(appWindow.mAppPreferredFrameRate, 0, FLOAT_TOLERANCE);
// Application is in focus.
appWindow.mToken.mDisplayContent.mCurrentFocus = appWindow;
appWindow.updateFrameRateSelectionPriorityIfNeeded();
// Priority changes.
assertEquals(appWindow.mFrameRateSelectionPriority, 1);
- assertEquals(appWindow.mDenyListFrameRate, 0, FLOAT_TOLERANCE);
+ assertEquals(appWindow.mAppPreferredFrameRate, 0, FLOAT_TOLERANCE);
// Update the mode ID to a requested number.
appWindow.mAttrs.preferredDisplayModeId = 1;
appWindow.updateFrameRateSelectionPriorityIfNeeded();
// Priority changes.
assertEquals(appWindow.mFrameRateSelectionPriority, 0);
- assertEquals(appWindow.mDenyListFrameRate, 0, FLOAT_TOLERANCE);
+ assertEquals(appWindow.mAppPreferredFrameRate, 60, FLOAT_TOLERANCE);
// Remove the mode ID request.
appWindow.mAttrs.preferredDisplayModeId = 0;
appWindow.updateFrameRateSelectionPriorityIfNeeded();
// Priority changes.
assertEquals(appWindow.mFrameRateSelectionPriority, 1);
- assertEquals(appWindow.mDenyListFrameRate, 0, FLOAT_TOLERANCE);
+ assertEquals(appWindow.mAppPreferredFrameRate, 0, FLOAT_TOLERANCE);
// Verify we called actions on Transactions correctly.
verify(appWindow.getPendingTransaction(), never()).setFrameRateSelectionPriority(
@@ -160,14 +160,14 @@
verify(appWindow.getPendingTransaction(), times(2)).setFrameRateSelectionPriority(
appWindow.getSurfaceControl(), 1);
verify(appWindow.getPendingTransaction(), never()).setFrameRate(
- any(SurfaceControl.class), anyInt(), anyInt());
+ any(SurfaceControl.class), anyInt(), anyInt(), anyInt());
}
@Test
public void testApplicationNotInFocusWithModeId() {
final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
- assertEquals(appWindow.mDenyListFrameRate, 0, FLOAT_TOLERANCE);
+ assertEquals(appWindow.mAppPreferredFrameRate, 0, FLOAT_TOLERANCE);
final WindowState inFocusWindow = createWindow(null, TYPE_APPLICATION, "inFocus");
appWindow.mToken.mDisplayContent.mCurrentFocus = inFocusWindow;
@@ -175,28 +175,28 @@
appWindow.updateFrameRateSelectionPriorityIfNeeded();
// The window is not in focus.
assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
- assertEquals(appWindow.mDenyListFrameRate, 0, FLOAT_TOLERANCE);
+ assertEquals(appWindow.mAppPreferredFrameRate, 0, FLOAT_TOLERANCE);
// Update the mode ID to a requested number.
appWindow.mAttrs.preferredDisplayModeId = 1;
appWindow.updateFrameRateSelectionPriorityIfNeeded();
// Priority changes.
assertEquals(appWindow.mFrameRateSelectionPriority, 2);
- assertEquals(appWindow.mDenyListFrameRate, 0, FLOAT_TOLERANCE);
+ assertEquals(appWindow.mAppPreferredFrameRate, 60, FLOAT_TOLERANCE);
verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority(
appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET);
verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority(
appWindow.getSurfaceControl(), 2);
verify(appWindow.getPendingTransaction(), never()).setFrameRate(
- any(SurfaceControl.class), anyInt(), anyInt());
+ any(SurfaceControl.class), anyInt(), anyInt(), anyInt());
}
@Test
public void testApplicationNotInFocusWithoutModeId() {
final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
- assertEquals(appWindow.mDenyListFrameRate, 0, FLOAT_TOLERANCE);
+ assertEquals(appWindow.mAppPreferredFrameRate, 0, FLOAT_TOLERANCE);
final WindowState inFocusWindow = createWindow(null, TYPE_APPLICATION, "inFocus");
appWindow.mToken.mDisplayContent.mCurrentFocus = inFocusWindow;
@@ -204,19 +204,19 @@
appWindow.updateFrameRateSelectionPriorityIfNeeded();
// The window is not in focus.
assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
- assertEquals(appWindow.mDenyListFrameRate, 0, FLOAT_TOLERANCE);
+ assertEquals(appWindow.mAppPreferredFrameRate, 0, FLOAT_TOLERANCE);
// Make sure that the mode ID is not set.
appWindow.mAttrs.preferredDisplayModeId = 0;
appWindow.updateFrameRateSelectionPriorityIfNeeded();
// Priority doesn't change.
assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET);
- assertEquals(appWindow.mDenyListFrameRate, 0, FLOAT_TOLERANCE);
+ assertEquals(appWindow.mAppPreferredFrameRate, 0, FLOAT_TOLERANCE);
verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority(
appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET);
verify(appWindow.getPendingTransaction(), never()).setFrameRate(
- any(SurfaceControl.class), anyInt(), anyInt());
+ any(SurfaceControl.class), anyInt(), anyInt(), anyInt());
}
@Test
@@ -233,7 +233,7 @@
appWindow.updateFrameRateSelectionPriorityIfNeeded();
assertEquals(RefreshRatePolicy.LAYER_PRIORITY_UNSET, appWindow.mFrameRateSelectionPriority);
- assertEquals(60, appWindow.mDenyListFrameRate, FLOAT_TOLERANCE);
+ assertEquals(60, appWindow.mAppPreferredFrameRate, FLOAT_TOLERANCE);
// Call the function a few times.
appWindow.updateFrameRateSelectionPriorityIfNeeded();
@@ -243,6 +243,7 @@
verify(appWindow.getPendingTransaction(), never()).setFrameRateSelectionPriority(
any(SurfaceControl.class), anyInt());
verify(appWindow.getPendingTransaction(), times(1)).setFrameRate(
- appWindow.getSurfaceControl(), 60, Surface.FRAME_RATE_COMPATIBILITY_EXACT);
+ appWindow.getSurfaceControl(), 60,
+ Surface.FRAME_RATE_COMPATIBILITY_EXACT, Surface.CHANGE_FRAME_RATE_ALWAYS);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
index ef3c7ae..20b987d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
@@ -71,9 +71,11 @@
cameraUsingWindow.mAttrs.packageName = "com.android.test";
assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
mPolicy.addNonHighRefreshRatePackage("com.android.test");
- assertEquals(LOW_MODE_ID, mPolicy.getPreferredModeId(cameraUsingWindow));
+ assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(60, mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
mPolicy.removeNonHighRefreshRatePackage("com.android.test");
assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
@@ -109,6 +111,7 @@
mPolicy.addNonHighRefreshRatePackage("com.android.test");
assertEquals(LOW_MODE_ID, mPolicy.getPreferredModeId(overrideWindow));
assertEquals(0, mPolicy.getPreferredRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(overrideWindow), FLOAT_TOLERANCE);
}
@Test
@@ -123,6 +126,7 @@
mPolicy.addNonHighRefreshRatePackage("com.android.test");
assertEquals(0, mPolicy.getPreferredModeId(overrideWindow));
assertEquals(0, mPolicy.getPreferredRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(overrideWindow), FLOAT_TOLERANCE);
}
@Test
@@ -132,13 +136,31 @@
cameraUsingWindow.mAttrs.packageName = "com.android.test";
mPolicy.addNonHighRefreshRatePackage("com.android.test");
- assertEquals(LOW_MODE_ID, mPolicy.getPreferredModeId(cameraUsingWindow));
+ assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(60, mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
cameraUsingWindow.mActivityRecord.mSurfaceAnimator.startAnimation(
cameraUsingWindow.getPendingTransaction(), mock(AnimationAdapter.class),
false /* hidden */, ANIMATION_TYPE_APP_TRANSITION);
assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ }
+
+ @Test
+ public void testAppMaxRefreshRate() {
+ final WindowState window = createWindow(null, TYPE_BASE_APPLICATION, "window");
+ window.mAttrs.preferredMaxDisplayRefreshRate = 60f;
+ assertEquals(0, mPolicy.getPreferredModeId(window));
+ assertEquals(0, mPolicy.getPreferredRefreshRate(window), FLOAT_TOLERANCE);
+ assertEquals(60, mPolicy.getPreferredMaxRefreshRate(window), FLOAT_TOLERANCE);
+
+ window.mActivityRecord.mSurfaceAnimator.startAnimation(
+ window.getPendingTransaction(), mock(AnimationAdapter.class),
+ false /* hidden */, ANIMATION_TYPE_APP_TRANSITION);
+ assertEquals(0, mPolicy.getPreferredModeId(window));
+ assertEquals(0, mPolicy.getPreferredRefreshRate(window), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(window), FLOAT_TOLERANCE);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
index 619aee6..b89539c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -231,7 +231,7 @@
@Override
public SurfaceControl.Transaction setFrameRate(SurfaceControl sc, float frameRate,
- int compatibility) {
+ int compatibility, int changeFrameRateStrategy) {
return this;
}