Loading core/java/android/view/SurfaceControl.java +92 −3 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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(); Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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); } } } Loading core/jni/android_view_SurfaceControl.cpp +50 −2 Original line number Diff line number Diff line Loading @@ -205,6 +205,12 @@ static struct { jfieldID render; } gRefreshRateRangesClassInfo; static struct { jclass clazz; jmethodID ctor; jfieldID timeoutMillis; } gIdleScreenRefreshRateConfigClassInfo; static struct { jclass clazz; jmethodID ctor; Loading @@ -212,6 +218,7 @@ static struct { jfieldID allowGroupSwitching; jfieldID primaryRanges; jfieldID appRequestRanges; jfieldID idleScreenRefreshRateConfig; } gDesiredDisplayModeSpecsClassInfo; static struct { Loading Loading @@ -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); Loading @@ -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; } Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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 = Loading @@ -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"); Loading services/core/java/com/android/server/display/DisplayDeviceConfig.java +6 −0 Original line number Diff line number Diff line Loading @@ -3471,6 +3471,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; } } Loading services/core/java/com/android/server/display/LocalDisplayAdapter.java +2 −1 Original line number Diff line number Diff line Loading @@ -1103,7 +1103,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { new SurfaceControl.DesiredDisplayModeSpecs(baseSfModeId, mDisplayModeSpecs.allowGroupSwitching, mDisplayModeSpecs.primary, mDisplayModeSpecs.appRequest))); mDisplayModeSpecs.appRequest, mDisplayModeSpecs.mIdleScreenRefreshRateConfig))); } } Loading services/core/java/com/android/server/display/mode/DisplayModeDirector.java +91 −7 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -184,6 +187,8 @@ public class DisplayModeDirector { private final boolean mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled; private final DisplayManagerFlags mDisplayManagerFlags; private final boolean mDvrrSupported; Loading @@ -206,7 +211,7 @@ public class DisplayModeDirector { .isDisplaysRefreshRatesSynchronizationEnabled(); mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled = displayManagerFlags .isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled(); mDisplayManagerFlags = displayManagerFlags; mContext = context; mHandler = new DisplayModeDirectorHandler(handler.getLooper()); mInjector = injector; Loading Loading @@ -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 = Loading Loading @@ -422,7 +427,8 @@ public class DisplayModeDirector { appRequestSummary.maxPhysicalRefreshRate), new RefreshRateRange( appRequestSummary.minRenderFrameRate, appRequestSummary.maxRenderFrameRate))); appRequestSummary.maxRenderFrameRate)), mBrightnessObserver.getIdleScreenRefreshRateConfig()); } } Loading Loading @@ -763,6 +769,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. */ Loading @@ -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; } /** Loading @@ -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)); } /** Loading Loading @@ -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); } /** Loading @@ -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); } } } Loading Loading @@ -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 = Loading Loading @@ -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); Loading Loading @@ -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 Loading Loading @@ -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 { Loading Loading
core/java/android/view/SurfaceControl.java +92 −3 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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(); Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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); } } } Loading
core/jni/android_view_SurfaceControl.cpp +50 −2 Original line number Diff line number Diff line Loading @@ -205,6 +205,12 @@ static struct { jfieldID render; } gRefreshRateRangesClassInfo; static struct { jclass clazz; jmethodID ctor; jfieldID timeoutMillis; } gIdleScreenRefreshRateConfigClassInfo; static struct { jclass clazz; jmethodID ctor; Loading @@ -212,6 +218,7 @@ static struct { jfieldID allowGroupSwitching; jfieldID primaryRanges; jfieldID appRequestRanges; jfieldID idleScreenRefreshRateConfig; } gDesiredDisplayModeSpecsClassInfo; static struct { Loading Loading @@ -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); Loading @@ -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; } Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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 = Loading @@ -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"); Loading
services/core/java/com/android/server/display/DisplayDeviceConfig.java +6 −0 Original line number Diff line number Diff line Loading @@ -3471,6 +3471,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; } } Loading
services/core/java/com/android/server/display/LocalDisplayAdapter.java +2 −1 Original line number Diff line number Diff line Loading @@ -1103,7 +1103,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { new SurfaceControl.DesiredDisplayModeSpecs(baseSfModeId, mDisplayModeSpecs.allowGroupSwitching, mDisplayModeSpecs.primary, mDisplayModeSpecs.appRequest))); mDisplayModeSpecs.appRequest, mDisplayModeSpecs.mIdleScreenRefreshRateConfig))); } } Loading
services/core/java/com/android/server/display/mode/DisplayModeDirector.java +91 −7 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -184,6 +187,8 @@ public class DisplayModeDirector { private final boolean mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled; private final DisplayManagerFlags mDisplayManagerFlags; private final boolean mDvrrSupported; Loading @@ -206,7 +211,7 @@ public class DisplayModeDirector { .isDisplaysRefreshRatesSynchronizationEnabled(); mIsBackUpSmoothDisplayAndForcePeakRefreshRateEnabled = displayManagerFlags .isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled(); mDisplayManagerFlags = displayManagerFlags; mContext = context; mHandler = new DisplayModeDirectorHandler(handler.getLooper()); mInjector = injector; Loading Loading @@ -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 = Loading Loading @@ -422,7 +427,8 @@ public class DisplayModeDirector { appRequestSummary.maxPhysicalRefreshRate), new RefreshRateRange( appRequestSummary.minRenderFrameRate, appRequestSummary.maxRenderFrameRate))); appRequestSummary.maxRenderFrameRate)), mBrightnessObserver.getIdleScreenRefreshRateConfig()); } } Loading Loading @@ -763,6 +769,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. */ Loading @@ -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; } /** Loading @@ -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)); } /** Loading Loading @@ -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); } /** Loading @@ -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); } } } Loading Loading @@ -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 = Loading Loading @@ -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); Loading Loading @@ -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 Loading Loading @@ -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 { Loading