Merge "High Brightness Mode (HBM) Refresh Rate Limiting." into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
410dd5be58
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.hardware.display;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.Nullable;
|
||||
import android.graphics.Point;
|
||||
import android.hardware.SensorManager;
|
||||
@@ -29,6 +30,9 @@ import android.view.DisplayInfo;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceControl.Transaction;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -37,6 +41,16 @@ import java.util.Objects;
|
||||
* @hide Only for use within the system server.
|
||||
*/
|
||||
public abstract class DisplayManagerInternal {
|
||||
|
||||
@IntDef(prefix = {"REFRESH_RATE_LIMIT_"}, value = {
|
||||
REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface RefreshRateLimitType {}
|
||||
|
||||
/** Refresh rate should be limited when High Brightness Mode is active. */
|
||||
public static final int REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE = 1;
|
||||
|
||||
/**
|
||||
* Called by the power manager to initialize power management facilities.
|
||||
*/
|
||||
@@ -296,9 +310,10 @@ public abstract class DisplayManagerInternal {
|
||||
public abstract int getRefreshRateSwitchingType();
|
||||
|
||||
/**
|
||||
* TODO: b/191384041 - Replace this with getRefreshRateLimitations()
|
||||
* Return the refresh rate restriction for the specified display and sensor pairing. If the
|
||||
* specified sensor is identified as an associated sensor in the specified display's
|
||||
* display-device-config file, then return any refresh rate restrictions that it might specify.
|
||||
* display-device-config file, then return any refresh rate restrictions that it might define.
|
||||
* If no restriction is specified, or the sensor is not associated with the display, then null
|
||||
* will be returned.
|
||||
*
|
||||
@@ -312,6 +327,15 @@ public abstract class DisplayManagerInternal {
|
||||
public abstract RefreshRateRange getRefreshRateForDisplayAndSensor(
|
||||
int displayId, String name, String type);
|
||||
|
||||
/**
|
||||
* Returns a list of various refresh rate limitations for the specified display.
|
||||
*
|
||||
* @param displayId The display to get limitations for.
|
||||
*
|
||||
* @return a list of {@link RefreshRateLimitation}s describing the various limits.
|
||||
*/
|
||||
public abstract List<RefreshRateLimitation> getRefreshRateLimitations(int displayId);
|
||||
|
||||
/**
|
||||
* Describes the requested power state of the display.
|
||||
*
|
||||
@@ -613,4 +637,25 @@ public abstract class DisplayManagerInternal {
|
||||
return "(" + min + " " + max + ")";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a limitation on a display's refresh rate. Includes the allowed refresh rate
|
||||
* range as well as information about when it applies, such as high-brightness-mode.
|
||||
*/
|
||||
public static final class RefreshRateLimitation {
|
||||
@RefreshRateLimitType public int type;
|
||||
|
||||
/** The range the that refresh rate should be limited to. */
|
||||
public RefreshRateRange range;
|
||||
|
||||
public RefreshRateLimitation(@RefreshRateLimitType int type, float min, float max) {
|
||||
this.type = type;
|
||||
range = new RefreshRateRange(min, max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RefreshRateLimitation(" + type + ": " + range + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ package com.android.server.display;
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.display.DisplayManagerInternal;
|
||||
import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
|
||||
import android.os.Environment;
|
||||
import android.os.PowerManager;
|
||||
import android.text.TextUtils;
|
||||
@@ -86,6 +88,9 @@ public class DisplayDeviceConfig {
|
||||
// The details of the proximity sensor associated with this display.
|
||||
private final SensorData mProximitySensor = new SensorData();
|
||||
|
||||
private final List<RefreshRateLimitation> mRefreshRateLimitations =
|
||||
new ArrayList<>(2 /*initialCapacity*/);
|
||||
|
||||
// Nits and backlight values that are loaded from either the display device config file, or
|
||||
// config.xml. These are the raw values and just used for the dumpsys
|
||||
private float[] mRawNits;
|
||||
@@ -306,6 +311,10 @@ public class DisplayDeviceConfig {
|
||||
return hbmData;
|
||||
}
|
||||
|
||||
public List<RefreshRateLimitation> getRefreshRateLimitations() {
|
||||
return mRefreshRateLimitations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String str = "DisplayDeviceConfig{"
|
||||
@@ -329,6 +338,7 @@ public class DisplayDeviceConfig {
|
||||
+ ", mBrightnessRampSlowIncrease=" + mBrightnessRampSlowIncrease
|
||||
+ ", mAmbientLightSensor=" + mAmbientLightSensor
|
||||
+ ", mProximitySensor=" + mProximitySensor
|
||||
+ ", mRefreshRateLimitations= " + Arrays.toString(mRefreshRateLimitations.toArray())
|
||||
+ "}";
|
||||
return str;
|
||||
}
|
||||
@@ -647,6 +657,13 @@ public class DisplayDeviceConfig {
|
||||
mHbmData.timeWindowMillis = hbmTiming.getTimeWindowSecs_all().longValue() * 1000;
|
||||
mHbmData.timeMaxMillis = hbmTiming.getTimeMaxSecs_all().longValue() * 1000;
|
||||
mHbmData.timeMinMillis = hbmTiming.getTimeMinSecs_all().longValue() * 1000;
|
||||
final RefreshRateRange rr = hbm.getRefreshRate_all();
|
||||
if (rr != null) {
|
||||
final float min = rr.getMinimum().floatValue();
|
||||
final float max = rr.getMaximum().floatValue();
|
||||
mRefreshRateLimitations.add(new RefreshRateLimitation(
|
||||
DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, min, max));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ import android.hardware.display.DisplayManagerGlobal;
|
||||
import android.hardware.display.DisplayManagerInternal;
|
||||
import android.hardware.display.DisplayManagerInternal.DisplayGroupListener;
|
||||
import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
|
||||
import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
|
||||
import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
|
||||
import android.hardware.display.DisplayViewport;
|
||||
import android.hardware.display.DisplayedContentSample;
|
||||
@@ -130,6 +131,7 @@ import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
@@ -2111,6 +2113,11 @@ public final class DisplayManagerService extends SystemService {
|
||||
DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED);
|
||||
}
|
||||
|
||||
private DisplayDevice getDeviceForDisplayLocked(int displayId) {
|
||||
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
|
||||
return display == null ? null : display.getPrimaryDisplayDeviceLocked();
|
||||
}
|
||||
|
||||
private final class DisplayManagerHandler extends Handler {
|
||||
public DisplayManagerHandler(Looper looper) {
|
||||
super(looper, null, true /*async*/);
|
||||
@@ -3295,6 +3302,19 @@ public final class DisplayManagerService extends SystemService {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RefreshRateLimitation> getRefreshRateLimitations(int displayId) {
|
||||
final DisplayDeviceConfig config;
|
||||
synchronized (mSyncRoot) {
|
||||
final DisplayDevice device = getDeviceForDisplayLocked(displayId);
|
||||
if (device == null) {
|
||||
return null;
|
||||
}
|
||||
config = device.getDisplayDeviceConfig();
|
||||
}
|
||||
return config.getRefreshRateLimitations();
|
||||
}
|
||||
}
|
||||
|
||||
class DesiredDisplayModeSpecsObserver
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.display;
|
||||
|
||||
import static android.hardware.display.DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ContentResolver;
|
||||
@@ -26,8 +28,10 @@ import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.hardware.display.BrightnessInfo;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.DisplayManagerInternal;
|
||||
import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
|
||||
import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
|
||||
import android.hardware.fingerprint.IUdfpsHbmListener;
|
||||
import android.net.Uri;
|
||||
@@ -102,6 +106,7 @@ public class DisplayModeDirector {
|
||||
private final DisplayObserver mDisplayObserver;
|
||||
private final UdfpsObserver mUdfpsObserver;
|
||||
private final SensorObserver mSensorObserver;
|
||||
private final HbmObserver mHbmObserver;
|
||||
private final DeviceConfigInterface mDeviceConfig;
|
||||
private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
|
||||
|
||||
@@ -127,7 +132,7 @@ public class DisplayModeDirector {
|
||||
private int mModeSwitchingType = DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS;
|
||||
|
||||
public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) {
|
||||
this(context, handler, new RealInjector());
|
||||
this(context, handler, new RealInjector(context));
|
||||
}
|
||||
|
||||
public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler,
|
||||
@@ -143,11 +148,13 @@ public class DisplayModeDirector {
|
||||
mDisplayObserver = new DisplayObserver(context, handler);
|
||||
mBrightnessObserver = new BrightnessObserver(context, handler);
|
||||
mUdfpsObserver = new UdfpsObserver();
|
||||
mSensorObserver = new SensorObserver(context, (displayId, priority, vote) -> {
|
||||
final BallotBox ballotBox = (displayId, priority, vote) -> {
|
||||
synchronized (mLock) {
|
||||
updateVoteLocked(displayId, priority, vote);
|
||||
}
|
||||
});
|
||||
};
|
||||
mSensorObserver = new SensorObserver(context, ballotBox);
|
||||
mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler());
|
||||
mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
|
||||
mDeviceConfig = injector.getDeviceConfig();
|
||||
mAlwaysRespectAppRequest = false;
|
||||
@@ -165,6 +172,7 @@ public class DisplayModeDirector {
|
||||
mDisplayObserver.observe();
|
||||
mBrightnessObserver.observe(sensorManager);
|
||||
mSensorObserver.observe();
|
||||
mHbmObserver.observe();
|
||||
synchronized (mLock) {
|
||||
// We may have a listener already registered before the call to start, so go ahead and
|
||||
// notify them to pick up our newly initialized state.
|
||||
@@ -596,6 +604,7 @@ public class DisplayModeDirector {
|
||||
mBrightnessObserver.dumpLocked(pw);
|
||||
mUdfpsObserver.dumpLocked(pw);
|
||||
mSensorObserver.dumpLocked(pw);
|
||||
mHbmObserver.dumpLocked(pw);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -938,13 +947,16 @@ public class DisplayModeDirector {
|
||||
// user seeing the display flickering when the switches occur.
|
||||
public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8;
|
||||
|
||||
// High-brightness-mode may need a specific range of refresh-rates to function properly.
|
||||
public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 9;
|
||||
|
||||
// The proximity sensor needs the refresh rate to be locked in order to function, so this is
|
||||
// set to a high priority.
|
||||
public static final int PRIORITY_PROXIMITY = 9;
|
||||
public static final int PRIORITY_PROXIMITY = 10;
|
||||
|
||||
// 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 = 10;
|
||||
public static final int PRIORITY_UDFPS = 11;
|
||||
|
||||
// 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.
|
||||
@@ -1021,29 +1033,30 @@ public class DisplayModeDirector {
|
||||
|
||||
public static String priorityToString(int priority) {
|
||||
switch (priority) {
|
||||
case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE:
|
||||
return "PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE";
|
||||
case PRIORITY_APP_REQUEST_MAX_REFRESH_RATE:
|
||||
return "PRIORITY_APP_REQUEST_MAX_REFRESH_RATE";
|
||||
case PRIORITY_APP_REQUEST_SIZE:
|
||||
return "PRIORITY_APP_REQUEST_SIZE";
|
||||
case PRIORITY_DEFAULT_REFRESH_RATE:
|
||||
return "PRIORITY_DEFAULT_REFRESH_RATE";
|
||||
case PRIORITY_FLICKER_REFRESH_RATE:
|
||||
return "PRIORITY_FLICKER_REFRESH_RATE";
|
||||
case PRIORITY_FLICKER_REFRESH_RATE_SWITCH:
|
||||
return "PRIORITY_FLICKER_REFRESH_RATE_SWITCH";
|
||||
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_BASE_MODE_REFRESH_RATE:
|
||||
return "PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE";
|
||||
case PRIORITY_APP_REQUEST_SIZE:
|
||||
return "PRIORITY_APP_REQUEST_SIZE";
|
||||
case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE:
|
||||
return "PRIORITY_USER_SETTING_PEAK_REFRESH_RATE";
|
||||
case PRIORITY_HIGH_BRIGHTNESS_MODE:
|
||||
return "PRIORITY_HIGH_BRIGHTNESS_MODE";
|
||||
case PRIORITY_PROXIMITY:
|
||||
return "PRIORITY_PROXIMITY";
|
||||
case PRIORITY_LOW_POWER_MODE:
|
||||
return "PRIORITY_LOW_POWER_MODE";
|
||||
case PRIORITY_UDFPS:
|
||||
return "PRIORITY_UDFPS";
|
||||
case PRIORITY_PROXIMITY:
|
||||
return "PRIORITY_PROXIMITY";
|
||||
|
||||
case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
|
||||
return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE";
|
||||
case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE:
|
||||
return "PRIORITY_USER_SETTING_PEAK_REFRESH_RATE";
|
||||
default:
|
||||
return Integer.toString(priority);
|
||||
}
|
||||
@@ -2155,6 +2168,75 @@ public class DisplayModeDirector {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens to DisplayManager for HBM status and applies any refresh-rate restrictions for
|
||||
* HBM that are associated with that display. Restrictions are retrieved from
|
||||
* DisplayManagerInternal but originate in the display-device-config file.
|
||||
*/
|
||||
private static class HbmObserver implements DisplayManager.DisplayListener {
|
||||
private final BallotBox mBallotBox;
|
||||
private final Handler mHandler;
|
||||
private final SparseBooleanArray mHbmEnabled = new SparseBooleanArray();
|
||||
private final Injector mInjector;
|
||||
|
||||
private DisplayManagerInternal mDisplayManagerInternal;
|
||||
|
||||
HbmObserver(Injector injector, BallotBox ballotBox, Handler handler) {
|
||||
mInjector = injector;
|
||||
mBallotBox = ballotBox;
|
||||
mHandler = handler;
|
||||
}
|
||||
|
||||
public void observe() {
|
||||
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
|
||||
mInjector.registerDisplayListener(this, mHandler,
|
||||
DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
|
||||
| DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayAdded(int displayId) {}
|
||||
|
||||
@Override
|
||||
public void onDisplayRemoved(int displayId) {
|
||||
mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayChanged(int displayId) {
|
||||
final BrightnessInfo info = mInjector.getBrightnessInfo(displayId);
|
||||
if (info == null) {
|
||||
// Display no longer there. Assume we'll get an onDisplayRemoved very soon.
|
||||
return;
|
||||
}
|
||||
final boolean isHbmEnabled =
|
||||
info.highBrightnessMode != BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
|
||||
if (isHbmEnabled == mHbmEnabled.get(displayId)) {
|
||||
// no change, ignore.
|
||||
return;
|
||||
}
|
||||
Vote vote = null;
|
||||
mHbmEnabled.put(displayId, isHbmEnabled);
|
||||
if (isHbmEnabled) {
|
||||
final List<RefreshRateLimitation> limits =
|
||||
mDisplayManagerInternal.getRefreshRateLimitations(displayId);
|
||||
for (int i = 0; limits != null && i < limits.size(); i++) {
|
||||
final RefreshRateLimitation limitation = limits.get(i);
|
||||
if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) {
|
||||
vote = Vote.forRefreshRates(limitation.range.min, limitation.range.max);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, vote);
|
||||
}
|
||||
|
||||
void dumpLocked(PrintWriter pw) {
|
||||
pw.println(" HbmObserver");
|
||||
pw.println(" mHbmEnabled: " + mHbmEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener {
|
||||
public DeviceConfigDisplaySettings() {
|
||||
}
|
||||
@@ -2309,10 +2391,21 @@ public class DisplayModeDirector {
|
||||
|
||||
void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
|
||||
@NonNull ContentObserver observer);
|
||||
|
||||
void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener,
|
||||
Handler handler, long flags);
|
||||
|
||||
BrightnessInfo getBrightnessInfo(int displayId);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static class RealInjector implements Injector {
|
||||
private final Context mContext;
|
||||
private DisplayManager mDisplayManager;
|
||||
|
||||
RealInjector(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
@@ -2339,6 +2432,28 @@ public class DisplayModeDirector {
|
||||
cr.registerContentObserver(PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/,
|
||||
observer, UserHandle.USER_SYSTEM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerDisplayListener(DisplayManager.DisplayListener listener,
|
||||
Handler handler, long flags) {
|
||||
getDisplayManager().registerDisplayListener(listener, handler, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BrightnessInfo getBrightnessInfo(int displayId) {
|
||||
final Display display = getDisplayManager().getDisplay(displayId);
|
||||
if (display != null) {
|
||||
return display.getBrightnessInfo();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private DisplayManager getDisplayManager() {
|
||||
if (mDisplayManager == null) {
|
||||
mDisplayManager = mContext.getSystemService(DisplayManager.class);
|
||||
}
|
||||
return mDisplayManager;
|
||||
}
|
||||
}
|
||||
|
||||
interface BallotBox {
|
||||
|
||||
@@ -77,6 +77,10 @@
|
||||
<xs:annotation name="final"/>
|
||||
</xs:element>
|
||||
<xs:element name="timing" type="hbmTiming" minOccurs="1" maxOccurs="1"/>
|
||||
<xs:element type="refreshRateRange" name="refreshRate" minOccurs="0" maxOccurs="1">
|
||||
<xs:annotation name="nullable"/>
|
||||
<xs:annotation name="final"/>
|
||||
</xs:element>
|
||||
</xs:all>
|
||||
<xs:attribute name="enabled" type="xs:boolean" use="optional"/>
|
||||
</xs:complexType>
|
||||
|
||||
@@ -44,10 +44,12 @@ package com.android.server.display.config {
|
||||
ctor public HighBrightnessMode();
|
||||
method public boolean getEnabled();
|
||||
method @NonNull public final java.math.BigDecimal getMinimumLux_all();
|
||||
method @Nullable public final com.android.server.display.config.RefreshRateRange getRefreshRate_all();
|
||||
method public com.android.server.display.config.HbmTiming getTiming_all();
|
||||
method @NonNull public final java.math.BigDecimal getTransitionPoint_all();
|
||||
method public void setEnabled(boolean);
|
||||
method public final void setMinimumLux_all(@NonNull java.math.BigDecimal);
|
||||
method public final void setRefreshRate_all(@Nullable com.android.server.display.config.RefreshRateRange);
|
||||
method public void setTiming_all(com.android.server.display.config.HbmTiming);
|
||||
method public final void setTransitionPoint_all(@NonNull java.math.BigDecimal);
|
||||
}
|
||||
|
||||
@@ -48,8 +48,11 @@ import android.database.ContentObserver;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.hardware.display.BrightnessInfo;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.DisplayManager.DisplayListener;
|
||||
import android.hardware.display.DisplayManagerInternal;
|
||||
import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
|
||||
import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
|
||||
import android.hardware.fingerprint.IUdfpsHbmListener;
|
||||
import android.os.Handler;
|
||||
@@ -120,7 +123,7 @@ public class DisplayModeDirectorTest {
|
||||
mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
|
||||
final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext);
|
||||
when(mContext.getContentResolver()).thenReturn(resolver);
|
||||
mInjector = new FakesInjector();
|
||||
mInjector = spy(new FakesInjector());
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
|
||||
@@ -1256,13 +1259,163 @@ public class DisplayModeDirectorTest {
|
||||
assertNull(vote);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHbmVoting_forHdr() {
|
||||
DisplayModeDirector director =
|
||||
createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
|
||||
director.start(createMockSensorManager());
|
||||
|
||||
ArgumentCaptor<DisplayListener> captor =
|
||||
ArgumentCaptor.forClass(DisplayListener.class);
|
||||
verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class),
|
||||
eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
|
||||
| DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
|
||||
DisplayListener listener = captor.getValue();
|
||||
|
||||
// Specify Limitation
|
||||
when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID)).thenReturn(
|
||||
List.of(new RefreshRateLimitation(
|
||||
DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE,
|
||||
60.f, 60.f)));
|
||||
|
||||
// Verify that there is no HBM vote initially
|
||||
Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
|
||||
// Turn on HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertVoteForRefreshRate(vote, 60.f);
|
||||
|
||||
// Turn off HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHbmVoting_forSunlight() {
|
||||
DisplayModeDirector director =
|
||||
createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
|
||||
director.start(createMockSensorManager());
|
||||
|
||||
ArgumentCaptor<DisplayListener> captor =
|
||||
ArgumentCaptor.forClass(DisplayListener.class);
|
||||
verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class),
|
||||
eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
|
||||
| DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
|
||||
DisplayListener listener = captor.getValue();
|
||||
|
||||
// Specify Limitation
|
||||
when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID)).thenReturn(
|
||||
List.of(new RefreshRateLimitation(
|
||||
DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE,
|
||||
60.f, 60.f)));
|
||||
|
||||
// Verify that there is no HBM vote initially
|
||||
Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
|
||||
// Turn on HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertVoteForRefreshRate(vote, 60.f);
|
||||
|
||||
// Turn off HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHbmVoting_forSunlight_NoLimitation() {
|
||||
DisplayModeDirector director =
|
||||
createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
|
||||
director.start(createMockSensorManager());
|
||||
|
||||
ArgumentCaptor<DisplayListener> captor =
|
||||
ArgumentCaptor.forClass(DisplayListener.class);
|
||||
verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class),
|
||||
eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
|
||||
| DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
|
||||
DisplayListener listener = captor.getValue();
|
||||
|
||||
// Specify Limitation for different display
|
||||
when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID + 1)).thenReturn(
|
||||
List.of(new RefreshRateLimitation(
|
||||
DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE,
|
||||
60.f, 60.f)));
|
||||
|
||||
// Verify that there is no HBM vote initially
|
||||
Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
|
||||
// Turn on HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
|
||||
// Turn off HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHbmVoting_RemovedDisplay() {
|
||||
DisplayModeDirector director =
|
||||
createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
|
||||
director.start(createMockSensorManager());
|
||||
|
||||
ArgumentCaptor<DisplayListener> captor =
|
||||
ArgumentCaptor.forClass(DisplayListener.class);
|
||||
verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class),
|
||||
eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
|
||||
| DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
|
||||
DisplayListener listener = captor.getValue();
|
||||
|
||||
// Specify Limitation for different display
|
||||
when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID)).thenReturn(
|
||||
List.of(new RefreshRateLimitation(
|
||||
DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE,
|
||||
60.f, 60.f)));
|
||||
|
||||
// Verify that there is no HBM vote initially
|
||||
Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
|
||||
// Turn on HBM
|
||||
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
|
||||
new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT));
|
||||
listener.onDisplayChanged(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertVoteForRefreshRate(vote, 60.f);
|
||||
|
||||
// Turn off HBM
|
||||
listener.onDisplayRemoved(DISPLAY_ID);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
|
||||
assertNull(vote);
|
||||
}
|
||||
|
||||
private void assertVoteForRefreshRate(Vote vote, float refreshRate) {
|
||||
assertThat(vote).isNotNull();
|
||||
final RefreshRateRange expectedRange = new RefreshRateRange(refreshRate, refreshRate);
|
||||
assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
|
||||
}
|
||||
|
||||
private static class FakeDeviceConfig extends FakeDeviceConfigInterface {
|
||||
public static class FakeDeviceConfig extends FakeDeviceConfigInterface {
|
||||
@Override
|
||||
public String getProperty(String namespace, String name) {
|
||||
Preconditions.checkArgument(DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace));
|
||||
@@ -1403,7 +1556,7 @@ public class DisplayModeDirectorTest {
|
||||
mHandler.runWithScissors(() -> { }, 500 /*timeout*/);
|
||||
}
|
||||
|
||||
static class FakesInjector implements DisplayModeDirector.Injector {
|
||||
public static class FakesInjector implements DisplayModeDirector.Injector {
|
||||
private final FakeDeviceConfig mDeviceConfig;
|
||||
private ContentObserver mBrightnessObserver;
|
||||
private ContentObserver mPeakRefreshRateObserver;
|
||||
@@ -1444,6 +1597,14 @@ public class DisplayModeDirectorTest {
|
||||
mPeakRefreshRateObserver = observer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerDisplayListener(DisplayListener listener, Handler handler, long flag) {}
|
||||
|
||||
@Override
|
||||
public BrightnessInfo getBrightnessInfo(int displayId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
void notifyPeakRefreshRateChanged() {
|
||||
if (mPeakRefreshRateObserver != null) {
|
||||
mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
|
||||
|
||||
Reference in New Issue
Block a user