From 97ba024fb03838b814cfb921c35ad3f0ac0c9ff9 Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Mon, 7 Sep 2020 15:49:35 +0200 Subject: Add TestApi to always select the app requested display mode The added test API is used to ignore all votes in DisplayModeDirector app votes. This way only the app requested display mode will be picked. The API will be used for testing app mode switch requests. Bug: 159113268 Bug: 158316271 Test: m Change-Id: I257636ae2a6ed74044e71e49a99024682c3a92c5 --- api/test-current.txt | 3 ++ .../android/hardware/display/DisplayManager.java | 24 +++++++++ .../hardware/display/DisplayManagerGlobal.java | 26 ++++++++++ .../android/hardware/display/IDisplayManager.aidl | 6 +++ core/res/AndroidManifest.xml | 8 +++ packages/Shell/AndroidManifest.xml | 3 ++ .../server/display/DisplayManagerService.java | 35 +++++++++++++ .../server/display/DisplayModeDirector.java | 60 ++++++++++++++++++---- .../server/display/DisplayModeDirectorTest.java | 38 ++++++++++++++ 9 files changed, 192 insertions(+), 11 deletions(-) diff --git a/api/test-current.txt b/api/test-current.txt index de2919b8936a..9e5fb33163f9 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 392f56212058..8f99edf61ece 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 0f9c7088a1d0..b046d1df5b8c 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 c697106d0c17..85da6424377a 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 560e3c11d2f4..85dc92d7f252 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 190015cebe30..f5f58efb72e6 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 43a396d8e5d7..b8dbd6267bc5 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); + } } -- cgit v1.2.3-59-g8ed1b