diff options
| author | 2020-09-21 12:02:28 +0000 | |
|---|---|---|
| committer | 2020-09-21 12:02:28 +0000 | |
| commit | 768cbbd32ca04a33c8058ed69b86246c744e0004 (patch) | |
| tree | b454b8ebe81a63de49f4ca4a3e99cee2627b6682 | |
| parent | fe03f74eae46711af494f666c81d8ae02b3937c6 (diff) | |
| parent | 97ba024fb03838b814cfb921c35ad3f0ac0c9ff9 (diff) | |
Merge "Add TestApi to always select the app requested display mode"
9 files changed, 192 insertions, 11 deletions
diff --git a/api/test-current.txt b/api/test-current.txt index 7a7cdd18e50d..eae570bcead0 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"; @@ -1313,6 +1314,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 @@ -841,6 +841,30 @@ public final class DisplayManager { } /** + * 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. */ public interface DisplayListener { 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 c9a4ab081a5b..4fd9e1dfc0ea 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3914,6 +3914,14 @@ <permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" android:protectionLevel="signature" /> + <!-- Allows an application to override the display mode requests + so the app requested mode will be selected and user settings and display + policies will be ignored. + @hide + @TestApi --> + <permission android:name="android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS" + android:protectionLevel="signature" /> + <!-- @SystemApi Allows an application to control VPN. <p>Not for use by third-party applications.</p> @hide --> 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 @@ <!-- Permissions required for CTS test - AdbManagerTest --> <uses-permission android:name="android.permission.MANAGE_DEBUGGING" /> + <!-- Permission needed for CTS test - DisplayTest --> + <uses-permission android:name="android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS" /> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" android:defaultToDeviceProtectedStorage="true" diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 4a12ee71adbe..97c4cf531a53 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -1179,6 +1179,15 @@ public final class DisplayManagerService extends SystemService { return mWideColorSpace.getId(); } + void setShouldAlwaysRespectAppRequestedModeInternal(boolean enabled) { + mDisplayModeDirector.setShouldAlwaysRespectAppRequestedMode(enabled); + } + + + boolean shouldAlwaysRespectAppRequestedModeInternal() { + return mDisplayModeDirector.shouldAlwaysRespectAppRequestedMode(); + } + private void setBrightnessConfigurationForUserInternal( @Nullable BrightnessConfiguration c, @UserIdInt int userId, @Nullable String packageName) { @@ -2463,6 +2472,32 @@ public final class DisplayManagerService extends SystemService { } } + @Override // Binder call + public void setShouldAlwaysRespectAppRequestedMode(boolean enabled) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS, + "Permission required to override display mode requests."); + final long token = Binder.clearCallingIdentity(); + try { + setShouldAlwaysRespectAppRequestedModeInternal(enabled); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override // Binder call + public boolean shouldAlwaysRespectAppRequestedMode() { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS, + "Permission required to override display mode requests."); + final long token = Binder.clearCallingIdentity(); + try { + return shouldAlwaysRespectAppRequestedModeInternal(); + } finally { + Binder.restoreCallingIdentity(token); + } + } + private boolean validatePackageName(int uid, String packageName) { if (packageName != null) { String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index b1c91a690d7f..4f5a0faee8dd 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -56,8 +56,8 @@ import java.util.List; import java.util.Objects; /** - * The DisplayModeDirector is responsible for determining what modes are allowed to be - * automatically picked by the system based on system-wide and display-specific configuration. + * The DisplayModeDirector is responsible for determining what modes are allowed to be automatically + * picked by the system based on system-wide and display-specific configuration. */ public class DisplayModeDirector { private static final String TAG = "DisplayModeDirector"; @@ -97,17 +97,20 @@ public class DisplayModeDirector { private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; private DesiredDisplayModeSpecsListener mDesiredDisplayModeSpecsListener; + private boolean mAlwaysRespectAppRequest; + public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) { mContext = context; mHandler = new DisplayModeDirectorHandler(handler.getLooper()); mVotesByDisplay = new SparseArray<>(); 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<Vote> votes, int lowestConsideredPriority, /*out*/ VoteSummary summary) { + SparseArray<Vote> 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) { @@ -349,6 +366,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. * * @param pw The stream to dump information to. @@ -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<Vote> votes = new SparseArray<>(); + SparseArray<SparseArray<Vote>> 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); + } } |