Merge "Add TestApi to always select the app requested display mode"

This commit is contained in:
Marin Shalamanov
2020-09-21 12:02:28 +00:00
committed by Android (Google) Code Review
9 changed files with 192 additions and 11 deletions

View File

@@ -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
}

View File

@@ -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.
*/

View File

@@ -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) {

View File

@@ -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();
}

View File

@@ -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 -->

View File

@@ -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"

View File

@@ -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);

View File

@@ -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) {
@@ -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);

View File

@@ -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);
}
}