Introduce SurfaceControlCompat.Transaction#setFrameRate API
Relnote: "Add setFrameRate/clearFrameRate APIs to
SurfaceControlCompat.Transaction in order to control the
frame rate alongside the change strategy for seamless or
default transitions."
Bug: 304785682
Test: Added tests to SurfaceControlCompatTest
Change-Id: I6045cfe9bba4247fe93f7eb6cdc67e61d65dbf29
diff --git a/graphics/graphics-core/api/current.txt b/graphics/graphics-core/api/current.txt
index 83cce7a..f8106c2 100644
--- a/graphics/graphics-core/api/current.txt
+++ b/graphics/graphics-core/api/current.txt
@@ -327,7 +327,11 @@
field public static final int BUFFER_TRANSFORM_ROTATE_180 = 3; // 0x3
field public static final int BUFFER_TRANSFORM_ROTATE_270 = 7; // 0x7
field public static final int BUFFER_TRANSFORM_ROTATE_90 = 4; // 0x4
+ field public static final int CHANGE_FRAME_RATE_ALWAYS = 1; // 0x1
+ field public static final int CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS = 0; // 0x0
field public static final androidx.graphics.surface.SurfaceControlCompat.Companion Companion;
+ field public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0; // 0x0
+ field public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; // 0x1
}
public static final class SurfaceControlCompat.Builder {
@@ -344,6 +348,7 @@
@RequiresApi(android.os.Build.VERSION_CODES.Q) public static final class SurfaceControlCompat.Transaction implements java.lang.AutoCloseable {
ctor public SurfaceControlCompat.Transaction();
method @RequiresApi(android.os.Build.VERSION_CODES.S) public androidx.graphics.surface.SurfaceControlCompat.Transaction addTransactionCommittedListener(java.util.concurrent.Executor executor, androidx.graphics.surface.SurfaceControlCompat.TransactionCommittedListener listener);
+ method public androidx.graphics.surface.SurfaceControlCompat.Transaction clearFrameRate(androidx.graphics.surface.SurfaceControlCompat surfaceControl);
method public void close();
method public void commit();
method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public void commitTransactionOnDraw(android.view.AttachedSurfaceControl attachedSurfaceControl);
@@ -358,6 +363,7 @@
method public androidx.graphics.surface.SurfaceControlCompat.Transaction setDamageRegion(androidx.graphics.surface.SurfaceControlCompat surfaceControl, android.graphics.Region? region);
method public androidx.graphics.surface.SurfaceControlCompat.Transaction setDataSpace(androidx.graphics.surface.SurfaceControlCompat surfaceControl, int dataSpace);
method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public androidx.graphics.surface.SurfaceControlCompat.Transaction setExtendedRangeBrightness(androidx.graphics.surface.SurfaceControlCompat surfaceControl, @FloatRange(from=1.0, fromInclusive=true) float currentBufferRatio, @FloatRange(from=1.0, fromInclusive=true) float desiredRatio);
+ method public androidx.graphics.surface.SurfaceControlCompat.Transaction setFrameRate(androidx.graphics.surface.SurfaceControlCompat surfaceControl, float frameRate, int compatibility, int changeFrameRateStrategy);
method public androidx.graphics.surface.SurfaceControlCompat.Transaction setLayer(androidx.graphics.surface.SurfaceControlCompat surfaceControl, int z);
method public androidx.graphics.surface.SurfaceControlCompat.Transaction setOpaque(androidx.graphics.surface.SurfaceControlCompat surfaceControl, boolean isOpaque);
method public androidx.graphics.surface.SurfaceControlCompat.Transaction setPosition(androidx.graphics.surface.SurfaceControlCompat surfaceControl, float x, float y);
diff --git a/graphics/graphics-core/api/restricted_current.txt b/graphics/graphics-core/api/restricted_current.txt
index 1977cae..ea20f69 100644
--- a/graphics/graphics-core/api/restricted_current.txt
+++ b/graphics/graphics-core/api/restricted_current.txt
@@ -328,7 +328,11 @@
field public static final int BUFFER_TRANSFORM_ROTATE_180 = 3; // 0x3
field public static final int BUFFER_TRANSFORM_ROTATE_270 = 7; // 0x7
field public static final int BUFFER_TRANSFORM_ROTATE_90 = 4; // 0x4
+ field public static final int CHANGE_FRAME_RATE_ALWAYS = 1; // 0x1
+ field public static final int CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS = 0; // 0x0
field public static final androidx.graphics.surface.SurfaceControlCompat.Companion Companion;
+ field public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0; // 0x0
+ field public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; // 0x1
}
public static final class SurfaceControlCompat.Builder {
@@ -345,6 +349,7 @@
@RequiresApi(android.os.Build.VERSION_CODES.Q) public static final class SurfaceControlCompat.Transaction implements java.lang.AutoCloseable {
ctor public SurfaceControlCompat.Transaction();
method @RequiresApi(android.os.Build.VERSION_CODES.S) public androidx.graphics.surface.SurfaceControlCompat.Transaction addTransactionCommittedListener(java.util.concurrent.Executor executor, androidx.graphics.surface.SurfaceControlCompat.TransactionCommittedListener listener);
+ method public androidx.graphics.surface.SurfaceControlCompat.Transaction clearFrameRate(androidx.graphics.surface.SurfaceControlCompat surfaceControl);
method public void close();
method public void commit();
method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public void commitTransactionOnDraw(android.view.AttachedSurfaceControl attachedSurfaceControl);
@@ -359,6 +364,7 @@
method public androidx.graphics.surface.SurfaceControlCompat.Transaction setDamageRegion(androidx.graphics.surface.SurfaceControlCompat surfaceControl, android.graphics.Region? region);
method public androidx.graphics.surface.SurfaceControlCompat.Transaction setDataSpace(androidx.graphics.surface.SurfaceControlCompat surfaceControl, int dataSpace);
method @RequiresApi(android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public androidx.graphics.surface.SurfaceControlCompat.Transaction setExtendedRangeBrightness(androidx.graphics.surface.SurfaceControlCompat surfaceControl, @FloatRange(from=1.0, fromInclusive=true) float currentBufferRatio, @FloatRange(from=1.0, fromInclusive=true) float desiredRatio);
+ method public androidx.graphics.surface.SurfaceControlCompat.Transaction setFrameRate(androidx.graphics.surface.SurfaceControlCompat surfaceControl, float frameRate, int compatibility, int changeFrameRateStrategy);
method public androidx.graphics.surface.SurfaceControlCompat.Transaction setLayer(androidx.graphics.surface.SurfaceControlCompat surfaceControl, int z);
method public androidx.graphics.surface.SurfaceControlCompat.Transaction setOpaque(androidx.graphics.surface.SurfaceControlCompat surfaceControl, boolean isOpaque);
method public androidx.graphics.surface.SurfaceControlCompat.Transaction setPosition(androidx.graphics.surface.SurfaceControlCompat surfaceControl, float x, float y);
diff --git a/graphics/graphics-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlCompatTest.kt b/graphics/graphics-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlCompatTest.kt
index b42c7c6..a63e68b 100644
--- a/graphics/graphics-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlCompatTest.kt
+++ b/graphics/graphics-core/src/androidTest/java/androidx/graphics/surface/SurfaceControlCompatTest.kt
@@ -1482,6 +1482,137 @@
}
}
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.Q)
+ @Test
+ fun testSetFrameRate120WithDefaultCompatibilityAndAlwaysChangeStrategy() {
+ testFrameRate(
+ 120f,
+ SurfaceControlCompat.FRAME_RATE_COMPATIBILITY_DEFAULT,
+ SurfaceControlCompat.CHANGE_FRAME_RATE_ALWAYS
+ )
+ }
+
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.Q)
+ @Test
+ fun testSetFrameRateNegativeWithDefaultCompatibilityAndAlwaysChangeStrategy() {
+ testFrameRate(
+ -50f,
+ SurfaceControlCompat.FRAME_RATE_COMPATIBILITY_DEFAULT,
+ SurfaceControlCompat.CHANGE_FRAME_RATE_ALWAYS
+ )
+ }
+
+ @SuppressLint("NewApi")
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.Q)
+ @Test
+ fun testSetFrameRateZeroWithDefaultCompatibilityAndAlwaysChangeStrategy() {
+ testFrameRate(
+ 0f,
+ SurfaceControlCompat.FRAME_RATE_COMPATIBILITY_DEFAULT,
+ SurfaceControlCompat.CHANGE_FRAME_RATE_ALWAYS
+ )
+ }
+
+ @SuppressLint("NewApi")
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.Q)
+ @Test
+ fun testSetFrameRateInvalidCompatibility() {
+ testFrameRate(
+ 120f,
+ 42,
+ SurfaceControlCompat.CHANGE_FRAME_RATE_ALWAYS
+ )
+ }
+
+ @SuppressLint("NewApi")
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.Q)
+ @Test
+ fun testSetFrameRateInvalidStrategy() {
+ testFrameRate(
+ 120f,
+ SurfaceControlCompat.FRAME_RATE_COMPATIBILITY_DEFAULT,
+ 108
+ )
+ }
+
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.Q)
+ @Test
+ fun testClearFrameRate() {
+ ActivityScenario.launch(SurfaceControlWrapperTestActivity::class.java)
+ .moveToState(
+ Lifecycle.State.CREATED
+ ).onActivity {
+ val callback = object : SurfaceHolderCallback() {
+ override fun surfaceCreated(sh: SurfaceHolder) {
+
+ val surfaceControl = SurfaceControlCompat.Builder()
+ .setName("testSurfaceControl")
+ .setParent(it.mSurfaceView)
+ .build()
+ SurfaceControlCompat.Transaction()
+ .clearFrameRate(surfaceControl)
+ .commit()
+ }
+ }
+
+ it.addSurface(it.mSurfaceView, callback)
+ }
+ }
+
+ private fun testFrameRate(frameRate: Float, compatibility: Int, strategy: Int) {
+ ActivityScenario.launch(SurfaceControlWrapperTestActivity::class.java)
+ .moveToState(
+ Lifecycle.State.CREATED
+ ).onActivity {
+ val callback = object : SurfaceHolderCallback() {
+ override fun surfaceCreated(sh: SurfaceHolder) {
+
+ val surfaceControl = SurfaceControlCompat.Builder()
+ .setName("testSurfaceControl")
+ .setParent(it.mSurfaceView)
+ .build()
+ SurfaceControlCompat.Transaction()
+ .setFrameRate(surfaceControl, frameRate, compatibility, strategy)
+ .commit()
+ }
+ }
+
+ it.addSurface(it.mSurfaceView, callback)
+ }
+ }
+
+ @SuppressLint("NewApi")
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.S_V2)
+ @Test
+ fun testSetDataSpaceThrowsOnUnsupportedPlatforms() {
+ ActivityScenario.launch(SurfaceControlWrapperTestActivity::class.java)
+ .moveToState(
+ Lifecycle.State.CREATED
+ ).onActivity {
+ val callback = object : SurfaceHolderCallback() {
+ override fun surfaceCreated(sh: SurfaceHolder) {
+
+ assertThrows(UnsupportedOperationException::class.java) {
+ val surfaceControl = SurfaceControlCompat.Builder()
+ .setName("testSurfaceControl")
+ .setParent(it.mSurfaceView)
+ .build()
+
+ val extendedDataspace = DataSpace.pack(
+ DataSpace.STANDARD_BT709,
+ DataSpace.TRANSFER_SRGB, DataSpace.RANGE_EXTENDED
+ )
+ SurfaceControlCompat.Transaction()
+ .setDataSpace(surfaceControl, extendedDataspace)
+ .commit()
+ }
+ }
+ }
+
+ it.addSurface(it.mSurfaceView, callback)
+ }
+ }
+
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@Test
fun testSetExtendedRangeBrightness() {
diff --git a/graphics/graphics-core/src/main/cpp/graphics-core.cpp b/graphics/graphics-core/src/main/cpp/graphics-core.cpp
index 47a529f..4603022 100644
--- a/graphics/graphics-core/src/main/cpp/graphics-core.cpp
+++ b/graphics/graphics-core/src/main/cpp/graphics-core.cpp
@@ -486,6 +486,28 @@
return static_cast<jint>(fd);
}
+void JniBindings_nSetFrameRate(JNIEnv *env, jclass,
+ jlong surfaceTransaction,
+ jlong surfaceControl,
+ jfloat framerate,
+ jint compatibility,
+ jint changeFrameRateStrategy) {
+ auto st = reinterpret_cast<ASurfaceTransaction *>(surfaceTransaction);
+ auto sc = reinterpret_cast<ASurfaceControl *>(surfaceControl);
+
+ if (android_get_device_api_level() >= 31) {
+ ASurfaceTransaction_setFrameRateWithChangeStrategy(
+ st,
+ sc,
+ framerate,
+ compatibility,
+ changeFrameRateStrategy
+ );
+ } else if (android_get_device_api_level() >= 30) {
+ ASurfaceTransaction_setFrameRate(st, sc, framerate, compatibility);
+ }
+}
+
void loadRectInfo(JNIEnv *env) {
gRectInfo.clazz = env->FindClass("android/graphics/Rect");
@@ -621,6 +643,11 @@
"nGetPreviousReleaseFenceFd",
"(JJ)I",
(void *)JniBindings_nGetPreviousReleaseFenceFd
+ },
+ {
+ "nSetFrameRate",
+ "(JJFII)V",
+ (void *) JniBindings_nSetFrameRate
}
};
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlCompat.kt b/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlCompat.kt
index 355dbda..d616a42 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlCompat.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlCompat.kt
@@ -53,12 +53,13 @@
internal val scImpl: SurfaceControlImpl
) {
- /**
- * Constants for [Transaction.setBufferTransform].
- *
- * Various transformations that can be applied to a buffer.
- */
companion object {
+
+ /**
+ * Constants for [Transaction.setBufferTransform].
+ *
+ * Various transformations that can be applied to a buffer.
+ */
@Suppress("AcronymName")
@IntDef(
value = [BUFFER_TRANSFORM_IDENTITY, BUFFER_TRANSFORM_MIRROR_HORIZONTAL,
@@ -96,6 +97,55 @@
* Rotates the buffer 270 degrees clockwise. Maps a point (x, y) to (y, -x)
*/
const val BUFFER_TRANSFORM_ROTATE_270 = 7
+
+ /**
+ * Constants for [Transaction.setFrameRate]
+ */
+ @IntDef(
+ value = [CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, CHANGE_FRAME_RATE_ALWAYS]
+ )
+ internal annotation class ChangeFrameRateStrategy
+
+ /**
+ * Change the frame rate only if the transition is going to be seamless.
+ */
+ const val CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS = 0
+
+ /**
+ * Change the frame rate even if the transition is going to be non-seamless, i.e.
+ * with visual interruptions for the user.
+ */
+ const val CHANGE_FRAME_RATE_ALWAYS = 1
+
+ /**
+ * Constants for configuring compatibility for [Transaction.setFrameRate]
+ */
+ @IntDef(
+ value = [FRAME_RATE_COMPATIBILITY_DEFAULT, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE]
+ )
+ internal annotation class FrameRateCompatibility
+
+ /**
+ * There are no inherent restrictions on the frame rate. When the system selects a frame
+ * rate other than what the app requested, the app will be able to run at the system frame
+ * rate without requiring pull down (the mechanical process of "pulling", physically moving,
+ * frame content downward to advance it from one frame to the next at a repetitive rate).
+ * This value should be used when displaying game content, UIs, and anything that isn't
+ * video.
+ */
+ const val FRAME_RATE_COMPATIBILITY_DEFAULT = 0
+
+ /**
+ * This compositing layer is being used to display content with an inherently fixed frame
+ * rate, e.g. a video that has a specific frame rate. When the system selects a frame rate
+ * other than what the app requested, the app will need to do pull down or use some other
+ * technique to adapt to the system's frame rate. Pull down involves the mechanical process
+ * of "pulling", physically moving, frame content downward to advance it from one frame to
+ * the next at a repetitive rate). The user experience is likely to be worse
+ * (e.g. more frame stuttering) than it would be if the system had chosen the app's
+ * requested frame rate. This value should be used for video content.
+ */
+ const val FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1
}
/**
@@ -486,6 +536,74 @@
}
/**
+ * Sets the intended frame rate for [SurfaceControlCompat].
+ *
+ * On devices that are capable of running the display at different refresh rates, the
+ * system may choose a display refresh rate to better match this surface's frame rate.
+ * Usage of this API won't directly affect the application's frame production pipeline.
+ * However, because the system may change the display refresh rate, calls to this function
+ * may result in changes to Choreographer callback timings, and changes to the time interval
+ * at which the system releases buffers back to the application.
+ *
+ * This method is only supported on Android R+ and is ignored on older platform versions.
+ *
+ * @param surfaceControl The target [SurfaceControlCompat] that will have it's frame rate
+ * changed
+ * @param frameRate The intended frame rate of this surface, in frames per second. 0 is a
+ * special value that indicates the app will accept the system's choice for the display
+ * frame rate, which is the default behavior if this function isn't called. Must be
+ * greater than or equal to 0.
+ * The frameRate param does not need to be a valid refresh rate for this device's display
+ * - e.g., it's fine to pass 30fps to a device that can only run the display at 60fps.
+ * @param compatibility The frame rate compatibility of this surface. The compatibility
+ * value may influence the system's choice of display frame rate. This must be either
+ * [FRAME_RATE_COMPATIBILITY_DEFAULT] or [FRAME_RATE_COMPATIBILITY_FIXED_SOURCE]
+ * This parameter is ignored when frameRate is 0.
+ * @param changeFrameRateStrategy Whether display refresh rate transitions should be
+ * seamless. A seamless transition does not have any visual interruptions, such as a black
+ * screen for a second or two. Must be either [CHANGE_FRAME_RATE_ALWAYS] or
+ * [CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS]. This parameter is only supported on Android S and
+ * when [frameRate] is not 0. This is ignored on older Android versions and when [frameRate]
+ * is 0.
+ */
+ fun setFrameRate(
+ surfaceControl: SurfaceControlCompat,
+ frameRate: Float,
+ @FrameRateCompatibility compatibility: Int,
+ @ChangeFrameRateStrategy changeFrameRateStrategy: Int
+ ): Transaction {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ mImpl.setFrameRate(
+ surfaceControl.scImpl,
+ frameRate,
+ compatibility,
+ changeFrameRateStrategy
+ )
+ }
+ return this
+ }
+
+ /**
+ * Clears the frame rate which was set for the surface SurfaceControl.
+ *
+ * This is equivalent to calling [setFrameRate] with 0 for the framerate and
+ * [FRAME_RATE_COMPATIBILITY_DEFAULT]
+ *
+ * Note that this only has an effect for surfaces presented on the display. If this surface
+ * is consumed by something other than the system compositor, e.g. a media codec, this call
+ * has no effect.
+ *
+ * This is only supported on Android R and above. This is ignored on older Android versions.
+ * @param surfaceControl [SurfaceControlCompat] to clear the frame rate
+ */
+ fun clearFrameRate(surfaceControl: SurfaceControlCompat): Transaction {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ mImpl.clearFrameRate(surfaceControl.scImpl)
+ }
+ return this
+ }
+
+ /**
* Sets the desired extended range brightness for the layer. This only applies for layers
* that are displaying [HardwareBuffer] instances with a DataSpace of
* [DataSpace.RANGE_EXTENDED].
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlImpl.kt b/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlImpl.kt
index 3dc97ae..6362285 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlImpl.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlImpl.kt
@@ -328,6 +328,25 @@
): Transaction
/**
+ * See [SurfaceControlCompat.Transaction.setFrameRate]
+ */
+ @RequiresApi(Build.VERSION_CODES.R)
+ fun setFrameRate(
+ scImpl: SurfaceControlImpl,
+ frameRate: Float,
+ compatibility: Int,
+ changeFrameRateStrategy: Int
+ ): Transaction
+
+ /**
+ * See [SurfaceControlCompat.Transaction.clearFrameRate]
+ */
+ @RequiresApi(Build.VERSION_CODES.R)
+ fun clearFrameRate(
+ scImpl: SurfaceControlImpl,
+ ): Transaction
+
+ /**
* Commit the transaction, clearing it's state, and making it usable as a new transaction.
* This will not release any resources and [SurfaceControlImpl.Transaction.close] must be
* called to release the transaction.
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlV29.kt b/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlV29.kt
index 7440f62..8d5a96f 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlV29.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlV29.kt
@@ -28,6 +28,8 @@
import androidx.graphics.lowlatency.FrontBufferUtils
import androidx.graphics.surface.SurfaceControlCompat.Companion.BUFFER_TRANSFORM_ROTATE_270
import androidx.graphics.surface.SurfaceControlCompat.Companion.BUFFER_TRANSFORM_ROTATE_90
+import androidx.graphics.surface.SurfaceControlCompat.Companion.CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
+import androidx.graphics.surface.SurfaceControlCompat.Companion.FRAME_RATE_COMPATIBILITY_DEFAULT
import androidx.hardware.SyncFenceCompat
import androidx.hardware.SyncFenceImpl
import androidx.hardware.SyncFenceV19
@@ -401,6 +403,37 @@
}
/**
+ * See [SurfaceControlCompat.Transaction.setFrameRate]
+ */
+ override fun setFrameRate(
+ scImpl: SurfaceControlImpl,
+ frameRate: Float,
+ compatibility: Int,
+ changeFrameRateStrategy: Int
+ ): Transaction {
+ transaction.setFrameRate(
+ scImpl.asWrapperSurfaceControl(),
+ frameRate,
+ compatibility,
+ changeFrameRateStrategy
+ )
+ return this
+ }
+
+ /**
+ * See [SurfaceControlCompat.Transaction.clearFrameRate]
+ */
+ override fun clearFrameRate(scImpl: SurfaceControlImpl): SurfaceControlImpl.Transaction {
+ setFrameRate(
+ scImpl,
+ 0f,
+ FRAME_RATE_COMPATIBILITY_DEFAULT,
+ CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
+ )
+ return this
+ }
+
+ /**
* See [SurfaceControlWrapper.Transaction.close]
*/
override fun close() {
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlV33.kt b/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlV33.kt
index 6633e744..6ea12ea 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlV33.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlV33.kt
@@ -305,6 +305,41 @@
return this
}
+ override fun setFrameRate(
+ scImpl: SurfaceControlImpl,
+ frameRate: Float,
+ compatibility: Int,
+ changeFrameRateStrategy: Int
+ ): Transaction {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ SurfaceControlVerificationHelperV31.setFrameRate(
+ mTransaction,
+ scImpl.asFrameworkSurfaceControl(),
+ frameRate,
+ compatibility,
+ changeFrameRateStrategy
+ )
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ SurfaceControlVerificationHelperV30.setFrameRate(
+ mTransaction,
+ scImpl.asFrameworkSurfaceControl(),
+ frameRate,
+ compatibility
+ )
+ }
+ return this
+ }
+
+ override fun clearFrameRate(scImpl: SurfaceControlImpl): SurfaceControlImpl.Transaction {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ SurfaceControlVerificationHelperV34.clearFrameRate(
+ mTransaction,
+ scImpl.asFrameworkSurfaceControl()
+ )
+ }
+ return this
+ }
+
/**
* See [SurfaceControlImpl.Transaction.commit]
*/
@@ -367,3 +402,42 @@
transaction.setDataSpace(surfaceControl, dataspace)
}
}
+
+@RequiresApi(Build.VERSION_CODES.S)
+private object SurfaceControlVerificationHelperV31 {
+ @androidx.annotation.DoNotInline
+ fun setFrameRate(
+ transaction: Transaction,
+ surfaceControl: SurfaceControl,
+ frameRate: Float,
+ compatibility: Int,
+ strategy: Int
+ ) {
+ transaction.setFrameRate(surfaceControl, frameRate, compatibility, strategy)
+ }
+}
+
+@RequiresApi(Build.VERSION_CODES.R)
+private object SurfaceControlVerificationHelperV30 {
+ @androidx.annotation.DoNotInline
+ fun setFrameRate(
+ transaction: Transaction,
+ surfaceControl: SurfaceControl,
+ frameRate: Float,
+ compatibility: Int
+ ) {
+ transaction.setFrameRate(surfaceControl, frameRate, compatibility)
+ }
+}
+
+@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+private object SurfaceControlVerificationHelperV34 {
+
+ @androidx.annotation.DoNotInline
+ fun clearFrameRate(
+ transaction: Transaction,
+ surfaceControl: SurfaceControl
+ ) {
+ transaction.clearFrameRate(surfaceControl)
+ }
+}
diff --git a/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlWrapper.kt b/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlWrapper.kt
index 2459469..6c6b44c 100644
--- a/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlWrapper.kt
+++ b/graphics/graphics-core/src/main/java/androidx/graphics/surface/SurfaceControlWrapper.kt
@@ -192,6 +192,16 @@
@JniVisible
external fun nGetPreviousReleaseFenceFd(surfaceControl: Long, transactionStats: Long): Int
+ @JvmStatic
+ @JniVisible
+ external fun nSetFrameRate(
+ surfaceTransaction: Long,
+ surfaceControl: Long,
+ frameRate: Float,
+ compatibility: Int,
+ changeFrameRateStrategy: Int
+ )
+
init {
System.loadLibrary("graphics-core")
}
@@ -658,6 +668,22 @@
return this
}
+ fun setFrameRate(
+ surfaceControl: SurfaceControlWrapper,
+ frameRate: Float,
+ compatibility: Int,
+ changeFrameRateStrategy: Int
+ ): Transaction {
+ JniBindings.nSetFrameRate(
+ mNativeSurfaceTransaction,
+ surfaceControl.mNativeSurfaceControl,
+ frameRate,
+ compatibility,
+ changeFrameRateStrategy
+ )
+ return this
+ }
+
/**
* Destroys the transaction object.
*/