Merge changes from topic "getsuggestedframerate" into main
* changes:
Adds getSuggestedFrameRate api
Adds support for getSuggestedFrameRate api
adds a flag for getSuggestedFrameRates api
diff --git a/core/api/current.txt b/core/api/current.txt
index 8bd4367..bebf98a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -51080,6 +51080,7 @@
method @NonNull public android.view.DisplayShape getShape();
method @Deprecated public void getSize(android.graphics.Point);
method public int getState();
+ method @FlaggedApi("com.android.server.display.feature.flags.enable_get_suggested_frame_rate") public float getSuggestedFrameRate(int);
method public android.view.Display.Mode[] getSupportedModes();
method @Deprecated public float[] getSupportedRefreshRates();
method @Deprecated public int getWidth();
@@ -51097,6 +51098,8 @@
field public static final int FLAG_ROUND = 16; // 0x10
field public static final int FLAG_SECURE = 2; // 0x2
field public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 1; // 0x1
+ field @FlaggedApi("com.android.server.display.feature.flags.enable_get_suggested_frame_rate") public static final int FRAME_RATE_CATEGORY_HIGH = 1; // 0x1
+ field @FlaggedApi("com.android.server.display.feature.flags.enable_get_suggested_frame_rate") public static final int FRAME_RATE_CATEGORY_NORMAL = 0; // 0x0
field public static final int INVALID_DISPLAY = -1; // 0xffffffff
field public static final int STATE_DOZE = 3; // 0x3
field public static final int STATE_DOZE_SUSPEND = 4; // 0x4
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index e940e55bd..910e644 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -22,6 +22,7 @@
import static com.android.server.display.feature.flags.Flags.FLAG_HIGHEST_HDR_SDR_RATIO_API;
import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_HAS_ARR_SUPPORT;
+import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_GET_SUGGESTED_FRAME_RATE;
import android.Manifest;
import android.annotation.FlaggedApi;
@@ -1278,6 +1279,60 @@
}
}
+ @FlaggedApi(FLAG_ENABLE_GET_SUGGESTED_FRAME_RATE)
+ public static final int FRAME_RATE_CATEGORY_NORMAL = 0;
+ @FlaggedApi(FLAG_ENABLE_GET_SUGGESTED_FRAME_RATE)
+ public static final int FRAME_RATE_CATEGORY_HIGH = 1;
+
+ /**
+ * @hide
+ */
+ @IntDef(prefix = {"FRAME_RATE_CATEGORY_"},
+ value = {
+ FRAME_RATE_CATEGORY_NORMAL,
+ FRAME_RATE_CATEGORY_HIGH
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FrameRateCategory {}
+
+ /**
+ * <p> Gets the display-defined frame rate given a descriptive frame rate category. </p>
+ *
+ * <p> For example, an animation that does not require fast render rates can use
+ * the {@link #FRAME_RATE_CATEGORY_NORMAL} to get the suggested frame rate.
+ * The suggested frame rate then can be used in the
+ * {@link Surface.FrameRateParams.Builder#setDesiredRateRange} for desiredMinRate.
+ *
+ * <pre>{@code
+ * float desiredMinRate = display.getSuggestedFrameRate(FRAME_RATE_CATEGORY_NORMAL);
+ * Surface.FrameRateParams params = new Surface.FrameRateParams.Builder().
+ * setDesiredRateRange(desiredMinRate, Float.MAX).build();
+ * surface.setFrameRate(params);
+ * }</pre>
+ * </p>
+ *
+ * @param category either {@link #FRAME_RATE_CATEGORY_NORMAL}
+ * or {@link #FRAME_RATE_CATEGORY_HIGH}
+ *
+ * @see Surface#setFrameRate(Surface.FrameRateParams)
+ * @see SurfaceControl.Transaction#setFrameRate(SurfaceControl, Surface.FrameRateParams)
+ * @throws IllegalArgumentException when category is not {@link #FRAME_RATE_CATEGORY_NORMAL}
+ * or {@link #FRAME_RATE_CATEGORY_HIGH}
+ */
+ @FlaggedApi(FLAG_ENABLE_GET_SUGGESTED_FRAME_RATE)
+ public float getSuggestedFrameRate(@FrameRateCategory int category) {
+ synchronized (mLock) {
+ updateDisplayInfoLocked();
+ if (category == FRAME_RATE_CATEGORY_HIGH) {
+ return mDisplayInfo.frameRateCategoryRate.getHigh();
+ } else if (category == FRAME_RATE_CATEGORY_NORMAL) {
+ return mDisplayInfo.frameRateCategoryRate.getNormal();
+ } else {
+ throw new IllegalArgumentException("Invalid FrameRateCategory provided");
+ }
+ }
+ }
+
/**
* <p> Returns true if the connected display can be switched into a mode with minimal
* post processing. </p>
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 26fce90..8f112f3 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -204,6 +204,12 @@
public boolean hasArrSupport;
/**
+ * Represents frame rate for the FrameRateCategory Normal and High.
+ * @see android.view.Display#getSuggestedFrameRate(int) for more details.
+ */
+ public FrameRateCategoryRate frameRateCategoryRate;
+
+ /**
* The default display mode.
*/
public int defaultModeId;
@@ -443,6 +449,7 @@
&& modeId == other.modeId
&& renderFrameRate == other.renderFrameRate
&& hasArrSupport == other.hasArrSupport
+ && Objects.equals(frameRateCategoryRate, other.frameRateCategoryRate)
&& defaultModeId == other.defaultModeId
&& userPreferredModeId == other.userPreferredModeId
&& Arrays.equals(supportedModes, other.supportedModes)
@@ -505,6 +512,7 @@
modeId = other.modeId;
renderFrameRate = other.renderFrameRate;
hasArrSupport = other.hasArrSupport;
+ frameRateCategoryRate = other.frameRateCategoryRate;
defaultModeId = other.defaultModeId;
userPreferredModeId = other.userPreferredModeId;
supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length);
@@ -562,6 +570,8 @@
modeId = source.readInt();
renderFrameRate = source.readFloat();
hasArrSupport = source.readBoolean();
+ frameRateCategoryRate = source.readParcelable(null,
+ android.view.FrameRateCategoryRate.class);
defaultModeId = source.readInt();
userPreferredModeId = source.readInt();
int nModes = source.readInt();
@@ -636,6 +646,7 @@
dest.writeInt(modeId);
dest.writeFloat(renderFrameRate);
dest.writeBoolean(hasArrSupport);
+ dest.writeParcelable(frameRateCategoryRate, flags);
dest.writeInt(defaultModeId);
dest.writeInt(userPreferredModeId);
dest.writeInt(supportedModes.length);
@@ -883,6 +894,8 @@
sb.append(renderFrameRate);
sb.append(", hasArrSupport ");
sb.append(hasArrSupport);
+ sb.append(", frameRateCategoryRate ");
+ sb.append(frameRateCategoryRate);
sb.append(", defaultMode ");
sb.append(defaultModeId);
sb.append(", userPreferredModeId ");
diff --git a/core/java/android/view/FrameRateCategoryRate.java b/core/java/android/view/FrameRateCategoryRate.java
new file mode 100644
index 0000000..3c674b8
--- /dev/null
+++ b/core/java/android/view/FrameRateCategoryRate.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class to create and manage FrameRateCategoryRate for
+ * categories Normal and High.
+ * @hide
+ */
+public class FrameRateCategoryRate implements Parcelable {
+
+ private final float mNormal;
+ private final float mHigh;
+
+ /**
+ * Creates a FrameRateCategoryRate with the provided rates
+ * for the categories Normal and High respectively;
+ *
+ * @param normal rate for the category Normal.
+ * @param high rate for the category High.
+ * @hide
+ */
+ public FrameRateCategoryRate(float normal, float high) {
+ this.mNormal = normal;
+ this.mHigh = high;
+ }
+
+ /**
+ * @return the value for the category normal;
+ * @hide
+ */
+ public float getNormal() {
+ return mNormal;
+ }
+
+ /**
+ * @return the value for the category high;
+ * @hide
+ */
+ public float getHigh() {
+ return mHigh;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof FrameRateCategoryRate)) {
+ return false;
+ }
+ FrameRateCategoryRate that = (FrameRateCategoryRate) o;
+ return mNormal == that.mNormal && mHigh == that.mHigh;
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 1;
+ result = 31 * result + Float.hashCode(mNormal);
+ result = 31 * result + Float.hashCode(mHigh);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "FrameRateCategoryRate {"
+ + "normal=" + mNormal
+ + ", high=" + mHigh
+ + '}';
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeFloat(mNormal);
+ dest.writeFloat(mHigh);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<FrameRateCategoryRate> CREATOR =
+ new Creator<>() {
+ @Override
+ public FrameRateCategoryRate createFromParcel(Parcel in) {
+ return new FrameRateCategoryRate(in.readFloat(), in.readFloat());
+ }
+
+ @Override
+ public FrameRateCategoryRate[] newArray(int size) {
+ return new FrameRateCategoryRate[size];
+ }
+ };
+}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index ece2a60..0d55544 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -1798,6 +1798,7 @@
public int activeDisplayModeId;
public float renderFrameRate;
public boolean hasArrSupport;
+ public FrameRateCategoryRate frameRateCategoryRate;
public int[] supportedColorModes;
public int activeColorMode;
@@ -1816,6 +1817,7 @@
+ ", activeDisplayModeId=" + activeDisplayModeId
+ ", renderFrameRate=" + renderFrameRate
+ ", hasArrSupport=" + hasArrSupport
+ + ", frameRateCategoryRate=" + frameRateCategoryRate
+ ", supportedColorModes=" + Arrays.toString(supportedColorModes)
+ ", activeColorMode=" + activeColorMode
+ ", hdrCapabilities=" + hdrCapabilities
@@ -1836,13 +1838,15 @@
&& activeColorMode == that.activeColorMode
&& Objects.equals(hdrCapabilities, that.hdrCapabilities)
&& preferredBootDisplayMode == that.preferredBootDisplayMode
- && hasArrSupport == that.hasArrSupport;
+ && hasArrSupport == that.hasArrSupport
+ && Objects.equals(frameRateCategoryRate, that.frameRateCategoryRate);
}
@Override
public int hashCode() {
return Objects.hash(Arrays.hashCode(supportedDisplayModes), activeDisplayModeId,
- renderFrameRate, activeColorMode, hdrCapabilities, hasArrSupport);
+ renderFrameRate, activeColorMode, hdrCapabilities, hasArrSupport,
+ frameRateCategoryRate);
}
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index f162b74..7fefe17 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -117,6 +117,7 @@
jfieldID activeDisplayModeId;
jfieldID renderFrameRate;
jfieldID hasArrSupport;
+ jfieldID frameRateCategoryRate;
jfieldID supportedColorModes;
jfieldID activeColorMode;
jfieldID hdrCapabilities;
@@ -292,6 +293,11 @@
jfieldID frameNumber;
} gStalledTransactionInfoClassInfo;
+static struct {
+ jclass clazz;
+ jmethodID ctor;
+} gFrameRateCategoryRateClassInfo;
+
constexpr ui::Dataspace pickDataspaceFromColorMode(const ui::ColorMode colorMode) {
switch (colorMode) {
case ui::ColorMode::DISPLAY_P3:
@@ -1388,6 +1394,13 @@
return object;
}
+static jobject convertFrameRateCategoryRateToJavaObject(
+ JNIEnv* env, const ui::FrameRateCategoryRate& frameRateCategoryRate) {
+ return env->NewObject(gFrameRateCategoryRateClassInfo.clazz,
+ gFrameRateCategoryRateClassInfo.ctor, frameRateCategoryRate.getNormal(),
+ frameRateCategoryRate.getHigh());
+}
+
static jobject convertDisplayModeToJavaObject(JNIEnv* env, const ui::DisplayMode& config) {
jobject object = env->NewObject(gDisplayModeClassInfo.clazz, gDisplayModeClassInfo.ctor);
env->SetIntField(object, gDisplayModeClassInfo.id, config.id);
@@ -1456,6 +1469,8 @@
info.activeDisplayModeId);
env->SetFloatField(object, gDynamicDisplayInfoClassInfo.renderFrameRate, info.renderFrameRate);
env->SetBooleanField(object, gDynamicDisplayInfoClassInfo.hasArrSupport, info.hasArrSupport);
+ env->SetObjectField(object, gDynamicDisplayInfoClassInfo.frameRateCategoryRate,
+ convertFrameRateCategoryRateToJavaObject(env, info.frameRateCategoryRate));
jintArray colorModesArray = env->NewIntArray(info.supportedColorModes.size());
if (colorModesArray == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
@@ -2666,6 +2681,15 @@
GetFieldIDOrDie(env, dynamicInfoClazz, "renderFrameRate", "F");
gDynamicDisplayInfoClassInfo.hasArrSupport =
GetFieldIDOrDie(env, dynamicInfoClazz, "hasArrSupport", "Z");
+
+ gDynamicDisplayInfoClassInfo.frameRateCategoryRate =
+ GetFieldIDOrDie(env, dynamicInfoClazz, "frameRateCategoryRate",
+ "Landroid/view/FrameRateCategoryRate;");
+ jclass frameRateCategoryRateClazz = FindClassOrDie(env, "android/view/FrameRateCategoryRate");
+ gFrameRateCategoryRateClassInfo.clazz = MakeGlobalRefOrDie(env, frameRateCategoryRateClazz);
+ gFrameRateCategoryRateClassInfo.ctor =
+ GetMethodIDOrDie(env, frameRateCategoryRateClazz, "<init>", "(FF)V");
+
gDynamicDisplayInfoClassInfo.supportedColorModes =
GetFieldIDOrDie(env, dynamicInfoClazz, "supportedColorModes", "[I");
gDynamicDisplayInfoClassInfo.activeColorMode =
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 0807c70..4ad7c10 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -26,6 +26,7 @@
import android.view.DisplayCutout;
import android.view.DisplayEventReceiver;
import android.view.DisplayShape;
+import android.view.FrameRateCategoryRate;
import android.view.RoundedCorners;
import android.view.Surface;
@@ -300,6 +301,11 @@
public boolean hasArrSupport;
/**
+ * Represents frame rate for the FrameRateCategory Normal and High.
+ * @see android.view.Display#getSuggestedFrameRate(int) for more details.
+ */
+ public FrameRateCategoryRate frameRateCategoryRate;
+ /**
* The default mode of the display.
*/
public int defaultModeId;
@@ -548,7 +554,8 @@
|| !Objects.equals(roundedCorners, other.roundedCorners)
|| installOrientation != other.installOrientation
|| !Objects.equals(displayShape, other.displayShape)
- || hasArrSupport != other.hasArrSupport) {
+ || hasArrSupport != other.hasArrSupport
+ || !Objects.equals(frameRateCategoryRate, other.frameRateCategoryRate)) {
diff |= DIFF_OTHER;
}
return diff;
@@ -567,6 +574,7 @@
modeId = other.modeId;
renderFrameRate = other.renderFrameRate;
hasArrSupport = other.hasArrSupport;
+ frameRateCategoryRate = other.frameRateCategoryRate;
defaultModeId = other.defaultModeId;
userPreferredModeId = other.userPreferredModeId;
supportedModes = other.supportedModes;
@@ -612,6 +620,7 @@
sb.append(", modeId ").append(modeId);
sb.append(", renderFrameRate ").append(renderFrameRate);
sb.append(", hasArrSupport ").append(hasArrSupport);
+ sb.append(", frameRateCategoryRate ").append(frameRateCategoryRate);
sb.append(", defaultModeId ").append(defaultModeId);
sb.append(", userPreferredModeId ").append(userPreferredModeId);
sb.append(", supportedModes ").append(Arrays.toString(supportedModes));
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index f9c3a46..a4bb8c3 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -45,6 +45,7 @@
import android.view.DisplayCutout;
import android.view.DisplayEventReceiver;
import android.view.DisplayShape;
+import android.view.FrameRateCategoryRate;
import android.view.RoundedCorners;
import android.view.SurfaceControl;
@@ -247,6 +248,7 @@
private boolean mDisplayModeSpecsInvalid;
private int mActiveColorMode;
private boolean mHasArrSupport;
+ private FrameRateCategoryRate mFrameRateCategoryRate;
private Display.HdrCapabilities mHdrCapabilities;
private boolean mAllmSupported;
private boolean mGameContentTypeSupported;
@@ -313,6 +315,7 @@
changed |= updateAllmSupport(dynamicInfo.autoLowLatencyModeSupported);
changed |= updateGameContentTypeSupport(dynamicInfo.gameContentTypeSupported);
changed |= updateHasArrSupportLocked(dynamicInfo.hasArrSupport);
+ changed |= updateFrameRateCategoryRatesLocked(dynamicInfo.frameRateCategoryRate);
if (changed) {
mHavePendingChanges = true;
@@ -604,6 +607,15 @@
return true;
}
+ private boolean updateFrameRateCategoryRatesLocked(
+ FrameRateCategoryRate newFrameRateCategoryRate) {
+ if (Objects.equals(mFrameRateCategoryRate, newFrameRateCategoryRate)) {
+ return false;
+ }
+ mFrameRateCategoryRate = newFrameRateCategoryRate;
+ return true;
+ }
+
private boolean updateHasArrSupportLocked(boolean newHasArrSupport) {
if (mHasArrSupport == newHasArrSupport) {
return false;
@@ -695,6 +707,7 @@
}
mInfo.hdrCapabilities = mHdrCapabilities;
mInfo.hasArrSupport = mHasArrSupport;
+ mInfo.frameRateCategoryRate = mFrameRateCategoryRate;
mInfo.appVsyncOffsetNanos = mActiveSfDisplayMode.appVsyncOffsetNanos;
mInfo.presentationDeadlineNanos = mActiveSfDisplayMode.presentationDeadlineNanos;
mInfo.state = mState;
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 074a4d8..7cfdcaf 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -507,6 +507,7 @@
mBaseDisplayInfo.modeId = deviceInfo.modeId;
mBaseDisplayInfo.renderFrameRate = deviceInfo.renderFrameRate;
mBaseDisplayInfo.hasArrSupport = deviceInfo.hasArrSupport;
+ mBaseDisplayInfo.frameRateCategoryRate = deviceInfo.frameRateCategoryRate;
mBaseDisplayInfo.defaultModeId = deviceInfo.defaultModeId;
mBaseDisplayInfo.userPreferredModeId = deviceInfo.userPreferredModeId;
mBaseDisplayInfo.supportedModes = Arrays.copyOf(
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 36cadf5..f49608b 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -430,3 +430,11 @@
bug: "350617205"
is_fixed_read_only: true
}
+
+flag {
+ name: "enable_get_suggested_frame_rate"
+ namespace: "core_graphics"
+ description: "Flag for an API to get suggested frame rates"
+ bug: "361433796"
+ is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
index cbe3d79..6f8c17a 100644
--- a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
+++ b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
@@ -402,6 +402,7 @@
|| first.modeId != second.modeId
|| first.renderFrameRate != second.renderFrameRate
|| first.hasArrSupport != second.hasArrSupport
+ || !Objects.equals(first.frameRateCategoryRate, second.frameRateCategoryRate)
|| first.defaultModeId != second.defaultModeId
|| first.userPreferredModeId != second.userPreferredModeId
|| !Arrays.equals(first.supportedModes, second.supportedModes)
diff --git a/services/tests/wmtests/src/com/android/server/wm/DeferredDisplayUpdaterDiffTest.java b/services/tests/wmtests/src/com/android/server/wm/DeferredDisplayUpdaterDiffTest.java
index 44b69f1..c9c31df 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DeferredDisplayUpdaterDiffTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DeferredDisplayUpdaterDiffTest.java
@@ -39,6 +39,7 @@
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.DisplayShape;
+import android.view.FrameRateCategoryRate;
import android.view.RoundedCorner;
import android.view.RoundedCorners;
import android.view.SurfaceControl.RefreshRateRange;
@@ -235,6 +236,9 @@
} else if (type.isArray() && type.getComponentType().equals(Display.Mode.class)) {
field.set(first, new Display.Mode[]{new Display.Mode(100, 200, 300)});
field.set(second, new Display.Mode[]{new Display.Mode(10, 20, 30)});
+ } else if (type.equals(FrameRateCategoryRate.class)) {
+ field.set(first, new FrameRateCategoryRate(16666667, 11111111));
+ field.set(second, new FrameRateCategoryRate(11111111, 8333333));
} else {
throw new IllegalArgumentException("Field " + field
+ " is not supported by this test, please add implementation of setting "