Add preferredMaxDisplayRefreshRate

Add a new private window attribute for allowing apps to specify the max
display refresh rate. This is useful for use cases such as keyguard
where the refresh rate should be limited to preserve power.

In the next CLs the preferredDiplayModeId would be enabled for
frame rate override (60-on-120) and the preferredMaxDisplayRefreshRate
would be the alternative to control the display refresh rate (as opposed
to the frame rate experienced by the app).

Test: atest RefreshRatePolicyTest
Test: atest DisplayModeDirectorTest
Test: Launch camera app and observe refresh rate
Bug: 183226498
Change-Id: I1c5e9f6047cbea4bfb581251b8dd2b9058b3e378
This commit is contained in:
Ady Abraham
2021-04-14 13:32:23 -07:00
parent a91e5123fc
commit 26c834522b
9 changed files with 299 additions and 45 deletions

View File

@@ -190,6 +190,8 @@ public abstract class DisplayManagerInternal {
* 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 @@ public abstract class DisplayManagerInternal {
* 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.

View File

@@ -3009,6 +3009,14 @@ public interface WindowManager extends ViewManager {
*/
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}.

View File

@@ -61,7 +61,6 @@ import java.io.PrintWriter;
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 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
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 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
// 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 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
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 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
@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);

View File

@@ -1498,8 +1498,8 @@ public final class DisplayManagerService extends SystemService {
}
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 @@ public final class DisplayManagerService extends SystemService {
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 @@ public final class DisplayManagerService extends SystemService {
@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

View File

@@ -922,6 +922,11 @@ public class DisplayModeDirector {
// 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.
@@ -930,19 +935,19 @@ public class DisplayModeDirector {
// @see android.view.WindowManager.LayoutParams#preferredDisplayModeId
// 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;
public static final int PRIORITY_APP_REQUEST_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;
// 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 = 8;
// 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 +958,7 @@ public class DisplayModeDirector {
// 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.
@@ -997,6 +1002,8 @@ public class DisplayModeDirector {
return "PRIORITY_FLICKER";
case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE";
case PRIORITY_APP_REQUEST_MAX_REFRESH_RATE:
return "PRIORITY_APP_REQUEST_MAX_REFRESH_RATE";
case PRIORITY_APP_REQUEST_REFRESH_RATE:
return "PRIORITY_APP_REQUEST_REFRESH_RATE";
case PRIORITY_APP_REQUEST_SIZE:
@@ -1182,14 +1189,17 @@ public class DisplayModeDirector {
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);
}
}
@@ -1217,6 +1227,29 @@ public class DisplayModeDirector {
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 +1271,12 @@ public class DisplayModeDirector {
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);
}
}
}

View File

@@ -901,6 +901,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
&& preferredModeId != 0) {
mTmpApplySurfaceChangesTransactionState.preferredModeId = preferredModeId;
}
final float preferredMaxRefreshRate = getDisplayPolicy().getRefreshRatePolicy()
.getPreferredMaxRefreshRate(w);
if (mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate == 0
&& preferredMaxRefreshRate != 0) {
mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate =
preferredMaxRefreshRate;
}
}
}
@@ -4229,6 +4237,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mLastHasContent,
mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,
mTmpApplySurfaceChangesTransactionState.preferredModeId,
mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate,
mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
true /* inTraversal, must call performTraversalInTrans... below */);
}
@@ -4512,12 +4521,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
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;
@@ -4526,6 +4536,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
preferMinimalPostProcessing = false;
preferredRefreshRate = 0;
preferredModeId = 0;
preferredMaxRefreshRate = 0;
}
}

View File

@@ -95,18 +95,10 @@ class RefreshRatePolicy {
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;
}
@@ -147,4 +139,29 @@ class RefreshRatePolicy {
}
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 the app set a preferredDisplayModeId, we ignore the max preferred refresh rate
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;
}
}

View File

@@ -23,10 +23,12 @@ import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REF
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.INVALID_SIZE;
import static com.android.server.display.DisplayModeDirector.Vote.PRIORITY_FLICKER;
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;
@@ -724,6 +726,164 @@ public class DisplayModeDirectorTest {
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);
DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(DISPLAY_ID, votes);
votes.put(PRIORITY_FLICKER, 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);
// TODO(b/183226498): ideally the refresh rate range should be a single value since
// PRIORITY_FLICKER voted, however since PRIORITY_APP_REQUEST_MAX_REFRESH_RATE votes for
// range, PRIORITY_FLICKER is ignored. The same thing would happen with
// PRIORITY_LOW_POWER_MODE so this is not a regression. This will be fixed in a subsequent
// CL.
//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);
}
@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_REFRESH_RATE);
assertNotNull(appRequestRefreshRate);
assertThat(appRequestRefreshRate.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(appRequestRefreshRate.refreshRateRange.max).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);
assertNull(appRequestMaxRefreshRate);
director.getAppRequestObserver().setAppRequest(DISPLAY_ID, 90, 0);
appRequestRefreshRate =
director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_REFRESH_RATE);
assertNotNull(appRequestRefreshRate);
assertThat(appRequestRefreshRate.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
assertThat(appRequestRefreshRate.refreshRateRange.max).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_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_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_REFRESH_RATE);
assertNotNull(appRequestRefreshRate);
assertThat(appRequestRefreshRate.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
assertThat(appRequestRefreshRate.refreshRateRange.max).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);
}
private void assertVoteForRefreshRate(Vote vote, float refreshRate) {
assertThat(vote).isNotNull();
final DisplayModeDirector.RefreshRateRange expectedRange =

View File

@@ -71,9 +71,11 @@ public class RefreshRatePolicyTest extends WindowTestsBase {
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 @@ public class RefreshRatePolicyTest extends WindowTestsBase {
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 @@ public class RefreshRatePolicyTest extends WindowTestsBase {
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 @@ public class RefreshRatePolicyTest extends WindowTestsBase {
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);
}
}