setFrameRate: Make shouldBeSeamless an enum

Change the shouldBeSeamless parameter to an enum
in order to make the API easier to understand.

This changes
 - SurfaceControl.setFrameRate
 - Surface.setFrameRate
 - ANativeWindow_setFrameRateWithChangeStrategy
 - ASurfaceTransaction_setFrameRateWithChangeStrategy

Bug: 179116474
Test: atest SetFrameRateTest
Change-Id: I55265399238e2c95fbb90fd33a4c2513d1fc5cec
diff --git a/core/api/current.txt b/core/api/current.txt
index 4aa38d6..5d05f4f 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -47801,11 +47801,13 @@
     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, int);
     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);
     method public void writeToParcel(android.os.Parcel, int);
+    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 @NonNull public static final android.os.Parcelable.Creator<android.view.Surface> CREATOR;
     field public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0; // 0x0
     field public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; // 0x1
@@ -47849,7 +47851,7 @@
     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 setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float, int, int);
     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 f8c4d15..aa3c9d6 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -97,7 +97,7 @@
     private static native int nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled);
 
     private static native int nativeSetFrameRate(
-            long nativeObject, float frameRate, int compatibility, boolean shouldBeSeamless);
+            long nativeObject, float frameRate, int compatibility, int changeFrameRateStrategy);
 
     public static final @android.annotation.NonNull Parcelable.Creator<Surface> CREATOR =
             new Parcelable.Creator<Surface>() {
@@ -226,6 +226,26 @@
      */
     public static final int FRAME_RATE_COMPATIBILITY_EXACT = 100;
 
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"CHANGE_FRAME_RATE_"},
+            value = {CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, CHANGE_FRAME_RATE_ALWAYS})
+    public @interface ChangeFrameRateStrategy {}
+
+    /**
+     * Change the frame rate only if the transition is going to be seamless.
+     */
+    public static final int 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. Non-seamless switches might be used when the benefit of matching
+     * the content's frame rate outweighs the cost of the transition, for example when
+     * displaying long-running video content.
+     */
+    public static final int CHANGE_FRAME_RATE_ALWAYS = 1;
+
     /**
      * Create an empty surface, which will later be filled in by readFromParcel().
      * @hide
@@ -921,25 +941,21 @@
      * 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. See
-     * the FRAME_RATE_COMPATIBILITY_* values for more info.
+     * compatibility value may influence the system's choice of display frame rate.
      *
-     * @param shouldBeSeamless Whether display refresh rate transitions should be seamless. A
+     * @param changeFrameRateStrategy 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. Non-seamless switches might be used when the benefit of matching the content's
-     * frame rate outweighs the cost of the transition, for example when displaying
-     * long-running video content.
+     * screen for a second or two.
      *
      * @throws IllegalArgumentException If frameRate or compatibility are invalid.
      */
     public void setFrameRate(@FloatRange(from = 0.0) float frameRate,
-            @FrameRateCompatibility int compatibility, boolean shouldBeSeamless) {
+            @FrameRateCompatibility int compatibility,
+            @ChangeFrameRateStrategy int changeFrameRateStrategy) {
         synchronized (mLock) {
             checkNotReleasedLocked();
             int error = nativeSetFrameRate(mNativeObject, frameRate, compatibility,
-                    shouldBeSeamless);
+                    changeFrameRateStrategy);
             if (error == -EINVAL) {
                 throw new IllegalArgumentException("Invalid argument to Surface.setFrameRate()");
             } else if (error != 0) {
@@ -952,11 +968,11 @@
      * 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)
+     * @see #setFrameRate(float, int, int)
      */
     public void setFrameRate(
             @FloatRange(from = 0.0) float frameRate, @FrameRateCompatibility int compatibility) {
-        setFrameRate(frameRate, compatibility, /* shouldBeSeamless = */ true);
+        setFrameRate(frameRate, compatibility, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
     }
 
     /**
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 03dd100..dd470e5 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -209,7 +209,7 @@
             @Size(4) float[] spotColor, float lightPosY, float lightPosZ, float lightRadius);
 
     private static native void nativeSetFrameRate(long transactionObj, long nativeObject,
-            float frameRate, int compatibility, boolean shouldBeSeamless);
+            float frameRate, int compatibility, int changeFrameRateStrategy);
     private static native long nativeGetHandle(long nativeObject);
 
     private static native long nativeAcquireFrameRateFlexibilityToken();
@@ -3229,13 +3229,14 @@
          * 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)
+         * @see #setFrameRate(SurfaceControl, float, int, int)
          */
         @NonNull
         public Transaction setFrameRate(@NonNull SurfaceControl sc,
                 @FloatRange(from = 0.0) float frameRate,
                 @Surface.FrameRateCompatibility int compatibility) {
-            return setFrameRate(sc, frameRate, compatibility, /*shouldBeSeamless*/ true);
+            return setFrameRate(sc, frameRate, compatibility,
+                    Surface.CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
         }
 
         /**
@@ -3256,27 +3257,21 @@
          *                  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. 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. Non-seamless switches might be
-         *                         used when the benefit of matching the content's frame rate
-         *                         outweighs the cost of the transition, for example when
-         *                         displaying long-running video content.
+         *                      value may influence the system's choice of display frame rate.
+         * @param changeFrameRateStrategy 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.
          * @return This transaction object.
          */
         @NonNull
         public Transaction setFrameRate(@NonNull SurfaceControl sc,
                 @FloatRange(from = 0.0) float frameRate,
                 @Surface.FrameRateCompatibility int compatibility,
-                boolean shouldBeSeamless) {
+                @Surface.ChangeFrameRateStrategy int changeFrameRateStrategy) {
             checkPreconditions(sc);
             nativeSetFrameRate(mNativeObject, sc.mNativeObject, frameRate, compatibility,
-                    shouldBeSeamless);
+                    changeFrameRateStrategy);
             return this;
         }
 
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 5b29f0b..0957067 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -438,7 +438,7 @@
 }
 
 static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat frameRate,
-                               jint compatibility, jboolean shouldBeSeamless) {
+                               jint compatibility, jint changeFrameRateStrategy) {
     Surface* surface = reinterpret_cast<Surface*>(nativeObject);
     ANativeWindow* anw = static_cast<ANativeWindow*>(surface);
     // Our compatibility is a Surface.FRAME_RATE_COMPATIBILITY_* value, and
@@ -446,7 +446,7 @@
     // 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, double(frameRate), compatibility,
-                        int(shouldBeSeamless));
+                        int(changeFrameRateStrategy));
 }
 
 // ----------------------------------------------------------------------------
