diff --git a/core/api/current.txt b/core/api/current.txt index 629bfe9fa269a..ba52ccae153d8 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -52173,6 +52173,7 @@ package android.view { method public android.graphics.Canvas lockHardwareCanvas(); method public void readFromParcel(android.os.Parcel); method public void release(); + method public void setFrameRate(@FloatRange(from=0.0) float, int, boolean); method public void setFrameRate(@FloatRange(from=0.0) float, int); method @Deprecated public void unlockCanvas(android.graphics.Canvas); method public void unlockCanvasAndPost(android.graphics.Canvas); @@ -52220,6 +52221,7 @@ package android.view { method @NonNull public android.view.SurfaceControl.Transaction setAlpha(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0, to=1.0) float); method @NonNull public android.view.SurfaceControl.Transaction setBufferSize(@NonNull android.view.SurfaceControl, @IntRange(from=0) int, @IntRange(from=0) int); method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float, int); + method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float, int, boolean); method @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int); method @NonNull public android.view.SurfaceControl.Transaction setLayer(@NonNull android.view.SurfaceControl, @IntRange(from=java.lang.Integer.MIN_VALUE, to=java.lang.Integer.MAX_VALUE) int); method @NonNull public android.view.SurfaceControl.Transaction setVisibility(@NonNull android.view.SurfaceControl, boolean); diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 5b79174a6cd81..a2777fe985d50 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -97,7 +97,7 @@ public class Surface implements Parcelable { private static native int nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled); private static native int nativeSetFrameRate( - long nativeObject, float frameRate, int compatibility); + long nativeObject, float frameRate, int compatibility, boolean shouldBeSeamless); public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { @@ -915,13 +915,20 @@ public class Surface implements Parcelable { * compatibility value may influence the system's choice of display frame rate. See * the FRAME_RATE_COMPATIBILITY_* values for more info. * + * @param shouldBeSeamless Whether display refresh rate transitions should be seamless. A + * seamless transition is one that doesn't have any visual interruptions, such as a black + * screen for a second or two. True indicates that any frame rate changes caused by this + * request should be seamless. False indicates that non-seamless refresh rates are also + * acceptable. + * * @throws IllegalArgumentException If frameRate or compatibility are invalid. */ - public void setFrameRate( - @FloatRange(from = 0.0) float frameRate, @FrameRateCompatibility int compatibility) { + public void setFrameRate(@FloatRange(from = 0.0) float frameRate, + @FrameRateCompatibility int compatibility, boolean shouldBeSeamless) { synchronized (mLock) { checkNotReleasedLocked(); - int error = nativeSetFrameRate(mNativeObject, frameRate, compatibility); + int error = nativeSetFrameRate(mNativeObject, frameRate, compatibility, + shouldBeSeamless); if (error == -EINVAL) { throw new IllegalArgumentException("Invalid argument to Surface.setFrameRate()"); } else if (error != 0) { @@ -930,6 +937,17 @@ public class Surface implements Parcelable { } } + /** + * Sets the intended frame rate for this surface. Any switching of refresh rates is + * most probably going to be seamless. + * + * @see #setFrameRate(float, int, boolean) + */ + public void setFrameRate( + @FloatRange(from = 0.0) float frameRate, @FrameRateCompatibility int compatibility) { + setFrameRate(frameRate, compatibility, /* shouldBeSeamless = */ true); + } + /** * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or * when a SurfaceTexture could not successfully be allocated. diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index af31b817d5202..d7ee6ad151669 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -212,8 +212,8 @@ public final class SurfaceControl implements Parcelable { private static native void nativeSetGlobalShadowSettings(@Size(4) float[] ambientColor, @Size(4) float[] spotColor, float lightPosY, float lightPosZ, float lightRadius); - private static native void nativeSetFrameRate( - long transactionObj, long nativeObject, float frameRate, int compatibility); + private static native void nativeSetFrameRate(long transactionObj, long nativeObject, + float frameRate, int compatibility, boolean shouldBeSeamless); private static native long nativeGetHandle(long nativeObject); private static native long nativeAcquireFrameRateFlexibilityToken(); @@ -3255,6 +3255,19 @@ public final class SurfaceControl implements Parcelable { return this; } + /** + * Sets the intended frame rate for this surface. Any switching of refresh rates is + * most probably going to be seamless. + * + * @see #setFrameRate(SurfaceControl, float, int, boolean) + */ + @NonNull + public Transaction setFrameRate(@NonNull SurfaceControl sc, + @FloatRange(from = 0.0) float frameRate, + @Surface.FrameRateCompatibility int compatibility) { + return setFrameRate(sc, frameRate, compatibility, /*shouldBeSeamless*/ true); + } + /** * Sets the intended frame rate for the surface {@link SurfaceControl}. *

@@ -3275,14 +3288,22 @@ public final class SurfaceControl implements Parcelable { * @param compatibility The frame rate compatibility of this surface. The compatibility * value may influence the system's choice of display frame rate. See * the Surface.FRAME_RATE_COMPATIBILITY_* values for more info. + * @param shouldBeSeamless Whether display refresh rate transitions should be seamless. A + * seamless transition is one that doesn't have any visual + * interruptions, such as a black screen for a second or two. True + * indicates that any frame rate changes caused by this request + * should be seamless. False indicates that non-seamless refresh + * rates are also acceptable. * @return This transaction object. */ @NonNull public Transaction setFrameRate(@NonNull SurfaceControl sc, @FloatRange(from = 0.0) float frameRate, - @Surface.FrameRateCompatibility int compatibility) { + @Surface.FrameRateCompatibility int compatibility, + boolean shouldBeSeamless) { checkPreconditions(sc); - nativeSetFrameRate(mNativeObject, sc.mNativeObject, frameRate, compatibility); + nativeSetFrameRate(mNativeObject, sc.mNativeObject, frameRate, compatibility, + shouldBeSeamless); return this; } diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 3a1ccd9de79e7..5b29f0bb89326 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -438,14 +438,15 @@ static jint nativeSetAutoRefreshEnabled(JNIEnv* env, jclass clazz, jlong nativeO } static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat frameRate, - jint compatibility) { + jint compatibility, jboolean shouldBeSeamless) { Surface* surface = reinterpret_cast(nativeObject); ANativeWindow* anw = static_cast(surface); // Our compatibility is a Surface.FRAME_RATE_COMPATIBILITY_* value, and // NATIVE_WINDOW_SET_FRAME_RATE takes an // ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value. The values are identical // though, so no need to explicitly convert. - return anw->perform(surface, NATIVE_WINDOW_SET_FRAME_RATE, float(frameRate), compatibility); + return anw->perform(surface, NATIVE_WINDOW_SET_FRAME_RATE, double(frameRate), compatibility, + int(shouldBeSeamless)); } // ---------------------------------------------------------------------------- @@ -474,7 +475,7 @@ static const JNINativeMethod gSurfaceMethods[] = { (void*)nativeAttachAndQueueBufferWithColorSpace}, {"nativeSetSharedBufferModeEnabled", "(JZ)I", (void*)nativeSetSharedBufferModeEnabled}, {"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled}, - {"nativeSetFrameRate", "(JFI)I", (void*)nativeSetFrameRate}, + {"nativeSetFrameRate", "(JFIZ)I", (void*)nativeSetFrameRate}, {"nativeGetFromBlastBufferQueue", "(JJ)J", (void*)nativeGetFromBlastBufferQueue}, }; diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index f1ec85a8570fb..6ec656c167904 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -738,14 +738,15 @@ static void nativeSetShadowRadius(JNIEnv* env, jclass clazz, jlong transactionOb } static void nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject, - jfloat frameRate, jint compatibility) { + jfloat frameRate, jint compatibility, jboolean shouldBeSeamless) { auto transaction = reinterpret_cast(transactionObj); const auto ctrl = reinterpret_cast(nativeObject); // Our compatibility is a Surface.FRAME_RATE_COMPATIBILITY_* value, and // Transaction::setFrameRate() takes an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value. The // values are identical though, so no need to convert anything. - transaction->setFrameRate(ctrl, frameRate, static_cast(compatibility)); + transaction->setFrameRate(ctrl, frameRate, static_cast(compatibility), + bool(shouldBeSeamless)); } static jlong nativeAcquireFrameRateFlexibilityToken(JNIEnv* env, jclass clazz) { @@ -1668,7 +1669,7 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSetBlurRegions }, {"nativeSetShadowRadius", "(JJF)V", (void*)nativeSetShadowRadius }, - {"nativeSetFrameRate", "(JJFI)V", + {"nativeSetFrameRate", "(JJFIZ)V", (void*)nativeSetFrameRate }, {"nativeAcquireFrameRateFlexibilityToken", "()J", (void*)nativeAcquireFrameRateFlexibilityToken }, diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index 3027eac3a2248..d134b37c6b706 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -247,6 +247,7 @@ LIBANDROID { ASurfaceTransaction_setDamageRegion; # introduced=29 ASurfaceTransaction_setDesiredPresentTime; # introduced=29 ASurfaceTransaction_setFrameRate; # introduced=30 + ASurfaceTransaction_setFrameRateWithSeamlessness; # introduced=31 ASurfaceTransaction_setGeometry; # introduced=29 ASurfaceTransaction_setHdrMetadata_cta861_3; # introduced=29 ASurfaceTransaction_setHdrMetadata_smpte2086; # introduced=29 diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp index c503721319fb1..189be800e0189 100644 --- a/native/android/surface_control.cpp +++ b/native/android/surface_control.cpp @@ -560,9 +560,18 @@ void ASurfaceTransaction_setColor(ASurfaceTransaction* aSurfaceTransaction, void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl, float frameRate, int8_t compatibility) { + ASurfaceTransaction_setFrameRateWithSeamlessness(aSurfaceTransaction, aSurfaceControl, + frameRate, compatibility, + /*shouldBeSeamless*/ true); +} + +void ASurfaceTransaction_setFrameRateWithSeamlessness(ASurfaceTransaction* aSurfaceTransaction, + ASurfaceControl* aSurfaceControl, + float frameRate, int8_t compatibility, + bool shouldBeSeamless) { CHECK_NOT_NULL(aSurfaceTransaction); CHECK_NOT_NULL(aSurfaceControl); Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); sp surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); - transaction->setFrameRate(surfaceControl, frameRate, compatibility); + transaction->setFrameRate(surfaceControl, frameRate, compatibility, shouldBeSeamless); }