@@ -40,6 +40,7 @@ class FpsManagerTest {
4040 pauseHandler()
4141 idleHandler(vsyncCount = 10 ) {
4242 assert (fpsManager.preRender(it))
43+ fpsManager.postRender()
4344 }
4445 }
4546
@@ -50,6 +51,7 @@ class FpsManagerTest {
5051 val frameRenderedPattern = mutableListOf<Boolean >()
5152 idleHandler(vsyncCount = 10 ) {
5253 frameRenderedPattern.add(fpsManager.preRender(it))
54+ fpsManager.postRender()
5355 }
5456 Assert .assertArrayEquals(
5557 arrayOf(
@@ -68,6 +70,7 @@ class FpsManagerTest {
6870 val frameRenderedPattern = mutableListOf<Boolean >()
6971 idleHandler(vsyncCount = vsyncCount) {
7072 frameRenderedPattern.add(fpsManager.preRender(it))
73+ fpsManager.postRender()
7174 }
7275 Assert .assertArrayEquals(
7376 Array (vsyncCount) { it == 8 || it == 17 },
@@ -83,6 +86,7 @@ class FpsManagerTest {
8386 val frameRenderedPattern = mutableListOf<Boolean >()
8487 idleHandler(vsyncCount = vsyncCount) {
8588 frameRenderedPattern.add(fpsManager.preRender(it))
89+ fpsManager.postRender()
8690 }
8791 Assert .assertArrayEquals(
8892 // 6 frames should be rendered in total during 2 seconds with 3 FPS
@@ -99,6 +103,7 @@ class FpsManagerTest {
99103 val frameRenderedPattern = mutableListOf<Boolean >()
100104 idleHandler(vsyncCount = vsyncCount) {
101105 frameRenderedPattern.add(fpsManager.preRender(it))
106+ fpsManager.postRender()
102107 }
103108 Assert .assertArrayEquals(
104109 Array (vsyncCount) { it == 59 || it == 119 },
@@ -114,11 +119,97 @@ class FpsManagerTest {
114119 val frameRenderedPattern = mutableListOf<Boolean >()
115120 idleHandler(vsyncCount = vsyncCount) {
116121 frameRenderedPattern.add(fpsManager.preRender(it))
122+ fpsManager.postRender()
123+ }
124+ Assert .assertArrayEquals(
125+ Array (vsyncCount) { true },
126+ frameRenderedPattern.toTypedArray()
127+ )
128+ }
129+
130+ @Test
131+ fun userRefreshRateSameAsScreenRefreshRateTest () {
132+ fpsManager.setUserRefreshRate(SCREEN_FPS )
133+ pauseHandler()
134+ val frameRenderedPattern = mutableListOf<Boolean >()
135+ idleHandler(vsyncCount = 5 * SCREEN_FPS ) {
136+ frameRenderedPattern.add(fpsManager.preRender(it))
137+ fpsManager.postRender()
138+ }
139+ Assert .assertArrayEquals(
140+ Array (5 * SCREEN_FPS ) { true },
141+ frameRenderedPattern.toTypedArray()
142+ )
143+ }
144+
145+ @Test
146+ fun `user refresh rate changes mid render with listener` () {
147+ val fpsValueArray = mutableListOf<Double >()
148+ val fpsChangedListener = OnFpsChangedListener {
149+ fpsValueArray.add(it)
150+ }
151+ fpsManager.fpsChangedListener = fpsChangedListener
152+ pauseHandler()
153+ val frameRenderedPattern = mutableListOf<Boolean >()
154+ val vsyncCount = 90
155+
156+ // First set user refresh rate to be the same as screen refresh rate
157+ fpsManager.setUserRefreshRate(SCREEN_FPS )
158+ idleHandler(vsyncCount = vsyncCount) {
159+ frameRenderedPattern.add(fpsManager.preRender(it))
160+ fpsManager.postRender()
117161 }
118162 Assert .assertArrayEquals(
119163 Array (vsyncCount) { true },
120164 frameRenderedPattern.toTypedArray()
121165 )
166+ Assert .assertEquals(1 , fpsValueArray.size)
167+ Assert .assertEquals(SCREEN_FPS .toDouble(), fpsValueArray.last(), EPS )
168+
169+ frameRenderedPattern.clear()
170+
171+ // Now change the user refresh ratio to be half of the screen refresh rate
172+ fpsManager.setUserRefreshRate(SCREEN_FPS / 2 )
173+ // That triggers a new listener with the FPS value for the remaining 30 frames out of the 90 above
174+ Assert .assertEquals(2 , fpsValueArray.size)
175+ Assert .assertEquals(SCREEN_FPS .toDouble(), fpsValueArray.last(), EPS )
176+
177+ // Now render vsyncCount frames with the new user refresh rate
178+ idleHandler(vsyncCount = vsyncCount) {
179+ frameRenderedPattern.add(fpsManager.preRender(it))
180+ fpsManager.postRender()
181+ }
182+ Assert .assertArrayEquals(
183+ // We expect every other frame to be rendered (user SCREEN_FPS/2 FPS)
184+ Array (vsyncCount) { it % 2 != 0 },
185+ frameRenderedPattern.toTypedArray()
186+ )
187+ Assert .assertEquals(3 , fpsValueArray.size)
188+ Assert .assertEquals(SCREEN_FPS / 2.0 , fpsValueArray.last(), EPS )
189+
190+ frameRenderedPattern.clear()
191+
192+ // Reset user refresh rate to be the same as screen one
193+ fpsManager.setUserRefreshRate(SCREEN_FPS )
194+ // That triggers a new listener with the FPS value for the remaining 30 frames out of the 90 above
195+ Assert .assertEquals(4 , fpsValueArray.size)
196+ Assert .assertEquals(SCREEN_FPS / 2.0 , fpsValueArray.last(), EPS )
197+
198+ idleHandler(vsyncCount = vsyncCount) {
199+ frameRenderedPattern.add(fpsManager.preRender(it))
200+ fpsManager.postRender()
201+ }
202+ Assert .assertArrayEquals(
203+ Array (vsyncCount) { true },
204+ frameRenderedPattern.toTypedArray()
205+ )
206+ Assert .assertEquals(5 , fpsValueArray.size)
207+ Assert .assertEquals(SCREEN_FPS .toDouble(), fpsValueArray.last(), EPS )
208+
209+ fpsManager.onSurfaceDestroyed()
210+ // One last FPS value for the remaining 30 frames out of the 90 above
211+ Assert .assertEquals(6 , fpsValueArray.size)
212+ Assert .assertEquals(SCREEN_FPS .toDouble(), fpsValueArray.last(), EPS )
122213 }
123214
124215 @Test
@@ -184,12 +275,11 @@ class FpsManagerTest {
184275 private fun pauseHandler () = Shadows .shadowOf(Looper .getMainLooper()).pause()
185276
186277 private fun idleHandler (vsyncCount : Int , actionOnVsync : ((Long ) -> Unit )) {
187- for (i in 0 until vsyncCount) {
188- Choreographer .getInstance().postFrameCallback { frameTimeNs ->
189- actionOnVsync.invoke(frameTimeNs)
190- }
191- Shadows .shadowOf(Looper .getMainLooper())
192- .idleFor(CHOREOGRAPHER_POST_FRAME_CALLBACK_DELAY_MS .toLong(), TimeUnit .MILLISECONDS )
278+ val choreographer = Choreographer .getInstance()
279+ val looper = Shadows .shadowOf(Looper .getMainLooper())
280+ repeat(vsyncCount) {
281+ choreographer.postFrameCallback(actionOnVsync)
282+ looper.idleFor(CHOREOGRAPHER_POST_FRAME_CALLBACK_DELAY_MS .toLong(), TimeUnit .MILLISECONDS )
193283 }
194284 }
195285
0 commit comments