diff --git a/api/test-current.txt b/api/test-current.txt
index de2919b8936a4..9e5fb33163f99 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -17,6 +17,7 @@ package android {
field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
field public static final String NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK";
+ field public static final String OVERRIDE_DISPLAY_MODE_REQUESTS = "android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS";
field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
@@ -1304,6 +1305,8 @@ package android.hardware.display {
method public android.graphics.Point getStableDisplaySize();
method public boolean isMinimalPostProcessingRequested(int);
method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
+ method @RequiresPermission(android.Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS) public void setShouldAlwaysRespectAppRequestedMode(boolean);
+ method @RequiresPermission(android.Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS) public boolean shouldAlwaysRespectAppRequestedMode();
field public static final int VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 512; // 0x200
field public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1024; // 0x400
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 392f56212058b..8f99edf61ece3 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -840,6 +840,30 @@ public final class DisplayManager {
return mGlobal.getMinimumBrightnessCurve();
}
+ /**
+ * When enabled the app requested mode is always selected regardless of user settings and
+ * policies for low brightness, low battery, etc.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS)
+ public void setShouldAlwaysRespectAppRequestedMode(boolean enabled) {
+ mGlobal.setShouldAlwaysRespectAppRequestedMode(enabled);
+ }
+
+ /**
+ * Returns whether we are running in a mode which always selects the app requested display mode
+ * and ignores user settings and policies for low brightness, low battery etc.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS)
+ public boolean shouldAlwaysRespectAppRequestedMode() {
+ return mGlobal.shouldAlwaysRespectAppRequestedMode();
+ }
+
/**
* Listens for changes in available display devices.
*/
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 0f9c7088a1d01..b046d1df5b8c1 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -699,6 +699,32 @@ public final class DisplayManagerGlobal {
}
}
+ /**
+ * When enabled the app requested display resolution and refresh rate is always selected
+ * in DisplayModeDirector regardless of user settings and policies for low brightness, low
+ * battery etc.
+ */
+ public void setShouldAlwaysRespectAppRequestedMode(boolean enabled) {
+ try {
+ mDm.setShouldAlwaysRespectAppRequestedMode(enabled);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether DisplayModeDirector is running in a mode which always selects the app
+ * requested display mode and ignores user settings and policies for low brightness, low
+ * battery etc.
+ */
+ public boolean shouldAlwaysRespectAppRequestedMode() {
+ try {
+ return mDm.shouldAlwaysRespectAppRequestedMode();
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
@Override
public void onDisplayEvent(int displayId, int event) {
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index c697106d0c171..85da6424377aa 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -128,4 +128,10 @@ interface IDisplayManager {
// The wide gamut color space is returned from composition pipeline
// based on hardware capability.
int getPreferredWideGamutColorSpaceId();
+
+ // When enabled the app requested display resolution and refresh rate is always selected
+ // in DisplayModeDirector regardless of user settings and policies for low brightness, low
+ // battery etc.
+ void setShouldAlwaysRespectAppRequestedMode(boolean enabled);
+ boolean shouldAlwaysRespectAppRequestedMode();
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 560e3c11d2f45..85dc92d7f252f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3910,6 +3910,14 @@
+
+
+
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 190015cebe302..f5f58efb72e6c 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -323,6 +323,9 @@
+
+
+
();
mSupportedModesByDisplay = new SparseArray<>();
- mDefaultModeByDisplay = new SparseArray<>();
+ mDefaultModeByDisplay = new SparseArray<>();
mAppRequestObserver = new AppRequestObserver();
mSettingsObserver = new SettingsObserver(context, handler);
mDisplayObserver = new DisplayObserver(context, handler);
mBrightnessObserver = new BrightnessObserver(context, handler);
mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
+ mAlwaysRespectAppRequest = false;
}
/**
@@ -127,7 +130,6 @@ public class DisplayModeDirector {
// notify them to pick up our newly initialized state.
notifyDesiredDisplayModeSpecsChangedLocked();
}
-
}
@NonNull
@@ -173,9 +175,14 @@ public class DisplayModeDirector {
// VoteSummary is returned as an output param to cut down a bit on the number of temporary
// objects.
private void summarizeVotes(
- SparseArray votes, int lowestConsideredPriority, /*out*/ VoteSummary summary) {
+ SparseArray votes,
+ int lowestConsideredPriority,
+ int highestConsideredPriority,
+ /*out*/ VoteSummary summary) {
summary.reset();
- for (int priority = Vote.MAX_PRIORITY; priority >= lowestConsideredPriority; priority--) {
+ for (int priority = highestConsideredPriority;
+ priority >= lowestConsideredPriority;
+ priority--) {
Vote vote = votes.get(priority);
if (vote == null) {
continue;
@@ -217,8 +224,16 @@ public class DisplayModeDirector {
int[] availableModes = new int[]{defaultMode.getModeId()};
VoteSummary primarySummary = new VoteSummary();
int lowestConsideredPriority = Vote.MIN_PRIORITY;
- while (lowestConsideredPriority <= Vote.MAX_PRIORITY) {
- summarizeVotes(votes, lowestConsideredPriority, primarySummary);
+ int highestConsideredPriority = Vote.MAX_PRIORITY;
+
+ if (mAlwaysRespectAppRequest) {
+ lowestConsideredPriority = Vote.PRIORITY_APP_REQUEST_REFRESH_RATE;
+ highestConsideredPriority = Vote.PRIORITY_APP_REQUEST_SIZE;
+ }
+
+ while (lowestConsideredPriority <= highestConsideredPriority) {
+ summarizeVotes(
+ votes, lowestConsideredPriority, highestConsideredPriority, primarySummary);
// If we don't have anything specifying the width / height of the display, just use
// the default width and height. We don't want these switching out from underneath
@@ -261,7 +276,10 @@ public class DisplayModeDirector {
VoteSummary appRequestSummary = new VoteSummary();
summarizeVotes(
- votes, Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, appRequestSummary);
+ votes,
+ Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF,
+ Vote.MAX_PRIORITY,
+ appRequestSummary);
appRequestSummary.minRefreshRate =
Math.min(appRequestSummary.minRefreshRate, primarySummary.minRefreshRate);
appRequestSummary.maxRefreshRate =
@@ -338,8 +356,7 @@ public class DisplayModeDirector {
}
/**
- * Sets the desiredDisplayModeSpecsListener for changes to display mode and refresh rate
- * ranges.
+ * Sets the desiredDisplayModeSpecsListener for changes to display mode and refresh rate ranges.
*/
public void setDesiredDisplayModeSpecsListener(
@Nullable DesiredDisplayModeSpecsListener desiredDisplayModeSpecsListener) {
@@ -348,6 +365,26 @@ public class DisplayModeDirector {
}
}
+ /**
+ * When enabled the app requested display mode is always selected and all
+ * other votes will be ignored. This is used for testing purposes.
+ */
+ public void setShouldAlwaysRespectAppRequestedMode(boolean enabled) {
+ synchronized (mLock) {
+ mAlwaysRespectAppRequest = enabled;
+ }
+ }
+
+ /**
+ * Returns whether we are running in a mode which always selects the app requested display mode
+ * and ignores user settings and policies for low brightness, low battery etc.
+ */
+ public boolean shouldAlwaysRespectAppRequestedMode() {
+ synchronized (mLock) {
+ return mAlwaysRespectAppRequest;
+ }
+ }
+
/**
* Print the object's state and debug information into the given stream.
*
@@ -380,6 +417,7 @@ public class DisplayModeDirector {
pw.println(" " + Vote.priorityToString(p) + " -> " + vote);
}
}
+ pw.println(" mAlwaysRespectAppRequest: " + mAlwaysRespectAppRequest);
mSettingsObserver.dumpLocked(pw);
mAppRequestObserver.dumpLocked(pw);
mBrightnessObserver.dumpLocked(pw);
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 43a396d8e5d7d..b8dbd6267bc51 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -302,4 +302,42 @@ public class DisplayModeDirectorTest {
verifyBrightnessObserverCall(director, 90, 90, 0, 90, 90);
verifyBrightnessObserverCall(director, 120, 90, 0, 120, 90);
}
+
+ @Test
+ public void testVotingWithAlwaysRespectAppRequest() {
+ final int displayId = 0;
+ DisplayModeDirector director = createDirectorFromFpsRange(50, 90);
+ SparseArray votes = new SparseArray<>();
+ SparseArray> votesByDisplay = new SparseArray<>();
+ votesByDisplay.put(displayId, votes);
+ votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, 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));
+ 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);
+ Truth.assertThat(director.shouldAlwaysRespectAppRequestedMode()).isFalse();
+ DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.baseModeId).isEqualTo(60);
+
+ director.setShouldAlwaysRespectAppRequestedMode(true);
+ Truth.assertThat(director.shouldAlwaysRespectAppRequestedMode()).isTrue();
+ desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
+ Truth.assertThat(desiredSpecs.baseModeId).isEqualTo(90);
+
+ director.setShouldAlwaysRespectAppRequestedMode(false);
+ Truth.assertThat(director.shouldAlwaysRespectAppRequestedMode()).isFalse();
+
+ desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.baseModeId).isEqualTo(60);
+ }
}