summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/SurfaceControl.java95
-rw-r--r--core/jni/android_view_SurfaceControl.cpp52
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceConfig.java6
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java3
-rw-r--r--services/core/java/com/android/server/display/mode/DisplayModeDirector.java98
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java15
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java93
7 files changed, 342 insertions, 20 deletions
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 4f5b51d04c4b..cfdf8fab05c2 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -2099,6 +2099,65 @@ public final class SurfaceControl implements Parcelable {
}
}
+ /**
+ * Contains information of the idle time of the screen after which the refresh rate is to be
+ * reduced.
+ *
+ * @hide
+ */
+ public static final class IdleScreenRefreshRateConfig {
+ /**
+ * The time(in ms) after which the refresh rate is to be reduced. Defaults to -1, which
+ * means no timeout has been configured for the current conditions
+ */
+ public int timeoutMillis;
+
+ public IdleScreenRefreshRateConfig() {
+ timeoutMillis = -1;
+ }
+
+ public IdleScreenRefreshRateConfig(int timeoutMillis) {
+ this.timeoutMillis = timeoutMillis;
+ }
+
+ /**
+ * Checks whether the two objects have the same values.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof IdleScreenRefreshRateConfig) || other == null) {
+ return false;
+ }
+
+ IdleScreenRefreshRateConfig
+ idleScreenRefreshRateConfig = (IdleScreenRefreshRateConfig) other;
+ return timeoutMillis == idleScreenRefreshRateConfig.timeoutMillis;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(timeoutMillis);
+ }
+
+ @Override
+ public String toString() {
+ return "timeoutMillis: " + timeoutMillis;
+ }
+
+ /**
+ * Copies the supplied object's values to this object.
+ */
+ public void copyFrom(IdleScreenRefreshRateConfig other) {
+ if (other != null) {
+ this.timeoutMillis = other.timeoutMillis;
+ }
+ }
+ }
+
/**
* Contains information about desired display configuration.
@@ -2132,6 +2191,15 @@ public final class SurfaceControl implements Parcelable {
*/
public final RefreshRateRanges appRequestRanges;
+ /**
+ * Represents the idle time of the screen after which the associated display's refresh rate
+ * is to be reduced to preserve power
+ * Defaults to null, meaning that the device is not configured to have a timeout.
+ * Timeout value of -1 refers that the current conditions require no timeout
+ */
+ @Nullable
+ public IdleScreenRefreshRateConfig idleScreenRefreshRateConfig;
+
public DesiredDisplayModeSpecs() {
this.primaryRanges = new RefreshRateRanges();
this.appRequestRanges = new RefreshRateRanges();
@@ -2144,13 +2212,17 @@ public final class SurfaceControl implements Parcelable {
}
public DesiredDisplayModeSpecs(int defaultMode, boolean allowGroupSwitching,
- RefreshRateRanges primaryRanges, RefreshRateRanges appRequestRanges) {
+ RefreshRateRanges primaryRanges, RefreshRateRanges appRequestRanges,
+ @Nullable IdleScreenRefreshRateConfig idleScreenRefreshRateConfig) {
this.defaultMode = defaultMode;
this.allowGroupSwitching = allowGroupSwitching;
this.primaryRanges =
new RefreshRateRanges(primaryRanges.physical, primaryRanges.render);
this.appRequestRanges =
new RefreshRateRanges(appRequestRanges.physical, appRequestRanges.render);
+ this.idleScreenRefreshRateConfig =
+ (idleScreenRefreshRateConfig == null) ? null : new IdleScreenRefreshRateConfig(
+ idleScreenRefreshRateConfig.timeoutMillis);
}
@Override
@@ -2165,7 +2237,9 @@ public final class SurfaceControl implements Parcelable {
return other != null && defaultMode == other.defaultMode
&& allowGroupSwitching == other.allowGroupSwitching
&& primaryRanges.equals(other.primaryRanges)
- && appRequestRanges.equals(other.appRequestRanges);
+ && appRequestRanges.equals(other.appRequestRanges)
+ && Objects.equals(
+ idleScreenRefreshRateConfig, other.idleScreenRefreshRateConfig);
}
@Override
@@ -2181,6 +2255,7 @@ public final class SurfaceControl implements Parcelable {
allowGroupSwitching = other.allowGroupSwitching;
primaryRanges.copyFrom(other.primaryRanges);
appRequestRanges.copyFrom(other.appRequestRanges);
+ copyIdleScreenRefreshRateConfig(other.idleScreenRefreshRateConfig);
}
@Override
@@ -2188,7 +2263,21 @@ public final class SurfaceControl implements Parcelable {
return "defaultMode=" + defaultMode
+ " allowGroupSwitching=" + allowGroupSwitching
+ " primaryRanges=" + primaryRanges
- + " appRequestRanges=" + appRequestRanges;
+ + " appRequestRanges=" + appRequestRanges
+ + " idleScreenRefreshRate=" + String.valueOf(idleScreenRefreshRateConfig);
+ }
+
+ private void copyIdleScreenRefreshRateConfig(IdleScreenRefreshRateConfig other) {
+ if (idleScreenRefreshRateConfig == null) {
+ if (other != null) {
+ idleScreenRefreshRateConfig =
+ new IdleScreenRefreshRateConfig(other.timeoutMillis);
+ }
+ } else if (other == null) {
+ idleScreenRefreshRateConfig = null;
+ } else {
+ idleScreenRefreshRateConfig.copyFrom(other);
+ }
}
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 1eab9910b651..1aa635c6ceb7 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -208,10 +208,17 @@ static struct {
static struct {
jclass clazz;
jmethodID ctor;
+ jfieldID timeoutMillis;
+} gIdleScreenRefreshRateConfigClassInfo;
+
+static struct {
+ jclass clazz;
+ jmethodID ctor;
jfieldID defaultMode;
jfieldID allowGroupSwitching;
jfieldID primaryRanges;
jfieldID appRequestRanges;
+ jfieldID idleScreenRefreshRateConfig;
} gDesiredDisplayModeSpecsClassInfo;
static struct {
@@ -1407,6 +1414,18 @@ static jboolean nativeSetDesiredDisplayModeSpecs(JNIEnv* env, jclass clazz, jobj
return ranges;
};
+ const auto makeIdleScreenRefreshRateConfig = [env](jobject obj)
+ -> std::optional<gui::DisplayModeSpecs::IdleScreenRefreshRateConfig> {
+ if (obj == NULL) {
+ return std::nullopt;
+ }
+ gui::DisplayModeSpecs::IdleScreenRefreshRateConfig idleScreenRefreshRateConfig;
+ idleScreenRefreshRateConfig.timeoutMillis =
+ env->GetIntField(obj, gIdleScreenRefreshRateConfigClassInfo.timeoutMillis);
+
+ return idleScreenRefreshRateConfig;
+ };
+
gui::DisplayModeSpecs specs;
specs.defaultMode = env->GetIntField(DesiredDisplayModeSpecs,
gDesiredDisplayModeSpecsClassInfo.defaultMode);
@@ -1421,6 +1440,10 @@ static jboolean nativeSetDesiredDisplayModeSpecs(JNIEnv* env, jclass clazz, jobj
makeRanges(env->GetObjectField(DesiredDisplayModeSpecs,
gDesiredDisplayModeSpecsClassInfo.appRequestRanges));
+ specs.idleScreenRefreshRateConfig = makeIdleScreenRefreshRateConfig(
+ env->GetObjectField(DesiredDisplayModeSpecs,
+ gDesiredDisplayModeSpecsClassInfo.idleScreenRefreshRateConfig));
+
size_t result = SurfaceComposerClient::setDesiredDisplayModeSpecs(token, specs);
return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}
@@ -1440,6 +1463,17 @@ static jobject nativeGetDesiredDisplayModeSpecs(JNIEnv* env, jclass clazz, jobje
rangeToJava(ranges.physical), rangeToJava(ranges.render));
};
+ const auto idleScreenRefreshRateConfigToJava =
+ [env](const std::optional<gui::DisplayModeSpecs::IdleScreenRefreshRateConfig>&
+ idleScreenRefreshRateConfig) -> jobject {
+ if (!idleScreenRefreshRateConfig.has_value()) {
+ return NULL; // Return null if input config is null
+ }
+ return env->NewObject(gIdleScreenRefreshRateConfigClassInfo.clazz,
+ gIdleScreenRefreshRateConfigClassInfo.ctor,
+ idleScreenRefreshRateConfig->timeoutMillis);
+ };
+
gui::DisplayModeSpecs specs;
if (SurfaceComposerClient::getDesiredDisplayModeSpecs(token, &specs) != NO_ERROR) {
return nullptr;
@@ -1448,7 +1482,8 @@ static jobject nativeGetDesiredDisplayModeSpecs(JNIEnv* env, jclass clazz, jobje
return env->NewObject(gDesiredDisplayModeSpecsClassInfo.clazz,
gDesiredDisplayModeSpecsClassInfo.ctor, specs.defaultMode,
specs.allowGroupSwitching, rangesToJava(specs.primaryRanges),
- rangesToJava(specs.appRequestRanges));
+ rangesToJava(specs.appRequestRanges),
+ idleScreenRefreshRateConfigToJava(specs.idleScreenRefreshRateConfig));
}
static jobject nativeGetDisplayNativePrimaries(JNIEnv* env, jclass, jobject tokenObj) {
@@ -2607,13 +2642,23 @@ int register_android_view_SurfaceControl(JNIEnv* env)
GetFieldIDOrDie(env, RefreshRateRangesClazz, "render",
"Landroid/view/SurfaceControl$RefreshRateRange;");
+ jclass IdleScreenRefreshRateConfigClazz =
+ FindClassOrDie(env, "android/view/SurfaceControl$IdleScreenRefreshRateConfig");
+ gIdleScreenRefreshRateConfigClassInfo.clazz =
+ MakeGlobalRefOrDie(env, IdleScreenRefreshRateConfigClazz);
+ gIdleScreenRefreshRateConfigClassInfo.ctor =
+ GetMethodIDOrDie(env, gIdleScreenRefreshRateConfigClassInfo.clazz, "<init>", "(I)V");
+ gIdleScreenRefreshRateConfigClassInfo.timeoutMillis =
+ GetFieldIDOrDie(env, gIdleScreenRefreshRateConfigClassInfo.clazz, "timeoutMillis", "I");
+
jclass DesiredDisplayModeSpecsClazz =
FindClassOrDie(env, "android/view/SurfaceControl$DesiredDisplayModeSpecs");
gDesiredDisplayModeSpecsClassInfo.clazz = MakeGlobalRefOrDie(env, DesiredDisplayModeSpecsClazz);
gDesiredDisplayModeSpecsClassInfo.ctor =
GetMethodIDOrDie(env, gDesiredDisplayModeSpecsClassInfo.clazz, "<init>",
"(IZLandroid/view/SurfaceControl$RefreshRateRanges;Landroid/view/"
- "SurfaceControl$RefreshRateRanges;)V");
+ "SurfaceControl$RefreshRateRanges;Landroid/view/"
+ "SurfaceControl$IdleScreenRefreshRateConfig;)V");
gDesiredDisplayModeSpecsClassInfo.defaultMode =
GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "defaultMode", "I");
gDesiredDisplayModeSpecsClassInfo.allowGroupSwitching =
@@ -2624,6 +2669,9 @@ int register_android_view_SurfaceControl(JNIEnv* env)
gDesiredDisplayModeSpecsClassInfo.appRequestRanges =
GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "appRequestRanges",
"Landroid/view/SurfaceControl$RefreshRateRanges;");
+ gDesiredDisplayModeSpecsClassInfo.idleScreenRefreshRateConfig =
+ GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "idleScreenRefreshRateConfig",
+ "Landroid/view/SurfaceControl$IdleScreenRefreshRateConfig;");
jclass jankDataClazz =
FindClassOrDie(env, "android/view/SurfaceControl$JankData");
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 411666942b6d..831dcf476a49 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -3376,6 +3376,12 @@ public class DisplayDeviceConfig {
throw new RuntimeException("Lux values should be in ascending order in the"
+ " idle screen refresh rate timeout config");
}
+
+ int timeout = point.getTimeout().intValue();
+ if (timeout < 0) {
+ throw new RuntimeException("The timeout value cannot be negative in"
+ + " idle screen refresh rate timeout config");
+ }
previousLux = newLux;
}
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index b2fd9edf61fe..c84c9b1f306e 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -1073,7 +1073,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
new SurfaceControl.DesiredDisplayModeSpecs(baseSfModeId,
mDisplayModeSpecs.allowGroupSwitching,
mDisplayModeSpecs.primary,
- mDisplayModeSpecs.appRequest)));
+ mDisplayModeSpecs.appRequest,
+ mDisplayModeSpecs.mIdleScreenRefreshRateConfig)));
}
}
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index 495ae87fe0b9..572d32e80c12 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -64,6 +64,8 @@ import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.IdleScreenRefreshRateConfig;
import android.view.SurfaceControl.RefreshRateRange;
import android.view.SurfaceControl.RefreshRateRanges;
@@ -74,6 +76,7 @@ import com.android.internal.display.BrightnessSynchronizer;
import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
import com.android.server.display.DisplayDeviceConfig;
+import com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholdPoint;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.utils.AmbientFilter;
@@ -184,6 +187,8 @@ public class DisplayModeDirector {
private final boolean mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled;
+ private final DisplayManagerFlags mDisplayManagerFlags;
+
private final boolean mDvrrSupported;
@@ -206,7 +211,7 @@ public class DisplayModeDirector {
.isDisplaysRefreshRatesSynchronizationEnabled();
mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled = displayManagerFlags
.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled();
-
+ mDisplayManagerFlags = displayManagerFlags;
mContext = context;
mHandler = new DisplayModeDirectorHandler(handler.getLooper());
mInjector = injector;
@@ -374,7 +379,7 @@ public class DisplayModeDirector {
final RefreshRateRanges ranges = new RefreshRateRanges(range, range);
return new DesiredDisplayModeSpecs(defaultMode.getModeId(),
/*allowGroupSwitching */ false,
- ranges, ranges);
+ ranges, ranges, mBrightnessObserver.getIdleScreenRefreshRateConfig());
}
boolean modeSwitchingDisabled =
@@ -422,7 +427,8 @@ public class DisplayModeDirector {
appRequestSummary.maxPhysicalRefreshRate),
new RefreshRateRange(
appRequestSummary.minRenderFrameRate,
- appRequestSummary.maxRenderFrameRate)));
+ appRequestSummary.maxRenderFrameRate)),
+ mBrightnessObserver.getIdleScreenRefreshRateConfig());
}
}
@@ -764,6 +770,16 @@ public class DisplayModeDirector {
public boolean allowGroupSwitching;
/**
+ * Represents the idle time of the screen after which the associated display's refresh rate
+ * is to be reduced to preserve power
+ * Defaults to null, meaning that the device is not configured to have a timeout based on
+ * the surrounding conditions
+ * -1 means that the current conditions require no timeout
+ */
+ @Nullable
+ public IdleScreenRefreshRateConfig mIdleScreenRefreshRateConfig;
+
+ /**
* The primary refresh rate ranges.
*/
public final RefreshRateRanges primary;
@@ -783,11 +799,13 @@ public class DisplayModeDirector {
public DesiredDisplayModeSpecs(int baseModeId,
boolean allowGroupSwitching,
@NonNull RefreshRateRanges primary,
- @NonNull RefreshRateRanges appRequest) {
+ @NonNull RefreshRateRanges appRequest,
+ @Nullable SurfaceControl.IdleScreenRefreshRateConfig idleScreenRefreshRateConfig) {
this.baseModeId = baseModeId;
this.allowGroupSwitching = allowGroupSwitching;
this.primary = primary;
this.appRequest = appRequest;
+ this.mIdleScreenRefreshRateConfig = idleScreenRefreshRateConfig;
}
/**
@@ -797,9 +815,10 @@ public class DisplayModeDirector {
public String toString() {
return String.format("baseModeId=%d allowGroupSwitching=%b"
+ " primary=%s"
- + " appRequest=%s",
+ + " appRequest=%s"
+ + " idleScreenRefreshRateConfig=%s",
baseModeId, allowGroupSwitching, primary.toString(),
- appRequest.toString());
+ appRequest.toString(), String.valueOf(mIdleScreenRefreshRateConfig));
}
/**
@@ -830,12 +849,18 @@ public class DisplayModeDirector {
desiredDisplayModeSpecs.appRequest)) {
return false;
}
+
+ if (!Objects.equals(mIdleScreenRefreshRateConfig,
+ desiredDisplayModeSpecs.mIdleScreenRefreshRateConfig)) {
+ return false;
+ }
return true;
}
@Override
public int hashCode() {
- return Objects.hash(baseModeId, allowGroupSwitching, primary, appRequest);
+ return Objects.hash(baseModeId, allowGroupSwitching, primary, appRequest,
+ mIdleScreenRefreshRateConfig);
}
/**
@@ -853,6 +878,14 @@ public class DisplayModeDirector {
appRequest.physical.max = other.appRequest.physical.max;
appRequest.render.min = other.appRequest.render.min;
appRequest.render.max = other.appRequest.render.max;
+
+ if (other.mIdleScreenRefreshRateConfig == null) {
+ mIdleScreenRefreshRateConfig = null;
+ } else {
+ mIdleScreenRefreshRateConfig =
+ new IdleScreenRefreshRateConfig(
+ other.mIdleScreenRefreshRateConfig.timeoutMillis);
+ }
}
}
@@ -1543,12 +1576,20 @@ public class DisplayModeDirector {
private float mAmbientLux = -1.0f;
private AmbientFilter mAmbientFilter;
+ /**
+ * The current timeout configuration. This value is used by surface flinger to track the
+ * time after which an idle screen's refresh rate is to be reduced.
+ */
+ @Nullable
+ private SurfaceControl.IdleScreenRefreshRateConfig mIdleScreenRefreshRateConfig;
+
private float mBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
private final Context mContext;
private final Injector mInjector;
private final Handler mHandler;
+
private final boolean mVsyncLowLightBlockingVoteEnabled;
private final IThermalEventListener.Stub mThermalListener =
@@ -1643,6 +1684,11 @@ public class DisplayModeDirector {
return mRefreshRateInLowZone;
}
+ @VisibleForTesting
+ IdleScreenRefreshRateConfig getIdleScreenRefreshRateConfig() {
+ return mIdleScreenRefreshRateConfig;
+ }
+
private void loadLowBrightnessThresholds(@Nullable DisplayDeviceConfig displayDeviceConfig,
boolean attemptReadFromFeatureParams) {
loadRefreshRateInHighZone(displayDeviceConfig, attemptReadFromFeatureParams);
@@ -2381,6 +2427,10 @@ public class DisplayModeDirector {
// is interrupted by a new sensor event.
mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS);
}
+
+ if (mDisplayManagerFlags.isIdleScreenRefreshRateTimeoutEnabled()) {
+ updateIdleScreenRefreshRate(mAmbientLux);
+ }
}
@Override
@@ -2440,6 +2490,40 @@ public class DisplayModeDirector {
}
};
}
+
+ private void updateIdleScreenRefreshRate(float ambientLux) {
+ List<IdleScreenRefreshRateTimeoutLuxThresholdPoint>
+ idleScreenRefreshRateTimeoutLuxThresholdPoints;
+ synchronized (mLock) {
+ if (mDefaultDisplayDeviceConfig == null || mDefaultDisplayDeviceConfig
+ .getIdleScreenRefreshRateTimeoutLuxThresholdPoint().isEmpty()) {
+ // Setting this to null will let surface flinger know that the idle timer is not
+ // configured in the display configs
+ mIdleScreenRefreshRateConfig = null;
+ return;
+ }
+
+ idleScreenRefreshRateTimeoutLuxThresholdPoints =
+ mDefaultDisplayDeviceConfig
+ .getIdleScreenRefreshRateTimeoutLuxThresholdPoint();
+ }
+ int newTimeout = -1;
+ for (IdleScreenRefreshRateTimeoutLuxThresholdPoint point :
+ idleScreenRefreshRateTimeoutLuxThresholdPoints) {
+ int newLux = point.getLux().intValue();
+ if (newLux <= ambientLux) {
+ newTimeout = point.getTimeout().intValue();
+ }
+ }
+ if (mIdleScreenRefreshRateConfig == null
+ || newTimeout != mIdleScreenRefreshRateConfig.timeoutMillis) {
+ mIdleScreenRefreshRateConfig =
+ new IdleScreenRefreshRateConfig(newTimeout);
+ synchronized (mLock) {
+ notifyDesiredDisplayModeSpecsChangedLocked();
+ }
+ }
+ }
}
private class UdfpsObserver extends IUdfpsRefreshRateRequestCallback.Stub {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 14de527aa1f7..7fd96c57c215 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -49,6 +49,7 @@ import android.os.Looper;
import android.view.Display;
import android.view.DisplayAddress;
import android.view.SurfaceControl;
+import android.view.SurfaceControl.IdleScreenRefreshRateConfig;
import android.view.SurfaceControl.RefreshRateRange;
import android.view.SurfaceControl.RefreshRateRanges;
@@ -830,18 +831,20 @@ public class LocalDisplayAdapterTest {
.get()
.getModeId();
+ IdleScreenRefreshRateConfig
+ idleScreenRefreshRateConfig = new SurfaceControl.IdleScreenRefreshRateConfig(500);
displayDevice.setDesiredDisplayModeSpecsLocked(
new DisplayModeDirector.DesiredDisplayModeSpecs(
/*baseModeId*/ baseModeId,
/*allowGroupSwitching*/ false,
- REFRESH_RATE_RANGES, REFRESH_RATE_RANGES
+ REFRESH_RATE_RANGES, REFRESH_RATE_RANGES, idleScreenRefreshRateConfig
));
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
verify(mSurfaceControlProxy).setDesiredDisplayModeSpecs(display.token,
new SurfaceControl.DesiredDisplayModeSpecs(
/* baseModeId */ 0,
/* allowGroupSwitching */ false,
- REFRESH_RATE_RANGES, REFRESH_RATE_RANGES
+ REFRESH_RATE_RANGES, REFRESH_RATE_RANGES, idleScreenRefreshRateConfig
));
// Change the display
@@ -862,12 +865,13 @@ public class LocalDisplayAdapterTest {
baseModeId = displayDevice.getDisplayDeviceInfoLocked().supportedModes[0].getModeId();
+ idleScreenRefreshRateConfig = new SurfaceControl.IdleScreenRefreshRateConfig(600);
// The traversal request will call setDesiredDisplayModeSpecsLocked on the display device
displayDevice.setDesiredDisplayModeSpecsLocked(
new DisplayModeDirector.DesiredDisplayModeSpecs(
/*baseModeId*/ baseModeId,
/*allowGroupSwitching*/ false,
- REFRESH_RATE_RANGES, REFRESH_RATE_RANGES
+ REFRESH_RATE_RANGES, REFRESH_RATE_RANGES, idleScreenRefreshRateConfig
));
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
@@ -877,7 +881,7 @@ public class LocalDisplayAdapterTest {
new SurfaceControl.DesiredDisplayModeSpecs(
/* baseModeId */ 2,
/* allowGroupSwitching */ false,
- REFRESH_RATE_RANGES, REFRESH_RATE_RANGES
+ REFRESH_RATE_RANGES, REFRESH_RATE_RANGES, idleScreenRefreshRateConfig
));
}
@@ -1319,7 +1323,8 @@ public class LocalDisplayAdapterTest {
new SurfaceControl.DesiredDisplayModeSpecs(
/* defaultMode */ 0,
/* allowGroupSwitching */ false,
- REFRESH_RATE_RANGES, REFRESH_RATE_RANGES
+ REFRESH_RATE_RANGES, REFRESH_RATE_RANGES,
+ new IdleScreenRefreshRateConfig(100)
);
private FakeDisplay(int port) {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
index 3eced7fa025c..3a59c84b636c 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
@@ -75,6 +75,8 @@ import android.util.SparseArray;
import android.util.TypedValue;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.IdleScreenRefreshRateConfig;
import android.view.SurfaceControl.RefreshRateRange;
import android.view.SurfaceControl.RefreshRateRanges;
@@ -91,6 +93,7 @@ import com.android.internal.util.test.FakeSettingsProviderRule;
import com.android.modules.utils.testing.ExtendedMockitoRule;
import com.android.server.display.DisplayDeviceConfig;
import com.android.server.display.TestUtils;
+import com.android.server.display.config.IdleScreenRefreshRateTimeoutLuxThresholdPoint;
import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.mode.DisplayModeDirector.BrightnessObserver;
import com.android.server.display.mode.DisplayModeDirector.DesiredDisplayModeSpecs;
@@ -112,6 +115,7 @@ import org.mockito.Mockito;
import org.mockito.quality.Strictness;
import org.mockito.stubbing.Answer;
+import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -1405,6 +1409,81 @@ public class DisplayModeDirectorTest {
}
@Test
+ public void testIdleScreenTimeOnLuxChanges() throws Exception {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f, 120.f}, 0);
+ setPeakRefreshRate(120 /*fps*/);
+ director.getSettingsObserver().setDefaultRefreshRate(120);
+ director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+
+ // Set the DisplayDeviceConfig
+ DisplayDeviceConfig ddcMock = mock(DisplayDeviceConfig.class);
+ when(ddcMock.getDefaultHighBlockingZoneRefreshRate()).thenReturn(90);
+ when(ddcMock.getHighDisplayBrightnessThresholds()).thenReturn(new float[] { 200 });
+ when(ddcMock.getHighAmbientBrightnessThresholds()).thenReturn(new float[] { 8000 });
+ when(ddcMock.getDefaultLowBlockingZoneRefreshRate()).thenReturn(90);
+ when(ddcMock.getLowDisplayBrightnessThresholds()).thenReturn(new float[] {});
+ when(ddcMock.getLowAmbientBrightnessThresholds()).thenReturn(new float[] {});
+
+ director.defaultDisplayDeviceUpdated(ddcMock); // set the ddc
+
+ Sensor lightSensor = createLightSensor();
+ SensorManager sensorManager = createMockSensorManager(lightSensor);
+ director.start(sensorManager);
+
+ // Get the sensor listener so that we can give it new light sensor events
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1)))
+ .registerListener(
+ listenerCaptor.capture(),
+ eq(lightSensor),
+ anyInt(),
+ any(Handler.class));
+ SensorEventListener sensorListener = listenerCaptor.getValue();
+
+ // Disable the idle screen flag
+ when(mDisplayManagerFlags.isIdleScreenRefreshRateTimeoutEnabled())
+ .thenReturn(false);
+
+ // Sensor reads 5 lux, with idleScreenRefreshRate timeout not configured
+ sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 5));
+ waitForIdleSync();
+ assertEquals(null, director.getBrightnessObserver().getIdleScreenRefreshRateConfig());
+
+ // Enable the idle screen flag
+ when(mDisplayManagerFlags.isIdleScreenRefreshRateTimeoutEnabled())
+ .thenReturn(true);
+ sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 8));
+ waitForIdleSync();
+ assertEquals(null, director.getBrightnessObserver().getIdleScreenRefreshRateConfig());
+
+ // Configure DDC with idle screen timeout
+ when(ddcMock.getIdleScreenRefreshRateTimeoutLuxThresholdPoint())
+ .thenReturn(List.of(getIdleScreenRefreshRateTimeoutLuxThresholdPoint(6, 1000),
+ getIdleScreenRefreshRateTimeoutLuxThresholdPoint(100, 800)));
+
+ // Sensor reads 5 lux
+ sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 5));
+ waitForIdleSync();
+ assertEquals(new SurfaceControl.IdleScreenRefreshRateConfig(-1),
+ director.getBrightnessObserver().getIdleScreenRefreshRateConfig());
+
+ // Sensor reads 50 lux
+ sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 50));
+ waitForIdleSync();
+ assertEquals(new IdleScreenRefreshRateConfig(1000),
+ director.getBrightnessObserver().getIdleScreenRefreshRateConfig());
+
+ // Sensor reads 200 lux
+ sensorListener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 200));
+ waitForIdleSync();
+ assertEquals(new SurfaceControl.IdleScreenRefreshRateConfig(800),
+ director.getBrightnessObserver().getIdleScreenRefreshRateConfig());
+
+ }
+
+ @Test
public void testLockFpsForHighZoneWithThermalCondition() throws Exception {
// First, configure brightness zones or DMD won't register for sensor data.
final FakeDeviceConfig config = mInjector.getDeviceConfig();
@@ -1440,11 +1519,11 @@ public class DisplayModeDirectorTest {
// Get the display listener so that we can send it new brightness events
ArgumentCaptor<DisplayListener> displayListenerCaptor =
- ArgumentCaptor.forClass(DisplayListener.class);
+ ArgumentCaptor.forClass(DisplayListener.class);
verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(),
any(Handler.class),
eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
- | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS));
DisplayListener displayListener = displayListenerCaptor.getValue();
// Get the sensor listener so that we can give it new light sensor events
@@ -3746,4 +3825,14 @@ public class DisplayModeDirectorTest {
}
}
}
+
+ private IdleScreenRefreshRateTimeoutLuxThresholdPoint
+ getIdleScreenRefreshRateTimeoutLuxThresholdPoint(int lux, int timeout) {
+ IdleScreenRefreshRateTimeoutLuxThresholdPoint
+ idleScreenRefreshRateTimeoutLuxThresholdPoint =
+ new IdleScreenRefreshRateTimeoutLuxThresholdPoint();
+ idleScreenRefreshRateTimeoutLuxThresholdPoint.setLux(BigInteger.valueOf(lux));
+ idleScreenRefreshRateTimeoutLuxThresholdPoint.setTimeout(BigInteger.valueOf(timeout));
+ return idleScreenRefreshRateTimeoutLuxThresholdPoint;
+ }
}