@@ -475,7 +475,7 @@
          (void*)nativeAttachAndQueueBufferWithColorSpace},
         {"nativeSetSharedBufferModeEnabled", "(JZ)I", (void*)nativeSetSharedBufferModeEnabled},
         {"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled},
-        {"nativeSetFrameRate", "(JFIZ)I", (void*)nativeSetFrameRate},
+        {"nativeSetFrameRate", "(JFII)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 31cc77f..b10c80a 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -782,7 +782,7 @@
 }
 
 static void nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
-                               jfloat frameRate, jint compatibility, jboolean shouldBeSeamless) {
+                               jfloat frameRate, jint compatibility, jint changeFrameRateStrategy) {
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
 
     const auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
@@ -790,7 +790,7 @@
     // 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<int8_t>(compatibility),
-                              bool(shouldBeSeamless));
+                              static_cast<int8_t>(changeFrameRateStrategy));
 }
 
 static jlong nativeAcquireFrameRateFlexibilityToken(JNIEnv* env, jclass clazz) {
@@ -1775,7 +1775,7 @@
             (void*) nativeSetStretchEffect },
     {"nativeSetShadowRadius", "(JJF)V",
             (void*)nativeSetShadowRadius },
-    {"nativeSetFrameRate", "(JJFIZ)V",
+    {"nativeSetFrameRate", "(JJFII)V",
             (void*)nativeSetFrameRate },
     {"nativeAcquireFrameRateFlexibilityToken", "()J",
             (void*)nativeAcquireFrameRateFlexibilityToken },
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index b01878b..1de6221 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -253,7 +253,7 @@
     ASurfaceTransaction_setDamageRegion; # introduced=29
     ASurfaceTransaction_setDesiredPresentTime; # introduced=29
     ASurfaceTransaction_setFrameRate; # introduced=30
-    ASurfaceTransaction_setFrameRateWithSeamlessness; # introduced=31
+    ASurfaceTransaction_setFrameRateWithChangeStrategy; # 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 e8cf63f..6c12c43 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -596,24 +596,25 @@
     color.g = g;
     color.b = b;
 
-    transaction->setBackgroundColor(surfaceControl, color, alpha, static_cast<ui::Dataspace>(dataspace));
+    transaction->setBackgroundColor(surfaceControl, color, alpha,
+                                    static_cast<ui::Dataspace>(dataspace));
 }
 
 void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* aSurfaceTransaction,
                                       ASurfaceControl* aSurfaceControl, float frameRate,
                                       int8_t compatibility) {
-    ASurfaceTransaction_setFrameRateWithSeamlessness(aSurfaceTransaction, aSurfaceControl,
-                                                     frameRate, compatibility,
-                                                     /*shouldBeSeamless*/ true);
+    ASurfaceTransaction_setFrameRateWithChangeStrategy(
+            aSurfaceTransaction, aSurfaceControl, frameRate, compatibility,
+            ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
 }
 
-void ASurfaceTransaction_setFrameRateWithSeamlessness(ASurfaceTransaction* aSurfaceTransaction,
-                                                      ASurfaceControl* aSurfaceControl,
-                                                      float frameRate, int8_t compatibility,
-                                                      bool shouldBeSeamless) {
+void ASurfaceTransaction_setFrameRateWithChangeStrategy(ASurfaceTransaction* aSurfaceTransaction,
+                                                        ASurfaceControl* aSurfaceControl,
+                                                        float frameRate, int8_t compatibility,
+                                                        int8_t changeFrameRateStrategy) {
     CHECK_NOT_NULL(aSurfaceTransaction);
     CHECK_NOT_NULL(aSurfaceControl);
     Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
     sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
-    transaction->setFrameRate(surfaceControl, frameRate, compatibility, shouldBeSeamless);
+    transaction->setFrameRate(surfaceControl, frameRate, compatibility, changeFrameRateStrategy);
 }